summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig8
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/glue.c2
-rw-r--r--drivers/acpi/pci_link.c12
-rw-r--r--drivers/acpi/power.c9
-rw-r--r--drivers/acpi/scan.c4
-rw-r--r--drivers/acpi/sleep.c8
-rw-r--r--drivers/acpi/utils.c30
-rw-r--r--drivers/amba/bus.c53
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ata_generic.c2
-rw-r--r--drivers/ata/ata_piix.c36
-rw-r--r--drivers/ata/libata-core.c7
-rw-r--r--drivers/ata/libata-eh.c24
-rw-r--r--drivers/ata/pata_ep93xx.c1044
-rw-r--r--drivers/base/bus.c3
-rw-r--r--drivers/base/core.c58
-rw-r--r--drivers/base/cpu.c4
-rw-r--r--drivers/base/devres.c35
-rw-r--r--drivers/base/devtmpfs.c6
-rw-r--r--drivers/base/dma-buf.c12
-rw-r--r--drivers/base/driver.c2
-rw-r--r--drivers/base/power/domain.c176
-rw-r--r--drivers/base/power/domain_governor.c166
-rw-r--r--drivers/base/power/main.c10
-rw-r--r--drivers/base/power/qos.c19
-rw-r--r--drivers/base/power/runtime.c103
-rw-r--r--drivers/base/power/sysfs.c54
-rw-r--r--drivers/base/power/wakeup.c174
-rw-r--r--drivers/base/regmap/Kconfig4
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/internal.h26
-rw-r--r--drivers/base/regmap/regcache-lzo.c11
-rw-r--r--drivers/base/regmap/regcache-rbtree.c44
-rw-r--r--drivers/base/regmap/regcache.c34
-rw-r--r--drivers/base/regmap/regmap-debugfs.c18
-rw-r--r--drivers/base/regmap/regmap-i2c.c13
-rw-r--r--drivers/base/regmap/regmap-irq.c184
-rw-r--r--drivers/base/regmap/regmap-mmio.c224
-rw-r--r--drivers/base/regmap/regmap-spi.c13
-rw-r--r--drivers/base/regmap/regmap.c276
-rw-r--r--drivers/bcma/scan.c19
-rw-r--r--drivers/block/DAC960.c23
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c4
-rw-r--r--drivers/block/virtio_blk.c21
-rw-r--r--drivers/bluetooth/ath3k.c1
-rw-r--r--drivers/bluetooth/bcm203x.c1
-rw-r--r--drivers/bluetooth/bfusb.c1
-rw-r--r--drivers/bluetooth/bpa10x.c1
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/hw_random/Kconfig17
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/omap-rng.c22
-rw-r--r--drivers/char/hw_random/pseries-rng.c96
-rw-r--r--drivers/char/mem.c42
-rw-r--r--drivers/char/ramoops.c250
-rw-r--r--drivers/char/virtio_console.c7
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c30
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.h2
-rw-r--r--drivers/clk/clkdev.c142
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c2
-rw-r--r--drivers/cpuidle/cpuidle.c13
-rw-r--r--drivers/crypto/Kconfig30
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c2
-rw-r--r--drivers/crypto/caam/caamalg.c14
-rw-r--r--drivers/crypto/caam/ctrl.c16
-rw-r--r--drivers/crypto/nx/Makefile11
-rw-r--r--drivers/crypto/nx/nx-aes-cbc.c141
-rw-r--r--drivers/crypto/nx/nx-aes-ccm.c468
-rw-r--r--drivers/crypto/nx/nx-aes-ctr.c178
-rw-r--r--drivers/crypto/nx/nx-aes-ecb.c139
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c353
-rw-r--r--drivers/crypto/nx/nx-aes-xcbc.c236
-rw-r--r--drivers/crypto/nx/nx-sha256.c246
-rw-r--r--drivers/crypto/nx/nx-sha512.c265
-rw-r--r--drivers/crypto/nx/nx.c716
-rw-r--r--drivers/crypto/nx/nx.h193
-rw-r--r--drivers/crypto/nx/nx_csbcpb.h205
-rw-r--r--drivers/crypto/nx/nx_debugfs.c103
-rw-r--r--drivers/crypto/ux500/Kconfig30
-rw-r--r--drivers/crypto/ux500/Makefile8
-rw-r--r--drivers/crypto/ux500/cryp/Makefile13
-rw-r--r--drivers/crypto/ux500/cryp/cryp.c389
-rw-r--r--drivers/crypto/ux500/cryp/cryp.h308
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c1784
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irq.c45
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irq.h31
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irqp.h125
-rw-r--r--drivers/crypto/ux500/cryp/cryp_p.h123
-rw-r--r--drivers/crypto/ux500/hash/Makefile11
-rw-r--r--drivers/crypto/ux500/hash/hash_alg.h395
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c2009
-rw-r--r--drivers/devfreq/Kconfig2
-rw-r--r--drivers/devfreq/governor_performance.c7
-rw-r--r--drivers/devfreq/governor_powersave.c7
-rw-r--r--drivers/dma/at_hdmac.c4
-rw-r--r--drivers/dma/ep93xx_dma.c4
-rw-r--r--drivers/dma/pl330.c3
-rw-r--r--drivers/edac/edac_core.h4
-rw-r--r--drivers/edac/edac_device.c8
-rw-r--r--drivers/edac/i7core_edac.c10
-rw-r--r--drivers/edac/sb_edac.c6
-rw-r--r--drivers/extcon/Kconfig32
-rw-r--r--drivers/extcon/Makefile7
-rw-r--r--drivers/extcon/extcon-max8997.c (renamed from drivers/misc/max8997-muic.c)206
-rw-r--r--drivers/extcon/extcon_class.c832
-rw-r--r--drivers/extcon/extcon_gpio.c169
-rw-r--r--drivers/firewire/core-card.c1
-rw-r--r--drivers/firewire/core-transaction.c9
-rw-r--r--drivers/firewire/core.h15
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/devres.c3
-rw-r--r--drivers/gpio/gpio-em.c418
-rw-r--r--drivers/gpio/gpio-pxa.c116
-rw-r--r--drivers/gpio/gpio-tegra.c39
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c2
-rw-r--r--drivers/hid/Kconfig36
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-apple.c5
-rw-r--r--drivers/hid/hid-aureal.c54
-rw-r--r--drivers/hid/hid-core.c316
-rw-r--r--drivers/hid/hid-generic.c53
-rw-r--r--drivers/hid/hid-hyperv.c15
-rw-r--r--drivers/hid/hid-ids.h8
-rw-r--r--drivers/hid/hid-input.c36
-rw-r--r--drivers/hid/hid-lg.c55
-rw-r--r--drivers/hid/hid-lg.h5
-rw-r--r--drivers/hid/hid-lg4ff.c258
-rw-r--r--drivers/hid/hid-logitech-dj.c76
-rw-r--r--drivers/hid/hid-multitouch.c233
-rw-r--r--drivers/hid/hid-uclogic.c141
-rw-r--r--drivers/hid/hid-wacom.c302
-rw-r--r--drivers/hid/hid-waltop.c230
-rw-r--r--drivers/hid/hid-wiimote-core.c16
-rw-r--r--drivers/hid/hidraw.c19
-rw-r--r--drivers/hid/usbhid/hid-core.c146
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hid/usbhid/hiddev.c9
-rw-r--r--drivers/hid/usbhid/usbhid.h1
-rw-r--r--drivers/hid/usbhid/usbmouse.c7
-rw-r--r--drivers/hv/channel_mgmt.c73
-rw-r--r--drivers/hv/hv.c2
-rw-r--r--drivers/hv/hv_kvp.c3
-rw-r--r--drivers/hv/hv_util.c9
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hwmon/Kconfig15
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/acpi_power_meter.c166
-rw-r--r--drivers/hwmon/ad7314.c11
-rw-r--r--drivers/hwmon/fam15h_power.c13
-rw-r--r--drivers/hwmon/ina2xx.c368
-rw-r--r--drivers/hwmon/it87.c384
-rw-r--r--drivers/hwmon/k10temp.c13
-rw-r--r--drivers/hwmon/k8temp.c13
-rw-r--r--drivers/hwmon/ntc_thermistor.c191
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-imx.c8
-rw-r--r--drivers/i2c/busses/i2c-mxs.c6
-rw-r--r--drivers/i2c/busses/i2c-pnx.c157
-rw-r--r--drivers/i2c/busses/i2c-powermac.c98
-rw-r--r--drivers/i2c/busses/i2c-s6000.c2
-rw-r--r--drivers/i2c/busses/i2c-s6000.h2
-rw-r--r--drivers/iio/Kconfig54
-rw-r--r--drivers/iio/Makefile13
-rw-r--r--drivers/iio/adc/Kconfig16
-rw-r--r--drivers/iio/adc/Makefile5
-rw-r--r--drivers/iio/adc/at91_adc.c802
-rw-r--r--drivers/iio/amplifiers/Kconfig17
-rw-r--r--drivers/iio/amplifiers/Makefile5
-rw-r--r--drivers/iio/amplifiers/ad8366.c222
-rw-r--r--drivers/iio/iio_core.h (renamed from drivers/staging/iio/iio_core.h)6
-rw-r--r--drivers/iio/iio_core_trigger.h (renamed from drivers/staging/iio/iio_core_trigger.h)0
-rw-r--r--drivers/iio/industrialio-buffer.c (renamed from drivers/staging/iio/industrialio-buffer.c)91
-rw-r--r--drivers/iio/industrialio-core.c (renamed from drivers/staging/iio/industrialio-core.c)94
-rw-r--r--drivers/iio/industrialio-event.c (renamed from drivers/staging/iio/industrialio-event.c)14
-rw-r--r--drivers/iio/industrialio-trigger.c (renamed from drivers/staging/iio/industrialio-trigger.c)24
-rw-r--r--drivers/iio/inkern.c (renamed from drivers/staging/iio/inkern.c)8
-rw-r--r--drivers/iio/kfifo_buf.c (renamed from drivers/staging/iio/kfifo_buf.c)3
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/Makefile1
-rw-r--r--drivers/infiniband/core/cma.c42
-rw-r--r--drivers/infiniband/core/umem.c2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c108
-rw-r--r--drivers/infiniband/core/verbs.c15
-rw-r--r--drivers/infiniband/hw/cxgb4/Makefile2
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c36
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c340
-rw-r--r--drivers/infiniband/hw/cxgb4/ev.c8
-rw-r--r--drivers/infiniband/hw/cxgb4/id_table.c112
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h134
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c21
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c19
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c105
-rw-r--r--drivers/infiniband/hw/cxgb4/resource.c180
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h24
-rw-r--r--drivers/infiniband/hw/cxgb4/user.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c3
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c13
-rw-r--r--drivers/infiniband/hw/mlx4/main.c104
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h2
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c2
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c54
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c7
-rw-r--r--drivers/infiniband/hw/ocrdma/Kconfig8
-rw-r--r--drivers/infiniband/hw/ocrdma/Makefile5
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h393
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_abi.h134
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c172
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.h42
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c2640
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h132
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c577
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h1672
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c2537
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.h94
-rw-r--r--drivers/infiniband/hw/qib/qib.h35
-rw-r--r--drivers/infiniband/hw/qib/qib_driver.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_mad.c63
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c7
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_ruc.c12
-rw-r--r--drivers/infiniband/hw/qib/qib_sysfs.c7
-rw-r--r--drivers/infiniband/hw/qib/qib_tx.c25
-rw-r--r--drivers/infiniband/hw/qib/qib_uc.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c16
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h145
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c5
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c3
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c10
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c3
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c16
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c18
-rw-r--r--drivers/input/joystick/iforce/iforce.h1
-rw-r--r--drivers/input/joystick/xpad.c35
-rw-r--r--drivers/input/misc/cm109.c33
-rw-r--r--drivers/input/misc/keyspan_remote.c23
-rw-r--r--drivers/input/misc/powermate.c13
-rw-r--r--drivers/input/misc/yealink.c31
-rw-r--r--drivers/input/mouse/appletouch.c59
-rw-r--r--drivers/input/mouse/bcm5974.c24
-rw-r--r--drivers/input/tablet/acecad.c15
-rw-r--r--drivers/input/tablet/aiptek.c28
-rw-r--r--drivers/input/tablet/gtco.c110
-rw-r--r--drivers/input/tablet/kbtab.c15
-rw-r--r--drivers/input/tablet/wacom_sys.c11
-rw-r--r--drivers/input/tablet/wacom_wac.c16
-rw-r--r--drivers/input/touchscreen/Kconfig4
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c77
-rw-r--r--drivers/iommu/Kconfig4
-rw-r--r--drivers/iommu/Makefile2
-rw-r--r--drivers/iommu/dmar.c11
-rw-r--r--drivers/iommu/intel-iommu.c3
-rw-r--r--drivers/iommu/intel_irq_remapping.c (renamed from drivers/iommu/intr_remapping.c)359
-rw-r--r--drivers/iommu/intr_remapping.h17
-rw-r--r--drivers/iommu/irq_remapping.c166
-rw-r--r--drivers/iommu/irq_remapping.h90
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c1
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c1
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c1
-rw-r--r--drivers/isdn/hisax/hfc_usb.c1
-rw-r--r--drivers/isdn/hisax/st5481_init.c1
-rw-r--r--drivers/isdn/i4l/isdn_common.c5
-rw-r--r--drivers/isdn/i4l/isdn_tty.c466
-rw-r--r--drivers/macintosh/Kconfig23
-rw-r--r--drivers/macintosh/Makefile14
-rw-r--r--drivers/macintosh/ams/ams-i2c.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c480
-rw-r--r--drivers/macintosh/windfarm.h51
-rw-r--r--drivers/macintosh/windfarm_ad7417_sensor.c347
-rw-r--r--drivers/macintosh/windfarm_core.c23
-rw-r--r--drivers/macintosh/windfarm_cpufreq_clamp.c6
-rw-r--r--drivers/macintosh/windfarm_fcu_controls.c613
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c135
-rw-r--r--drivers/macintosh/windfarm_lm87_sensor.c201
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c109
-rw-r--r--drivers/macintosh/windfarm_mpu.h105
-rw-r--r--drivers/macintosh/windfarm_pm72.c847
-rw-r--r--drivers/macintosh/windfarm_pm81.c25
-rw-r--r--drivers/macintosh/windfarm_pm91.c33
-rw-r--r--drivers/macintosh/windfarm_rm31.c740
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c1
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c132
-rw-r--r--drivers/md/bitmap.c1100
-rw-r--r--drivers/md/bitmap.h60
-rw-r--r--drivers/md/dm-raid.c22
-rw-r--r--drivers/md/dm-thin.c32
-rw-r--r--drivers/md/md.c372
-rw-r--r--drivers/md/md.h12
-rw-r--r--drivers/md/raid1.c22
-rw-r--r--drivers/md/raid10.c1317
-rw-r--r--drivers/md/raid10.h34
-rw-r--r--drivers/md/raid5.c252
-rw-r--r--drivers/md/raid5.h7
-rw-r--r--drivers/media/video/gspca/ov534_9.c2
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c4
-rw-r--r--drivers/memory/Kconfig43
-rw-r--r--drivers/memory/Makefile7
-rw-r--r--drivers/memory/emif.c1670
-rw-r--r--drivers/memory/emif.h589
-rw-r--r--drivers/memory/tegra20-mc.c257
-rw-r--r--drivers/memory/tegra30-mc.c382
-rw-r--r--drivers/mfd/Kconfig44
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/ab5500-core.c1439
-rw-r--r--drivers/mfd/ab5500-debugfs.c807
-rw-r--r--drivers/mfd/ab5500-debugfs.h22
-rw-r--r--drivers/mfd/da9052-core.c8
-rw-r--r--drivers/mfd/db5500-prcmu.c451
-rw-r--r--drivers/mfd/mc13xxx-core.c3
-rw-r--r--drivers/mfd/palmas.c509
-rw-r--r--drivers/mfd/tps65090.c11
-rw-r--r--drivers/mfd/tps6586x.c86
-rw-r--r--drivers/mfd/tps65911-comparator.c2
-rw-r--r--drivers/mfd/twl-core.c7
-rw-r--r--drivers/mfd/wm8994-irq.c6
-rw-r--r--drivers/misc/Kconfig35
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/ad525x_dpot.c2
-rw-r--r--drivers/misc/bh1780gli.c2
-rw-r--r--drivers/misc/bmp085-i2c.c91
-rw-r--r--drivers/misc/bmp085-spi.c91
-rw-r--r--drivers/misc/bmp085.c356
-rw-r--r--drivers/misc/bmp085.h33
-rw-r--r--drivers/misc/c2port/Kconfig6
-rw-r--r--drivers/misc/eeprom/at25.c19
-rw-r--r--drivers/misc/mei/Kconfig (renamed from drivers/staging/mei/Kconfig)0
-rw-r--r--drivers/misc/mei/Makefile (renamed from drivers/staging/mei/Makefile)0
-rw-r--r--drivers/misc/mei/hw.h (renamed from drivers/staging/mei/hw.h)0
-rw-r--r--drivers/misc/mei/init.c (renamed from drivers/staging/mei/init.c)4
-rw-r--r--drivers/misc/mei/interface.c (renamed from drivers/staging/mei/interface.c)2
-rw-r--r--drivers/misc/mei/interface.h (renamed from drivers/staging/mei/interface.h)5
-rw-r--r--drivers/misc/mei/interrupt.c (renamed from drivers/staging/mei/interrupt.c)2
-rw-r--r--drivers/misc/mei/iorw.c (renamed from drivers/staging/mei/iorw.c)2
-rw-r--r--drivers/misc/mei/main.c (renamed from drivers/staging/mei/main.c)41
-rw-r--r--drivers/misc/mei/mei_dev.h (renamed from drivers/staging/mei/mei_dev.h)2
-rw-r--r--drivers/misc/mei/wd.c (renamed from drivers/staging/mei/wd.c)76
-rw-r--r--drivers/misc/pch_phub.c4
-rw-r--r--drivers/misc/pti.c2
-rw-r--r--drivers/mmc/host/mmci.c18
-rw-r--r--drivers/mmc/host/mxs-mmc.c8
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c9
-rw-r--r--drivers/mmc/host/sdhci-tegra.c24
-rw-r--r--drivers/mtd/devices/docg3.c16
-rw-r--r--drivers/mtd/nand/autcpu12.c10
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c9
-rw-r--r--drivers/mtd/nand/h1910.c2
-rw-r--r--drivers/mtd/nand/orion_nand.c47
-rw-r--r--drivers/mtd/ubi/Kconfig8
-rw-r--r--drivers/mtd/ubi/Makefile5
-rw-r--r--drivers/mtd/ubi/attach.c (renamed from drivers/mtd/ubi/scan.c)970
-rw-r--r--drivers/mtd/ubi/build.c85
-rw-r--r--drivers/mtd/ubi/cdev.c36
-rw-r--r--drivers/mtd/ubi/debug.c137
-rw-r--r--drivers/mtd/ubi/debug.h98
-rw-r--r--drivers/mtd/ubi/eba.c68
-rw-r--r--drivers/mtd/ubi/gluebi.c2
-rw-r--r--drivers/mtd/ubi/io.c211
-rw-r--r--drivers/mtd/ubi/kapi.c61
-rw-r--r--drivers/mtd/ubi/scan.h174
-rw-r--r--drivers/mtd/ubi/ubi-media.h8
-rw-r--r--drivers/mtd/ubi/ubi.h179
-rw-r--r--drivers/mtd/ubi/upd.c16
-rw-r--r--drivers/mtd/ubi/vmt.c62
-rw-r--r--drivers/mtd/ubi/vtbl.c228
-rw-r--r--drivers/mtd/ubi/wl.c260
-rw-r--r--drivers/net/can/flexcan.c6
-rw-r--r--drivers/net/can/sja1000/Kconfig2
-rw-r--r--drivers/net/ethernet/3com/typhoon.c3
-rw-r--r--drivers/net/ethernet/amd/ariadne.c8
-rw-r--r--drivers/net/ethernet/amd/atarilance.c11
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c41
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h23
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c235
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h11
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c22
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c62
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h53
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h15
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c2221
-rw-r--r--drivers/net/ethernet/emulex/benet/Makefile2
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h40
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c95
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h58
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c77
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h4
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c125
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c182
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h75
-rw-r--r--drivers/net/ethernet/freescale/fec.c9
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/alloc.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c2
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c71
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c3
-rw-r--r--drivers/net/ethernet/realtek/r8169.c2
-rw-r--r--drivers/net/ethernet/s6gmac.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c4
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c4
-rw-r--r--drivers/net/irda/Kconfig6
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/kingsun-sir.c42
-rw-r--r--drivers/net/irda/ks959-sir.c31
-rw-r--r--drivers/net/irda/ksdazzle-sir.c46
-rw-r--r--drivers/net/irda/stir4200.c6
-rw-r--r--drivers/net/ppp/ppp_async.c2
-rw-r--r--drivers/net/ppp/ppp_generic.c14
-rw-r--r--drivers/net/ppp/ppp_synctty.c4
-rw-r--r--drivers/net/ppp/pppoe.c6
-rw-r--r--drivers/net/ppp/pptp.c2
-rw-r--r--drivers/net/usb/asix.c1
-rw-r--r--drivers/net/usb/catc.c26
-rw-r--r--drivers/net/usb/cdc-phonet.c1
-rw-r--r--drivers/net/usb/cdc_eem.c1
-rw-r--r--drivers/net/usb/cdc_ether.c57
-rw-r--r--drivers/net/usb/cdc_ncm.c1
-rw-r--r--drivers/net/usb/cdc_subset.c1
-rw-r--r--drivers/net/usb/cx82310_eth.c1
-rw-r--r--drivers/net/usb/dm9601.c1
-rw-r--r--drivers/net/usb/gl620a.c1
-rw-r--r--drivers/net/usb/hso.c106
-rw-r--r--drivers/net/usb/int51x1.c1
-rw-r--r--drivers/net/usb/ipheth.c35
-rw-r--r--drivers/net/usb/kalmia.c3
-rw-r--r--drivers/net/usb/kaweth.c64
-rw-r--r--drivers/net/usb/lg-vl600.c1
-rw-r--r--drivers/net/usb/mcs7830.c1
-rw-r--r--drivers/net/usb/net1080.c1
-rw-r--r--drivers/net/usb/pegasus.c1
-rw-r--r--drivers/net/usb/plusb.c1
-rw-r--r--drivers/net/usb/qmi_wwan.c40
-rw-r--r--drivers/net/usb/rndis_host.c1
-rw-r--r--drivers/net/usb/rtl8150.c18
-rw-r--r--drivers/net/usb/sierra_net.c1
-rw-r--r--drivers/net/usb/smsc75xx.c1
-rw-r--r--drivers/net/usb/smsc95xx.c1
-rw-r--r--drivers/net/usb/zaurus.c1
-rw-r--r--drivers/net/virtio_net.c2
-rw-r--r--drivers/net/wan/Kconfig31
-rw-r--r--drivers/net/wan/Makefile5
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c1
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c7
-rw-r--r--drivers/net/wireless/libertas/if_usb.c1
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c1
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c1
-rw-r--r--drivers/net/wireless/p54/p54usb.c1
-rw-r--r--drivers/net/wireless/rndis_wlan.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/wireless/zd1201.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/of/address.c1
-rw-r--r--drivers/of/base.c41
-rw-r--r--drivers/parisc/superio.c2
-rw-r--r--drivers/parport/parport_amiga.c36
-rw-r--r--drivers/parport/parport_atari.c9
-rw-r--r--drivers/parport/parport_mfc3.c35
-rw-r--r--drivers/parport/parport_pc.c292
-rw-r--r--drivers/parport/parport_sunbpp.c21
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/host-bridge.c96
-rw-r--r--drivers/pci/pci-acpi.c2
-rw-r--r--drivers/pci/pci-driver.c6
-rw-r--r--drivers/pci/pci.c30
-rw-r--r--drivers/pci/pcie/portdrv_core.c2
-rw-r--r--drivers/pci/probe.c154
-rw-r--r--drivers/pci/quirks.c58
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/pxa2xx_hx4700.c121
-rw-r--r--drivers/pinctrl/Kconfig57
-rw-r--r--drivers/pinctrl/Makefile14
-rw-r--r--drivers/pinctrl/core.c244
-rw-r--r--drivers/pinctrl/core.h12
-rw-r--r--drivers/pinctrl/devicetree.c249
-rw-r--r--drivers/pinctrl/devicetree.h35
-rw-r--r--drivers/pinctrl/pinconf.c56
-rw-r--r--drivers/pinctrl/pinconf.h17
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c4
-rw-r--r--drivers/pinctrl/pinctrl-imx.c620
-rw-r--r--drivers/pinctrl/pinctrl-imx.h106
-rw-r--r--drivers/pinctrl/pinctrl-imx23.c305
-rw-r--r--drivers/pinctrl/pinctrl-imx28.c421
-rw-r--r--drivers/pinctrl/pinctrl-imx51.c1322
-rw-r--r--drivers/pinctrl/pinctrl-imx53.c1649
-rw-r--r--drivers/pinctrl/pinctrl-imx6q.c2331
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c528
-rw-r--r--drivers/pinctrl/pinctrl-mxs.h91
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c857
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c (renamed from drivers/gpio/gpio-nomadik.c)857
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.h77
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c30
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c20
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c439
-rw-r--r--drivers/pinctrl/pinctrl-tegra.h23
-rw-r--r--drivers/pinctrl/pinctrl-tegra20.c40
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c40
-rw-r--r--drivers/pinctrl/pinctrl-u300.c20
-rw-r--r--drivers/pinctrl/pinmux.c97
-rw-r--r--drivers/pinctrl/pinmux.h18
-rw-r--r--drivers/pinctrl/spear/Kconfig34
-rw-r--r--drivers/pinctrl/spear/Makefile7
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c354
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h142
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear300.c708
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear310.c431
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear320.c3468
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.c588
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.h92
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c2
-rw-r--r--drivers/power/bq27x00_battery.c2
-rw-r--r--drivers/ps3/ps3av.c24
-rw-r--r--drivers/ptp/Kconfig2
-rw-r--r--drivers/regulator/88pm8607.c179
-rw-r--r--drivers/regulator/Kconfig33
-rw-r--r--drivers/regulator/Makefile5
-rw-r--r--drivers/regulator/aat2870-regulator.c10
-rw-r--r--drivers/regulator/ab3100.c65
-rw-r--r--drivers/regulator/ab8500.c235
-rw-r--r--drivers/regulator/ad5398.c19
-rw-r--r--drivers/regulator/anatop-regulator.c9
-rw-r--r--drivers/regulator/core.c456
-rw-r--r--drivers/regulator/da903x.c209
-rw-r--r--drivers/regulator/da9052-regulator.c441
-rw-r--r--drivers/regulator/db8500-prcmu.c133
-rw-r--r--drivers/regulator/dummy.c7
-rw-r--r--drivers/regulator/fixed.c69
-rw-r--r--drivers/regulator/gpio-regulator.c22
-rw-r--r--drivers/regulator/isl6271a-regulator.c73
-rw-r--r--drivers/regulator/lp3971.c87
-rw-r--r--drivers/regulator/lp3972.c74
-rw-r--r--drivers/regulator/max1586.c28
-rw-r--r--drivers/regulator/max8649.c110
-rw-r--r--drivers/regulator/max8660.c165
-rw-r--r--drivers/regulator/max8925-regulator.c83
-rw-r--r--drivers/regulator/max8952.c70
-rw-r--r--drivers/regulator/max8997.c342
-rw-r--r--drivers/regulator/max8998.c122
-rw-r--r--drivers/regulator/mc13783-regulator.c12
-rw-r--r--drivers/regulator/mc13892-regulator.c25
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c54
-rw-r--r--drivers/regulator/mc13xxx.h2
-rw-r--r--drivers/regulator/of_regulator.c47
-rw-r--r--drivers/regulator/palmas-regulator.c822
-rw-r--r--drivers/regulator/pcap-regulator.c54
-rw-r--r--drivers/regulator/pcf50633-regulator.c199
-rw-r--r--drivers/regulator/rc5t583-regulator.c255
-rw-r--r--drivers/regulator/s5m8767.c327
-rw-r--r--drivers/regulator/tps6105x-regulator.c11
-rw-r--r--drivers/regulator/tps62360-regulator.c380
-rw-r--r--drivers/regulator/tps65023-regulator.c244
-rw-r--r--drivers/regulator/tps6507x-regulator.c22
-rw-r--r--drivers/regulator/tps65090-regulator.c150
-rw-r--r--drivers/regulator/tps65217-regulator.c78
-rw-r--r--drivers/regulator/tps6524x-regulator.c47
-rw-r--r--drivers/regulator/tps6586x-regulator.c108
-rw-r--r--drivers/regulator/tps65910-regulator.c343
-rw-r--r--drivers/regulator/tps65912-regulator.c60
-rw-r--r--drivers/regulator/twl-regulator.c127
-rw-r--r--drivers/regulator/userspace-consumer.c20
-rw-r--r--drivers/regulator/virtual.c26
-rw-r--r--drivers/regulator/wm831x-dcdc.c174
-rw-r--r--drivers/regulator/wm831x-isink.c8
-rw-r--r--drivers/regulator/wm831x-ldo.c201
-rw-r--r--drivers/regulator/wm8350-regulator.c11
-rw-r--r--drivers/regulator/wm8400-regulator.c176
-rw-r--r--drivers/regulator/wm8994-regulator.c111
-rw-r--r--drivers/remoteproc/remoteproc_core.c3
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/rtc-pl031.c18
-rw-r--r--drivers/s390/char/con3215.c142
-rw-r--r--drivers/s390/char/keyboard.c30
-rw-r--r--drivers/s390/char/keyboard.h14
-rw-r--r--drivers/s390/char/sclp_cmd.c12
-rw-r--r--drivers/s390/char/sclp_tty.c33
-rw-r--r--drivers/s390/char/sclp_vt220.c33
-rw-r--r--drivers/s390/char/tape.h43
-rw-r--r--drivers/s390/char/tape_34xx.c136
-rw-r--r--drivers/s390/char/tape_3590.c105
-rw-r--r--drivers/s390/char/tape_char.c13
-rw-r--r--drivers/s390/char/tape_core.c16
-rw-r--r--drivers/s390/char/tty3270.c121
-rw-r--r--drivers/s390/cio/ccwgroup.c112
-rw-r--r--drivers/s390/cio/cio.c73
-rw-r--r--drivers/s390/cio/device.c13
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/qdio_main.c47
-rw-r--r--drivers/s390/crypto/ap_bus.c24
-rw-r--r--drivers/s390/crypto/ap_bus.h7
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c3
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c3
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c3
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c5
-rw-r--r--drivers/s390/net/claw.c165
-rw-r--r--drivers/s390/net/ctcm_main.c52
-rw-r--r--drivers/s390/net/ctcm_main.h8
-rw-r--r--drivers/s390/net/ctcm_sysfs.c37
-rw-r--r--drivers/s390/net/lcs.c52
-rw-r--r--drivers/s390/net/qeth_core.h24
-rw-r--r--drivers/s390/net/qeth_core_main.c178
-rw-r--r--drivers/s390/net/qeth_core_sys.c49
-rw-r--r--drivers/s390/net/qeth_l2_main.c16
-rw-r--r--drivers/s390/net/qeth_l3_main.c16
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/aacraid/src.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c3
-rw-r--r--drivers/scsi/atari_scsi.c26
-rw-r--r--drivers/scsi/atari_scsi.h5
-rw-r--r--drivers/scsi/be2iscsi/be.h4
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c2
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h154
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c493
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h15
-rw-r--r--drivers/scsi/be2iscsi/be_main.c447
-rw-r--r--drivers/scsi/be2iscsi/be_main.h17
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c522
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h50
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h3
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c32
-rw-r--r--drivers/scsi/bfa/bfad.c17
-rw-r--r--drivers/scsi/bfa/bfad_attr.c20
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h2
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_hsi.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c6
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c3
-rw-r--r--drivers/scsi/bnx2i/bnx2i_sysfs.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c70
-rw-r--r--drivers/scsi/esp_scsi.c2
-rw-r--r--drivers/scsi/fcoe/fcoe.c41
-rw-r--r--drivers/scsi/fcoe/fcoe.h4
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c8
-rw-r--r--drivers/scsi/hpsa.c683
-rw-r--r--drivers/scsi/hpsa.h85
-rw-r--r--drivers/scsi/hpsa_cmd.h37
-rw-r--r--drivers/scsi/isci/host.c703
-rw-r--r--drivers/scsi/isci/host.h124
-rw-r--r--drivers/scsi/isci/init.c212
-rw-r--r--drivers/scsi/isci/phy.c76
-rw-r--r--drivers/scsi/isci/phy.h9
-rw-r--r--drivers/scsi/isci/port.c68
-rw-r--r--drivers/scsi/isci/port.h11
-rw-r--r--drivers/scsi/isci/port_config.c18
-rw-r--r--drivers/scsi/isci/probe_roms.c12
-rw-r--r--drivers/scsi/isci/probe_roms.h2
-rw-r--r--drivers/scsi/isci/registers.h8
-rw-r--r--drivers/scsi/isci/remote_device.c576
-rw-r--r--drivers/scsi/isci/remote_device.h63
-rw-r--r--drivers/scsi/isci/remote_node_context.c393
-rw-r--r--drivers/scsi/isci/remote_node_context.h43
-rw-r--r--drivers/scsi/isci/request.c715
-rw-r--r--drivers/scsi/isci/request.h125
-rw-r--r--drivers/scsi/isci/scu_completion_codes.h2
-rw-r--r--drivers/scsi/isci/task.c800
-rw-r--r--drivers/scsi/isci/task.h132
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.c30
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.h6
-rw-r--r--drivers/scsi/libfc/fc_lport.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c46
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h418
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c141
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c18
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c377
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c9
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c414
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c785
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c21
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c4
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h68
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c38
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h10
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c312
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c597
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c243
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h3
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c23
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c10
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c3
-rw-r--r--drivers/scsi/scsi.c6
-rw-r--r--drivers/scsi/scsi_error.c6
-rw-r--r--drivers/scsi/scsi_lib.c10
-rw-r--r--drivers/scsi/scsi_pm.c2
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_transport_fc.c24
-rw-r--r--drivers/scsi/scsi_transport_spi.c4
-rw-r--r--drivers/scsi/sd.c5
-rw-r--r--drivers/scsi/sg.c183
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/storvsc_drv.c20
-rw-r--r--drivers/scsi/ufs/ufshcd.c8
-rw-r--r--drivers/sh/clk/cpg.c77
-rw-r--r--drivers/sh/intc/dynamic.c8
-rw-r--r--drivers/spi/spi-imx.c8
-rw-r--r--drivers/staging/Kconfig16
-rw-r--r--drivers/staging/Makefile7
-rw-r--r--drivers/staging/android/Kconfig33
-rw-r--r--drivers/staging/android/Makefile3
-rw-r--r--drivers/staging/android/alarm-dev.c137
-rw-r--r--drivers/staging/android/alarm.c601
-rw-r--r--drivers/staging/android/android_alarm.h59
-rw-r--r--drivers/staging/android/binder.h10
-rw-r--r--drivers/staging/android/logger.c113
-rw-r--r--drivers/staging/android/persistent_ram.c473
-rw-r--r--drivers/staging/android/persistent_ram.h78
-rw-r--r--drivers/staging/android/ram_console.c2
-rw-r--r--drivers/staging/android/switch/Kconfig11
-rw-r--r--drivers/staging/android/switch/Makefile4
-rw-r--r--drivers/staging/android/switch/switch.h53
-rw-r--r--drivers/staging/android/switch/switch_class.c174
-rw-r--r--drivers/staging/android/switch/switch_gpio.c172
-rw-r--r--drivers/staging/android/timed_output.c1
-rw-r--r--drivers/staging/asus_oled/asus_oled.c6
-rw-r--r--drivers/staging/bcm/Adapter.h883
-rw-r--r--drivers/staging/bcm/DDRInit.c26
-rw-r--r--drivers/staging/bcm/IPv6Protocol.c409
-rw-r--r--drivers/staging/bcm/Misc.c2
-rw-r--r--drivers/staging/ccg/Kconfig20
-rw-r--r--drivers/staging/ccg/Makefile4
-rw-r--r--drivers/staging/ccg/TODO6
-rw-r--r--drivers/staging/ccg/ccg.c1299
-rw-r--r--drivers/staging/ccg/sysfs-class-ccg_usb158
-rw-r--r--drivers/staging/comedi/Kconfig253
-rw-r--r--drivers/staging/comedi/comedi.h2
-rw-r--r--drivers/staging/comedi/comedi_fops.c729
-rw-r--r--drivers/staging/comedi/comedidev.h72
-rw-r--r--drivers/staging/comedi/drivers.c326
-rw-r--r--drivers/staging/comedi/drivers/8255.c73
-rw-r--r--drivers/staging/comedi/drivers/acl7225b.c55
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c3556
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h145
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c18
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c263
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7230.c133
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7296.c77
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7432.c149
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c301
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c106
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c182
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c250
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c223
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c103
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c130
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c33
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c113
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c99
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c85
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c87
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c256
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c120
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c44
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c9
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c109
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c142
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c175
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c131
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c123
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c132
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c216
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c38
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c373
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c163
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c87
-rw-r--r--drivers/staging/comedi/drivers/das08.c132
-rw-r--r--drivers/staging/comedi/drivers/das08.h2
-rw-r--r--drivers/staging/comedi/drivers/das16.c891
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c219
-rw-r--r--drivers/staging/comedi/drivers/das1800.c61
-rw-r--r--drivers/staging/comedi/drivers/das6402.c68
-rw-r--r--drivers/staging/comedi/drivers/das800.c8
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c15
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c283
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c309
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c116
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c42
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c37
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c397
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c234
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c43
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c79
-rw-r--r--drivers/staging/comedi/drivers/fl512.c47
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c98
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c289
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c36
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c84
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c98
-rw-r--r--drivers/staging/comedi/drivers/me4000.c432
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c101
-rw-r--r--drivers/staging/comedi/drivers/mite.h4
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c236
-rw-r--r--drivers/staging/comedi/drivers/mpc8260cpm.c114
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c37
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c15
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c12
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c360
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c238
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c94
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c82
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c13
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c142
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c198
-rw-r--r--drivers/staging/comedi/drivers/ni_tio_internal.h36
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c75
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c65
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c37
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c46
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c57
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c166
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c153
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c166
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c51
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c37
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c63
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c224
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c661
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c542
-rw-r--r--drivers/staging/comedi/drivers/poc.c205
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c16
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c188
-rw-r--r--drivers/staging/comedi/drivers/rti800.c54
-rw-r--r--drivers/staging/comedi/drivers/rti802.c37
-rw-r--r--drivers/staging/comedi/drivers/s526.c495
-rw-r--r--drivers/staging/comedi/drivers/s626.c137
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c69
-rw-r--r--drivers/staging/comedi/drivers/skel.c9
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c223
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c453
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c149
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c93
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c48
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c113
-rw-r--r--drivers/staging/comedi/internal.h6
-rw-r--r--drivers/staging/et131x/et131x.c10
-rw-r--r--drivers/staging/frontier/alphatrack.c15
-rw-r--r--drivers/staging/frontier/tranzport.c16
-rw-r--r--drivers/staging/gdm72xx/Kconfig46
-rw-r--r--drivers/staging/gdm72xx/Makefile6
-rw-r--r--drivers/staging/gdm72xx/TODO5
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c460
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.h93
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c754
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.h72
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.c798
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.h85
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c1026
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.h92
-rw-r--r--drivers/staging/gdm72xx/hci.h218
-rw-r--r--drivers/staging/gdm72xx/netlink_k.c150
-rw-r--r--drivers/staging/gdm72xx/netlink_k.h24
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.c159
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.h21
-rw-r--r--drivers/staging/gdm72xx/usb_boot.c404
-rw-r--r--drivers/staging/gdm72xx/usb_boot.h22
-rw-r--r--drivers/staging/gdm72xx/usb_ids.h82
-rw-r--r--drivers/staging/gdm72xx/wm_ioctl.h97
-rw-r--r--drivers/staging/iio/Documentation/device.txt4
-rw-r--r--drivers/staging/iio/Documentation/generic_buffer.c4
-rw-r--r--drivers/staging/iio/Documentation/iio_event_monitor.c2
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl25836
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x13
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio741
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-ad719220
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-dds81
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-light15
-rw-r--r--drivers/staging/iio/Documentation/trigger.txt2
-rw-r--r--drivers/staging/iio/Kconfig46
-rw-r--r--drivers/staging/iio/Makefile8
-rw-r--r--drivers/staging/iio/TODO2
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c123
-rw-r--r--drivers/staging/iio/accel/adis16201_ring.c9
-rw-r--r--drivers/staging/iio/accel/adis16201_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c108
-rw-r--r--drivers/staging/iio/accel/adis16203_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16203_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c115
-rw-r--r--drivers/staging/iio/accel/adis16204_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16204_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c159
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c17
-rw-r--r--drivers/staging/iio/accel/adis16209_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c39
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c129
-rw-r--r--drivers/staging/iio/accel/adis16240_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16240_trigger.c10
-rw-r--r--drivers/staging/iio/accel/kxsd9.c16
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c50
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c25
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c66
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c12
-rw-r--r--drivers/staging/iio/adc/Kconfig27
-rw-r--r--drivers/staging/iio/adc/Makefile1
-rw-r--r--drivers/staging/iio/adc/ad7192.c81
-rw-r--r--drivers/staging/iio/adc/ad7280a.c31
-rw-r--r--drivers/staging/iio/adc/ad7291.c26
-rw-r--r--drivers/staging/iio/adc/ad7298.h1
-rw-r--r--drivers/staging/iio/adc/ad7298_core.c79
-rw-r--r--drivers/staging/iio/adc/ad7298_ring.c46
-rw-r--r--drivers/staging/iio/adc/ad7476.h1
-rw-r--r--drivers/staging/iio/adc/ad7476_core.c60
-rw-r--r--drivers/staging/iio/adc/ad7476_ring.c58
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c39
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c2
-rw-r--r--drivers/staging/iio/adc/ad7606_ring.c30
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c2
-rw-r--r--drivers/staging/iio/adc/ad7780.c44
-rw-r--r--drivers/staging/iio/adc/ad7793.c103
-rw-r--r--drivers/staging/iio/adc/ad7816.c26
-rw-r--r--drivers/staging/iio/adc/ad7887.h1
-rw-r--r--drivers/staging/iio/adc/ad7887_core.c20
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c46
-rw-r--r--drivers/staging/iio/adc/ad799x.h1
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c62
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c44
-rw-r--r--drivers/staging/iio/adc/adt7310.c40
-rw-r--r--drivers/staging/iio/adc/adt7410.c40
-rw-r--r--drivers/staging/iio/adc/lpc32xx_adc.c35
-rw-r--r--drivers/staging/iio/adc/max1363_core.c33
-rw-r--r--drivers/staging/iio/adc/max1363_ring.c10
-rw-r--r--drivers/staging/iio/adc/spear_adc.c448
-rw-r--r--drivers/staging/iio/addac/adt7316.c152
-rw-r--r--drivers/staging/iio/buffer.h193
-rw-r--r--drivers/staging/iio/cdc/ad7150.c24
-rw-r--r--drivers/staging/iio/cdc/ad7152.c30
-rw-r--r--drivers/staging/iio/cdc/ad7746.c49
-rw-r--r--drivers/staging/iio/consumer.h96
-rw-r--r--drivers/staging/iio/dac/Kconfig6
-rw-r--r--drivers/staging/iio/dac/ad5064.c29
-rw-r--r--drivers/staging/iio/dac/ad5360.c21
-rw-r--r--drivers/staging/iio/dac/ad5380.c25
-rw-r--r--drivers/staging/iio/dac/ad5421.c19
-rw-r--r--drivers/staging/iio/dac/ad5446.c293
-rw-r--r--drivers/staging/iio/dac/ad5446.h20
-rw-r--r--drivers/staging/iio/dac/ad5504.c27
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c23
-rw-r--r--drivers/staging/iio/dac/ad5686.c25
-rw-r--r--drivers/staging/iio/dac/ad5764.c17
-rw-r--r--drivers/staging/iio/dac/ad5791.c25
-rw-r--r--drivers/staging/iio/dac/max517.c15
-rw-r--r--drivers/staging/iio/dds/dds.h110
-rw-r--r--drivers/staging/iio/driver.h34
-rw-r--r--drivers/staging/iio/events.h105
-rw-r--r--drivers/staging/iio/frequency/Kconfig (renamed from drivers/staging/iio/dds/Kconfig)0
-rw-r--r--drivers/staging/iio/frequency/Makefile (renamed from drivers/staging/iio/dds/Makefile)0
-rw-r--r--drivers/staging/iio/frequency/ad5930.c (renamed from drivers/staging/iio/dds/ad5930.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9832.c (renamed from drivers/staging/iio/dds/ad9832.c)36
-rw-r--r--drivers/staging/iio/frequency/ad9832.h (renamed from drivers/staging/iio/dds/ad9832.h)0
-rw-r--r--drivers/staging/iio/frequency/ad9834.c (renamed from drivers/staging/iio/dds/ad9834.c)74
-rw-r--r--drivers/staging/iio/frequency/ad9834.h (renamed from drivers/staging/iio/dds/ad9834.h)0
-rw-r--r--drivers/staging/iio/frequency/ad9850.c (renamed from drivers/staging/iio/dds/ad9850.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9852.c (renamed from drivers/staging/iio/dds/ad9852.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9910.c (renamed from drivers/staging/iio/dds/ad9910.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9951.c (renamed from drivers/staging/iio/dds/ad9951.c)12
-rw-r--r--drivers/staging/iio/frequency/dds.h110
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c18
-rw-r--r--drivers/staging/iio/gyro/adis16080_core.c16
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c12
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c116
-rw-r--r--drivers/staging/iio/gyro/adis16260_ring.c16
-rw-r--r--drivers/staging/iio/gyro/adis16260_trigger.c10
-rw-r--r--drivers/staging/iio/gyro/adxrs450.h2
-rw-r--r--drivers/staging/iio/gyro/adxrs450_core.c24
-rw-r--r--drivers/staging/iio/iio.h471
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.c4
-rw-r--r--drivers/staging/iio/iio_hwmon.c4
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c35
-rw-r--r--drivers/staging/iio/iio_simple_dummy_buffer.c21
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c8
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c83
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c141
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c20
-rw-r--r--drivers/staging/iio/imu/adis16400_trigger.c10
-rw-r--r--drivers/staging/iio/kfifo_buf.h8
-rw-r--r--drivers/staging/iio/light/Kconfig37
-rw-r--r--drivers/staging/iio/light/Makefile2
-rw-r--r--drivers/staging/iio/light/isl29018.c211
-rw-r--r--drivers/staging/iio/light/isl29028.c566
-rw-r--r--drivers/staging/iio/light/tsl2563.c24
-rw-r--r--drivers/staging/iio/light/tsl2583.c34
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x.h100
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x_core.c2082
-rw-r--r--drivers/staging/iio/machine.h24
-rw-r--r--drivers/staging/iio/magnetometer/Kconfig8
-rw-r--r--drivers/staging/iio/magnetometer/ak8975.c19
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c522
-rw-r--r--drivers/staging/iio/meter/ade7753.c22
-rw-r--r--drivers/staging/iio/meter/ade7754.c22
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c299
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c33
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c10
-rw-r--r--drivers/staging/iio/meter/ade7759.c22
-rw-r--r--drivers/staging/iio/meter/ade7854-i2c.c22
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c22
-rw-r--r--drivers/staging/iio/meter/ade7854.c28
-rw-r--r--drivers/staging/iio/meter/meter.h2
-rw-r--r--drivers/staging/iio/resolver/ad2s1200.c12
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c38
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c11
-rw-r--r--drivers/staging/iio/ring_sw.c2
-rw-r--r--drivers/staging/iio/ring_sw.h2
-rw-r--r--drivers/staging/iio/sysfs.h117
-rw-r--r--drivers/staging/iio/trigger.h119
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c10
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c10
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c8
-rw-r--r--drivers/staging/iio/trigger/iio-trig-sysfs.c10
-rw-r--r--drivers/staging/iio/trigger_consumer.h52
-rw-r--r--drivers/staging/iio/types.h53
-rw-r--r--drivers/staging/ipack/Kconfig20
-rw-r--r--drivers/staging/ipack/Makefile6
-rw-r--r--drivers/staging/ipack/TODO46
-rw-r--r--drivers/staging/ipack/bridges/Kconfig8
-rw-r--r--drivers/staging/ipack/bridges/Makefile1
-rw-r--r--drivers/staging/ipack/bridges/tpci200.c1141
-rw-r--r--drivers/staging/ipack/bridges/tpci200.h162
-rw-r--r--drivers/staging/ipack/devices/Kconfig7
-rw-r--r--drivers/staging/ipack/devices/Makefile1
-rw-r--r--drivers/staging/ipack/devices/ipoctal.c901
-rw-r--r--drivers/staging/ipack/devices/ipoctal.h80
-rw-r--r--drivers/staging/ipack/devices/scc2698.h228
-rw-r--r--drivers/staging/ipack/ipack.c205
-rw-r--r--drivers/staging/ipack/ipack.h183
-rw-r--r--drivers/staging/line6/config.h48
-rw-r--r--drivers/staging/line6/driver.c88
-rw-r--r--drivers/staging/line6/midi.c2
-rw-r--r--drivers/staging/line6/midibuf.c2
-rw-r--r--drivers/staging/line6/pcm.c2
-rw-r--r--drivers/staging/line6/toneport.c2
-rw-r--r--drivers/staging/media/as102/as102_drv.c34
-rw-r--r--drivers/staging/media/as102/as102_fe.c2
-rw-r--r--drivers/staging/media/as102/as102_fw.c5
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.c12
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.h2
-rw-r--r--drivers/staging/media/easycap/easycap_ioctl.c1
-rw-r--r--drivers/staging/media/easycap/easycap_main.c6
-rw-r--r--drivers/staging/media/go7007/README2
-rw-r--r--drivers/staging/media/go7007/go7007.txt1
-rw-r--r--drivers/staging/media/go7007/s2250-loader.c26
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c80
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c100
-rw-r--r--drivers/staging/media/lirc/lirc_ttusbir.c13
-rw-r--r--drivers/staging/mei/TODO10
-rw-r--r--drivers/staging/mei/mei-amt-version.c481
-rw-r--r--drivers/staging/mei/mei.h110
-rw-r--r--drivers/staging/mei/mei.txt215
-rw-r--r--drivers/staging/net/Kconfig38
-rw-r--r--drivers/staging/net/Makefile5
-rw-r--r--drivers/staging/net/TODO5
-rw-r--r--drivers/staging/net/pc300-falc-lh.h (renamed from drivers/net/wan/pc300-falc-lh.h)0
-rw-r--r--drivers/staging/net/pc300.h (renamed from drivers/net/wan/pc300.h)0
-rw-r--r--drivers/staging/net/pc300_drv.c (renamed from drivers/net/wan/pc300_drv.c)0
-rw-r--r--drivers/staging/net/pc300_tty.c (renamed from drivers/net/wan/pc300_tty.c)0
-rw-r--r--drivers/staging/nvec/nvec.h2
-rw-r--r--drivers/staging/octeon/ethernet-rx.c2
-rw-r--r--drivers/staging/octeon/ethernet-tx.c10
-rw-r--r--drivers/staging/octeon/ethernet-util.h2
-rw-r--r--drivers/staging/octeon/ethernet.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c29
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c2
-rw-r--r--drivers/staging/omapdrm/Makefile1
-rw-r--r--drivers/staging/omapdrm/omap_dmm_tiler.c4
-rw-r--r--drivers/staging/omapdrm/omap_drv.c6
-rw-r--r--drivers/staging/omapdrm/omap_drv.h14
-rw-r--r--drivers/staging/omapdrm/omap_fb.c7
-rw-r--r--drivers/staging/omapdrm/omap_gem.c130
-rw-r--r--drivers/staging/omapdrm/omap_gem_dmabuf.c220
-rw-r--r--drivers/staging/omapdrm/tcm-sita.c2
-rw-r--r--drivers/staging/ozwpan/README2
-rw-r--r--drivers/staging/ozwpan/ozappif.h12
-rw-r--r--drivers/staging/ozwpan/ozcdev.c17
-rw-r--r--drivers/staging/ozwpan/ozevent.c195
-rw-r--r--drivers/staging/ozwpan/ozevent.h11
-rw-r--r--drivers/staging/ozwpan/ozeventdef.h19
-rw-r--r--drivers/staging/ozwpan/ozhcd.c6
-rw-r--r--drivers/staging/ozwpan/ozmain.c8
-rw-r--r--drivers/staging/ozwpan/ozusbsvc.c2
-rw-r--r--drivers/staging/panel/panel.c2
-rw-r--r--drivers/staging/quatech_usb2/Kconfig15
-rw-r--r--drivers/staging/quatech_usb2/Makefile1
-rw-r--r--drivers/staging/quatech_usb2/TODO8
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c1976
-rw-r--r--drivers/staging/ramster/Kconfig2
-rw-r--r--drivers/staging/ramster/cluster/tcp.c4
-rw-r--r--drivers/staging/ramster/xvmalloc.c2
-rw-r--r--drivers/staging/ramster/zcache-main.c6
-rw-r--r--drivers/staging/rtl8187se/Makefile2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c26
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c7
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8187se/r8180.h10
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c33
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c16
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c4
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c6
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.h2
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c1329
-rw-r--r--drivers/staging/rtl8192e/Kconfig4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c3
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c13
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h3
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c22
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib.h18
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c10
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c35
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c14
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c7
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U.h9
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c60
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c74
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c12
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTType.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c12
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c4
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c16
-rw-r--r--drivers/staging/rtl8192u/r819xU_phyreg.h2
-rw-r--r--drivers/staging/rtl8712/big_endian.h94
-rw-r--r--drivers/staging/rtl8712/drv_types.h2
-rw-r--r--drivers/staging/rtl8712/generic.h178
-rw-r--r--drivers/staging/rtl8712/hal_init.c1
-rw-r--r--drivers/staging/rtl8712/ieee80211.h2
-rw-r--r--drivers/staging/rtl8712/if_ether.h141
-rw-r--r--drivers/staging/rtl8712/ip.h137
-rw-r--r--drivers/staging/rtl8712/little_endian.h94
-rw-r--r--drivers/staging/rtl8712/os_intfs.c4
-rw-r--r--drivers/staging/rtl8712/osdep_service.h3
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c7
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_bitdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h4
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c6
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c9
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_byteorder.h32
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c19
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c8
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h6
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h4
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h2
-rw-r--r--drivers/staging/rtl8712/swab.h131
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c4
-rw-r--r--drivers/staging/rtl8712/usb_intf.c36
-rw-r--r--drivers/staging/rtl8712/usb_ops.c1
-rw-r--r--drivers/staging/rtl8712/wifi.h1
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c6
-rw-r--r--drivers/staging/rts5139/ms.c11
-rw-r--r--drivers/staging/rts5139/ms.h2
-rw-r--r--drivers/staging/rts5139/ms_mg.c4
-rw-r--r--drivers/staging/rts5139/rts51x.c83
-rw-r--r--drivers/staging/rts5139/rts51x.h10
-rw-r--r--drivers/staging/rts5139/rts51x_card.c52
-rw-r--r--drivers/staging/rts5139/rts51x_card.h11
-rw-r--r--drivers/staging/rts5139/rts51x_chip.c178
-rw-r--r--drivers/staging/rts5139/rts51x_chip.h95
-rw-r--r--drivers/staging/rts5139/rts51x_fop.c5
-rw-r--r--drivers/staging/rts5139/rts51x_fop.h5
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c93
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.h5
-rw-r--r--drivers/staging/rts5139/rts51x_sys.h54
-rw-r--r--drivers/staging/rts5139/rts51x_transport.c282
-rw-r--r--drivers/staging/rts5139/rts51x_transport.h12
-rw-r--r--drivers/staging/rts5139/sd.c142
-rw-r--r--drivers/staging/rts5139/sd.h29
-rw-r--r--drivers/staging/rts5139/sd_cprm.c166
-rw-r--r--drivers/staging/rts5139/xd.c122
-rw-r--r--drivers/staging/rts5139/xd.h2
-rw-r--r--drivers/staging/rts_pstor/ms.c2
-rw-r--r--drivers/staging/rts_pstor/rtsx_transport.c4
-rw-r--r--drivers/staging/sep/sep_driver_config.h6
-rw-r--r--drivers/staging/sep/sep_main.c12
-rw-r--r--drivers/staging/serial/68360serial.c2979
-rw-r--r--drivers/staging/serial/Kconfig16
-rw-r--r--drivers/staging/serial/Makefile1
-rw-r--r--drivers/staging/serial/TODO6
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c79
-rw-r--r--drivers/staging/sm7xx/smtcfb.c232
-rw-r--r--drivers/staging/sm7xx/smtcfb.h8
-rw-r--r--drivers/staging/telephony/ixj.c228
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c2
-rw-r--r--drivers/staging/tidspbridge/core/ue_deh.c2
-rw-r--r--drivers/staging/usbip/stub_dev.c12
-rw-r--r--drivers/staging/usbip/usbip_common.h17
-rw-r--r--drivers/staging/usbip/usbip_protocol.txt2
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c20
-rw-r--r--drivers/staging/usbip/vhci_hcd.c8
-rw-r--r--drivers/staging/usbip/vhci_rx.c2
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c4
-rw-r--r--drivers/staging/vme/Makefile7
-rw-r--r--drivers/staging/vme/TODO5
-rw-r--r--drivers/staging/vme/devices/Kconfig3
-rw-r--r--drivers/staging/vme/devices/vme_pio2_cntr.c2
-rw-r--r--drivers/staging/vme/devices/vme_pio2_core.c3
-rw-r--r--drivers/staging/vme/devices/vme_pio2_gpio.c5
-rw-r--r--drivers/staging/vme/devices/vme_user.c45
-rw-r--r--drivers/staging/vme/vme.h174
-rw-r--r--drivers/staging/vme/vme_api.txt396
-rw-r--r--drivers/staging/vt6655/wpa.c4
-rw-r--r--drivers/staging/vt6656/dpc.c2
-rw-r--r--drivers/staging/vt6656/ioctl.c24
-rw-r--r--drivers/staging/vt6656/main_usb.c4
-rw-r--r--drivers/staging/vt6656/wpa.c4
-rw-r--r--drivers/staging/wlags49_h2/README.ubuntu2
-rw-r--r--drivers/staging/wlags49_h2/hcf.c10
-rw-r--r--drivers/staging/wlags49_h2/hcf.h12
-rw-r--r--drivers/staging/wlags49_h2/mmd.c12
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c3
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c9
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c4
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.c8
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c11
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c10
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c4
-rw-r--r--drivers/staging/xgifb/XGI_main.h221
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c101
-rw-r--r--drivers/staging/xgifb/XGIfb.h6
-rw-r--r--drivers/staging/xgifb/vb_init.c78
-rw-r--r--drivers/staging/xgifb/vb_setmode.c1457
-rw-r--r--drivers/staging/xgifb/vb_struct.h27
-rw-r--r--drivers/staging/xgifb/vb_table.h725
-rw-r--r--drivers/staging/xgifb/vgatypes.h2
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c40
-rw-r--r--drivers/staging/zsmalloc/zsmalloc_int.h2
-rw-r--r--drivers/target/Kconfig1
-rw-r--r--drivers/target/Makefile1
-rw-r--r--drivers/target/iscsi/iscsi_target.c821
-rw-r--r--drivers/target/iscsi/iscsi_target.h3
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h12
-rw-r--r--drivers/target/iscsi/iscsi_target_datain_values.c35
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c23
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c28
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c17
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.c145
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c15
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c192
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h3
-rw-r--r--drivers/target/loopback/tcm_loop.c4
-rw-r--r--drivers/target/sbp/Kconfig11
-rw-r--r--drivers/target/sbp/Makefile1
-rw-r--r--drivers/target/sbp/sbp_target.c2621
-rw-r--r--drivers/target/sbp/sbp_target.h251
-rw-r--r--drivers/target/target_core_alua.c100
-rw-r--r--drivers/target/target_core_alua.h14
-rw-r--r--drivers/target/target_core_cdb.c118
-rw-r--r--drivers/target/target_core_configfs.c25
-rw-r--r--drivers/target/target_core_device.c84
-rw-r--r--drivers/target/target_core_file.c153
-rw-r--r--drivers/target/target_core_file.h4
-rw-r--r--drivers/target/target_core_iblock.c152
-rw-r--r--drivers/target/target_core_iblock.h1
-rw-r--r--drivers/target/target_core_internal.h25
-rw-r--r--drivers/target/target_core_pr.c70
-rw-r--r--drivers/target/target_core_pr.h8
-rw-r--r--drivers/target/target_core_pscsi.c179
-rw-r--r--drivers/target/target_core_pscsi.h1
-rw-r--r--drivers/target/target_core_rd.c168
-rw-r--r--drivers/target/target_core_rd.h20
-rw-r--r--drivers/target/target_core_tmr.c71
-rw-r--r--drivers/target/target_core_tpg.c5
-rw-r--r--drivers/target/target_core_transport.c994
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c18
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c3
-rw-r--r--drivers/target/tcm_fc/tfc_io.c2
-rw-r--r--drivers/tty/amiserial.c14
-rw-r--r--drivers/tty/bfin_jtag_comm.c44
-rw-r--r--drivers/tty/cyclades.c2
-rw-r--r--drivers/tty/hvc/hvc_console.c96
-rw-r--r--drivers/tty/hvc/hvc_console.h4
-rw-r--r--drivers/tty/hvc/hvc_xen.c4
-rw-r--r--drivers/tty/hvc/hvcs.c74
-rw-r--r--drivers/tty/hvc/hvsi.c128
-rw-r--r--drivers/tty/hvc/hvsi_lib.c2
-rw-r--r--drivers/tty/ipwireless/tty.c81
-rw-r--r--drivers/tty/mxser.c2
-rw-r--r--drivers/tty/n_r3964.c11
-rw-r--r--drivers/tty/n_tty.c9
-rw-r--r--drivers/tty/pty.c40
-rw-r--r--drivers/tty/serial/68328serial.c383
-rw-r--r--drivers/tty/serial/68328serial.h186
-rw-r--r--drivers/tty/serial/8250/8250.c312
-rw-r--r--drivers/tty/serial/8250/8250.h16
-rw-r--r--drivers/tty/serial/8250/8250_em.c186
-rw-r--r--drivers/tty/serial/8250/8250_pci.c63
-rw-r--r--drivers/tty/serial/8250/Kconfig8
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/amba-pl011.c117
-rw-r--r--drivers/tty/serial/bfin_uart.c74
-rw-r--r--drivers/tty/serial/clps711x.c1
-rw-r--r--drivers/tty/serial/crisv10.c36
-rw-r--r--drivers/tty/serial/imx.c8
-rw-r--r--drivers/tty/serial/mxs-auart.c10
-rw-r--r--drivers/tty/serial/of_serial.c26
-rw-r--r--drivers/tty/serial/omap-serial.c74
-rw-r--r--drivers/tty/serial/pch_uart.c53
-rw-r--r--drivers/tty/serial/serial_core.c1
-rw-r--r--drivers/tty/serial/sh-sci.c49
-rw-r--r--drivers/tty/synclink.c4
-rw-r--r--drivers/tty/synclink_gt.c4
-rw-r--r--drivers/tty/synclinkmp.c4
-rw-r--r--drivers/tty/tty_buffer.c85
-rw-r--r--drivers/tty/tty_io.c76
-rw-r--r--drivers/tty/tty_ldisc.c37
-rw-r--r--drivers/tty/tty_mutex.c60
-rw-r--r--drivers/tty/tty_port.c6
-rw-r--r--drivers/tty/vt/consolemap.c123
-rw-r--r--drivers/tty/vt/keyboard.c20
-rw-r--r--drivers/tty/vt/vt.c68
-rw-r--r--drivers/tty/vt/vt_ioctl.c25
-rw-r--r--drivers/uio/uio_pdrv_genirq.c8
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/cxacru.c34
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/atm/ueagle-atm.c15
-rw-r--r--drivers/usb/atm/usbatm.c30
-rw-r--r--drivers/usb/atm/xusbatm.c4
-rw-r--r--drivers/usb/chipidea/Kconfig32
-rw-r--r--drivers/usb/chipidea/Makefile14
-rw-r--r--drivers/usb/chipidea/bits.h90
-rw-r--r--drivers/usb/chipidea/ci.h313
-rw-r--r--drivers/usb/chipidea/ci13xxx_msm.c (renamed from drivers/usb/gadget/ci13xxx_msm.c)60
-rw-r--r--drivers/usb/chipidea/ci13xxx_pci.c (renamed from drivers/usb/gadget/ci13xxx_pci.c)154
-rw-r--r--drivers/usb/chipidea/core.c474
-rw-r--r--drivers/usb/chipidea/debug.c804
-rw-r--r--drivers/usb/chipidea/debug.h56
-rw-r--r--drivers/usb/chipidea/host.c160
-rw-r--r--drivers/usb/chipidea/host.h17
-rw-r--r--drivers/usb/chipidea/udc.c1809
-rw-r--r--drivers/usb/chipidea/udc.h93
-rw-r--r--drivers/usb/class/cdc-acm.c1
-rw-r--r--drivers/usb/class/cdc-wdm.c38
-rw-r--r--drivers/usb/class/usblp.c82
-rw-r--r--drivers/usb/core/Kconfig53
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/devio.c93
-rw-r--r--drivers/usb/core/driver.c103
-rw-r--r--drivers/usb/core/file.c4
-rw-r--r--drivers/usb/core/hcd.c15
-rw-r--r--drivers/usb/core/hub.c676
-rw-r--r--drivers/usb/core/inode.c748
-rw-r--r--drivers/usb/core/message.c38
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--drivers/usb/core/sysfs.c6
-rw-r--r--drivers/usb/core/urb.c21
-rw-r--r--drivers/usb/core/usb-acpi.c117
-rw-r--r--drivers/usb/core/usb.c9
-rw-r--r--drivers/usb/core/usb.h7
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c31
-rw-r--r--drivers/usb/dwc3/core.h40
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c32
-rw-r--r--drivers/usb/dwc3/ep0.c157
-rw-r--r--drivers/usb/dwc3/gadget.c151
-rw-r--r--drivers/usb/dwc3/gadget.h1
-rw-r--r--drivers/usb/dwc3/host.c19
-rw-r--r--drivers/usb/dwc3/io.h16
-rw-r--r--drivers/usb/gadget/Kconfig78
-rw-r--r--drivers/usb/gadget/Makefile6
-rw-r--r--drivers/usb/gadget/amd5536udc.c27
-rw-r--r--drivers/usb/gadget/amd5536udc.h1
-rw-r--r--drivers/usb/gadget/at91_udc.c77
-rw-r--r--drivers/usb/gadget/at91_udc.h3
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c76
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h1
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c2996
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h227
-rw-r--r--drivers/usb/gadget/composite.c107
-rw-r--r--drivers/usb/gadget/dummy_hcd.c8
-rw-r--r--drivers/usb/gadget/f_fs.c52
-rw-r--r--drivers/usb/gadget/f_hid.c2
-rw-r--r--drivers/usb/gadget/f_loopback.c4
-rw-r--r--drivers/usb/gadget/f_mass_storage.c7
-rw-r--r--drivers/usb/gadget/f_rndis.c30
-rw-r--r--drivers/usb/gadget/f_sourcesink.c424
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c371
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.h1
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c55
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h12
-rw-r--r--drivers/usb/gadget/fusb300_udc.c4
-rw-r--r--drivers/usb/gadget/fusb300_udc.h1
-rw-r--r--drivers/usb/gadget/g_ffs.c200
-rw-r--r--drivers/usb/gadget/g_zero.h5
-rw-r--r--drivers/usb/gadget/gadget_chips.h3
-rw-r--r--drivers/usb/gadget/goku_udc.c32
-rw-r--r--drivers/usb/gadget/goku_udc.h1
-rw-r--r--drivers/usb/gadget/imx_udc.c53
-rw-r--r--drivers/usb/gadget/langwell_udc.c3434
-rw-r--r--drivers/usb/gadget/langwell_udc.h224
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c3538
-rw-r--r--drivers/usb/gadget/m66592-udc.c10
-rw-r--r--drivers/usb/gadget/m66592-udc.h2
-rw-r--r--drivers/usb/gadget/mv_udc.h1
-rw-r--r--drivers/usb/gadget/mv_udc_core.c19
-rw-r--r--drivers/usb/gadget/omap_udc.c19
-rw-r--r--drivers/usb/gadget/omap_udc.h1
-rw-r--r--drivers/usb/gadget/pch_udc.c29
-rw-r--r--drivers/usb/gadget/printer.c470
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c26
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c29
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h3
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c1633
-rw-r--r--drivers/usb/gadget/s3c-hsotg.h377
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c9
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c14
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c2480
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.h146
-rw-r--r--drivers/usb/gadget/u_ether.c8
-rw-r--r--drivers/usb/gadget/u_ether.h46
-rw-r--r--drivers/usb/gadget/u_serial.c57
-rw-r--r--drivers/usb/gadget/zero.c19
-rw-r--r--drivers/usb/host/Kconfig43
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/bcma-hcd.c335
-rw-r--r--drivers/usb/host/ehci-dbg.c6
-rw-r--r--drivers/usb/host/ehci-fsl.c41
-rw-r--r--drivers/usb/host/ehci-fsl.h13
-rw-r--r--drivers/usb/host/ehci-hcd.c36
-rw-r--r--drivers/usb/host/ehci-hub.c22
-rw-r--r--drivers/usb/host/ehci-omap.c22
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-platform.c6
-rw-r--r--drivers/usb/host/ehci-q.c19
-rw-r--r--drivers/usb/host/ehci-s5p.c4
-rw-r--r--drivers/usb/host/ehci-sched.c55
-rw-r--r--drivers/usb/host/ehci-sead3.c266
-rw-r--r--drivers/usb/host/ehci-sh.c8
-rw-r--r--drivers/usb/host/ehci-spear.c36
-rw-r--r--drivers/usb/host/ehci-tegra.c82
-rw-r--r--drivers/usb/host/fhci-tds.c2
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c41
-rw-r--r--drivers/usb/host/isp1760-hcd.c9
-rw-r--r--drivers/usb/host/isp1760-if.c8
-rw-r--r--drivers/usb/host/ohci-at91.c16
-rw-r--r--drivers/usb/host/ohci-au1xxx.c3
-rw-r--r--drivers/usb/host/ohci-cns3xxx.c3
-rw-r--r--drivers/usb/host/ohci-da8xx.c2
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-ep93xx.c9
-rw-r--r--drivers/usb/host/ohci-exynos.c3
-rw-r--r--drivers/usb/host/ohci-hcd.c21
-rw-r--r--drivers/usb/host/ohci-nxp.c173
-rw-r--r--drivers/usb/host/ohci-omap.c10
-rw-r--r--drivers/usb/host/ohci-platform.c4
-rw-r--r--drivers/usb/host/ohci-pnx8550.c3
-rw-r--r--drivers/usb/host/ohci-ppc-of.c5
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c3
-rw-r--r--drivers/usb/host/ohci-ps3.c3
-rw-r--r--drivers/usb/host/ohci-pxa27x.c3
-rw-r--r--drivers/usb/host/ohci-s3c2410.c3
-rw-r--r--drivers/usb/host/ohci-sa1111.c4
-rw-r--r--drivers/usb/host/ohci-sh.c8
-rw-r--r--drivers/usb/host/ohci-spear.c36
-rw-r--r--drivers/usb/host/ohci-ssb.c260
-rw-r--r--drivers/usb/host/ohci-tmio.c3
-rw-r--r--drivers/usb/host/ohci-xls.c3
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c13
-rw-r--r--drivers/usb/host/pci-quirks.c32
-rw-r--r--drivers/usb/host/r8a66597-hcd.c20
-rw-r--r--drivers/usb/host/ssb-hcd.c280
-rw-r--r--drivers/usb/host/xhci-hub.c41
-rw-r--r--drivers/usb/host/xhci-mem.c39
-rw-r--r--drivers/usb/host/xhci-pci.c14
-rw-r--r--drivers/usb/host/xhci-ring.c28
-rw-r--r--drivers/usb/host/xhci.c483
-rw-r--r--drivers/usb/host/xhci.h17
-rw-r--r--drivers/usb/image/mdc800.c19
-rw-r--r--drivers/usb/misc/appledisplay.c12
-rw-r--r--drivers/usb/misc/emi26.c59
-rw-r--r--drivers/usb/misc/emi62.c62
-rw-r--r--drivers/usb/misc/idmouse.c9
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/ldusb.c15
-rw-r--r--drivers/usb/misc/legousbtower.c45
-rw-r--r--drivers/usb/misc/rio500.c65
-rw-r--r--drivers/usb/misc/usblcd.c24
-rw-r--r--drivers/usb/misc/usbtest.c17
-rw-r--r--drivers/usb/misc/uss720.c49
-rw-r--r--drivers/usb/misc/yurex.c54
-rw-r--r--drivers/usb/musb/Kconfig8
-rw-r--r--drivers/usb/musb/Makefile1
-rw-r--r--drivers/usb/musb/cppi_dma.c1
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/musb_dsps.c711
-rw-r--r--drivers/usb/musb/musb_io.h2
-rw-r--r--drivers/usb/otg/gpio_vbus.c81
-rw-r--r--drivers/usb/otg/twl6030-usb.c4
-rw-r--r--drivers/usb/phy/Kconfig17
-rw-r--r--drivers/usb/phy/Makefile7
-rw-r--r--drivers/usb/phy/isp1301.c77
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c19
-rw-r--r--drivers/usb/serial/Kconfig9
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/aircable.c16
-rw-r--r--drivers/usb/serial/ark3116.c36
-rw-r--r--drivers/usb/serial/belkin_sa.c47
-rw-r--r--drivers/usb/serial/bus.c9
-rw-r--r--drivers/usb/serial/ch341.c48
-rw-r--r--drivers/usb/serial/console.c9
-rw-r--r--drivers/usb/serial/cp210x.c32
-rw-r--r--drivers/usb/serial/cyberjack.c27
-rw-r--r--drivers/usb/serial/cypress_m8.c45
-rw-r--r--drivers/usb/serial/digi_acceleport.c35
-rw-r--r--drivers/usb/serial/empeg.c13
-rw-r--r--drivers/usb/serial/ezusb.c2
-rw-r--r--drivers/usb/serial/f81232.c37
-rw-r--r--drivers/usb/serial/ftdi_sio.c47
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h8
-rw-r--r--drivers/usb/serial/funsoft.c9
-rw-r--r--drivers/usb/serial/garmin_gps.c29
-rw-r--r--drivers/usb/serial/generic.c68
-rw-r--r--drivers/usb/serial/hp4x.c9
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/io_tables.h7
-rw-r--r--drivers/usb/serial/io_ti.c27
-rw-r--r--drivers/usb/serial/ipaq.c52
-rw-r--r--drivers/usb/serial/ipw.c18
-rw-r--r--drivers/usb/serial/ir-usb.c72
-rw-r--r--drivers/usb/serial/iuu_phoenix.c47
-rw-r--r--drivers/usb/serial/keyspan.c53
-rw-r--r--drivers/usb/serial/keyspan.h7
-rw-r--r--drivers/usb/serial/keyspan_pda.c17
-rw-r--r--drivers/usb/serial/kl5kusb105.c18
-rw-r--r--drivers/usb/serial/kobil_sct.c19
-rw-r--r--drivers/usb/serial/mct_u232.c33
-rw-r--r--drivers/usb/serial/metro-usb.c92
-rw-r--r--drivers/usb/serial/mos7720.c49
-rw-r--r--drivers/usb/serial/mos7840.c298
-rw-r--r--drivers/usb/serial/moto_modem.c9
-rw-r--r--drivers/usb/serial/navman.c26
-rw-r--r--drivers/usb/serial/omninet.c24
-rw-r--r--drivers/usb/serial/opticon.c53
-rw-r--r--drivers/usb/serial/option.c18
-rw-r--r--drivers/usb/serial/oti6858.c44
-rw-r--r--drivers/usb/serial/pl2303.c114
-rw-r--r--drivers/usb/serial/qcaux.c9
-rw-r--r--drivers/usb/serial/qcserial.c41
-rw-r--r--drivers/usb/serial/quatech2.c1155
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/serial/siemens_mpi.c9
-rw-r--r--drivers/usb/serial/sierra.c56
-rw-r--r--drivers/usb/serial/spcp8x5.c24
-rw-r--r--drivers/usb/serial/ssu100.c33
-rw-r--r--drivers/usb/serial/symbolserial.c30
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c65
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.h1
-rw-r--r--drivers/usb/serial/usb-serial.c109
-rw-r--r--drivers/usb/serial/usb_debug.c9
-rw-r--r--drivers/usb/serial/usb_wwan.c50
-rw-r--r--drivers/usb/serial/visor.c98
-rw-r--r--drivers/usb/serial/vivopay-serial.c9
-rw-r--r--drivers/usb/serial/whiteheat.c569
-rw-r--r--drivers/usb/serial/zio.c9
-rw-r--r--drivers/usb/storage/ene_ub6250.c6
-rw-r--r--drivers/usb/storage/unusual_devs.h9
-rw-r--r--drivers/usb/storage/usb.c22
-rw-r--r--drivers/usb/usb-skeleton.c36
-rw-r--r--drivers/video/au1100fb.c2
-rw-r--r--drivers/video/clps711xfb.c1
-rw-r--r--drivers/video/mxsfb.c9
-rw-r--r--drivers/video/omap2/displays/Kconfig8
-rw-r--r--drivers/video/omap2/displays/Makefile2
-rw-r--r--drivers/video/omap2/displays/panel-taal.c22
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c (renamed from drivers/video/omap2/displays/panel-dvi.c)134
-rw-r--r--drivers/video/omap2/dss/dsi.c133
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c5
-rw-r--r--drivers/video/sh_mobile_lcdcfb.h1
-rw-r--r--drivers/video/udlfb.c2
-rw-r--r--drivers/virtio/Kconfig11
-rw-r--r--drivers/virtio/virtio.c11
-rw-r--r--drivers/virtio/virtio_balloon.c34
-rw-r--r--drivers/virtio/virtio_mmio.c163
-rw-r--r--drivers/vme/Kconfig (renamed from drivers/staging/vme/Kconfig)6
-rw-r--r--drivers/vme/Makefile7
-rw-r--r--drivers/vme/boards/Kconfig (renamed from drivers/staging/vme/boards/Kconfig)0
-rw-r--r--drivers/vme/boards/Makefile (renamed from drivers/staging/vme/boards/Makefile)0
-rw-r--r--drivers/vme/boards/vme_vmivme7805.c (renamed from drivers/staging/vme/boards/vme_vmivme7805.c)0
-rw-r--r--drivers/vme/boards/vme_vmivme7805.h (renamed from drivers/staging/vme/boards/vme_vmivme7805.h)0
-rw-r--r--drivers/vme/bridges/Kconfig (renamed from drivers/staging/vme/bridges/Kconfig)0
-rw-r--r--drivers/vme/bridges/Makefile (renamed from drivers/staging/vme/bridges/Makefile)0
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c (renamed from drivers/staging/vme/bridges/vme_ca91cx42.c)8
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.h (renamed from drivers/staging/vme/bridges/vme_ca91cx42.h)0
-rw-r--r--drivers/vme/bridges/vme_tsi148.c (renamed from drivers/staging/vme/bridges/vme_tsi148.c)189
-rw-r--r--drivers/vme/bridges/vme_tsi148.h (renamed from drivers/staging/vme/bridges/vme_tsi148.h)21
-rw-r--r--drivers/vme/vme.c (renamed from drivers/staging/vme/vme.c)41
-rw-r--r--drivers/vme/vme_bridge.h (renamed from drivers/staging/vme/vme_bridge.h)0
-rw-r--r--drivers/w1/Kconfig2
-rw-r--r--drivers/w1/slaves/w1_ds2408.c2
-rw-r--r--drivers/w1/w1.c2
-rw-r--r--drivers/w1/w1_io.c22
-rw-r--r--drivers/watchdog/Kconfig38
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/ar7_wdt.c33
-rw-r--r--drivers/watchdog/hpwdt.c59
-rw-r--r--drivers/watchdog/i6300esb.c14
-rw-r--r--drivers/watchdog/ie6xx_wdt.c348
-rw-r--r--drivers/watchdog/it87_wdt.c7
-rw-r--r--drivers/watchdog/ixp2000_wdt.c215
-rw-r--r--drivers/watchdog/pcwd_pci.c18
-rw-r--r--drivers/watchdog/pnx4008_wdt.c10
-rw-r--r--drivers/watchdog/s3c2410_wdt.c7
-rw-r--r--drivers/watchdog/sch311x_wdt.c39
-rw-r--r--drivers/watchdog/shwdt.c306
-rw-r--r--drivers/watchdog/sp5100_tco.c2
-rw-r--r--drivers/watchdog/via_wdt.c18
-rw-r--r--drivers/watchdog/wdt_pci.c34
-rw-r--r--drivers/watchdog/wm831x_wdt.c13
-rw-r--r--drivers/xen/Kconfig2
1681 files changed, 121540 insertions, 68773 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d236aef..bfc9186 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -140,4 +140,12 @@ source "drivers/virt/Kconfig"
source "drivers/devfreq/Kconfig"
+source "drivers/extcon/Kconfig"
+
+source "drivers/memory/Kconfig"
+
+source "drivers/iio/Kconfig"
+
+source "drivers/vme/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index f9b82f2..0ee98d5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -133,3 +133,7 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
+obj-$(CONFIG_EXTCON) += extcon/
+obj-$(CONFIG_MEMORY) += memory/
+obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_VME_BUS) += vme/
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 3263b68..3188da3 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -250,6 +250,10 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
return -ENODEV;
}
+ /* For D3cold we should execute _PS3, not _PS4. */
+ if (state == ACPI_STATE_D3_COLD)
+ object_name[3] = '3';
+
/*
* Transition Power
* ----------------
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 29a4a5c..1564e09 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -69,6 +69,7 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
up_read(&bus_type_sem);
return ret;
}
+EXPORT_SYMBOL_GPL(register_acpi_bus_type);
static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
{
@@ -85,6 +86,7 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
up_read(&bus_type_sem);
return ret;
}
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
/* Get device's handler per its address under its parent */
struct acpi_find_child {
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 4a29763..a128082 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -720,21 +720,21 @@ static int acpi_pci_link_add(struct acpi_device *device)
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.active == link->irq.possible[i]) {
- printk(" *%d", link->irq.possible[i]);
+ printk(KERN_CONT " *%d", link->irq.possible[i]);
found = 1;
} else
- printk(" %d", link->irq.possible[i]);
+ printk(KERN_CONT " %d", link->irq.possible[i]);
}
- printk(")");
+ printk(KERN_CONT ")");
if (!found)
- printk(" *%d", link->irq.active);
+ printk(KERN_CONT " *%d", link->irq.active);
if (!link->device->status.enabled)
- printk(", disabled.");
+ printk(KERN_CONT ", disabled.");
- printk("\n");
+ printk(KERN_CONT "\n");
list_add_tail(&link->list, &acpi_link_list);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 330bb4d..0500f71 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -660,7 +660,7 @@ int acpi_power_on_resources(struct acpi_device *device, int state)
int acpi_power_transition(struct acpi_device *device, int state)
{
- int result;
+ int result = 0;
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
return -EINVAL;
@@ -679,8 +679,11 @@ int acpi_power_transition(struct acpi_device *device, int state)
* (e.g. so the device doesn't lose power while transitioning). Then,
* we dereference all power resources used in the current list.
*/
- result = acpi_power_on_list(&device->power.states[state].resources);
- if (!result)
+ if (state < ACPI_STATE_D3_COLD)
+ result = acpi_power_on_list(
+ &device->power.states[state].resources);
+
+ if (!result && device->power.state < ACPI_STATE_D3_COLD)
acpi_power_off_list(
&device->power.states[device->power.state].resources);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7417267..85cbfdc 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -908,6 +908,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device->power.states[ACPI_STATE_D3].flags.valid = 1;
device->power.states[ACPI_STATE_D3].power = 0;
+ /* Set D3cold's explicit_set flag if _PS3 exists. */
+ if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
+ device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1;
+
acpi_bus_init_power(device);
return 0;
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eb6fd23..06527c5 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -887,7 +887,7 @@ int __init acpi_sleep_init(void)
status = acpi_get_sleep_type_data(i, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[i] = 1;
- printk(" S%d", i);
+ printk(KERN_CONT " S%d", i);
}
}
@@ -901,7 +901,7 @@ int __init acpi_sleep_init(void)
hibernation_set_ops(old_suspend_ordering ?
&acpi_hibernation_ops_old : &acpi_hibernation_ops);
sleep_states[ACPI_STATE_S4] = 1;
- printk(" S4");
+ printk(KERN_CONT " S4");
if (!nosigcheck) {
acpi_get_table(ACPI_SIG_FACS, 1,
(struct acpi_table_header **)&facs);
@@ -914,11 +914,11 @@ int __init acpi_sleep_init(void)
status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[ACPI_STATE_S5] = 1;
- printk(" S5");
+ printk(KERN_CONT " S5");
pm_power_off_prepare = acpi_power_off_prepare;
pm_power_off = acpi_power_off;
}
- printk(")\n");
+ printk(KERN_CONT ")\n");
/*
* Register the tts_notifier to reboot notifier list so that the _TTS
* object can also be evaluated when the system enters S5.
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index b002a47..adbbc1c 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -382,3 +382,33 @@ acpi_evaluate_reference(acpi_handle handle,
}
EXPORT_SYMBOL(acpi_evaluate_reference);
+
+acpi_status
+acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *output;
+
+ status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ output = buffer.pointer;
+
+ if (!output || output->type != ACPI_TYPE_PACKAGE
+ || !output->package.count
+ || output->package.elements[0].type != ACPI_TYPE_BUFFER
+ || output->package.elements[0].buffer.length > sizeof(*pld)) {
+ status = AE_TYPE;
+ goto out;
+ }
+
+ memcpy(pld, output->package.elements[0].buffer.pointer,
+ output->package.elements[0].buffer.length);
+out:
+ kfree(buffer.pointer);
+ return status;
+}
+EXPORT_SYMBOL(acpi_get_physical_device_location);
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index cc27322..b7e7285 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -527,9 +527,9 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
if (ret)
goto err_release;
- if (dev->irq[0] && dev->irq[0] != NO_IRQ)
+ if (dev->irq[0])
ret = device_create_file(&dev->dev, &dev_attr_irq0);
- if (ret == 0 && dev->irq[1] && dev->irq[1] != NO_IRQ)
+ if (ret == 0 && dev->irq[1])
ret = device_create_file(&dev->dev, &dev_attr_irq1);
if (ret == 0)
return ret;
@@ -543,6 +543,55 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
}
EXPORT_SYMBOL_GPL(amba_device_add);
+static struct amba_device *
+amba_aphb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid, u64 dma_mask)
+{
+ struct amba_device *dev;
+ int ret;
+
+ dev = amba_device_alloc(name, base, size);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->dma_mask = dma_mask;
+ dev->dev.coherent_dma_mask = dma_mask;
+ dev->irq[0] = irq1;
+ dev->irq[1] = irq2;
+ dev->periphid = periphid;
+ dev->dev.platform_data = pdata;
+ dev->dev.parent = parent;
+
+ ret = amba_device_add(dev, &iomem_resource);
+ if (ret) {
+ amba_device_put(dev);
+ return ERR_PTR(ret);
+ }
+
+ return dev;
+}
+
+struct amba_device *
+amba_apb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, 0);
+}
+EXPORT_SYMBOL_GPL(amba_apb_device_add);
+
+struct amba_device *
+amba_ahb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, ~0ULL);
+}
+EXPORT_SYMBOL_GPL(amba_ahb_device_add);
+
static void amba_device_initialize(struct amba_device *dev, const char *name)
{
device_initialize(&dev->dev);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6bdedd7..2be8ef1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -416,6 +416,15 @@ config PATA_EFAR
If unsure, say N.
+config PATA_EP93XX
+ tristate "Cirrus Logic EP93xx PATA support"
+ depends on ARCH_EP93XX
+ help
+ This option enables support for the PATA controller in
+ the Cirrus Logic EP9312 and EP9315 ARM CPU.
+
+ If unsure, say N.
+
config PATA_HPT366
tristate "HPT 366/368 PATA support"
depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7..a454a13 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
+obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7df56ec..aae1156 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -177,7 +177,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
return -ENODEV;
- if (id->driver_data & ATA_GEN_INTEL_IDER)
+ if ((id->driver_data & ATA_GEN_INTEL_IDER) && !all_generic_ide)
if (!is_intel_ider(dev))
return -ENODEV;
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 7857e8f..3c809bf 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1554,6 +1554,39 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev)
return false;
}
+static int prefer_ms_hyperv = 1;
+module_param(prefer_ms_hyperv, int, 0);
+
+static void piix_ignore_devices_quirk(struct ata_host *host)
+{
+#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
+ static const struct dmi_system_id ignore_hyperv[] = {
+ {
+ /* On Hyper-V hypervisors the disks are exposed on
+ * both the emulated SATA controller and on the
+ * paravirtualised drivers. The CD/DVD devices
+ * are only exposed on the emulated controller.
+ * Request we ignore ATA devices on this host.
+ */
+ .ident = "Hyper-V Virtual Machine",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ },
+ },
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv);
+
+ if (dmi && prefer_ms_hyperv) {
+ host->flags |= ATA_HOST_IGNORE_ATA;
+ dev_info(host->dev, "%s detected, ATA device ignore set\n",
+ dmi->ident);
+ }
+#endif
+}
+
/**
* piix_init_one - Register PIIX ATA PCI device with kernel services
* @pdev: PCI device to register
@@ -1669,6 +1702,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
}
host->flags |= ATA_HOST_PARALLEL_SCAN;
+ /* Allow hosts to specify device types to ignore when scanning. */
+ piix_ignore_devices_quirk(host);
+
pci_set_master(pdev);
return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 23763a1..cece3a4 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1973,6 +1973,12 @@ retry:
if (class == ATA_DEV_ATA) {
if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
goto err_out;
+ if (ap->host->flags & ATA_HOST_IGNORE_ATA &&
+ ata_id_is_ata(id)) {
+ ata_dev_dbg(dev,
+ "host indicates ignore ATA devices, ignored\n");
+ return -ENOENT;
+ }
} else {
if (ata_id_is_ata(id))
goto err_out;
@@ -4051,6 +4057,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
+ { "2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */
{ "Config Disk", NULL, ATA_HORKAGE_DISABLE },
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d1fbd59..6d53cf9 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2047,6 +2047,26 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
}
/**
+ * ata_eh_worth_retry - analyze error and decide whether to retry
+ * @qc: qc to possibly retry
+ *
+ * Look at the cause of the error and decide if a retry
+ * might be useful or not. We don't want to retry media errors
+ * because the drive itself has probably already taken 10-30 seconds
+ * doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & AC_ERR_MEDIA)
+ return 0; /* don't retry media errors */
+ if (qc->flags & ATA_QCFLAG_IO)
+ return 1; /* otherwise retry anything from fs stack */
+ if (qc->err_mask & AC_ERR_INVALID)
+ return 0; /* don't retry these */
+ return qc->err_mask != AC_ERR_DEV; /* retry if not dev error */
+}
+
+/**
* ata_eh_link_autopsy - analyze error and determine recovery action
* @link: host link to perform autopsy on
*
@@ -2120,9 +2140,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
/* determine whether the command is worth retrying */
- if (qc->flags & ATA_QCFLAG_IO ||
- (!(qc->err_mask & AC_ERR_INVALID) &&
- qc->err_mask != AC_ERR_DEV))
+ if (ata_eh_worth_retry(qc))
qc->flags |= ATA_QCFLAG_RETRY;
/* accumulate error info */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
new file mode 100644
index 0000000..6ef2e37
--- /dev/null
+++ b/drivers/ata/pata_ep93xx.c
@@ -0,0 +1,1044 @@
+/*
+ * EP93XX PATA controller driver.
+ *
+ * Copyright (c) 2012, Metasoft s.c.
+ * Rafal Prylowski <prylowski@metasoft.pl>
+ *
+ * Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
+ * PATA driver by Lennert Buytenhek and Alessandro Zummo.
+ * Read/Write timings, resource management and other improvements
+ * from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
+ * DMA engine support based on spi-ep93xx.c by Mika Westerberg.
+ *
+ * Original copyrights:
+ *
+ * Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
+ * PATA host controller driver.
+ *
+ * Copyright (c) 2009, Bartlomiej Zolnierkiewicz
+ *
+ * Heavily based on the ep93xx-ide.c driver:
+ *
+ * Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
+ * INESC Inovacao (INOV)
+ *
+ * EP93XX PATA controller driver.
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * An ATA driver for the Cirrus Logic EP93xx PATA controller.
+ *
+ * Based on an earlier version by Alessandro Zummo, which is:
+ * Copyright (C) 2006 Tower Technologies
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+
+#define DRV_NAME "ep93xx-ide"
+#define DRV_VERSION "1.0"
+
+enum {
+ /* IDE Control Register */
+ IDECTRL = 0x00,
+ IDECTRL_CS0N = (1 << 0),
+ IDECTRL_CS1N = (1 << 1),
+ IDECTRL_DIORN = (1 << 5),
+ IDECTRL_DIOWN = (1 << 6),
+ IDECTRL_INTRQ = (1 << 9),
+ IDECTRL_IORDY = (1 << 10),
+ /*
+ * the device IDE register to be accessed is selected through
+ * IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
+ * b4 b3 b2 b1 b0
+ * A2 A1 A0 CS1N CS0N
+ * the values filled in this structure allows the value to be directly
+ * ORed to the IDECTRL register, hence giving directly the A[2:0] and
+ * CS1N/CS0N values for each IDE register.
+ * The values correspond to the transformation:
+ * ((real IDE address) << 2) | CS1N value << 1 | CS0N value
+ */
+ IDECTRL_ADDR_CMD = 0 + 2, /* CS1 */
+ IDECTRL_ADDR_DATA = (ATA_REG_DATA << 2) + 2,
+ IDECTRL_ADDR_ERROR = (ATA_REG_ERR << 2) + 2,
+ IDECTRL_ADDR_FEATURE = (ATA_REG_FEATURE << 2) + 2,
+ IDECTRL_ADDR_NSECT = (ATA_REG_NSECT << 2) + 2,
+ IDECTRL_ADDR_LBAL = (ATA_REG_LBAL << 2) + 2,
+ IDECTRL_ADDR_LBAM = (ATA_REG_LBAM << 2) + 2,
+ IDECTRL_ADDR_LBAH = (ATA_REG_LBAH << 2) + 2,
+ IDECTRL_ADDR_DEVICE = (ATA_REG_DEVICE << 2) + 2,
+ IDECTRL_ADDR_STATUS = (ATA_REG_STATUS << 2) + 2,
+ IDECTRL_ADDR_COMMAND = (ATA_REG_CMD << 2) + 2,
+ IDECTRL_ADDR_ALTSTATUS = (0x06 << 2) + 1, /* CS0 */
+ IDECTRL_ADDR_CTL = (0x06 << 2) + 1, /* CS0 */
+
+ /* IDE Configuration Register */
+ IDECFG = 0x04,
+ IDECFG_IDEEN = (1 << 0),
+ IDECFG_PIO = (1 << 1),
+ IDECFG_MDMA = (1 << 2),
+ IDECFG_UDMA = (1 << 3),
+ IDECFG_MODE_SHIFT = 4,
+ IDECFG_MODE_MASK = (0xf << 4),
+ IDECFG_WST_SHIFT = 8,
+ IDECFG_WST_MASK = (0x3 << 8),
+
+ /* MDMA Operation Register */
+ IDEMDMAOP = 0x08,
+
+ /* UDMA Operation Register */
+ IDEUDMAOP = 0x0c,
+ IDEUDMAOP_UEN = (1 << 0),
+ IDEUDMAOP_RWOP = (1 << 1),
+
+ /* PIO/MDMA/UDMA Data Registers */
+ IDEDATAOUT = 0x10,
+ IDEDATAIN = 0x14,
+ IDEMDMADATAOUT = 0x18,
+ IDEMDMADATAIN = 0x1c,
+ IDEUDMADATAOUT = 0x20,
+ IDEUDMADATAIN = 0x24,
+
+ /* UDMA Status Register */
+ IDEUDMASTS = 0x28,
+ IDEUDMASTS_DMAIDE = (1 << 16),
+ IDEUDMASTS_INTIDE = (1 << 17),
+ IDEUDMASTS_SBUSY = (1 << 18),
+ IDEUDMASTS_NDO = (1 << 24),
+ IDEUDMASTS_NDI = (1 << 25),
+ IDEUDMASTS_N4X = (1 << 26),
+
+ /* UDMA Debug Status Register */
+ IDEUDMADEBUG = 0x2c,
+};
+
+struct ep93xx_pata_data {
+ const struct platform_device *pdev;
+ void __iomem *ide_base;
+ struct ata_timing t;
+ bool iordy;
+
+ unsigned long udma_in_phys;
+ unsigned long udma_out_phys;
+
+ struct dma_chan *dma_rx_channel;
+ struct ep93xx_dma_data dma_rx_data;
+ struct dma_chan *dma_tx_channel;
+ struct ep93xx_dma_data dma_tx_data;
+};
+
+static void ep93xx_pata_clear_regs(void __iomem *base)
+{
+ writel(IDECTRL_CS0N | IDECTRL_CS1N | IDECTRL_DIORN |
+ IDECTRL_DIOWN, base + IDECTRL);
+
+ writel(0, base + IDECFG);
+ writel(0, base + IDEMDMAOP);
+ writel(0, base + IDEUDMAOP);
+ writel(0, base + IDEDATAOUT);
+ writel(0, base + IDEDATAIN);
+ writel(0, base + IDEMDMADATAOUT);
+ writel(0, base + IDEMDMADATAIN);
+ writel(0, base + IDEUDMADATAOUT);
+ writel(0, base + IDEUDMADATAIN);
+ writel(0, base + IDEUDMADEBUG);
+}
+
+static bool ep93xx_pata_check_iordy(void __iomem *base)
+{
+ return !!(readl(base + IDECTRL) & IDECTRL_IORDY);
+}
+
+/*
+ * According to EP93xx User's Guide, WST field of IDECFG specifies number
+ * of HCLK cycles to hold the data bus after a PIO write operation.
+ * It should be programmed to guarantee following delays:
+ *
+ * PIO Mode [ns]
+ * 0 30
+ * 1 20
+ * 2 15
+ * 3 10
+ * 4 5
+ *
+ * Maximum possible value for HCLK is 100MHz.
+ */
+static int ep93xx_pata_get_wst(int pio_mode)
+{
+ int val;
+
+ if (pio_mode == 0)
+ val = 3;
+ else if (pio_mode < 3)
+ val = 2;
+ else
+ val = 1;
+
+ return val << IDECFG_WST_SHIFT;
+}
+
+static void ep93xx_pata_enable_pio(void __iomem *base, int pio_mode)
+{
+ writel(IDECFG_IDEEN | IDECFG_PIO |
+ ep93xx_pata_get_wst(pio_mode) |
+ (pio_mode << IDECFG_MODE_SHIFT), base + IDECFG);
+}
+
+/*
+ * Based on delay loop found in mach-pxa/mp900.c.
+ *
+ * Single iteration should take 5 cpu cycles. This is 25ns assuming the
+ * fastest ep93xx cpu speed (200MHz) and is better optimized for PIO4 timings
+ * than eg. 20ns.
+ */
+static void ep93xx_pata_delay(unsigned long count)
+{
+ __asm__ volatile (
+ "0:\n"
+ "mov r0, r0\n"
+ "subs %0, %1, #1\n"
+ "bge 0b\n"
+ : "=r" (count)
+ : "0" (count)
+ );
+}
+
+static unsigned long ep93xx_pata_wait_for_iordy(void __iomem *base,
+ unsigned long t2)
+{
+ /*
+ * According to ATA specification, IORDY pin can be first sampled
+ * tA = 35ns after activation of DIOR-/DIOW-. Maximum IORDY pulse
+ * width is tB = 1250ns.
+ *
+ * We are already t2 delay loop iterations after activation of
+ * DIOR-/DIOW-, so we set timeout to (1250 + 35) / 25 - t2 additional
+ * delay loop iterations.
+ */
+ unsigned long start = (1250 + 35) / 25 - t2;
+ unsigned long counter = start;
+
+ while (!ep93xx_pata_check_iordy(base) && counter--)
+ ep93xx_pata_delay(1);
+ return start - counter;
+}
+
+/* common part at start of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_begin(void __iomem *base, unsigned long addr,
+ unsigned long t1)
+{
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_delay(t1);
+}
+
+/* common part at end of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_end(void __iomem *base, unsigned long addr,
+ bool iordy, unsigned long t0, unsigned long t2,
+ unsigned long t2i)
+{
+ ep93xx_pata_delay(t2);
+ /* lengthen t2 if needed */
+ if (iordy)
+ t2 += ep93xx_pata_wait_for_iordy(base, t2);
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ if (t0 > t2 && t0 - t2 > t2i)
+ ep93xx_pata_delay(t0 - t2);
+ else
+ ep93xx_pata_delay(t2i);
+}
+
+static u16 ep93xx_pata_read(struct ep93xx_pata_data *drv_data,
+ unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ writel(IDECTRL_DIOWN | addr, base + IDECTRL);
+ /*
+ * The IDEDATAIN register is loaded from the DD pins at the positive
+ * edge of the DIORN signal. (EP93xx UG p27-14)
+ */
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+ return readl(base + IDEDATAIN);
+}
+
+/* IDE register read */
+static u16 ep93xx_pata_read_reg(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, true);
+}
+
+/* PIO data read */
+static u16 ep93xx_pata_read_data(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, false);
+}
+
+static void ep93xx_pata_write(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ /*
+ * Value from IDEDATAOUT register is driven onto the DD pins when
+ * DIOWN is low. (EP93xx UG p27-13)
+ */
+ writel(value, base + IDEDATAOUT);
+ writel(IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+}
+
+/* IDE register write */
+static void ep93xx_pata_write_reg(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, true);
+}
+
+/* PIO data write */
+static void ep93xx_pata_write_data(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, false);
+}
+
+static void ep93xx_pata_set_piomode(struct ata_port *ap,
+ struct ata_device *adev)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ struct ata_device *pair = ata_dev_pair(adev);
+ /*
+ * Calculate timings for the delay loop, assuming ep93xx cpu speed
+ * is 200MHz (maximum possible for ep93xx). If actual cpu speed is
+ * slower, we will wait a bit longer in each delay.
+ * Additional division of cpu speed by 5, because single iteration
+ * of our delay loop takes 5 cpu cycles (25ns).
+ */
+ unsigned long T = 1000000 / (200 / 5);
+
+ ata_timing_compute(adev, adev->pio_mode, &drv_data->t, T, 0);
+ if (pair && pair->pio_mode) {
+ struct ata_timing t;
+ ata_timing_compute(pair, pair->pio_mode, &t, T, 0);
+ ata_timing_merge(&t, &drv_data->t, &drv_data->t,
+ ATA_TIMING_SETUP | ATA_TIMING_8BIT);
+ }
+ drv_data->iordy = ata_pio_need_iordy(adev);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ adev->pio_mode - XFER_PIO_0);
+}
+
+/* Note: original code is ata_sff_check_status */
+static u8 ep93xx_pata_check_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_STATUS);
+}
+
+static u8 ep93xx_pata_check_altstatus(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_ALTSTATUS);
+}
+
+/* Note: original code is ata_sff_tf_load */
+static void ep93xx_pata_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ ep93xx_pata_write_reg(drv_data, tf->hob_feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->hob_nsect,
+ IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbal,
+ IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbam,
+ IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbah,
+ IDECTRL_ADDR_LBAH);
+ }
+
+ if (is_addr) {
+ ep93xx_pata_write_reg(drv_data, tf->feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->nsect, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->lbal, IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->lbam, IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->lbah, IDECTRL_ADDR_LBAH);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ ep93xx_pata_write_reg(drv_data, tf->device,
+ IDECTRL_ADDR_DEVICE);
+
+ ata_wait_idle(ap);
+}
+
+/* Note: original code is ata_sff_tf_read */
+static void ep93xx_pata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ tf->command = ep93xx_pata_check_status(ap);
+ tf->feature = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_FEATURE);
+ tf->nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ tf->lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+ tf->lbam = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAM);
+ tf->lbah = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAH);
+ tf->device = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl | ATA_HOB,
+ IDECTRL_ADDR_CTL);
+ tf->hob_feature = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_FEATURE);
+ tf->hob_nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ tf->hob_lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ tf->hob_lbam = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAM);
+ tf->hob_lbah = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAH);
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/* Note: original code is ata_sff_exec_command */
+static void ep93xx_pata_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, tf->command,
+ IDECTRL_ADDR_COMMAND);
+ ata_sff_pause(ap);
+}
+
+/* Note: original code is ata_sff_dev_select */
+static void ep93xx_pata_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 tmp = ATA_DEVICE_OBS;
+
+ if (device != 0)
+ tmp |= ATA_DEV1;
+
+ ep93xx_pata_write_reg(drv_data, tmp, IDECTRL_ADDR_DEVICE);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+/* Note: original code is ata_sff_set_devctl */
+static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ctl, IDECTRL_ADDR_CTL);
+}
+
+/* Note: original code is ata_sff_data_xfer */
+static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = adev->link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u16 *data = (u16 *)buf;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ while (words--)
+ if (rw == READ)
+ *data++ = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ else
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*data++),
+ IDECTRL_ADDR_DATA);
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ buf += buflen - 1;
+
+ if (rw == READ) {
+ *pad = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*pad),
+ IDECTRL_ADDR_DATA);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+/* Note: original code is ata_devchk */
+static bool ep93xx_pata_device_is_present(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 nsect, lbal;
+
+ ap->ops->sff_dev_select(ap, device);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return true;
+
+ return false;
+}
+
+/* Note: original code is ata_sff_wait_after_reset */
+static int ep93xx_pata_wait_after_reset(struct ata_link *link,
+ unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ int rc, ret = 0;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /*
+ * -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ /*
+ * if device 1 was found in ata_devchk, wait for register
+ * access briefly, then wait for BSY to clear.
+ */
+ if (dev1) {
+ int i;
+
+ ap->ops->sff_dev_select(ap, 1);
+
+ /*
+ * Wait for register access. Some ATAPI devices fail
+ * to set nsect/lbal after reset, so don't waste too
+ * much time on it. We're gonna wait for !BSY anyway.
+ */
+ for (i = 0; i < 2; i++) {
+ u8 nsect, lbal;
+
+ nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ if (nsect == 1 && lbal == 1)
+ break;
+ msleep(50); /* give drive a breather */
+ }
+
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
+ /* is all this really necessary? */
+ ap->ops->sff_dev_select(ap, 0);
+ if (dev1)
+ ap->ops->sff_dev_select(ap, 1);
+ if (dev0)
+ ap->ops->sff_dev_select(ap, 0);
+
+ return ret;
+}
+
+/* Note: original code is ata_bus_softreset */
+static int ep93xx_pata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl | ATA_SRST, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = ap->ctl;
+
+ return ep93xx_pata_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
+{
+ if (drv_data->dma_rx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ drv_data->dma_rx_channel = NULL;
+ }
+ if (drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_tx_channel);
+ drv_data->dma_tx_channel = NULL;
+ }
+}
+
+static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
+{
+ if (ep93xx_dma_chan_is_m2p(chan))
+ return false;
+
+ chan->private = filter_param;
+ return true;
+}
+
+static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
+{
+ const struct platform_device *pdev = drv_data->pdev;
+ dma_cap_mask_t mask;
+ struct dma_slave_config conf;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /*
+ * Request two channels for IDE. Another possibility would be
+ * to request only one channel, and reprogram it's direction at
+ * start of new transfer.
+ */
+ drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+ drv_data->dma_rx_data.name = "ep93xx-pata-rx";
+ drv_data->dma_rx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
+ if (!drv_data->dma_rx_channel)
+ return;
+
+ drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+ drv_data->dma_tx_data.name = "ep93xx-pata-tx";
+ drv_data->dma_tx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
+ if (!drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ return;
+ }
+
+ /* Configure receive channel direction and source address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_FROM_DEVICE;
+ conf.src_addr = drv_data->udma_in_phys;
+ conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure rx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ return;
+ }
+
+ /* Configure transmit channel direction and destination address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_TO_DEVICE;
+ conf.dst_addr = drv_data->udma_out_phys;
+ conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure tx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ }
+}
+
+static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
+{
+ struct dma_async_tx_descriptor *txd;
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+ struct ata_device *adev = qc->dev;
+ u32 v = qc->dma_dir == DMA_TO_DEVICE ? IDEUDMAOP_RWOP : 0;
+ struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE
+ ? drv_data->dma_tx_channel : drv_data->dma_rx_channel;
+
+ txd = channel->device->device_prep_slave_sg(channel, qc->sg,
+ qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL);
+ if (!txd) {
+ dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");
+ return;
+ }
+ txd->callback = NULL;
+ txd->callback_param = NULL;
+
+ if (dmaengine_submit(txd) < 0) {
+ dev_err(qc->ap->dev, "failed to submit dma transfer\n");
+ return;
+ }
+ dma_async_issue_pending(channel);
+
+ /*
+ * When enabling UDMA operation, IDEUDMAOP register needs to be
+ * programmed in three step sequence:
+ * 1) set or clear the RWOP bit,
+ * 2) perform dummy read of the register,
+ * 3) set the UEN bit.
+ */
+ writel(v, base + IDEUDMAOP);
+ readl(base + IDEUDMAOP);
+ writel(v | IDEUDMAOP_UEN, base + IDEUDMAOP);
+
+ writel(IDECFG_IDEEN | IDECFG_UDMA |
+ ((adev->xfer_mode - XFER_UDMA_0) << IDECFG_MODE_SHIFT),
+ base + IDECFG);
+}
+
+static void ep93xx_pata_dma_stop(struct ata_queued_cmd *qc)
+{
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+
+ /* terminate all dma transfers, if not yet finished */
+ dmaengine_terminate_all(drv_data->dma_rx_channel);
+ dmaengine_terminate_all(drv_data->dma_tx_channel);
+
+ /*
+ * To properly stop IDE-DMA, IDEUDMAOP register must to be cleared
+ * and IDECTRL register must be set to default value.
+ */
+ writel(0, base + IDEUDMAOP);
+ writel(readl(base + IDECTRL) | IDECTRL_DIOWN | IDECTRL_DIORN |
+ IDECTRL_CS0N | IDECTRL_CS1N, base + IDECTRL);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ qc->dev->pio_mode - XFER_PIO_0);
+
+ ata_sff_dma_pause(qc->ap);
+}
+
+static void ep93xx_pata_dma_setup(struct ata_queued_cmd *qc)
+{
+ qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+static u8 ep93xx_pata_dma_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u32 val = readl(drv_data->ide_base + IDEUDMASTS);
+
+ /*
+ * UDMA Status Register bits:
+ *
+ * DMAIDE - DMA request signal from UDMA state machine,
+ * INTIDE - INT line generated by UDMA because of errors in the
+ * state machine,
+ * SBUSY - UDMA state machine busy, not in idle state,
+ * NDO - error for data-out not completed,
+ * NDI - error for data-in not completed,
+ * N4X - error for data transferred not multiplies of four
+ * 32-bit words.
+ * (EP93xx UG p27-17)
+ */
+ if (val & IDEUDMASTS_NDO || val & IDEUDMASTS_NDI ||
+ val & IDEUDMASTS_N4X || val & IDEUDMASTS_INTIDE)
+ return ATA_DMA_ERR;
+
+ /* read INTRQ (INT[3]) pin input state */
+ if (readl(drv_data->ide_base + IDECTRL) & IDECTRL_INTRQ)
+ return ATA_DMA_INTR;
+
+ if (val & IDEUDMASTS_SBUSY || val & IDEUDMASTS_DMAIDE)
+ return ATA_DMA_ACTIVE;
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_softreset */
+static int ep93xx_pata_softreset(struct ata_link *al, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = al->ap;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (ep93xx_pata_device_is_present(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && ep93xx_pata_device_is_present(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->sff_dev_select(al->ap, 0);
+
+ /* issue bus reset */
+ rc = ep93xx_pata_bus_softreset(ap, devmask, deadline);
+ /* if link is ocuppied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(al))) {
+ ata_link_printk(al, KERN_ERR, "SRST failed (errno=%d)\n",
+ rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&al->device[0], devmask & (1 << 0),
+ &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_sff_dev_classify(&al->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_drain_fifo */
+static void ep93xx_pata_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct ep93xx_pata_data *drv_data;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ drv_data = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2)
+ ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DATA);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_printk(ap, KERN_DEBUG,
+ "drained %d bytes to clear DRQ.\n", count);
+
+}
+
+static int ep93xx_pata_port_start(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ /*
+ * Set timings to safe values at startup (= number of ns from ATA
+ * specification), we'll switch to properly calculated values later.
+ */
+ drv_data->t = *ata_timing_find_mode(XFER_PIO_0);
+ return 0;
+}
+
+static struct scsi_host_template ep93xx_pata_sht = {
+ ATA_BASE_SHT(DRV_NAME),
+ /* ep93xx dma implementation limit */
+ .sg_tablesize = 32,
+ /* ep93xx dma can't transfer 65536 bytes at once */
+ .dma_boundary = 0x7fff,
+};
+
+static struct ata_port_operations ep93xx_pata_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .qc_prep = ata_noop_qc_prep,
+
+ .softreset = ep93xx_pata_softreset,
+ .hardreset = ATA_OP_NULL,
+
+ .sff_dev_select = ep93xx_pata_dev_select,
+ .sff_set_devctl = ep93xx_pata_set_devctl,
+ .sff_check_status = ep93xx_pata_check_status,
+ .sff_check_altstatus = ep93xx_pata_check_altstatus,
+ .sff_tf_load = ep93xx_pata_tf_load,
+ .sff_tf_read = ep93xx_pata_tf_read,
+ .sff_exec_command = ep93xx_pata_exec_command,
+ .sff_data_xfer = ep93xx_pata_data_xfer,
+ .sff_drain_fifo = ep93xx_pata_drain_fifo,
+ .sff_irq_clear = ATA_OP_NULL,
+
+ .set_piomode = ep93xx_pata_set_piomode,
+
+ .bmdma_setup = ep93xx_pata_dma_setup,
+ .bmdma_start = ep93xx_pata_dma_start,
+ .bmdma_stop = ep93xx_pata_dma_stop,
+ .bmdma_status = ep93xx_pata_dma_status,
+
+ .cable_detect = ata_cable_unknown,
+ .port_start = ep93xx_pata_port_start,
+};
+
+static int __devinit ep93xx_pata_probe(struct platform_device *pdev)
+{
+ struct ep93xx_pata_data *drv_data;
+ struct ata_host *host;
+ struct ata_port *ap;
+ unsigned int irq;
+ struct resource *mem_res;
+ void __iomem *ide_base;
+ int err;
+
+ err = ep93xx_ide_acquire_gpio(pdev);
+ if (err)
+ return err;
+
+ /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
+ if (!ide_base) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ platform_set_drvdata(pdev, drv_data);
+ drv_data->pdev = pdev;
+ drv_data->ide_base = ide_base;
+ drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
+ drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
+ ep93xx_pata_dma_init(drv_data);
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ err = -ENXIO;
+ goto err_rel_dma;
+ }
+
+ ep93xx_pata_clear_regs(ide_base);
+
+ host->private_data = drv_data;
+
+ ap = host->ports[0];
+ ap->dev = &pdev->dev;
+ ap->ops = &ep93xx_pata_port_ops;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = ATA_PIO4;
+
+ /*
+ * Maximum UDMA modes:
+ * EP931x rev.E0 - UDMA2
+ * EP931x rev.E1 - UDMA3
+ * EP931x rev.E2 - UDMA4
+ *
+ * MWDMA support was removed from EP931x rev.E2,
+ * so this driver supports only UDMA modes.
+ */
+ if (drv_data->dma_rx_channel && drv_data->dma_tx_channel) {
+ int chip_rev = ep93xx_chip_revision();
+
+ if (chip_rev == EP93XX_CHIP_REV_E1)
+ ap->udma_mask = ATA_UDMA3;
+ else if (chip_rev == EP93XX_CHIP_REV_E2)
+ ap->udma_mask = ATA_UDMA4;
+ else
+ ap->udma_mask = ATA_UDMA2;
+ }
+
+ /* defaults, pio 0 */
+ ep93xx_pata_enable_pio(ide_base, 0);
+
+ dev_info(&pdev->dev, "version " DRV_VERSION "\n");
+
+ /* activate host */
+ err = ata_host_activate(host, irq, ata_bmdma_interrupt, 0,
+ &ep93xx_pata_sht);
+ if (err == 0)
+ return 0;
+
+err_rel_dma:
+ ep93xx_pata_release_dma(drv_data);
+err_rel_gpio:
+ ep93xx_ide_release_gpio(pdev);
+ return err;
+}
+
+static int __devexit ep93xx_pata_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct ep93xx_pata_data *drv_data = host->private_data;
+
+ ata_host_detach(host);
+ ep93xx_pata_release_dma(drv_data);
+ ep93xx_pata_clear_regs(drv_data->ide_base);
+ ep93xx_ide_release_gpio(pdev);
+ return 0;
+}
+
+static struct platform_driver ep93xx_pata_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ep93xx_pata_probe,
+ .remove = __devexit_p(ep93xx_pata_remove),
+};
+
+module_platform_driver(ep93xx_pata_platform_driver);
+
+MODULE_AUTHOR("Alessandro Zummo, Lennert Buytenhek, Joao Ramos, "
+ "Bartlomiej Zolnierkiewicz, Rafal Prylowski");
+MODULE_DESCRIPTION("low-level driver for cirrus ep93xx IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:pata_ep93xx");
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 26a06b8..2bcef65 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -21,8 +21,7 @@
#include "power/power.h"
/* /sys/devices/system */
-/* FIXME: make static after drivers/base/sys.c is deleted */
-struct kset *system_kset;
+static struct kset *system_kset;
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index e28ce98..346be8b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <linux/async.h>
#include <linux/pm_runtime.h>
+#include <linux/netdevice.h>
#include "base.h"
#include "power/power.h"
@@ -65,7 +66,7 @@ static inline int device_is_not_partition(struct device *dev)
* @dev: struct device to get the name of
*
* Will return the device's driver's name if it is bound to a device. If
- * the device is not bound to a device, it will return the name of the bus
+ * the device is not bound to a driver, it will return the name of the bus
* it is attached to. If it is not attached to a bus either, an empty
* string will be returned.
*/
@@ -878,8 +879,8 @@ EXPORT_SYMBOL_GPL(dev_set_name);
* to NULL prevents an entry from being created. class->dev_kobj must
* be set (or cleared) before any devices are registered to the class
* otherwise device_create_sys_dev_entry() and
- * device_remove_sys_dev_entry() will disagree about the the presence
- * of the link.
+ * device_remove_sys_dev_entry() will disagree about the presence of
+ * the link.
*/
static struct kobject *device_to_dev_kobj(struct device *dev)
{
@@ -1843,15 +1844,60 @@ void device_shutdown(void)
*/
#ifdef CONFIG_PRINTK
-
int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
+ char dict[128];
+ size_t dictlen = 0;
+ const char *subsys;
+
if (!dev)
return printk("%s(NULL device *): %pV", level, vaf);
- return printk("%s%s %s: %pV",
- level, dev_driver_string(dev), dev_name(dev), vaf);
+ if (dev->class)
+ subsys = dev->class->name;
+ else if (dev->bus)
+ subsys = dev->bus->name;
+ else
+ goto skip;
+
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "SUBSYSTEM=%s", subsys);
+
+ /*
+ * Add device identifier DEVICE=:
+ * b12:8 block dev_t
+ * c127:3 char dev_t
+ * n8 netdev ifindex
+ * +sound:card0 subsystem:devname
+ */
+ if (MAJOR(dev->devt)) {
+ char c;
+
+ if (strcmp(subsys, "block") == 0)
+ c = 'b';
+ else
+ c = 'c';
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=%c%u:%u",
+ c, MAJOR(dev->devt), MINOR(dev->devt));
+ } else if (strcmp(subsys, "net") == 0) {
+ struct net_device *net = to_net_dev(dev);
+
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=n%u", net->ifindex);
+ } else {
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=+%s:%s", subsys, dev_name(dev));
+ }
+skip:
+ return printk_emit(0, level[1] - '0',
+ dictlen ? dict : NULL, dictlen,
+ "%s %s: %pV",
+ dev_driver_string(dev), dev_name(dev), vaf);
}
EXPORT_SYMBOL(__dev_printk);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index adf937b..6345294 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -330,8 +330,4 @@ void __init cpu_dev_init(void)
panic("Failed to register CPU subsystem");
cpu_dev_register_generic();
-
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
- sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
-#endif
}
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 524bf96..2360adb 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -309,6 +309,10 @@ EXPORT_SYMBOL_GPL(devres_remove);
* which @match returns 1. If @match is NULL, it's considered to
* match all. If found, the resource is removed atomically and freed.
*
+ * Note that the release function for the resource will not be called,
+ * only the devres-allocated data will be freed. The caller becomes
+ * responsible for freeing any other data.
+ *
* RETURNS:
* 0 if devres is found and freed, -ENOENT if not found.
*/
@@ -326,6 +330,37 @@ int devres_destroy(struct device *dev, dr_release_t release,
}
EXPORT_SYMBOL_GPL(devres_destroy);
+
+/**
+ * devres_release - Find a device resource and destroy it, calling release
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically, the
+ * release function called and the resource freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_release(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ (*release)(dev, res);
+ devres_free(res);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devres_release);
+
static int remove_nodes(struct device *dev,
struct list_head *first, struct list_head *end,
struct list_head *todo)
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 8493536..765c3a2 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -7,9 +7,9 @@
* devtmpfs, a tmpfs-based filesystem is created. Every driver-core
* device which requests a device node, will add a node in this
* filesystem.
- * By default, all devices are named after the the name of the
- * device, owned by root and have a default mode of 0600. Subsystems
- * can overwrite the default setting if needed.
+ * By default, all devices are named after the name of the device,
+ * owned by root and have a default mode of 0600. Subsystems can
+ * overwrite the default setting if needed.
*/
#include <linux/kernel.h>
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 07cbbc6..05c64c1 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -293,7 +293,7 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
* cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
* preparations. Coherency is only guaranteed in the specified range for the
* specified access direction.
- * @dma_buf: [in] buffer to prepare cpu access for.
+ * @dmabuf: [in] buffer to prepare cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access.
@@ -320,7 +320,7 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
* cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
* actions. Coherency is only guaranteed in the specified range for the
* specified access direction.
- * @dma_buf: [in] buffer to complete cpu access for.
+ * @dmabuf: [in] buffer to complete cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access.
@@ -340,7 +340,7 @@ EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
/**
* dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
* space. The same restrictions as for kmap_atomic and friends apply.
- * @dma_buf: [in] buffer to map page from.
+ * @dmabuf: [in] buffer to map page from.
* @page_num: [in] page in PAGE_SIZE units to map.
*
* This call must always succeed, any necessary preparations that might fail
@@ -356,7 +356,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
/**
* dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
- * @dma_buf: [in] buffer to unmap page from.
+ * @dmabuf: [in] buffer to unmap page from.
* @page_num: [in] page in PAGE_SIZE units to unmap.
* @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic.
*
@@ -375,7 +375,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
/**
* dma_buf_kmap - Map a page of the buffer object into kernel address space. The
* same restrictions as for kmap and friends apply.
- * @dma_buf: [in] buffer to map page from.
+ * @dmabuf: [in] buffer to map page from.
* @page_num: [in] page in PAGE_SIZE units to map.
*
* This call must always succeed, any necessary preparations that might fail
@@ -391,7 +391,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap);
/**
* dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
- * @dma_buf: [in] buffer to unmap page from.
+ * @dmabuf: [in] buffer to unmap page from.
* @page_num: [in] page in PAGE_SIZE units to unmap.
* @vaddr: [in] kernel space pointer obtained from dma_buf_kmap.
*
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 3ec3896..207c27d 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -80,7 +80,7 @@ struct device *driver_find_device(struct device_driver *drv,
struct klist_iter i;
struct device *dev;
- if (!drv)
+ if (!drv || !drv->p)
return NULL;
klist_iter_init_node(&drv->p->klist_devices, &i,
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 73ce9fb..83aa694 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sched.h>
@@ -38,11 +39,13 @@
ktime_t __start = ktime_get(); \
type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \
s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \
- struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \
- if (__elapsed > __gpd_data->td.field) { \
- __gpd_data->td.field = __elapsed; \
+ struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \
+ if (!__retval && __elapsed > __td->field) { \
+ __td->field = __elapsed; \
dev_warn(dev, name " latency exceeded, new value %lld ns\n", \
__elapsed); \
+ genpd->max_off_time_changed = true; \
+ __td->constraint_changed = true; \
} \
__retval; \
})
@@ -211,6 +214,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns > genpd->power_on_latency_ns) {
genpd->power_on_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
if (genpd->name)
pr_warning("%s: Power-on latency exceeded, "
"new value %lld ns\n", genpd->name,
@@ -247,6 +251,53 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
#ifdef CONFIG_PM_RUNTIME
+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct generic_pm_domain_data *gpd_data;
+ struct device *dev;
+
+ gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
+
+ mutex_lock(&gpd_data->lock);
+ dev = gpd_data->base.dev;
+ if (!dev) {
+ mutex_unlock(&gpd_data->lock);
+ return NOTIFY_DONE;
+ }
+ mutex_unlock(&gpd_data->lock);
+
+ for (;;) {
+ struct generic_pm_domain *genpd;
+ struct pm_domain_data *pdd;
+
+ spin_lock_irq(&dev->power.lock);
+
+ pdd = dev->power.subsys_data ?
+ dev->power.subsys_data->domain_data : NULL;
+ if (pdd) {
+ to_gpd_data(pdd)->td.constraint_changed = true;
+ genpd = dev_to_genpd(dev);
+ } else {
+ genpd = ERR_PTR(-ENODATA);
+ }
+
+ spin_unlock_irq(&dev->power.lock);
+
+ if (!IS_ERR(genpd)) {
+ mutex_lock(&genpd->lock);
+ genpd->max_off_time_changed = true;
+ mutex_unlock(&genpd->lock);
+ }
+
+ dev = dev->parent;
+ if (!dev || dev->power.ignore_children)
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
/**
* __pm_genpd_save_device - Save the pre-suspend state of a device.
* @pdd: Domain data of the device to save the state of.
@@ -435,6 +486,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns > genpd->power_off_latency_ns) {
genpd->power_off_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
if (genpd->name)
pr_warning("%s: Power-off latency exceeded, "
"new value %lld ns\n", genpd->name,
@@ -443,17 +495,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
}
genpd->status = GPD_STATE_POWER_OFF;
- genpd->power_off_time = ktime_get();
-
- /* Update PM QoS information for devices in the domain. */
- list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
- struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
-
- pm_runtime_update_max_time_suspended(pdd->dev,
- td->start_latency_ns +
- td->restore_state_latency_ns +
- genpd->power_on_latency_ns);
- }
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
@@ -514,9 +555,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
if (ret)
return ret;
- pm_runtime_update_max_time_suspended(dev,
- dev_gpd_data(dev)->td.start_latency_ns);
-
/*
* If power.irq_safe is set, this routine will be run with interrupts
* off, so it can't use mutexes.
@@ -613,6 +651,12 @@ void pm_genpd_poweroff_unused(void)
#else
+static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ return NOTIFY_DONE;
+}
+
static inline void genpd_power_off_work_fn(struct work_struct *work) {}
#define pm_genpd_runtime_suspend NULL
@@ -1209,12 +1253,15 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
return -EINVAL;
- genpd_acquire_lock(genpd);
+ gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+ if (!gpd_data)
+ return -ENOMEM;
- if (genpd->status == GPD_STATE_POWER_OFF) {
- ret = -EINVAL;
- goto out;
- }
+ mutex_init(&gpd_data->lock);
+ gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+
+ genpd_acquire_lock(genpd);
if (genpd->prepared_count > 0) {
ret = -EAGAIN;
@@ -1227,26 +1274,35 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
goto out;
}
- gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
- if (!gpd_data) {
- ret = -ENOMEM;
- goto out;
- }
-
genpd->device_count++;
+ genpd->max_off_time_changed = true;
- dev->pm_domain = &genpd->domain;
dev_pm_get_subsys_data(dev);
+
+ mutex_lock(&gpd_data->lock);
+ spin_lock_irq(&dev->power.lock);
+ dev->pm_domain = &genpd->domain;
dev->power.subsys_data->domain_data = &gpd_data->base;
gpd_data->base.dev = dev;
- gpd_data->need_restore = false;
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+ gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
if (td)
gpd_data->td = *td;
+ gpd_data->td.constraint_changed = true;
+ gpd_data->td.effective_constraint_ns = -1;
+ spin_unlock_irq(&dev->power.lock);
+ mutex_unlock(&gpd_data->lock);
+
+ genpd_release_lock(genpd);
+
+ return 0;
+
out:
genpd_release_lock(genpd);
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ kfree(gpd_data);
return ret;
}
@@ -1290,12 +1346,15 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
struct device *dev)
{
+ struct generic_pm_domain_data *gpd_data;
struct pm_domain_data *pdd;
- int ret = -EINVAL;
+ int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
+ if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
+ || IS_ERR_OR_NULL(dev->pm_domain)
+ || pd_to_genpd(dev->pm_domain) != genpd)
return -EINVAL;
genpd_acquire_lock(genpd);
@@ -1305,21 +1364,27 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(pdd, &genpd->dev_list, list_node) {
- if (pdd->dev != dev)
- continue;
+ genpd->device_count--;
+ genpd->max_off_time_changed = true;
- list_del_init(&pdd->list_node);
- pdd->dev = NULL;
- dev_pm_put_subsys_data(dev);
- dev->pm_domain = NULL;
- kfree(to_gpd_data(pdd));
+ spin_lock_irq(&dev->power.lock);
+ dev->pm_domain = NULL;
+ pdd = dev->power.subsys_data->domain_data;
+ list_del_init(&pdd->list_node);
+ dev->power.subsys_data->domain_data = NULL;
+ spin_unlock_irq(&dev->power.lock);
- genpd->device_count--;
+ gpd_data = to_gpd_data(pdd);
+ mutex_lock(&gpd_data->lock);
+ pdd->dev = NULL;
+ mutex_unlock(&gpd_data->lock);
- ret = 0;
- break;
- }
+ genpd_release_lock(genpd);
+
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ kfree(gpd_data);
+ dev_pm_put_subsys_data(dev);
+ return 0;
out:
genpd_release_lock(genpd);
@@ -1348,6 +1413,26 @@ void pm_genpd_dev_always_on(struct device *dev, bool val)
EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
/**
+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
+ * @dev: Device to set/unset the flag for.
+ * @val: The new value of the device's "need restore" flag.
+ */
+void pm_genpd_dev_need_restore(struct device *dev, bool val)
+{
+ struct pm_subsys_data *psd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ psd = dev_to_psd(dev);
+ if (psd && psd->domain_data)
+ to_gpd_data(psd->domain_data)->need_restore = val;
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
+
+/**
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
* @genpd: Master PM domain to add the subdomain to.
* @subdomain: Subdomain to be added.
@@ -1378,7 +1463,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ list_for_each_entry(link, &genpd->master_links, master_node) {
if (link->slave == subdomain && link->master == genpd) {
ret = -EINVAL;
goto out;
@@ -1690,6 +1775,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->max_off_time_ns = -1;
+ genpd->max_off_time_changed = true;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 66a265b..28dee30 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,6 +14,31 @@
#ifdef CONFIG_PM_RUNTIME
+static int dev_update_qos_constraint(struct device *dev, void *data)
+{
+ s64 *constraint_ns_p = data;
+ s32 constraint_ns = -1;
+
+ if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+ constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+
+ if (constraint_ns < 0) {
+ constraint_ns = dev_pm_qos_read_value(dev);
+ constraint_ns *= NSEC_PER_USEC;
+ }
+ if (constraint_ns == 0)
+ return 0;
+
+ /*
+ * constraint_ns cannot be negative here, because the device has been
+ * suspended.
+ */
+ if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+ *constraint_ns_p = constraint_ns;
+
+ return 0;
+}
+
/**
* default_stop_ok - Default PM domain governor routine for stopping devices.
* @dev: Device to check.
@@ -21,14 +46,52 @@
bool default_stop_ok(struct device *dev)
{
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ unsigned long flags;
+ s64 constraint_ns;
dev_dbg(dev, "%s()\n", __func__);
- if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0)
- return true;
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (!td->constraint_changed) {
+ bool ret = td->cached_stop_ok;
- return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
- && td->break_even_ns < dev->power.max_time_suspended_ns;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+ return ret;
+ }
+ td->constraint_changed = false;
+ td->cached_stop_ok = false;
+ td->effective_constraint_ns = -1;
+ constraint_ns = __dev_pm_qos_read_value(dev);
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ if (constraint_ns < 0)
+ return false;
+
+ constraint_ns *= NSEC_PER_USEC;
+ /*
+ * We can walk the children without any additional locking, because
+ * they all have been suspended at this point and their
+ * effective_constraint_ns fields won't be modified in parallel with us.
+ */
+ if (!dev->power.ignore_children)
+ device_for_each_child(dev, &constraint_ns,
+ dev_update_qos_constraint);
+
+ if (constraint_ns > 0) {
+ constraint_ns -= td->start_latency_ns;
+ if (constraint_ns == 0)
+ return false;
+ }
+ td->effective_constraint_ns = constraint_ns;
+ td->cached_stop_ok = constraint_ns > td->stop_latency_ns ||
+ constraint_ns == 0;
+ /*
+ * The children have been suspended already, so we don't need to take
+ * their stop latencies into account here.
+ */
+ return td->cached_stop_ok;
}
/**
@@ -42,9 +105,27 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct gpd_link *link;
struct pm_domain_data *pdd;
- s64 min_dev_off_time_ns;
+ s64 min_off_time_ns;
s64 off_on_time_ns;
- ktime_t time_now = ktime_get();
+
+ if (genpd->max_off_time_changed) {
+ struct gpd_link *link;
+
+ /*
+ * We have to invalidate the cached results for the masters, so
+ * use the observation that default_power_down_ok() is not
+ * going to be called for any master until this instance
+ * returns.
+ */
+ list_for_each_entry(link, &genpd->slave_links, slave_node)
+ link->master->max_off_time_changed = true;
+
+ genpd->max_off_time_changed = false;
+ genpd->cached_power_down_ok = false;
+ genpd->max_off_time_ns = -1;
+ } else {
+ return genpd->cached_power_down_ok;
+ }
off_on_time_ns = genpd->power_off_latency_ns +
genpd->power_on_latency_ns;
@@ -61,6 +142,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
to_gpd_data(pdd)->td.save_state_latency_ns;
}
+ min_off_time_ns = -1;
/*
* Check if subdomains can be off for enough time.
*
@@ -73,8 +155,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
if (sd_max_off_ns < 0)
continue;
- sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
- sd->power_off_time));
/*
* Check if the subdomain is allowed to be off long enough for
* the current domain to turn off and on (that's how much time
@@ -82,60 +162,64 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
*/
if (sd_max_off_ns <= off_on_time_ns)
return false;
+
+ if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
+ min_off_time_ns = sd_max_off_ns;
}
/*
* Check if the devices in the domain can be off enough time.
*/
- min_dev_off_time_ns = -1;
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
struct gpd_timing_data *td;
- struct device *dev = pdd->dev;
- s64 dev_off_time_ns;
+ s64 constraint_ns;
- if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+ if (!pdd->dev->driver)
continue;
+ /*
+ * Check if the device is allowed to be off long enough for the
+ * domain to turn off and on (that's how much time it will
+ * have to wait worst case).
+ */
td = &to_gpd_data(pdd)->td;
- dev_off_time_ns = dev->power.max_time_suspended_ns -
- (td->start_latency_ns + td->restore_state_latency_ns +
- ktime_to_ns(ktime_sub(time_now,
- dev->power.suspend_time)));
- if (dev_off_time_ns <= off_on_time_ns)
- return false;
-
- if (min_dev_off_time_ns > dev_off_time_ns
- || min_dev_off_time_ns < 0)
- min_dev_off_time_ns = dev_off_time_ns;
- }
+ constraint_ns = td->effective_constraint_ns;
+ /* default_stop_ok() need not be called before us. */
+ if (constraint_ns < 0) {
+ constraint_ns = dev_pm_qos_read_value(pdd->dev);
+ constraint_ns *= NSEC_PER_USEC;
+ }
+ if (constraint_ns == 0)
+ continue;
- if (min_dev_off_time_ns < 0) {
/*
- * There are no latency constraints, so the domain can spend
- * arbitrary time in the "off" state.
+ * constraint_ns cannot be negative here, because the device has
+ * been suspended.
*/
- genpd->max_off_time_ns = -1;
- return true;
+ constraint_ns -= td->restore_state_latency_ns;
+ if (constraint_ns <= off_on_time_ns)
+ return false;
+
+ if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
+ min_off_time_ns = constraint_ns;
}
+ genpd->cached_power_down_ok = true;
+
/*
- * The difference between the computed minimum delta and the time needed
- * to turn the domain on is the maximum theoretical time this domain can
- * spend in the "off" state.
+ * If the computed minimum device off time is negative, there are no
+ * latency constraints, so the domain can spend arbitrary time in the
+ * "off" state.
*/
- min_dev_off_time_ns -= genpd->power_on_latency_ns;
+ if (min_off_time_ns < 0)
+ return true;
/*
- * If the difference between the computed minimum delta and the time
- * needed to turn the domain off and back on on is smaller than the
- * domain's power break even time, removing power from the domain is not
- * worth it.
+ * The difference between the computed minimum subdomain or device off
+ * time and the time needed to turn the domain on is the maximum
+ * theoretical time this domain can spend in the "off" state.
*/
- if (genpd->break_even_ns >
- min_dev_off_time_ns - genpd->power_off_latency_ns)
- return false;
-
- genpd->max_off_time_ns = min_dev_off_time_ns;
+ genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
return true;
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b462c0e..e0fb5b0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -889,6 +889,11 @@ static int dpm_suspend_noirq(pm_message_t state)
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &dpm_noirq_list);
put_device(dev);
+
+ if (pm_wakeup_pending()) {
+ error = -EBUSY;
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
if (error)
@@ -962,6 +967,11 @@ static int dpm_suspend_late(pm_message_t state)
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &dpm_late_early_list);
put_device(dev);
+
+ if (pm_wakeup_pending()) {
+ error = -EBUSY;
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
if (error)
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 7185557..fd849a2 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -352,21 +352,26 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
*
* Will register the notifier into a notification chain that gets called
* upon changes to the target value for the device.
+ *
+ * If the device's constraints object doesn't exist when this routine is called,
+ * it will be created (or error code will be returned if that fails).
*/
int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
{
- int retval = 0;
+ int ret = 0;
mutex_lock(&dev_pm_qos_mtx);
- /* Silently return if the constraints object is not present. */
- if (dev->power.constraints)
- retval = blocking_notifier_chain_register(
- dev->power.constraints->notifiers,
- notifier);
+ if (!dev->power.constraints)
+ ret = dev->power.power_state.event != PM_EVENT_INVALID ?
+ dev_pm_qos_constraints_allocate(dev) : -ENODEV;
+
+ if (!ret)
+ ret = blocking_notifier_chain_register(
+ dev->power.constraints->notifiers, notifier);
mutex_unlock(&dev_pm_qos_mtx);
- return retval;
+ return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index bd0f394..5989487 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -282,47 +282,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
return retval != -EACCES ? retval : -EIO;
}
-struct rpm_qos_data {
- ktime_t time_now;
- s64 constraint_ns;
-};
-
-/**
- * rpm_update_qos_constraint - Update a given PM QoS constraint data.
- * @dev: Device whose timing data to use.
- * @data: PM QoS constraint data to update.
- *
- * Use the suspend timing data of @dev to update PM QoS constraint data pointed
- * to by @data.
- */
-static int rpm_update_qos_constraint(struct device *dev, void *data)
-{
- struct rpm_qos_data *qos = data;
- unsigned long flags;
- s64 delta_ns;
- int ret = 0;
-
- spin_lock_irqsave(&dev->power.lock, flags);
-
- if (dev->power.max_time_suspended_ns < 0)
- goto out;
-
- delta_ns = dev->power.max_time_suspended_ns -
- ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
- if (delta_ns <= 0) {
- ret = -EBUSY;
- goto out;
- }
-
- if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
- qos->constraint_ns = delta_ns;
-
- out:
- spin_unlock_irqrestore(&dev->power.lock, flags);
-
- return ret;
-}
-
/**
* rpm_suspend - Carry out runtime suspend of given device.
* @dev: Device to suspend.
@@ -349,7 +308,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
{
int (*callback)(struct device *);
struct device *parent = NULL;
- struct rpm_qos_data qos;
int retval;
trace_rpm_suspend(dev, rpmflags);
@@ -445,38 +403,14 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto out;
}
- qos.constraint_ns = __dev_pm_qos_read_value(dev);
- if (qos.constraint_ns < 0) {
- /* Negative constraint means "never suspend". */
+ if (__dev_pm_qos_read_value(dev) < 0) {
+ /* Negative PM QoS constraint means "never suspend". */
retval = -EPERM;
goto out;
}
- qos.constraint_ns *= NSEC_PER_USEC;
- qos.time_now = ktime_get();
__update_runtime_status(dev, RPM_SUSPENDING);
- if (!dev->power.ignore_children) {
- if (dev->power.irq_safe)
- spin_unlock(&dev->power.lock);
- else
- spin_unlock_irq(&dev->power.lock);
-
- retval = device_for_each_child(dev, &qos,
- rpm_update_qos_constraint);
-
- if (dev->power.irq_safe)
- spin_lock(&dev->power.lock);
- else
- spin_lock_irq(&dev->power.lock);
-
- if (retval)
- goto fail;
- }
-
- dev->power.suspend_time = qos.time_now;
- dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
-
if (dev->pm_domain)
callback = dev->pm_domain->ops.runtime_suspend;
else if (dev->type && dev->type->pm)
@@ -529,8 +463,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
fail:
__update_runtime_status(dev, RPM_ACTIVE);
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);
@@ -704,9 +636,6 @@ static int rpm_resume(struct device *dev, int rpmflags)
if (dev->power.no_callbacks)
goto no_callback; /* Assume success. */
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
-
__update_runtime_status(dev, RPM_RESUMING);
if (dev->pm_domain)
@@ -1369,9 +1298,6 @@ void pm_runtime_init(struct device *dev)
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
(unsigned long)dev);
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
-
init_waitqueue_head(&dev->power.wait_queue);
}
@@ -1389,28 +1315,3 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put_sync(dev->parent);
}
-
-/**
- * pm_runtime_update_max_time_suspended - Update device's suspend time data.
- * @dev: Device to handle.
- * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
- *
- * Update the device's power.max_time_suspended_ns field by subtracting
- * @delta_ns from it. The resulting value of power.max_time_suspended_ns is
- * never negative.
- */
-void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->power.lock, flags);
-
- if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
- if (dev->power.max_time_suspended_ns > delta_ns)
- dev->power.max_time_suspended_ns -= delta_ns;
- else
- dev->power.max_time_suspended_ns = 0;
- }
-
- spin_unlock_irqrestore(&dev->power.lock, flags);
-}
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 95c12f6..48be2ad 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -314,22 +314,41 @@ static ssize_t wakeup_active_count_show(struct device *dev,
static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
-static ssize_t wakeup_hit_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wakeup_abort_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long count = 0;
+ bool enabled = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.wakeup) {
+ count = dev->power.wakeup->wakeup_count;
+ enabled = true;
+ }
+ spin_unlock_irq(&dev->power.lock);
+ return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL);
+
+static ssize_t wakeup_expire_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
unsigned long count = 0;
bool enabled = false;
spin_lock_irq(&dev->power.lock);
if (dev->power.wakeup) {
- count = dev->power.wakeup->hit_count;
+ count = dev->power.wakeup->expire_count;
enabled = true;
}
spin_unlock_irq(&dev->power.lock);
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
}
-static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL);
static ssize_t wakeup_active_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -398,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev,
}
static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ s64 msec = 0;
+ bool enabled = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.wakeup) {
+ msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+ enabled = true;
+ }
+ spin_unlock_irq(&dev->power.lock);
+ return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+ wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -486,11 +526,15 @@ static struct attribute *wakeup_attrs[] = {
&dev_attr_wakeup.attr,
&dev_attr_wakeup_count.attr,
&dev_attr_wakeup_active_count.attr,
- &dev_attr_wakeup_hit_count.attr,
+ &dev_attr_wakeup_abort_count.attr,
+ &dev_attr_wakeup_expire_count.attr,
&dev_attr_wakeup_active.attr,
&dev_attr_wakeup_total_time_ms.attr,
&dev_attr_wakeup_max_time_ms.attr,
&dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+ &dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
#endif
NULL,
};
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 2a3e581..cbb463b 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -14,16 +14,15 @@
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <trace/events/power.h>
#include "power.h"
-#define TIMEOUT 100
-
/*
* If set, the suspend/hibernate code will abort transitions to a sleep state
* if wakeup events are registered during or immediately before the transition.
*/
-bool events_check_enabled;
+bool events_check_enabled __read_mostly;
/*
* Combined counters of registered wakeup events and wakeup events in progress.
@@ -52,6 +51,8 @@ static void pm_wakeup_timer_fn(unsigned long data);
static LIST_HEAD(wakeup_sources);
+static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+
/**
* wakeup_source_prepare - Prepare a new wakeup source for initialization.
* @ws: Wakeup source to prepare.
@@ -132,6 +133,7 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_init(&ws->lock);
setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
ws->active = false;
+ ws->last_time = ktime_get();
spin_lock_irq(&events_lock);
list_add_rcu(&ws->entry, &wakeup_sources);
@@ -374,12 +376,33 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
*/
static void wakeup_source_activate(struct wakeup_source *ws)
{
+ unsigned int cec;
+
ws->active = true;
ws->active_count++;
ws->last_time = ktime_get();
+ if (ws->autosleep_enabled)
+ ws->start_prevent_time = ws->last_time;
/* Increment the counter of events in progress. */
- atomic_inc(&combined_event_count);
+ cec = atomic_inc_return(&combined_event_count);
+
+ trace_wakeup_source_activate(ws->name, cec);
+}
+
+/**
+ * wakeup_source_report_event - Report wakeup event using the given source.
+ * @ws: Wakeup source to report the event for.
+ */
+static void wakeup_source_report_event(struct wakeup_source *ws)
+{
+ ws->event_count++;
+ /* This is racy, but the counter is approximate anyway. */
+ if (events_check_enabled)
+ ws->wakeup_count++;
+
+ if (!ws->active)
+ wakeup_source_activate(ws);
}
/**
@@ -397,10 +420,7 @@ void __pm_stay_awake(struct wakeup_source *ws)
spin_lock_irqsave(&ws->lock, flags);
- ws->event_count++;
- if (!ws->active)
- wakeup_source_activate(ws);
-
+ wakeup_source_report_event(ws);
del_timer(&ws->timer);
ws->timer_expires = 0;
@@ -432,6 +452,17 @@ void pm_stay_awake(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_stay_awake);
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+ ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+ ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+ ktime_t now) {}
+#endif
+
/**
* wakup_source_deactivate - Mark given wakeup source as inactive.
* @ws: Wakeup source to handle.
@@ -442,6 +473,7 @@ EXPORT_SYMBOL_GPL(pm_stay_awake);
*/
static void wakeup_source_deactivate(struct wakeup_source *ws)
{
+ unsigned int cnt, inpr, cec;
ktime_t duration;
ktime_t now;
@@ -468,14 +500,23 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
ws->max_time = duration;
+ ws->last_time = now;
del_timer(&ws->timer);
ws->timer_expires = 0;
+ if (ws->autosleep_enabled)
+ update_prevent_sleep_time(ws, now);
+
/*
* Increment the counter of registered wakeup events and decrement the
* couter of wakeup events in progress simultaneously.
*/
- atomic_add(MAX_IN_PROGRESS, &combined_event_count);
+ cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
+ trace_wakeup_source_deactivate(ws->name, cec);
+
+ split_counters(&cnt, &inpr);
+ if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
+ wake_up(&wakeup_count_wait_queue);
}
/**
@@ -536,8 +577,10 @@ static void pm_wakeup_timer_fn(unsigned long data)
spin_lock_irqsave(&ws->lock, flags);
if (ws->active && ws->timer_expires
- && time_after_eq(jiffies, ws->timer_expires))
+ && time_after_eq(jiffies, ws->timer_expires)) {
wakeup_source_deactivate(ws);
+ ws->expire_count++;
+ }
spin_unlock_irqrestore(&ws->lock, flags);
}
@@ -564,9 +607,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
spin_lock_irqsave(&ws->lock, flags);
- ws->event_count++;
- if (!ws->active)
- wakeup_source_activate(ws);
+ wakeup_source_report_event(ws);
if (!msec) {
wakeup_source_deactivate(ws);
@@ -609,24 +650,6 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
EXPORT_SYMBOL_GPL(pm_wakeup_event);
/**
- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
- */
-static void pm_wakeup_update_hit_counts(void)
-{
- unsigned long flags;
- struct wakeup_source *ws;
-
- rcu_read_lock();
- list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
- spin_lock_irqsave(&ws->lock, flags);
- if (ws->active)
- ws->hit_count++;
- spin_unlock_irqrestore(&ws->lock, flags);
- }
- rcu_read_unlock();
-}
-
-/**
* pm_wakeup_pending - Check if power transition in progress should be aborted.
*
* Compare the current number of registered wakeup events with its preserved
@@ -648,32 +671,38 @@ bool pm_wakeup_pending(void)
events_check_enabled = !ret;
}
spin_unlock_irqrestore(&events_lock, flags);
- if (ret)
- pm_wakeup_update_hit_counts();
return ret;
}
/**
* pm_get_wakeup_count - Read the number of registered wakeup events.
* @count: Address to store the value at.
+ * @block: Whether or not to block.
*
- * Store the number of registered wakeup events at the address in @count. Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count. If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
*
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero). Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero. Otherwise return 'true'.
*/
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
- for (;;) {
- split_counters(&cnt, &inpr);
- if (inpr == 0 || signal_pending(current))
- break;
- pm_wakeup_update_hit_counts();
- schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+ if (block) {
+ DEFINE_WAIT(wait);
+
+ for (;;) {
+ prepare_to_wait(&wakeup_count_wait_queue, &wait,
+ TASK_INTERRUPTIBLE);
+ split_counters(&cnt, &inpr);
+ if (inpr == 0 || signal_pending(current))
+ break;
+
+ schedule();
+ }
+ finish_wait(&wakeup_count_wait_queue, &wait);
}
split_counters(&cnt, &inpr);
@@ -703,11 +732,37 @@ bool pm_save_wakeup_count(unsigned int count)
events_check_enabled = true;
}
spin_unlock_irq(&events_lock);
- if (!events_check_enabled)
- pm_wakeup_update_hit_counts();
return events_check_enabled;
}
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+ struct wakeup_source *ws;
+ ktime_t now = ktime_get();
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+ spin_lock_irq(&ws->lock);
+ if (ws->autosleep_enabled != set) {
+ ws->autosleep_enabled = set;
+ if (ws->active) {
+ if (set)
+ ws->start_prevent_time = now;
+ else
+ update_prevent_sleep_time(ws, now);
+ }
+ }
+ spin_unlock_irq(&ws->lock);
+ }
+ rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
static struct dentry *wakeup_sources_stats_dentry;
/**
@@ -723,27 +778,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
ktime_t max_time;
unsigned long active_count;
ktime_t active_time;
+ ktime_t prevent_sleep_time;
int ret;
spin_lock_irqsave(&ws->lock, flags);
total_time = ws->total_time;
max_time = ws->max_time;
+ prevent_sleep_time = ws->prevent_sleep_time;
active_count = ws->active_count;
if (ws->active) {
- active_time = ktime_sub(ktime_get(), ws->last_time);
+ ktime_t now = ktime_get();
+
+ active_time = ktime_sub(now, ws->last_time);
total_time = ktime_add(total_time, active_time);
if (active_time.tv64 > max_time.tv64)
max_time = active_time;
+
+ if (ws->autosleep_enabled)
+ prevent_sleep_time = ktime_add(prevent_sleep_time,
+ ktime_sub(now, ws->start_prevent_time));
} else {
active_time = ktime_set(0, 0);
}
- ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
- "%lld\t\t%lld\t\t%lld\t\t%lld\n",
- ws->name, active_count, ws->event_count, ws->hit_count,
+ ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
+ "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
+ ws->name, active_count, ws->event_count,
+ ws->wakeup_count, ws->expire_count,
ktime_to_ms(active_time), ktime_to_ms(total_time),
- ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+ ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+ ktime_to_ms(prevent_sleep_time));
spin_unlock_irqrestore(&ws->lock, flags);
@@ -758,8 +823,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
{
struct wakeup_source *ws;
- seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
- "active_since\ttotal_time\tmax_time\tlast_change\n");
+ seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
+ "expire_count\tactive_since\ttotal_time\tmax_time\t"
+ "last_change\tprevent_suspend_time\n");
rcu_read_lock();
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 0f6c7fb..6be390b 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -6,6 +6,7 @@ config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI)
select LZO_COMPRESS
select LZO_DECOMPRESS
+ select IRQ_DOMAIN if REGMAP_IRQ
bool
config REGMAP_I2C
@@ -14,5 +15,8 @@ config REGMAP_I2C
config REGMAP_SPI
tristate
+config REGMAP_MMIO
+ tristate
+
config REGMAP_IRQ
bool
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index defd579..5e75d1b 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index fcafc5b..b986b86 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -26,21 +26,30 @@ struct regmap_format {
size_t val_bytes;
void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val);
- void (*format_reg)(void *buf, unsigned int reg);
- void (*format_val)(void *buf, unsigned int val);
+ void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
+ void (*format_val)(void *buf, unsigned int val, unsigned int shift);
unsigned int (*parse_val)(void *buf);
};
+typedef void (*regmap_lock)(struct regmap *map);
+typedef void (*regmap_unlock)(struct regmap *map);
+
struct regmap {
- struct mutex lock;
+ struct mutex mutex;
+ spinlock_t spinlock;
+ regmap_lock lock;
+ regmap_unlock unlock;
struct device *dev; /* Device we do I/O on */
void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
+ void *bus_context;
+ const char *name;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
+ const char *debugfs_name;
#endif
unsigned int max_register;
@@ -52,6 +61,10 @@ struct regmap {
u8 read_flag_mask;
u8 write_flag_mask;
+ /* number of bits to (left) shift the reg value when formatting*/
+ int reg_shift;
+ int reg_stride;
+
/* regcache specific members */
const struct regcache_ops *cache_ops;
enum regcache_type cache_type;
@@ -79,6 +92,9 @@ struct regmap {
struct reg_default *patch;
int patch_regs;
+
+ /* if set, converts bulk rw to single rw */
+ bool use_single_rw;
};
struct regcache_ops {
@@ -101,11 +117,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
#ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void);
-extern void regmap_debugfs_init(struct regmap *map);
+extern void regmap_debugfs_init(struct regmap *map, const char *name);
extern void regmap_debugfs_exit(struct regmap *map);
#else
static inline void regmap_debugfs_initcall(void) { }
-static inline void regmap_debugfs_init(struct regmap *map) { }
+static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
static inline void regmap_debugfs_exit(struct regmap *map) { }
#endif
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index 483b06d..afd6aa9 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -108,7 +108,7 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map,
static inline int regcache_lzo_get_blkindex(struct regmap *map,
unsigned int reg)
{
- return (reg * map->cache_word_size) /
+ return ((reg / map->reg_stride) * map->cache_word_size) /
DIV_ROUND_UP(map->cache_size_raw,
regcache_lzo_block_count(map));
}
@@ -116,9 +116,10 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map,
static inline int regcache_lzo_get_blkpos(struct regmap *map,
unsigned int reg)
{
- return reg % (DIV_ROUND_UP(map->cache_size_raw,
- regcache_lzo_block_count(map)) /
- map->cache_word_size);
+ return (reg / map->reg_stride) %
+ (DIV_ROUND_UP(map->cache_size_raw,
+ regcache_lzo_block_count(map)) /
+ map->cache_word_size);
}
static inline int regcache_lzo_get_blksize(struct regmap *map)
@@ -322,7 +323,7 @@ static int regcache_lzo_write(struct regmap *map,
}
/* set the bit so we know we have to sync this register */
- set_bit(reg, lzo_block->sync_bmp);
+ set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
kfree(tmp_dst);
kfree(lzo_block->src);
return 0;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 92b779e..e6732cf 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx {
};
static inline void regcache_rbtree_get_base_top_reg(
+ struct regmap *map,
struct regcache_rbtree_node *rbnode,
unsigned int *base, unsigned int *top)
{
*base = rbnode->base_reg;
- *top = rbnode->base_reg + rbnode->blklen - 1;
+ *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
}
static unsigned int regcache_rbtree_get_register(
@@ -70,7 +71,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
rbnode = rbtree_ctx->cached_rbnode;
if (rbnode) {
- regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
if (reg >= base_reg && reg <= top_reg)
return rbnode;
}
@@ -78,7 +80,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
node = rbtree_ctx->root.rb_node;
while (node) {
rbnode = container_of(node, struct regcache_rbtree_node, node);
- regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
if (reg >= base_reg && reg <= top_reg) {
rbtree_ctx->cached_rbnode = rbnode;
return rbnode;
@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
return NULL;
}
-static int regcache_rbtree_insert(struct rb_root *root,
+static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
struct regcache_rbtree_node *rbnode)
{
struct rb_node **new, *parent;
@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
node);
/* base and top registers of the current rbnode */
- regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+ regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
&top_reg_tmp);
/* base register of the rbnode to be added */
base_reg = rbnode->base_reg;
@@ -138,19 +141,20 @@ static int rbtree_show(struct seq_file *s, void *ignored)
unsigned int base, top;
int nodes = 0;
int registers = 0;
- int average;
+ int this_registers, average;
- mutex_lock(&map->lock);
+ map->lock(map);
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
- regcache_rbtree_get_base_top_reg(n, &base, &top);
- seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1);
+ regcache_rbtree_get_base_top_reg(map, n, &base, &top);
+ this_registers = ((top - base) / map->reg_stride) + 1;
+ seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
nodes++;
- registers += top - base + 1;
+ registers += this_registers;
}
if (nodes)
@@ -161,7 +165,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
seq_printf(s, "%d nodes, %d registers, average %d registers\n",
nodes, registers, average);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return 0;
}
@@ -255,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
- reg_tmp = reg - rbnode->base_reg;
+ reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
*value = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size);
} else {
@@ -310,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
*/
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
- reg_tmp = reg - rbnode->base_reg;
+ reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
val = regcache_rbtree_get_register(rbnode, reg_tmp,
map->cache_word_size);
if (val == value)
@@ -321,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
/* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node;
node = rb_next(node)) {
- rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
+ rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
+ node);
for (i = 0; i < rbnode_tmp->blklen; i++) {
- reg_tmp = rbnode_tmp->base_reg + i;
- if (abs(reg_tmp - reg) != 1)
+ reg_tmp = rbnode_tmp->base_reg +
+ (i * map->reg_stride);
+ if (abs(reg_tmp - reg) != map->reg_stride)
continue;
/* decide where in the block to place our register */
- if (reg_tmp + 1 == reg)
+ if (reg_tmp + map->reg_stride == reg)
pos = i + 1;
else
pos = i;
@@ -357,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return -ENOMEM;
}
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
- regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
+ regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
@@ -397,7 +403,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
end = rbnode->blklen;
for (i = base; i < end; i++) {
- regtmp = rbnode->base_reg + i;
+ regtmp = rbnode->base_reg + (i * map->reg_stride);
val = regcache_rbtree_get_register(rbnode, i,
map->cache_word_size);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 74b6909..835883b 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -59,7 +59,7 @@ static int regcache_hw_init(struct regmap *map)
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size);
- if (regmap_volatile(map, i))
+ if (regmap_volatile(map, i * map->reg_stride))
continue;
count++;
}
@@ -76,9 +76,9 @@ static int regcache_hw_init(struct regmap *map)
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
val = regcache_get_val(map->reg_defaults_raw,
i, map->cache_word_size);
- if (regmap_volatile(map, i))
+ if (regmap_volatile(map, i * map->reg_stride))
continue;
- map->reg_defaults[j].reg = i;
+ map->reg_defaults[j].reg = i * map->reg_stride;
map->reg_defaults[j].def = val;
j++;
}
@@ -98,6 +98,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
int i;
void *tmp_buf;
+ for (i = 0; i < config->num_reg_defaults; i++)
+ if (config->reg_defaults[i].reg % map->reg_stride)
+ return -EINVAL;
+
if (map->cache_type == REGCACHE_NONE) {
map->cache_bypass = true;
return 0;
@@ -264,7 +268,7 @@ int regcache_sync(struct regmap *map)
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
- mutex_lock(&map->lock);
+ map->lock(map);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n",
@@ -278,6 +282,10 @@ int regcache_sync(struct regmap *map)
/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
+ if (map->patch[i].reg % map->reg_stride) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
@@ -296,7 +304,7 @@ out:
trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */
map->cache_bypass = bypass;
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -323,7 +331,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
- mutex_lock(&map->lock);
+ map->lock(map);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
@@ -342,7 +350,7 @@ out:
trace_regcache_sync(map->dev, name, "stop region");
/* Restore the bypass state */
map->cache_bypass = bypass;
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -362,11 +370,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
*/
void regcache_cache_only(struct regmap *map, bool enable)
{
- mutex_lock(&map->lock);
+ map->lock(map);
WARN_ON(map->cache_bypass && enable);
map->cache_only = enable;
trace_regmap_cache_only(map->dev, enable);
- mutex_unlock(&map->lock);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -381,9 +389,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
*/
void regcache_mark_dirty(struct regmap *map)
{
- mutex_lock(&map->lock);
+ map->lock(map);
map->cache_dirty = true;
- mutex_unlock(&map->lock);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
@@ -400,11 +408,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
*/
void regcache_cache_bypass(struct regmap *map, bool enable)
{
- mutex_lock(&map->lock);
+ map->lock(map);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
trace_regmap_cache_bypass(map->dev, enable);
- mutex_unlock(&map->lock);
+ map->unlock(map);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 251eb70..bb1ff17 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
val_len = 2 * map->format.val_bytes;
tot_len = reg_len + val_len + 3; /* : \n */
- for (i = 0; i < map->max_register + 1; i++) {
+ for (i = 0; i <= map->max_register; i += map->reg_stride) {
if (!regmap_readable(map, i))
continue;
@@ -197,7 +197,7 @@ static ssize_t regmap_access_read_file(struct file *file,
reg_len = regmap_calc_reg_len(map->max_register, buf, count);
tot_len = reg_len + 10; /* ': R W V P\n' */
- for (i = 0; i < map->max_register + 1; i++) {
+ for (i = 0; i <= map->max_register; i += map->reg_stride) {
/* Ignore registers which are neither readable nor writable */
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
continue;
@@ -242,10 +242,17 @@ static const struct file_operations regmap_access_fops = {
.llseek = default_llseek,
};
-void regmap_debugfs_init(struct regmap *map)
+void regmap_debugfs_init(struct regmap *map, const char *name)
{
- map->debugfs = debugfs_create_dir(dev_name(map->dev),
- regmap_debugfs_root);
+ if (name) {
+ map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
+ dev_name(map->dev), name);
+ name = map->debugfs_name;
+ } else {
+ name = dev_name(map->dev);
+ }
+
+ map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
if (!map->debugfs) {
dev_warn(map->dev, "Failed to create debugfs directory\n");
return;
@@ -274,6 +281,7 @@ void regmap_debugfs_init(struct regmap *map)
void regmap_debugfs_exit(struct regmap *map)
{
debugfs_remove_recursive(map->debugfs);
+ kfree(map->debugfs_name);
}
void regmap_debugfs_initcall(void)
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 9a3a8c5..5f6b247 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -15,8 +15,9 @@
#include <linux/module.h>
#include <linux/init.h>
-static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
+static int regmap_i2c_write(void *context, const void *data, size_t count)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;
@@ -29,10 +30,11 @@ static int regmap_i2c_write(struct device *dev, const void *data, size_t count)
return -EIO;
}
-static int regmap_i2c_gather_write(struct device *dev,
+static int regmap_i2c_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@@ -62,10 +64,11 @@ static int regmap_i2c_gather_write(struct device *dev,
return -EIO;
}
-static int regmap_i2c_read(struct device *dev,
+static int regmap_i2c_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
+ struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
struct i2c_msg xfer[2];
int ret;
@@ -107,7 +110,7 @@ static struct regmap_bus regmap_i2c = {
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
- return regmap_init(&i2c->dev, &regmap_i2c, config);
+ return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_i2c);
@@ -124,7 +127,7 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
- return devm_regmap_init(&i2c->dev, &regmap_i2c, config);
+ return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 1befaa7..4fac4b9 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
#include "internal.h"
@@ -26,18 +27,20 @@ struct regmap_irq_chip_data {
struct regmap_irq_chip *chip;
int irq_base;
+ struct irq_domain *domain;
- void *status_reg_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;
+
+ unsigned int irq_reg_stride;
};
static inline const
struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
int irq)
{
- return &data->chip->irqs[irq - data->irq_base];
+ return &data->chip->irqs[irq];
}
static void regmap_irq_lock(struct irq_data *data)
@@ -50,6 +53,7 @@ static void regmap_irq_lock(struct irq_data *data)
static void regmap_irq_sync_unlock(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct regmap *map = d->map;
int i, ret;
/*
@@ -58,11 +62,13 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
* suppress pointless writes.
*/
for (i = 0; i < d->chip->num_regs; i++) {
- ret = regmap_update_bits(d->map, d->chip->mask_base + i,
+ ret = regmap_update_bits(d->map, d->chip->mask_base +
+ (i * map->reg_stride *
+ d->irq_reg_stride),
d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
- d->chip->mask_base + i);
+ d->chip->mask_base + (i * map->reg_stride));
}
mutex_unlock(&d->lock);
@@ -71,17 +77,19 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
static void regmap_irq_enable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
- const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
+ struct regmap *map = d->map;
+ const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
- d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask;
+ d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
}
static void regmap_irq_disable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
- const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
+ struct regmap *map = d->map;
+ const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
- d->mask_buf[irq_data->reg_offset] |= irq_data->mask;
+ d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
static struct irq_chip regmap_irq_chip = {
@@ -98,18 +106,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
struct regmap_irq_chip *chip = data->chip;
struct regmap *map = data->map;
int ret, i;
- u8 *buf8 = data->status_reg_buf;
- u16 *buf16 = data->status_reg_buf;
- u32 *buf32 = data->status_reg_buf;
bool handled = false;
- ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf,
- chip->num_regs);
- if (ret != 0) {
- dev_err(map->dev, "Failed to read IRQ status: %d\n", ret);
- return IRQ_NONE;
- }
-
/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
@@ -118,36 +116,34 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* doing a write per register.
*/
for (i = 0; i < data->chip->num_regs; i++) {
- switch (map->format.val_bytes) {
- case 1:
- data->status_buf[i] = buf8[i];
- break;
- case 2:
- data->status_buf[i] = buf16[i];
- break;
- case 4:
- data->status_buf[i] = buf32[i];
- break;
- default:
- BUG();
+ ret = regmap_read(map, chip->status_base + (i * map->reg_stride
+ * data->irq_reg_stride),
+ &data->status_buf[i]);
+
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to read IRQ status: %d\n",
+ ret);
return IRQ_NONE;
}
data->status_buf[i] &= ~data->mask_buf[i];
if (data->status_buf[i] && chip->ack_base) {
- ret = regmap_write(map, chip->ack_base + i,
+ ret = regmap_write(map, chip->ack_base +
+ (i * map->reg_stride *
+ data->irq_reg_stride),
data->status_buf[i]);
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
- chip->ack_base + i, ret);
+ chip->ack_base + (i * map->reg_stride),
+ ret);
}
}
for (i = 0; i < chip->num_irqs; i++) {
- if (data->status_buf[chip->irqs[i].reg_offset] &
- chip->irqs[i].mask) {
- handle_nested_irq(data->irq_base + i);
+ if (data->status_buf[chip->irqs[i].reg_offset /
+ map->reg_stride] & chip->irqs[i].mask) {
+ handle_nested_irq(irq_find_mapping(data->domain, i));
handled = true;
}
}
@@ -158,6 +154,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
return IRQ_NONE;
}
+static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct regmap_irq_chip_data *data = h->host_data;
+
+ irq_set_chip_data(virq, data);
+ irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+ irq_set_nested_thread(virq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(virq, IRQF_VALID);
+#else
+ irq_set_noprobe(virq);
+#endif
+
+ return 0;
+}
+
+static struct irq_domain_ops regmap_domain_ops = {
+ .map = regmap_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
/**
* regmap_add_irq_chip(): Use standard regmap IRQ controller handling
*
@@ -178,30 +199,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct regmap_irq_chip_data **data)
{
struct regmap_irq_chip_data *d;
- int cur_irq, i;
+ int i;
int ret = -ENOMEM;
- irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
- if (irq_base < 0) {
- dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
- irq_base);
- return irq_base;
+ for (i = 0; i < chip->num_irqs; i++) {
+ if (chip->irqs[i].reg_offset % map->reg_stride)
+ return -EINVAL;
+ if (chip->irqs[i].reg_offset / map->reg_stride >=
+ chip->num_regs)
+ return -EINVAL;
+ }
+
+ if (irq_base) {
+ irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
+ if (irq_base < 0) {
+ dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
+ irq_base);
+ return irq_base;
+ }
}
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
+ *data = d;
+
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->status_buf)
goto err_alloc;
- d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs,
- GFP_KERNEL);
- if (!d->status_reg_buf)
- goto err_alloc;
-
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->mask_buf)
@@ -215,54 +243,59 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->map = map;
d->chip = chip;
d->irq_base = irq_base;
+
+ if (chip->irq_reg_stride)
+ d->irq_reg_stride = chip->irq_reg_stride;
+ else
+ d->irq_reg_stride = 1;
+
mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++)
- d->mask_buf_def[chip->irqs[i].reg_offset]
+ d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
|= chip->irqs[i].mask;
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
- ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]);
+ ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
+ * d->irq_reg_stride),
+ d->mask_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
- chip->mask_base + i, ret);
+ chip->mask_base + (i * map->reg_stride), ret);
goto err_alloc;
}
}
- /* Register them with genirq */
- for (cur_irq = irq_base;
- cur_irq < chip->num_irqs + irq_base;
- cur_irq++) {
- irq_set_chip_data(cur_irq, d);
- irq_set_chip_and_handler(cur_irq, &regmap_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(cur_irq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- irq_set_noprobe(cur_irq);
-#endif
+ if (irq_base)
+ d->domain = irq_domain_add_legacy(map->dev->of_node,
+ chip->num_irqs, irq_base, 0,
+ &regmap_domain_ops, d);
+ else
+ d->domain = irq_domain_add_linear(map->dev->of_node,
+ chip->num_irqs,
+ &regmap_domain_ops, d);
+ if (!d->domain) {
+ dev_err(map->dev, "Failed to create IRQ domain\n");
+ ret = -ENOMEM;
+ goto err_alloc;
}
ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
chip->name, d);
if (ret != 0) {
dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
- goto err_alloc;
+ goto err_domain;
}
return 0;
+err_domain:
+ /* Should really dispose of the domain but... */
err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
return ret;
@@ -281,9 +314,9 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
return;
free_irq(irq, d);
+ /* We should unmap the domain but... */
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
}
@@ -298,6 +331,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
*/
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
{
+ WARN_ON(!data->irq_base);
return data->irq_base;
}
EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
+
+/**
+ * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ *
+ * Useful for drivers to request their own IRQs.
+ *
+ * @data: regmap_irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs
+ */
+int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
+{
+ return irq_create_mapping(data->domain, irq);
+}
+EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
new file mode 100644
index 0000000..febd6de
--- /dev/null
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -0,0 +1,224 @@
+/*
+ * Register map access API - MMIO support
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct regmap_mmio_context {
+ void __iomem *regs;
+ unsigned val_bytes;
+};
+
+static int regmap_mmio_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ struct regmap_mmio_context *ctx = context;
+ u32 offset;
+
+ BUG_ON(reg_size != 4);
+
+ offset = be32_to_cpup(reg);
+
+ while (val_size) {
+ switch (ctx->val_bytes) {
+ case 1:
+ writeb(*(u8 *)val, ctx->regs + offset);
+ break;
+ case 2:
+ writew(be16_to_cpup(val), ctx->regs + offset);
+ break;
+ case 4:
+ writel(be32_to_cpup(val), ctx->regs + offset);
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ writeq(be64_to_cpup(val), ctx->regs + offset);
+ break;
+#endif
+ default:
+ /* Should be caught by regmap_mmio_check_config */
+ BUG();
+ }
+ val_size -= ctx->val_bytes;
+ val += ctx->val_bytes;
+ offset += ctx->val_bytes;
+ }
+
+ return 0;
+}
+
+static int regmap_mmio_write(void *context, const void *data, size_t count)
+{
+ BUG_ON(count < 4);
+
+ return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
+}
+
+static int regmap_mmio_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct regmap_mmio_context *ctx = context;
+ u32 offset;
+
+ BUG_ON(reg_size != 4);
+
+ offset = be32_to_cpup(reg);
+
+ while (val_size) {
+ switch (ctx->val_bytes) {
+ case 1:
+ *(u8 *)val = readb(ctx->regs + offset);
+ break;
+ case 2:
+ *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
+ break;
+ case 4:
+ *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
+ break;
+#endif
+ default:
+ /* Should be caught by regmap_mmio_check_config */
+ BUG();
+ }
+ val_size -= ctx->val_bytes;
+ val += ctx->val_bytes;
+ offset += ctx->val_bytes;
+ }
+
+ return 0;
+}
+
+static void regmap_mmio_free_context(void *context)
+{
+ kfree(context);
+}
+
+static struct regmap_bus regmap_mmio = {
+ .fast_io = true,
+ .write = regmap_mmio_write,
+ .gather_write = regmap_mmio_gather_write,
+ .read = regmap_mmio_read,
+ .free_context = regmap_mmio_free_context,
+};
+
+struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+ int min_stride;
+
+ if (config->reg_bits != 32)
+ return ERR_PTR(-EINVAL);
+
+ if (config->pad_bits)
+ return ERR_PTR(-EINVAL);
+
+ switch (config->val_bits) {
+ case 8:
+ /* The core treats 0 as 1 */
+ min_stride = 0;
+ break;
+ case 16:
+ min_stride = 2;
+ break;
+ case 32:
+ min_stride = 4;
+ break;
+#ifdef CONFIG_64BIT
+ case 64:
+ min_stride = 8;
+ break;
+#endif
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (config->reg_stride < min_stride)
+ return ERR_PTR(-EINVAL);
+
+ ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->regs = regs;
+ ctx->val_bytes = config->val_bits / 8;
+
+ return ctx;
+}
+
+/**
+ * regmap_init_mmio(): Initialise register map
+ *
+ * @dev: Device that will be interacted with
+ * @regs: Pointer to memory-mapped IO region
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+
+ ctx = regmap_mmio_gen_context(regs, config);
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ return regmap_init(dev, &regmap_mmio, ctx, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_mmio);
+
+/**
+ * devm_regmap_init_mmio(): Initialise managed register map
+ *
+ * @dev: Device that will be interacted with
+ * @regs: Pointer to memory-mapped IO region
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_mmio(struct device *dev,
+ void __iomem *regs,
+ const struct regmap_config *config)
+{
+ struct regmap_mmio_context *ctx;
+
+ ctx = regmap_mmio_gen_context(regs, config);
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ return devm_regmap_init(dev, &regmap_mmio, ctx, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 7c0c35a..ffa46a9 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -15,17 +15,19 @@
#include <linux/init.h>
#include <linux/module.h>
-static int regmap_spi_write(struct device *dev, const void *data, size_t count)
+static int regmap_spi_write(void *context, const void *data, size_t count)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write(spi, data, count);
}
-static int regmap_spi_gather_write(struct device *dev,
+static int regmap_spi_gather_write(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
struct spi_message m;
struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
@@ -38,10 +40,11 @@ static int regmap_spi_gather_write(struct device *dev,
return spi_sync(spi, &m);
}
-static int regmap_spi_read(struct device *dev,
+static int regmap_spi_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
+ struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write_then_read(spi, reg, reg_size, val, val_size);
@@ -66,7 +69,7 @@ static struct regmap_bus regmap_spi = {
struct regmap *regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
- return regmap_init(&spi->dev, &regmap_spi, config);
+ return regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_spi);
@@ -83,7 +86,7 @@ EXPORT_SYMBOL_GPL(regmap_init_spi);
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{
- return devm_regmap_init(&spi->dev, &regmap_spi, config);
+ return devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index bb80853..0bcda48 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -112,25 +112,36 @@ static void regmap_format_10_14_write(struct regmap *map,
out[0] = reg >> 2;
}
-static void regmap_format_8(void *buf, unsigned int val)
+static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
- b[0] = val;
+ b[0] = val << shift;
}
-static void regmap_format_16(void *buf, unsigned int val)
+static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
{
__be16 *b = buf;
- b[0] = cpu_to_be16(val);
+ b[0] = cpu_to_be16(val << shift);
}
-static void regmap_format_32(void *buf, unsigned int val)
+static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
+{
+ u8 *b = buf;
+
+ val <<= shift;
+
+ b[0] = val >> 16;
+ b[1] = val >> 8;
+ b[2] = val;
+}
+
+static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
{
__be32 *b = buf;
- b[0] = cpu_to_be32(val);
+ b[0] = cpu_to_be32(val << shift);
}
static unsigned int regmap_parse_8(void *buf)
@@ -149,6 +160,16 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
+static unsigned int regmap_parse_24(void *buf)
+{
+ u8 *b = buf;
+ unsigned int ret = b[2];
+ ret |= ((unsigned int)b[1]) << 8;
+ ret |= ((unsigned int)b[0]) << 16;
+
+ return ret;
+}
+
static unsigned int regmap_parse_32(void *buf)
{
__be32 *b = buf;
@@ -158,11 +179,41 @@ static unsigned int regmap_parse_32(void *buf)
return b[0];
}
+static void regmap_lock_mutex(struct regmap *map)
+{
+ mutex_lock(&map->mutex);
+}
+
+static void regmap_unlock_mutex(struct regmap *map)
+{
+ mutex_unlock(&map->mutex);
+}
+
+static void regmap_lock_spinlock(struct regmap *map)
+{
+ spin_lock(&map->spinlock);
+}
+
+static void regmap_unlock_spinlock(struct regmap *map)
+{
+ spin_unlock(&map->spinlock);
+}
+
+static void dev_get_regmap_release(struct device *dev, void *res)
+{
+ /*
+ * We don't actually have anything to do here; the goal here
+ * is not to manage the regmap but to provide a simple way to
+ * get the regmap back given a struct device.
+ */
+}
+
/**
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
+ * @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
@@ -171,9 +222,10 @@ static unsigned int regmap_parse_32(void *buf)
*/
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config)
{
- struct regmap *map;
+ struct regmap *map, **m;
int ret = -EINVAL;
if (!bus || !config)
@@ -185,20 +237,36 @@ struct regmap *regmap_init(struct device *dev,
goto err;
}
- mutex_init(&map->lock);
+ if (bus->fast_io) {
+ spin_lock_init(&map->spinlock);
+ map->lock = regmap_lock_spinlock;
+ map->unlock = regmap_unlock_spinlock;
+ } else {
+ mutex_init(&map->mutex);
+ map->lock = regmap_lock_mutex;
+ map->unlock = regmap_unlock_mutex;
+ }
map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
map->format.pad_bytes = config->pad_bits / 8;
map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
map->format.buf_size += map->format.pad_bytes;
+ map->reg_shift = config->pad_bits % 8;
+ if (config->reg_stride)
+ map->reg_stride = config->reg_stride;
+ else
+ map->reg_stride = 1;
+ map->use_single_rw = config->use_single_rw;
map->dev = dev;
map->bus = bus;
+ map->bus_context = bus_context;
map->max_register = config->max_register;
map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type;
+ map->name = config->name;
if (config->read_flag_mask || config->write_flag_mask) {
map->read_flag_mask = config->read_flag_mask;
@@ -207,7 +275,7 @@ struct regmap *regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask;
}
- switch (config->reg_bits) {
+ switch (config->reg_bits + map->reg_shift) {
case 2:
switch (config->val_bits) {
case 6:
@@ -273,12 +341,19 @@ struct regmap *regmap_init(struct device *dev,
map->format.format_val = regmap_format_16;
map->format.parse_val = regmap_parse_16;
break;
+ case 24:
+ map->format.format_val = regmap_format_24;
+ map->format.parse_val = regmap_parse_24;
+ break;
case 32:
map->format.format_val = regmap_format_32;
map->format.parse_val = regmap_parse_32;
break;
}
+ if (map->format.format_write)
+ map->use_single_rw = true;
+
if (!map->format.format_write &&
!(map->format.format_reg && map->format.format_val))
goto err_map;
@@ -289,14 +364,25 @@ struct regmap *regmap_init(struct device *dev,
goto err_map;
}
- regmap_debugfs_init(map);
+ regmap_debugfs_init(map, config->name);
ret = regcache_init(map, config);
if (ret < 0)
goto err_free_workbuf;
+ /* Add a devres resource for dev_get_regmap() */
+ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+ if (!m) {
+ ret = -ENOMEM;
+ goto err_cache;
+ }
+ *m = map;
+ devres_add(dev, m);
+
return map;
+err_cache:
+ regcache_exit(map);
err_free_workbuf:
kfree(map->work_buf);
err_map:
@@ -316,6 +402,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
+ * @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
@@ -325,6 +412,7 @@ static void devm_regmap_release(struct device *dev, void *res)
*/
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
+ void *bus_context,
const struct regmap_config *config)
{
struct regmap **ptr, *regmap;
@@ -333,7 +421,7 @@ struct regmap *devm_regmap_init(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- regmap = regmap_init(dev, bus, config);
+ regmap = regmap_init(dev, bus, bus_context, config);
if (!IS_ERR(regmap)) {
*ptr = regmap;
devres_add(dev, ptr);
@@ -360,7 +448,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{
int ret;
- mutex_lock(&map->lock);
+ map->lock(map);
regcache_exit(map);
regmap_debugfs_exit(map);
@@ -372,14 +460,14 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type;
- regmap_debugfs_init(map);
+ regmap_debugfs_init(map, config->name);
map->cache_bypass = false;
map->cache_only = false;
ret = regcache_init(map, config);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -391,11 +479,51 @@ void regmap_exit(struct regmap *map)
{
regcache_exit(map);
regmap_debugfs_exit(map);
+ if (map->bus->free_context)
+ map->bus->free_context(map->bus_context);
kfree(map->work_buf);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
+static int dev_get_regmap_match(struct device *dev, void *res, void *data)
+{
+ struct regmap **r = res;
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+
+ /* If the user didn't specify a name match any */
+ if (data)
+ return (*r)->name == data;
+ else
+ return 1;
+}
+
+/**
+ * dev_get_regmap(): Obtain the regmap (if any) for a device
+ *
+ * @dev: Device to retrieve the map for
+ * @name: Optional name for the register map, usually NULL.
+ *
+ * Returns the regmap for the device if one is present, or NULL. If
+ * name is specified then it must match the name specified when
+ * registering the device, if it is NULL then the first regmap found
+ * will be used. Devices with multiple register maps are very rare,
+ * generic code should normally not need to specify a name.
+ */
+struct regmap *dev_get_regmap(struct device *dev, const char *name)
+{
+ struct regmap **r = devres_find(dev, dev_get_regmap_release,
+ dev_get_regmap_match, (void *)name);
+
+ if (!r)
+ return NULL;
+ return *r;
+}
+EXPORT_SYMBOL_GPL(dev_get_regmap);
+
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len)
{
@@ -408,7 +536,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
/* Check for unwritable registers before we start */
if (map->writeable_reg)
for (i = 0; i < val_len / map->format.val_bytes; i++)
- if (!map->writeable_reg(map->dev, reg + i))
+ if (!map->writeable_reg(map->dev,
+ reg + (i * map->reg_stride)))
return -EINVAL;
if (!map->cache_bypass && map->format.parse_val) {
@@ -417,7 +546,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
for (i = 0; i < val_len / val_bytes; i++) {
memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
ival = map->format.parse_val(map->work_buf);
- ret = regcache_write(map, reg + i, ival);
+ ret = regcache_write(map, reg + (i * map->reg_stride),
+ ival);
if (ret) {
dev_err(map->dev,
"Error in caching of register: %u ret: %d\n",
@@ -431,7 +561,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
}
}
- map->format.format_reg(map->work_buf, reg);
+ map->format.format_reg(map->work_buf, reg, map->reg_shift);
u8[0] |= map->write_flag_mask;
@@ -444,12 +574,12 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
*/
if (val == (map->work_buf + map->format.pad_bytes +
map->format.reg_bytes))
- ret = map->bus->write(map->dev, map->work_buf,
+ ret = map->bus->write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes +
val_len);
else if (map->bus->gather_write)
- ret = map->bus->gather_write(map->dev, map->work_buf,
+ ret = map->bus->gather_write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);
@@ -464,7 +594,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
memcpy(buf, map->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
- ret = map->bus->write(map->dev, buf, len);
+ ret = map->bus->write(map->bus_context, buf, len);
kfree(buf);
}
@@ -498,7 +628,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_hw_write_start(map->dev, reg, 1);
- ret = map->bus->write(map->dev, map->work_buf,
+ ret = map->bus->write(map->bus_context, map->work_buf,
map->format.buf_size);
trace_regmap_hw_write_done(map->dev, reg, 1);
@@ -506,7 +636,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
return ret;
} else {
map->format.format_val(map->work_buf + map->format.reg_bytes
- + map->format.pad_bytes, val);
+ + map->format.pad_bytes, val, 0);
return _regmap_raw_write(map, reg,
map->work_buf +
map->format.reg_bytes +
@@ -529,11 +659,14 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
int ret;
- mutex_lock(&map->lock);
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_write(map, reg, val);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -560,11 +693,16 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
- mutex_lock(&map->lock);
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_raw_write(map, reg, val, val_len);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -593,8 +731,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (!map->format.parse_val)
return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
- mutex_lock(&map->lock);
+ map->lock(map);
/* No formatting is require if val_byte is 1 */
if (val_bytes == 1) {
@@ -609,13 +749,28 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_val(wval + i);
}
- ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+ /*
+ * Some devices does not support bulk write, for
+ * them we have a series of single write operations.
+ */
+ if (map->use_single_rw) {
+ for (i = 0; i < val_count; i++) {
+ ret = regmap_raw_write(map,
+ reg + (i * map->reg_stride),
+ val + (i * val_bytes),
+ val_bytes);
+ if (ret != 0)
+ return ret;
+ }
+ } else {
+ ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+ }
if (val_bytes != 1)
kfree(wval);
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
@@ -626,7 +781,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf;
int ret;
- map->format.format_reg(map->work_buf, reg);
+ map->format.format_reg(map->work_buf, reg, map->reg_shift);
/*
* Some buses or devices flag reads by setting the high bits in the
@@ -639,7 +794,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
trace_regmap_hw_read_start(map->dev, reg,
val_len / map->format.val_bytes);
- ret = map->bus->read(map->dev, map->work_buf,
+ ret = map->bus->read(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
@@ -672,6 +827,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
trace_regmap_reg_read(map->dev, reg, *val);
}
+ if (ret == 0 && !map->cache_bypass)
+ regcache_write(map, reg, *val);
+
return ret;
}
@@ -689,11 +847,14 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
int ret;
- mutex_lock(&map->lock);
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
ret = _regmap_read(map, reg, val);
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -718,7 +879,12 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int v;
int ret, i;
- mutex_lock(&map->lock);
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) {
@@ -730,16 +896,17 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
* cost as we expect to hit the cache.
*/
for (i = 0; i < val_count; i++) {
- ret = _regmap_read(map, reg + i, &v);
+ ret = _regmap_read(map, reg + (i * map->reg_stride),
+ &v);
if (ret != 0)
goto out;
- map->format.format_val(val + (i * val_bytes), v);
+ map->format.format_val(val + (i * val_bytes), v, 0);
}
}
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -765,18 +932,37 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if (!map->format.parse_val)
return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
if (vol || map->cache_type == REGCACHE_NONE) {
- ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
- if (ret != 0)
- return ret;
+ /*
+ * Some devices does not support bulk read, for
+ * them we have a series of single read operations.
+ */
+ if (map->use_single_rw) {
+ for (i = 0; i < val_count; i++) {
+ ret = regmap_raw_read(map,
+ reg + (i * map->reg_stride),
+ val + (i * val_bytes),
+ val_bytes);
+ if (ret != 0)
+ return ret;
+ }
+ } else {
+ ret = regmap_raw_read(map, reg, val,
+ val_bytes * val_count);
+ if (ret != 0)
+ return ret;
+ }
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_val(val + i);
} else {
for (i = 0; i < val_count; i++) {
unsigned int ival;
- ret = regmap_read(map, reg + i, &ival);
+ ret = regmap_read(map, reg + (i * map->reg_stride),
+ &ival);
if (ret != 0)
return ret;
memcpy(val + (i * val_bytes), &ival, val_bytes);
@@ -794,7 +980,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int ret;
unsigned int tmp, orig;
- mutex_lock(&map->lock);
+ map->lock(map);
ret = _regmap_read(map, reg, &orig);
if (ret != 0)
@@ -811,7 +997,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
}
out:
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
@@ -878,7 +1064,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
if (map->patch)
return -EBUSY;
- mutex_lock(&map->lock);
+ map->lock(map);
bypass = map->cache_bypass;
@@ -906,7 +1092,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
out:
map->cache_bypass = bypass;
- mutex_unlock(&map->lock);
+ map->unlock(map);
return ret;
}
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index f94cccc..3bea7fe 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -297,6 +297,23 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return -EILSEQ;
}
+ /* First Slave Address Descriptor should be port 0:
+ * the main register space for the core
+ */
+ tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
+ if (tmp <= 0) {
+ /* Try again to see if it is a bridge */
+ tmp = bcma_erom_get_addr_desc(bus, eromptr,
+ SCAN_ADDR_TYPE_BRIDGE, 0);
+ if (tmp <= 0) {
+ return -EILSEQ;
+ } else {
+ pr_info("Bridge found\n");
+ return -ENXIO;
+ }
+ }
+ core->addr = tmp;
+
/* get & parse slave ports */
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
@@ -309,7 +326,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
break;
} else {
if (i == 0 && j == 0)
- core->addr = tmp;
+ core->addr1 = tmp;
}
}
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 8db9089..9a13e88 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -6580,24 +6580,21 @@ static const struct file_operations dac960_user_command_proc_fops = {
static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
{
- struct proc_dir_entry *StatusProcEntry;
struct proc_dir_entry *ControllerProcEntry;
- struct proc_dir_entry *UserCommandProcEntry;
if (DAC960_ProcDirectoryEntry == NULL) {
- DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
- StatusProcEntry = proc_create("status", 0,
- DAC960_ProcDirectoryEntry,
- &dac960_proc_fops);
+ DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
+ proc_create("status", 0, DAC960_ProcDirectoryEntry,
+ &dac960_proc_fops);
}
- sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
- ControllerProcEntry = proc_mkdir(Controller->ControllerName,
- DAC960_ProcDirectoryEntry);
- proc_create_data("initial_status", 0, ControllerProcEntry, &dac960_initial_status_proc_fops, Controller);
- proc_create_data("current_status", 0, ControllerProcEntry, &dac960_current_status_proc_fops, Controller);
- UserCommandProcEntry = proc_create_data("user_command", S_IWUSR | S_IRUSR, ControllerProcEntry, &dac960_user_command_proc_fops, Controller);
- Controller->ControllerProcEntry = ControllerProcEntry;
+ sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
+ ControllerProcEntry = proc_mkdir(Controller->ControllerName,
+ DAC960_ProcDirectoryEntry);
+ proc_create_data("initial_status", 0, ControllerProcEntry, &dac960_initial_status_proc_fops, Controller);
+ proc_create_data("current_status", 0, ControllerProcEntry, &dac960_current_status_proc_fops, Controller);
+ proc_create_data("user_command", S_IWUSR | S_IRUSR, ControllerProcEntry, &dac960_user_command_proc_fops, Controller);
+ Controller->ControllerProcEntry = ControllerProcEntry;
}
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 00f9fc9..304000c 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -2510,8 +2510,10 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
up(&dd->port->cmd_slot);
return NULL;
}
- if (unlikely(*tag < 0))
+ if (unlikely(*tag < 0)) {
+ up(&dd->port->cmd_slot);
return NULL;
+ }
return dd->port->commands[*tag].sg;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 0d39f2f..693187d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -29,9 +29,6 @@ struct virtio_blk
/* The disk structure for the kernel. */
struct gendisk *disk;
- /* Request tracking. */
- struct list_head reqs;
-
mempool_t *pool;
/* Process context for config space updates */
@@ -55,7 +52,6 @@ struct virtio_blk
struct virtblk_req
{
- struct list_head list;
struct request *req;
struct virtio_blk_outhdr out_hdr;
struct virtio_scsi_inhdr in_hdr;
@@ -99,7 +95,6 @@ static void blk_done(struct virtqueue *vq)
}
__blk_end_request_all(vbr->req, error);
- list_del(&vbr->list);
mempool_free(vbr, vblk->pool);
}
/* In case queue is stopped waiting for more buffers. */
@@ -184,7 +179,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
return false;
}
- list_add_tail(&vbr->list, &vblk->reqs);
return true;
}
@@ -437,7 +431,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
goto out_free_index;
}
- INIT_LIST_HEAD(&vblk->reqs);
spin_lock_init(&vblk->lock);
vblk->vdev = vdev;
vblk->sg_elems = sg_elems;
@@ -583,21 +576,29 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
int index = vblk->index;
+ struct virtblk_req *vbr;
+ unsigned long flags;
/* Prevent config work handler from accessing the device. */
mutex_lock(&vblk->config_lock);
vblk->config_enable = false;
mutex_unlock(&vblk->config_lock);
- /* Nothing should be pending. */
- BUG_ON(!list_empty(&vblk->reqs));
-
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
flush_work(&vblk->config_work);
del_gendisk(vblk->disk);
+
+ /* Abort requests dispatched to driver. */
+ spin_lock_irqsave(&vblk->lock, flags);
+ while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
+ __blk_end_request_all(vbr->req, -EIO);
+ mempool_free(vbr, vblk->pool);
+ }
+ spin_unlock_irqrestore(&vblk->lock, flags);
+
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
mempool_destroy(vblk->pool);
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 57fd867..2812b15 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -439,6 +439,7 @@ static struct usb_driver ath3k_driver = {
.probe = ath3k_probe,
.disconnect = ath3k_disconnect,
.id_table = ath3k_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(ath3k_driver);
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 1e742a5..37ae175 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -279,6 +279,7 @@ static struct usb_driver bcm203x_driver = {
.probe = bcm203x_probe,
.disconnect = bcm203x_disconnect,
.id_table = bcm203x_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bcm203x_driver);
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index b8ac1c5..32e8251 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -749,6 +749,7 @@ static struct usb_driver bfusb_driver = {
.probe = bfusb_probe,
.disconnect = bfusb_disconnect,
.id_table = bfusb_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bfusb_driver);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d894340..609861a 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -508,6 +508,7 @@ static struct usb_driver bpa10x_driver = {
.probe = bpa10x_probe,
.disconnect = bpa10x_disconnect,
.id_table = bpa10x_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bpa10x_driver);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 9217121..461c68b 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1218,6 +1218,7 @@ static struct usb_driver btusb_driver = {
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(btusb_driver);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ee946865..ea6f632 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -585,14 +585,6 @@ config DEVPORT
source "drivers/s390/char/Kconfig"
-config RAMOOPS
- tristate "Log panic/oops to a RAM buffer"
- depends on HAS_IOMEM
- default n
- help
- This enables panic and oops messages to be logged to a circular
- buffer in RAM where it can be read back at some later point.
-
config MSM_SMD_PKT
bool "Enable device interface for some SMD packet ports"
default n
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0dc5d7c..d0b27a3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
obj-$(CONFIG_PS3_FLASH) += ps3flash.o
-obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 0689bf6..f45dad3 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -62,8 +62,8 @@ config HW_RANDOM_AMD
config HW_RANDOM_ATMEL
tristate "Atmel Random Number Generator support"
- depends on HW_RANDOM && ARCH_AT91SAM9G45
- default HW_RANDOM
+ depends on HW_RANDOM && HAVE_CLK
+ default (HW_RANDOM && ARCH_AT91)
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Atmel AT91 devices.
@@ -250,3 +250,16 @@ config UML_RANDOM
(check your distro, or download from
http://sourceforge.net/projects/gkernel/). rngd periodically reads
/dev/hwrng and injects the entropy into /dev/random.
+
+config HW_RANDOM_PSERIES
+ tristate "pSeries HW Random Number Generator support"
+ depends on HW_RANDOM && PPC64 && IBMVIO
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on POWER7+ machines and above
+
+ To compile this driver as a module, choose M here: the
+ module will be called pseries-rng.
+
+ If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b2ff526..d901dfa 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index a07a5ca..1412565 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -115,22 +115,12 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto err_region;
- }
-
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- ret = -EBUSY;
- goto err_region;
- }
-
- dev_set_drvdata(&pdev->dev, res);
- rng_base = ioremap(res->start, resource_size(res));
+ rng_base = devm_request_and_ioremap(&pdev->dev, res);
if (!rng_base) {
ret = -ENOMEM;
goto err_ioremap;
}
+ dev_set_drvdata(&pdev->dev, res);
ret = hwrng_register(&omap_rng_ops);
if (ret)
@@ -145,11 +135,8 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
return 0;
err_register:
- iounmap(rng_base);
rng_base = NULL;
err_ioremap:
- release_mem_region(res->start, resource_size(res));
-err_region:
if (cpu_is_omap24xx()) {
clk_disable(rng_ick);
clk_put(rng_ick);
@@ -159,20 +146,15 @@ err_region:
static int __exit omap_rng_remove(struct platform_device *pdev)
{
- struct resource *res = dev_get_drvdata(&pdev->dev);
-
hwrng_unregister(&omap_rng_ops);
omap_rng_write_reg(RNG_MASK_REG, 0x0);
- iounmap(rng_base);
-
if (cpu_is_omap24xx()) {
clk_disable(rng_ick);
clk_put(rng_ick);
}
- release_mem_region(res->start, resource_size(res));
rng_base = NULL;
return 0;
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
new file mode 100644
index 0000000..5f11979
--- /dev/null
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Michael Neuling IBM Corporation
+ *
+ * Driver for the pseries hardware RNG for POWER7+ and above
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/hw_random.h>
+#include <asm/vio.h>
+
+#define MODULE_NAME "pseries-rng"
+
+static int pseries_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) {
+ printk(KERN_ERR "pseries rng hcall error\n");
+ return 0;
+ }
+ return 8;
+}
+
+/**
+ * pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations
+ *
+ * This is a required function for a driver to operate in a CMO environment
+ * but this device does not make use of DMA allocations, return 0.
+ *
+ * Return value:
+ * Number of bytes of IO data the driver will need to perform well -> 0
+ */
+static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
+{
+ return 0;
+};
+
+static struct hwrng pseries_rng = {
+ .name = MODULE_NAME,
+ .data_read = pseries_rng_data_read,
+};
+
+static int __init pseries_rng_probe(struct vio_dev *dev,
+ const struct vio_device_id *id)
+{
+ return hwrng_register(&pseries_rng);
+}
+
+static int __exit pseries_rng_remove(struct vio_dev *dev)
+{
+ hwrng_unregister(&pseries_rng);
+ return 0;
+}
+
+static struct vio_device_id pseries_rng_driver_ids[] = {
+ { "ibm,random-v1", "ibm,random"},
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);
+
+static struct vio_driver pseries_rng_driver = {
+ .name = MODULE_NAME,
+ .probe = pseries_rng_probe,
+ .remove = pseries_rng_remove,
+ .get_desired_dma = pseries_rng_get_desired_dma,
+ .id_table = pseries_rng_driver_ids
+};
+
+static int __init rng_init(void)
+{
+ printk(KERN_INFO "Registering IBM pSeries RNG driver\n");
+ return vio_register_driver(&pseries_rng_driver);
+}
+
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+ vio_unregister_driver(&pseries_rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Neuling <mikey@neuling.org>");
+MODULE_DESCRIPTION("H/W RNG driver for IBM pSeries processors");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d6e9d08..67c3371 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -807,44 +807,6 @@ static const struct file_operations oldmem_fops = {
};
#endif
-static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
- unsigned long count, loff_t pos)
-{
- char *line, *p;
- int i;
- ssize_t ret = -EFAULT;
- size_t len = iov_length(iv, count);
-
- line = kmalloc(len + 1, GFP_KERNEL);
- if (line == NULL)
- return -ENOMEM;
-
- /*
- * copy all vectors into a single string, to ensure we do
- * not interleave our log line with other printk calls
- */
- p = line;
- for (i = 0; i < count; i++) {
- if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
- goto out;
- p += iv[i].iov_len;
- }
- p[0] = '\0';
-
- ret = printk("%s", line);
- /* printk can add a prefix */
- if (ret > len)
- ret = len;
-out:
- kfree(line);
- return ret;
-}
-
-static const struct file_operations kmsg_fops = {
- .aio_write = kmsg_writev,
- .llseek = noop_llseek,
-};
-
static const struct memdev {
const char *name;
umode_t mode;
@@ -863,7 +825,9 @@ static const struct memdev {
[7] = { "full", 0666, &full_fops, NULL },
[8] = { "random", 0666, &random_fops, NULL },
[9] = { "urandom", 0666, &urandom_fops, NULL },
- [11] = { "kmsg", 0, &kmsg_fops, NULL },
+#ifdef CONFIG_PRINTK
+ [11] = { "kmsg", 0644, &kmsg_fops, NULL },
+#endif
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
deleted file mode 100644
index 2a5e45d2..0000000
--- a/drivers/char/ramoops.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * RAM Oops/Panic logger
- *
- * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * 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
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kmsg_dump.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/ramoops.h>
-
-#define RAMOOPS_KERNMSG_HDR "===="
-#define MIN_MEM_SIZE 4096UL
-
-static ulong record_size = MIN_MEM_SIZE;
-module_param(record_size, ulong, 0400);
-MODULE_PARM_DESC(record_size,
- "size of each dump done on oops/panic");
-
-static ulong mem_address;
-module_param(mem_address, ulong, 0400);
-MODULE_PARM_DESC(mem_address,
- "start of reserved RAM used to store oops/panic logs");
-
-static ulong mem_size;
-module_param(mem_size, ulong, 0400);
-MODULE_PARM_DESC(mem_size,
- "size of reserved RAM used to store oops/panic logs");
-
-static int dump_oops = 1;
-module_param(dump_oops, int, 0600);
-MODULE_PARM_DESC(dump_oops,
- "set to 1 to dump oopses, 0 to only dump panics (default 1)");
-
-static struct ramoops_context {
- struct kmsg_dumper dump;
- void *virt_addr;
- phys_addr_t phys_addr;
- unsigned long size;
- unsigned long record_size;
- int dump_oops;
- int count;
- int max_count;
-} oops_cxt;
-
-static struct platform_device *dummy;
-static struct ramoops_platform_data *dummy_data;
-
-static void ramoops_do_dump(struct kmsg_dumper *dumper,
- enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
- const char *s2, unsigned long l2)
-{
- struct ramoops_context *cxt = container_of(dumper,
- struct ramoops_context, dump);
- unsigned long s1_start, s2_start;
- unsigned long l1_cpy, l2_cpy;
- int res, hdr_size;
- char *buf, *buf_orig;
- struct timeval timestamp;
-
- if (reason != KMSG_DUMP_OOPS &&
- reason != KMSG_DUMP_PANIC)
- return;
-
- /* Only dump oopses if dump_oops is set */
- if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
- return;
-
- buf = cxt->virt_addr + (cxt->count * cxt->record_size);
- buf_orig = buf;
-
- memset(buf, '\0', cxt->record_size);
- res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
- buf += res;
- do_gettimeofday(&timestamp);
- res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
- buf += res;
-
- hdr_size = buf - buf_orig;
- l2_cpy = min(l2, cxt->record_size - hdr_size);
- l1_cpy = min(l1, cxt->record_size - hdr_size - l2_cpy);
-
- s2_start = l2 - l2_cpy;
- s1_start = l1 - l1_cpy;
-
- memcpy(buf, s1 + s1_start, l1_cpy);
- memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
-
- cxt->count = (cxt->count + 1) % cxt->max_count;
-}
-
-static int __init ramoops_probe(struct platform_device *pdev)
-{
- struct ramoops_platform_data *pdata = pdev->dev.platform_data;
- struct ramoops_context *cxt = &oops_cxt;
- int err = -EINVAL;
-
- if (!pdata->mem_size || !pdata->record_size) {
- pr_err("The memory size and the record size must be "
- "non-zero\n");
- goto fail3;
- }
-
- pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
- pdata->record_size = rounddown_pow_of_two(pdata->record_size);
-
- /* Check for the minimum memory size */
- if (pdata->mem_size < MIN_MEM_SIZE &&
- pdata->record_size < MIN_MEM_SIZE) {
- pr_err("memory size too small, minium is %lu\n", MIN_MEM_SIZE);
- goto fail3;
- }
-
- if (pdata->mem_size < pdata->record_size) {
- pr_err("The memory size must be larger than the "
- "records size\n");
- goto fail3;
- }
-
- cxt->max_count = pdata->mem_size / pdata->record_size;
- cxt->count = 0;
- cxt->size = pdata->mem_size;
- cxt->phys_addr = pdata->mem_address;
- cxt->record_size = pdata->record_size;
- cxt->dump_oops = pdata->dump_oops;
-
- if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
- pr_err("request mem region failed\n");
- err = -EINVAL;
- goto fail3;
- }
-
- cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
- if (!cxt->virt_addr) {
- pr_err("ioremap failed\n");
- goto fail2;
- }
-
- cxt->dump.dump = ramoops_do_dump;
- err = kmsg_dump_register(&cxt->dump);
- if (err) {
- pr_err("registering kmsg dumper failed\n");
- goto fail1;
- }
-
- /*
- * Update the module parameter variables as well so they are visible
- * through /sys/module/ramoops/parameters/
- */
- mem_size = pdata->mem_size;
- mem_address = pdata->mem_address;
- record_size = pdata->record_size;
- dump_oops = pdata->dump_oops;
-
- return 0;
-
-fail1:
- iounmap(cxt->virt_addr);
-fail2:
- release_mem_region(cxt->phys_addr, cxt->size);
-fail3:
- return err;
-}
-
-static int __exit ramoops_remove(struct platform_device *pdev)
-{
- struct ramoops_context *cxt = &oops_cxt;
-
- if (kmsg_dump_unregister(&cxt->dump) < 0)
- pr_warn("could not unregister kmsg_dumper\n");
-
- iounmap(cxt->virt_addr);
- release_mem_region(cxt->phys_addr, cxt->size);
- return 0;
-}
-
-static struct platform_driver ramoops_driver = {
- .remove = __exit_p(ramoops_remove),
- .driver = {
- .name = "ramoops",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init ramoops_init(void)
-{
- int ret;
- ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
- if (ret == -ENODEV) {
- /*
- * If we didn't find a platform device, we use module parameters
- * building platform data on the fly.
- */
- pr_info("platform device not found, using module parameters\n");
- dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
- GFP_KERNEL);
- if (!dummy_data)
- return -ENOMEM;
- dummy_data->mem_size = mem_size;
- dummy_data->mem_address = mem_address;
- dummy_data->record_size = record_size;
- dummy_data->dump_oops = dump_oops;
- dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
- NULL, 0, dummy_data,
- sizeof(struct ramoops_platform_data));
-
- if (IS_ERR(dummy))
- ret = PTR_ERR(dummy);
- else
- ret = 0;
- }
-
- return ret;
-}
-
-static void __exit ramoops_exit(void)
-{
- platform_driver_unregister(&ramoops_driver);
- kfree(dummy_data);
-}
-
-module_init(ramoops_init);
-module_exit(ramoops_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
-MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index ddf86b6..cdf2f54 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1895,6 +1895,13 @@ static int virtcons_restore(struct virtio_device *vdev)
/* Get port open/close status on the host */
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+ /*
+ * If a port was open at the time of suspending, we
+ * have to let the host know that it's still open.
+ */
+ if (port->guest_connected)
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
}
return 0;
}
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 31ba11c..2c5d15b 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -167,6 +167,7 @@ static const struct config_registers v4_config_registers = {
.BOOTSTS = UNIMPLEMENTED,
.CTL_1 = UNIMPLEMENTED,
};
+
static const struct config_registers v5_config_registers = {
.CRC = 0,
.FAR = 1,
@@ -192,6 +193,31 @@ static const struct config_registers v5_config_registers = {
.CTL_1 = 19,
};
+static const struct config_registers v6_config_registers = {
+ .CRC = 0,
+ .FAR = 1,
+ .FDRI = 2,
+ .FDRO = 3,
+ .CMD = 4,
+ .CTL = 5,
+ .MASK = 6,
+ .STAT = 7,
+ .LOUT = 8,
+ .COR = 9,
+ .MFWR = 10,
+ .FLR = UNIMPLEMENTED,
+ .KEY = UNIMPLEMENTED,
+ .CBC = 11,
+ .IDCODE = 12,
+ .AXSS = 13,
+ .C0R_1 = 14,
+ .CSOB = 15,
+ .WBSTAR = 16,
+ .TIMER = 17,
+ .BOOTSTS = 22,
+ .CTL_1 = 24,
+};
+
/**
* hwicap_command_desync - Send a DESYNC command to the ICAP port.
* @drvdata: a pointer to the drvdata.
@@ -744,6 +770,8 @@ static int __devinit hwicap_of_probe(struct platform_device *op,
regs = &v4_config_registers;
} else if (!strcmp(family, "virtex5")) {
regs = &v5_config_registers;
+ } else if (!strcmp(family, "virtex6")) {
+ regs = &v6_config_registers;
}
}
return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
@@ -785,6 +813,8 @@ static int __devinit hwicap_drv_probe(struct platform_device *pdev)
regs = &v4_config_registers;
} else if (!strcmp(family, "virtex5")) {
regs = &v5_config_registers;
+ } else if (!strcmp(family, "virtex6")) {
+ regs = &v6_config_registers;
}
}
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
index 8cca119..d31ee23 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.h
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -86,7 +86,7 @@ struct hwicap_driver_config {
};
/* Number of times to poll the done regsiter */
-#define XHI_MAX_RETRIES 10
+#define XHI_MAX_RETRIES 5000
/************ Constant Definitions *************/
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 6db161f..c535cf8 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -35,7 +35,12 @@ static DEFINE_MUTEX(clocks_mutex);
static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
{
struct clk_lookup *p, *cl = NULL;
- int match, best = 0;
+ int match, best_found = 0, best_possible = 0;
+
+ if (dev_id)
+ best_possible += 2;
+ if (con_id)
+ best_possible += 1;
list_for_each_entry(p, &clocks, node) {
match = 0;
@@ -50,10 +55,10 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
match += 1;
}
- if (match > best) {
+ if (match > best_found) {
cl = p;
- if (match != 3)
- best = match;
+ if (match != best_possible)
+ best_found = match;
else
break;
}
@@ -89,6 +94,51 @@ void clk_put(struct clk *clk)
}
EXPORT_SYMBOL(clk_put);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_put(*(struct clk **)res);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+ struct clk **ptr, *clk;
+
+ ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ clk = clk_get(dev, id);
+ if (!IS_ERR(clk)) {
+ *ptr = clk;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL(devm_clk_get);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk **c = res;
+ if (!c || !*c) {
+ WARN_ON(!c || !*c);
+ return 0;
+ }
+ return *c == data;
+}
+
+void devm_clk_put(struct device *dev, struct clk *clk)
+{
+ int ret;
+
+ ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk);
+
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_clk_put);
+
void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
@@ -116,8 +166,9 @@ struct clk_lookup_alloc {
char con_id[MAX_CON_ID];
};
-struct clk_lookup * __init_refok
-clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
+static struct clk_lookup * __init_refok
+vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt,
+ va_list ap)
{
struct clk_lookup_alloc *cla;
@@ -132,16 +183,25 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
}
if (dev_fmt) {
- va_list ap;
-
- va_start(ap, dev_fmt);
vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
cla->cl.dev_id = cla->dev_id;
- va_end(ap);
}
return &cla->cl;
}
+
+struct clk_lookup * __init_refok
+clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
+{
+ struct clk_lookup *cl;
+ va_list ap;
+
+ va_start(ap, dev_fmt);
+ cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+ va_end(ap);
+
+ return cl;
+}
EXPORT_SYMBOL(clkdev_alloc);
int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
@@ -173,3 +233,65 @@ void clkdev_drop(struct clk_lookup *cl)
kfree(cl);
}
EXPORT_SYMBOL(clkdev_drop);
+
+/**
+ * clk_register_clkdev - register one clock lookup for a struct clk
+ * @clk: struct clk to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_id: format string describing device name
+ *
+ * con_id or dev_id may be NULL as a wildcard, just as in the rest of
+ * clkdev.
+ *
+ * To make things easier for mass registration, we detect error clks
+ * from a previous clk_register() call, and return the error code for
+ * those. This is to permit this function to be called immediately
+ * after clk_register().
+ */
+int clk_register_clkdev(struct clk *clk, const char *con_id,
+ const char *dev_fmt, ...)
+{
+ struct clk_lookup *cl;
+ va_list ap;
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ va_start(ap, dev_fmt);
+ cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+ va_end(ap);
+
+ if (!cl)
+ return -ENOMEM;
+
+ clkdev_add(cl);
+
+ return 0;
+}
+
+/**
+ * clk_register_clkdevs - register a set of clk_lookup for a struct clk
+ * @clk: struct clk to associate with all clk_lookups
+ * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized
+ * @num: number of clk_lookup structures to register
+ *
+ * To make things easier for mass registration, we detect error clks
+ * from a previous clk_register() call, and return the error code for
+ * those. This is to permit this function to be called immediately
+ * after clk_register().
+ */
+int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num)
+{
+ unsigned i;
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ for (i = 0; i < num; i++, cl++) {
+ cl->clk = clk;
+ clkdev_add(cl);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_register_clkdevs);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5138927..99c6b20 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,7 +18,7 @@ config DW_APB_TIMER
config CLKSRC_DBX500_PRCMU
bool "Clocksource PRCMU Timer"
- depends on UX500_SOC_DB5500 || UX500_SOC_DB8500
+ depends on UX500_SOC_DB8500
default y
help
Use the always on PRCMU Timer as clocksource
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 0bf1b89..74b830b 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -161,7 +161,7 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
static int __init db8500_cpufreq_register(void)
{
- if (!cpu_is_u8500v20_or_later())
+ if (!cpu_is_u8500_family())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2f0083a..d90519c 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -40,17 +40,6 @@ void disable_cpuidle(void)
off = 1;
}
-#if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT)
-static void cpuidle_kick_cpus(void)
-{
- cpu_idle_wait();
-}
-#elif defined(CONFIG_SMP)
-# error "Arch needs cpu_idle_wait() equivalent here"
-#else /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT && !CONFIG_SMP */
-static void cpuidle_kick_cpus(void) {}
-#endif
-
static int __cpuidle_register_device(struct cpuidle_device *dev);
static inline int cpuidle_enter(struct cpuidle_device *dev,
@@ -186,7 +175,7 @@ void cpuidle_uninstall_idle_handler(void)
{
if (enabled_devices) {
initialized = 0;
- cpuidle_kick_cpus();
+ kick_all_cpus_sync();
}
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ab9abb4..1092a77 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -111,6 +111,7 @@ config CRYPTO_DES_S390
depends on S390
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
+ select CRYPTO_DES
help
This is the s390 hardware accelerated implementation of the
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
@@ -164,6 +165,7 @@ config CRYPTO_DEV_MV_CESA
select CRYPTO_ALGAPI
select CRYPTO_AES
select CRYPTO_BLKCIPHER2
+ select CRYPTO_HASH
help
This driver allows you to utilize the Cryptographic Engines and
Security Accelerator (CESA) which can be found on the Marvell Orion
@@ -295,4 +297,32 @@ config CRYPTO_DEV_TEGRA_AES
To compile this driver as a module, choose M here: the module
will be called tegra-aes.
+config CRYPTO_DEV_NX
+ tristate "Support for Power7+ in-Nest cryptographic accleration"
+ depends on PPC64 && IBMVIO
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ select CRYPTO_ECB
+ select CRYPTO_CCM
+ select CRYPTO_GCM
+ select CRYPTO_AUTHENC
+ select CRYPTO_XCBC
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ help
+ Support for Power7+ in-Nest cryptographic acceleration. This
+ module supports acceleration for AES and SHA2 algorithms. If you
+ choose 'M' here, this module will be called nx_crypto.
+
+config CRYPTO_DEV_UX500
+ tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
+ depends on ARCH_U8500
+ select CRYPTO_ALGAPI
+ help
+ Driver for ST-Ericsson UX500 crypto engine.
+
+if CRYPTO_DEV_UX500
+ source "drivers/crypto/ux500/Kconfig"
+endif # if CRYPTO_DEV_UX500
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index f3e64ea..0139032 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ \ No newline at end of file
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 13f8e1a..802e851 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1244,9 +1244,9 @@ err_start_dev:
iounmap(core_dev->dev->ce_base);
err_iomap:
free_irq(core_dev->irq, dev);
+err_request_irq:
irq_dispose_mapping(core_dev->irq);
tasklet_kill(&core_dev->tasklet);
-err_request_irq:
crypto4xx_destroy_sdr(core_dev->dev);
err_build_sdr:
crypto4xx_destroy_gdr(core_dev->dev);
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 534a364..4eec389 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2267,8 +2267,11 @@ static void __exit caam_algapi_exit(void)
int i, err;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node)
- return;
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
pdev = of_find_device_by_node(dev_node);
if (!pdev)
@@ -2350,8 +2353,11 @@ static int __init caam_algapi_init(void)
int i = 0, err = 0;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node)
- return -ENODEV;
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
pdev = of_find_device_by_node(dev_node);
if (!pdev)
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index c5f61c5..77557eb 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -98,6 +98,12 @@ static int caam_probe(struct platform_device *pdev)
rspec = 0;
for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring")
rspec++;
+ if (!rspec) {
+ /* for backward compatible with device trees */
+ for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring")
+ rspec++;
+ }
+
ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL);
if (ctrlpriv->jrdev == NULL) {
iounmap(&topregs->ctrl);
@@ -111,6 +117,13 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->total_jobrs++;
ring++;
}
+ if (!ring) {
+ for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") {
+ caam_jr_probe(pdev, np, ring);
+ ctrlpriv->total_jobrs++;
+ ring++;
+ }
+ }
/* Check to see if QI present. If so, enable */
ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) &
@@ -226,6 +239,9 @@ static struct of_device_id caam_match[] = {
{
.compatible = "fsl,sec-v4.0",
},
+ {
+ .compatible = "fsl,sec4.0",
+ },
{},
};
MODULE_DEVICE_TABLE(of, caam_match);
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
new file mode 100644
index 0000000..411ce59
--- /dev/null
+++ b/drivers/crypto/nx/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+nx-crypto-objs := nx.o \
+ nx_debugfs.o \
+ nx-aes-cbc.o \
+ nx-aes-ecb.o \
+ nx-aes-gcm.o \
+ nx-aes-ccm.o \
+ nx-aes-ctr.o \
+ nx-aes-xcbc.o \
+ nx-sha256.o \
+ nx-sha512.o
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
new file mode 100644
index 0000000..69ed796
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -0,0 +1,141 @@
+/**
+ * AES CBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int cbc_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CBC;
+ memcpy(csbcpb->cpb.aes_cbc.key, in_key, key_len);
+
+ return 0;
+}
+
+static int cbc_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+ csbcpb->cpb.aes_cbc.iv);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int cbc_aes_nx_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return cbc_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int cbc_aes_nx_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return cbc_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_cbc_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = cbc_aes_nx_set_key,
+ .encrypt = cbc_aes_nx_encrypt,
+ .decrypt = cbc_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
new file mode 100644
index 0000000..7aeac67
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -0,0 +1,468 @@
+/**
+ * AES CCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
+ memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
+
+ csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
+ memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
+
+ return 0;
+
+}
+
+static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+
+ if (key_len < 3)
+ return -EINVAL;
+
+ key_len -= 3;
+
+ memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
+
+ return ccm_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+/* taken from crypto/ccm.c */
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+ __be32 data;
+
+ memset(block, 0, csize);
+ block += csize;
+
+ if (csize >= 4)
+ csize = 4;
+ else if (msglen > (unsigned int)(1 << (8 * csize)))
+ return -EOVERFLOW;
+
+ data = cpu_to_be32(msglen);
+ memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+ return 0;
+}
+
+/* taken from crypto/ccm.c */
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+ /* 2 <= L <= 8, so 1 <= L' <= 7. */
+ if (1 > iv[0] || iv[0] > 7)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* based on code from crypto/ccm.c */
+static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
+ unsigned int cryptlen, u8 *b0)
+{
+ unsigned int l, lp, m = authsize;
+ int rc;
+
+ memcpy(b0, iv, 16);
+
+ lp = b0[0];
+ l = lp + 1;
+
+ /* set m, bits 3-5 */
+ *b0 |= (8 * ((m - 2) / 2));
+
+ /* set adata, bit 6, if associated data is used */
+ if (assoclen)
+ *b0 |= 64;
+
+ rc = set_msg_len(b0 + 16 - l, cryptlen, l);
+
+ return rc;
+}
+
+static int generate_pat(u8 *iv,
+ struct aead_request *req,
+ struct nx_crypto_ctx *nx_ctx,
+ unsigned int authsize,
+ unsigned int nbytes,
+ u8 *out)
+{
+ struct nx_sg *nx_insg = nx_ctx->in_sg;
+ struct nx_sg *nx_outsg = nx_ctx->out_sg;
+ unsigned int iauth_len = 0;
+ struct vio_pfo_op *op = NULL;
+ u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
+ int rc;
+
+ /* zero the ctr value */
+ memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+ if (!req->assoclen) {
+ b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+ } else if (req->assoclen <= 14) {
+ /* if associated data is 14 bytes or less, we do 1 GCM
+ * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
+ * which is fed in through the source buffers here */
+ b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+ b1 = nx_ctx->priv.ccm.iauth_tag;
+ iauth_len = req->assoclen;
+
+ nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16,
+ nx_ctx->ap->sglen);
+
+ /* inlen should be negative, indicating to phyp that its a
+ * pointer to an sg list */
+ nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
+ sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
+ sizeof(struct nx_sg);
+
+ NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ op = &nx_ctx->op;
+ result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
+ } else if (req->assoclen <= 65280) {
+ /* if associated data is less than (2^16 - 2^8), we construct
+ * B1 differently and feed in the associated data to a CCA
+ * operation */
+ b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+ b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+ iauth_len = 14;
+
+ /* remaining assoc data must have scatterlist built for it */
+ nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen,
+ req->assoc, iauth_len,
+ req->assoclen - iauth_len);
+ nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
+ sizeof(struct nx_sg);
+
+ op = &nx_ctx->op_aead;
+ result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
+ } else {
+ /* if associated data is less than (2^32), we construct B1
+ * differently yet again and feed in the associated data to a
+ * CCA operation */
+ pr_err("associated data len is %u bytes (returning -EINVAL)\n",
+ req->assoclen);
+ rc = -EINVAL;
+ }
+
+ rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
+ if (rc)
+ goto done;
+
+ if (b1) {
+ memset(b1, 0, 16);
+ *(u16 *)b1 = (u16)req->assoclen;
+
+ scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
+ iauth_len, SCATTERWALK_FROM_SG);
+
+ rc = nx_hcall_sync(nx_ctx, op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto done;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+ memcpy(out, result, AES_BLOCK_SIZE);
+ }
+done:
+ return rc;
+}
+
+static int ccm_nx_decrypt(struct aead_request *req,
+ struct blkcipher_desc *desc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ unsigned int nbytes = req->cryptlen;
+ unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+ struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
+ int rc = -1;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ nbytes -= authsize;
+
+ /* copy out the auth tag to compare with later */
+ scatterwalk_map_and_copy(priv->oauth_tag,
+ req->src, nbytes, authsize,
+ SCATTERWALK_FROM_SG);
+
+ rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+ csbcpb->cpb.aes_ccm.in_pat_or_b0);
+ if (rc)
+ goto out;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_ccm.iv_or_ctr);
+ if (rc)
+ goto out;
+
+ NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+ authsize) ? -EBADMSG : 0;
+out:
+ return rc;
+}
+
+static int ccm_nx_encrypt(struct aead_request *req,
+ struct blkcipher_desc *desc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ unsigned int nbytes = req->cryptlen;
+ unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+ int rc = -1;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+ csbcpb->cpb.aes_ccm.in_pat_or_b0);
+ if (rc)
+ goto out;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_ccm.iv_or_ctr);
+ if (rc)
+ goto out;
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ /* copy out the auth tag */
+ scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
+ req->dst, nbytes, authsize,
+ SCATTERWALK_TO_SG);
+out:
+ return rc;
+}
+
+static int ccm4309_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct blkcipher_desc desc;
+ u8 *iv = nx_ctx->priv.ccm.iv;
+
+ iv[0] = 3;
+ memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+ memcpy(iv + 4, req->iv, 8);
+
+ desc.info = iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm_aes_nx_encrypt(struct aead_request *req)
+{
+ struct blkcipher_desc desc;
+ int rc;
+
+ desc.info = req->iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ rc = crypto_ccm_check_iv(desc.info);
+ if (rc)
+ return rc;
+
+ return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm4309_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct blkcipher_desc desc;
+ u8 *iv = nx_ctx->priv.ccm.iv;
+
+ iv[0] = 3;
+ memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+ memcpy(iv + 4, req->iv, 8);
+
+ desc.info = iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ return ccm_nx_decrypt(req, &desc);
+}
+
+static int ccm_aes_nx_decrypt(struct aead_request *req)
+{
+ struct blkcipher_desc desc;
+ int rc;
+
+ desc.info = req->iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ rc = crypto_ccm_check_iv(desc.info);
+ if (rc)
+ return rc;
+
+ return ccm_nx_decrypt(req, &desc);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_ccm_aes_alg = {
+ .cra_name = "ccm(aes)",
+ .cra_driver_name = "ccm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_aead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ccm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = ccm_aes_nx_set_key,
+ .setauthsize = ccm_aes_nx_setauthsize,
+ .encrypt = ccm_aes_nx_encrypt,
+ .decrypt = ccm_aes_nx_decrypt,
+ }
+};
+
+struct crypto_alg nx_ccm4309_aes_alg = {
+ .cra_name = "rfc4309(ccm(aes))",
+ .cra_driver_name = "rfc4309-ccm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ccm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = ccm4309_aes_nx_set_key,
+ .setauthsize = ccm4309_aes_nx_setauthsize,
+ .encrypt = ccm4309_aes_nx_encrypt,
+ .decrypt = ccm4309_aes_nx_decrypt,
+ .geniv = "seqiv",
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
new file mode 100644
index 0000000..52d4eb0
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ctr.c
@@ -0,0 +1,178 @@
+/**
+ * AES CTR routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ctr_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CTR;
+ memcpy(csbcpb->cpb.aes_ctr.key, in_key, key_len);
+
+ return 0;
+}
+
+static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+ if (key_len < CTR_RFC3686_NONCE_SIZE)
+ return -EINVAL;
+
+ memcpy(nx_ctx->priv.ctr.iv,
+ in_key + key_len - CTR_RFC3686_NONCE_SIZE,
+ CTR_RFC3686_NONCE_SIZE);
+
+ key_len -= CTR_RFC3686_NONCE_SIZE;
+
+ return ctr_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ctr_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+ csbcpb->cpb.aes_ctr.iv);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ u8 *iv = nx_ctx->priv.ctr.iv;
+
+ memcpy(iv + CTR_RFC3686_NONCE_SIZE,
+ desc->info, CTR_RFC3686_IV_SIZE);
+ iv[15] = 1;
+
+ desc->info = nx_ctx->priv.ctr.iv;
+
+ return ctr_aes_nx_crypt(desc, dst, src, nbytes);
+}
+
+struct crypto_alg nx_ctr_aes_alg = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ctr_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ctr_aes_nx_set_key,
+ .encrypt = ctr_aes_nx_crypt,
+ .decrypt = ctr_aes_nx_crypt,
+ }
+};
+
+struct crypto_alg nx_ctr3686_aes_alg = {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ctr_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .geniv = "seqiv",
+ .setkey = ctr3686_aes_nx_set_key,
+ .encrypt = ctr3686_aes_nx_crypt,
+ .decrypt = ctr3686_aes_nx_crypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
new file mode 100644
index 0000000..7b77bc2
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -0,0 +1,139 @@
+/**
+ * AES ECB routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ecb_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+ memcpy(csbcpb->cpb.aes_ecb.key, in_key, key_len);
+
+ return 0;
+}
+
+static int ecb_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes, NULL);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int ecb_aes_nx_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return ecb_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int ecb_aes_nx_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return ecb_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ecb_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = ecb_aes_nx_set_key,
+ .encrypt = ecb_aes_nx_encrypt,
+ .decrypt = ecb_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
new file mode 100644
index 0000000..9ab1c73
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -0,0 +1,353 @@
+/**
+ * AES GCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int gcm_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+ memcpy(csbcpb->cpb.aes_gcm.key, in_key, key_len);
+
+ csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_GCA;
+ memcpy(csbcpb_aead->cpb.aes_gca.key, in_key, key_len);
+
+ return 0;
+}
+
+static int gcm4106_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ char *nonce = nx_ctx->priv.gcm.nonce;
+ int rc;
+
+ if (key_len < 4)
+ return -EINVAL;
+
+ key_len -= 4;
+
+ rc = gcm_aes_nx_set_key(tfm, in_key, key_len);
+ if (rc)
+ goto out;
+
+ memcpy(nonce, in_key + key_len, 4);
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+ return -EINVAL;
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int nx_gca(struct nx_crypto_ctx *nx_ctx,
+ struct aead_request *req,
+ u8 *out)
+{
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+ int rc = -EINVAL;
+ struct scatter_walk walk;
+ struct nx_sg *nx_sg = nx_ctx->in_sg;
+
+ if (req->assoclen > nx_ctx->ap->databytelen)
+ goto out;
+
+ if (req->assoclen <= AES_BLOCK_SIZE) {
+ scatterwalk_start(&walk, req->assoc);
+ scatterwalk_copychunks(out, &walk, req->assoclen,
+ SCATTERWALK_FROM_SG);
+ scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
+
+ rc = 0;
+ goto out;
+ }
+
+ nx_sg = nx_walk_and_build(nx_sg, nx_ctx->ap->sglen, req->assoc, 0,
+ req->assoclen);
+ nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg) * sizeof(struct nx_sg);
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+ memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct blkcipher_desc desc;
+ unsigned int nbytes = req->cryptlen;
+ int rc = -EINVAL;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ goto out;
+
+ desc.info = nx_ctx->priv.gcm.iv;
+ /* initialize the counter */
+ *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
+
+ /* For scenarios where the input message is zero length, AES CTR mode
+ * may be used. Set the source data to be a single block (16B) of all
+ * zeros, and set the input IV value to be the same as the GMAC IV
+ * value. - nx_wb 4.8.1.3 */
+ if (nbytes == 0) {
+ char src[AES_BLOCK_SIZE] = {};
+ struct scatterlist sg;
+
+ desc.tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0);
+ if (IS_ERR(desc.tfm)) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ crypto_blkcipher_setkey(desc.tfm, csbcpb->cpb.aes_gcm.key,
+ NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_128 ? 16 :
+ NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_192 ? 24 : 32);
+
+ sg_init_one(&sg, src, AES_BLOCK_SIZE);
+ if (enc)
+ crypto_blkcipher_encrypt_iv(&desc, req->dst, &sg,
+ AES_BLOCK_SIZE);
+ else
+ crypto_blkcipher_decrypt_iv(&desc, req->dst, &sg,
+ AES_BLOCK_SIZE);
+ crypto_free_blkcipher(desc.tfm);
+
+ rc = 0;
+ goto out;
+ }
+
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8;
+
+ if (req->assoclen) {
+ rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad);
+ if (rc)
+ goto out;
+ }
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ nbytes -= AES_BLOCK_SIZE;
+
+ csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+
+ rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_gcm.iv_or_cnt);
+ if (rc)
+ goto out;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ if (enc) {
+ /* copy out the auth tag */
+ scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
+ req->dst, nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_TO_SG);
+ } else if (req->assoclen) {
+ u8 *itag = nx_ctx->priv.gcm.iauth_tag;
+ u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
+
+ scatterwalk_map_and_copy(itag, req->dst, nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_FROM_SG);
+ rc = memcmp(itag, otag,
+ crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
+ -EBADMSG : 0;
+ }
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+
+ memcpy(iv, req->iv, 12);
+
+ return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+
+ memcpy(iv, req->iv, 12);
+
+ return gcm_aes_nx_crypt(req, 0);
+}
+
+static int gcm4106_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+ char *nonce = nx_ctx->priv.gcm.nonce;
+
+ memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+ memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+ return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm4106_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+ char *nonce = nx_ctx->priv.gcm.nonce;
+
+ memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+ memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+ return gcm_aes_nx_crypt(req, 0);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_gcm_aes_alg = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_aead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_gcm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = gcm_aes_nx_set_key,
+ .setauthsize = gcm_aes_nx_setauthsize,
+ .encrypt = gcm_aes_nx_encrypt,
+ .decrypt = gcm_aes_nx_decrypt,
+ }
+};
+
+struct crypto_alg nx_gcm4106_aes_alg = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_gcm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .geniv = "seqiv",
+ .setkey = gcm4106_aes_nx_set_key,
+ .setauthsize = gcm4106_aes_nx_setauthsize,
+ .encrypt = gcm4106_aes_nx_encrypt,
+ .decrypt = gcm4106_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c
new file mode 100644
index 0000000..93923e4
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-xcbc.c
@@ -0,0 +1,236 @@
+/**
+ * AES XCBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+struct xcbc_state {
+ u8 state[AES_BLOCK_SIZE];
+ unsigned int count;
+ u8 buffer[AES_BLOCK_SIZE];
+};
+
+static int nx_xcbc_set_key(struct crypto_shash *desc,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ memcpy(nx_ctx->priv.xcbc.key, in_key, key_len);
+
+ return 0;
+}
+
+static int nx_xcbc_init(struct shash_desc *desc)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
+
+ memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE);
+ memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key);
+
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ AES_BLOCK_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_xcbc_update(struct shash_desc *desc,
+ const u8 *data,
+ unsigned int len)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u32 to_process, leftover;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.aes_xcbc.cv,
+ csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= AES_BLOCK_SIZE: copy into state, return 0
+ * 2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if (len + sctx->count <= AES_BLOCK_SIZE) {
+ memcpy(sctx->buffer + sctx->count, data, len);
+ sctx->count += len;
+ goto out;
+ }
+
+ /* to_process: the AES_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count + len) & ~(AES_BLOCK_SIZE - 1);
+ leftover = (sctx->count + len) & (AES_BLOCK_SIZE - 1);
+
+ /* the hardware will not accept a 0 byte operation for this algorithm
+ * and the operation MUST be finalized to be correct. So if we happen
+ * to get an update that falls on a block sized boundary, we must
+ * save off the last block to finalize with later. */
+ if (!leftover) {
+ to_process -= AES_BLOCK_SIZE;
+ leftover = AES_BLOCK_SIZE;
+ }
+
+ if (sctx->count) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buffer,
+ sctx->count, nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data, to_process,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buffer, data + len - leftover, leftover);
+ sctx->count = leftover;
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.aes_xcbc.cv,
+ csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+ } else if (sctx->count == 0) {
+ /* we've never seen an update, so this is a 0 byte op. The
+ * hardware cannot handle a 0 byte op, so just copy out the
+ * known 0 byte result. This is cheaper than allocating a
+ * software context to do a 0 byte op */
+ u8 data[] = { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
+ 0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 };
+ memcpy(out, data, sizeof(data));
+ goto out;
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
+ sctx->count, nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, AES_BLOCK_SIZE,
+ nx_ctx->ap->sglen);
+
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+
+ memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+out:
+ return rc;
+}
+
+struct shash_alg nx_shash_aes_xcbc_alg = {
+ .digestsize = AES_BLOCK_SIZE,
+ .init = nx_xcbc_init,
+ .update = nx_xcbc_update,
+ .final = nx_xcbc_final,
+ .setkey = nx_xcbc_set_key,
+ .descsize = sizeof(struct xcbc_state),
+ .statesize = sizeof(struct xcbc_state),
+ .base = {
+ .cra_name = "xcbc(aes)",
+ .cra_driver_name = "xcbc-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_aes_xcbc_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
new file mode 100644
index 0000000..9767315
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -0,0 +1,246 @@
+/**
+ * SHA-256 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha256_init(struct shash_desc *desc)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256];
+
+ NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ SHA256_DIGEST_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u64 to_process, leftover;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha256.input_partial_digest,
+ csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= SHA256_BLOCK_SIZE: copy into state, return 0
+ * 2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if (len + sctx->count <= SHA256_BLOCK_SIZE) {
+ memcpy(sctx->buf + sctx->count, data, len);
+ sctx->count += len;
+ goto out;
+ }
+
+ /* to_process: the SHA256_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count + len) & ~(SHA256_BLOCK_SIZE - 1);
+ leftover = (sctx->count + len) & (SHA256_BLOCK_SIZE - 1);
+
+ if (sctx->count) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count, nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+ to_process, nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buf, data + len - leftover, leftover);
+ sctx->count = leftover;
+
+ csbcpb->cpb.sha256.message_bit_length += (u64)
+ (csbcpb->cpb.sha256.spbc * 8);
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_sha256_final(struct shash_desc *desc, u8 *out)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ int rc;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha256.input_partial_digest,
+ csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ csbcpb->cpb.sha256.message_bit_length += (u64)(sctx->count * 8);
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count, nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA256_DIGEST_SIZE,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+ atomic64_add(csbcpb->cpb.sha256.message_bit_length,
+ &(nx_ctx->stats->sha256_bytes));
+ memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+out:
+ return rc;
+}
+
+static int nx_sha256_export(struct shash_desc *desc, void *out)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct sha256_state *octx = out;
+
+ octx->count = sctx->count +
+ (csbcpb->cpb.sha256.message_bit_length / 8);
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+ /* if no data has been processed yet, we need to export SHA256's
+ * initial data, in case this context gets imported into a software
+ * context */
+ if (csbcpb->cpb.sha256.message_bit_length)
+ memcpy(octx->state, csbcpb->cpb.sha256.message_digest,
+ SHA256_DIGEST_SIZE);
+ else {
+ octx->state[0] = SHA256_H0;
+ octx->state[1] = SHA256_H1;
+ octx->state[2] = SHA256_H2;
+ octx->state[3] = SHA256_H3;
+ octx->state[4] = SHA256_H4;
+ octx->state[5] = SHA256_H5;
+ octx->state[6] = SHA256_H6;
+ octx->state[7] = SHA256_H7;
+ }
+
+ return 0;
+}
+
+static int nx_sha256_import(struct shash_desc *desc, const void *in)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ const struct sha256_state *ictx = in;
+
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+
+ sctx->count = ictx->count & 0x3f;
+ csbcpb->cpb.sha256.message_bit_length = (ictx->count & ~0x3f) * 8;
+
+ if (csbcpb->cpb.sha256.message_bit_length) {
+ memcpy(csbcpb->cpb.sha256.message_digest, ictx->state,
+ SHA256_DIGEST_SIZE);
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+ }
+
+ return 0;
+}
+
+struct shash_alg nx_shash_sha256_alg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = nx_sha256_init,
+ .update = nx_sha256_update,
+ .final = nx_sha256_final,
+ .export = nx_sha256_export,
+ .import = nx_sha256_import,
+ .descsize = sizeof(struct sha256_state),
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_sha_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
new file mode 100644
index 0000000..3177b8c
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -0,0 +1,265 @@
+/**
+ * SHA-512 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha512_init(struct shash_desc *desc)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512];
+
+ NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ SHA512_DIGEST_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u64 to_process, leftover, spbc_bits;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha512.input_partial_digest,
+ csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= SHA512_BLOCK_SIZE: copy into state, return 0
+ * 2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) {
+ memcpy(sctx->buf + sctx->count[0], data, len);
+ sctx->count[0] += len;
+ goto out;
+ }
+
+ /* to_process: the SHA512_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count[0] + len) & ~(SHA512_BLOCK_SIZE - 1);
+ leftover = (sctx->count[0] + len) & (SHA512_BLOCK_SIZE - 1);
+
+ if (sctx->count[0]) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count[0], nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count[0],
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+ to_process, nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha512_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buf, data + len - leftover, leftover);
+ sctx->count[0] = leftover;
+
+ spbc_bits = csbcpb->cpb.sha512.spbc * 8;
+ csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
+ if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
+ csbcpb->cpb.sha512.message_bit_length_hi++;
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_sha512_final(struct shash_desc *desc, u8 *out)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ u64 count0;
+ int rc;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha512.input_partial_digest,
+ csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ count0 = sctx->count[0] * 8;
+
+ csbcpb->cpb.sha512.message_bit_length_lo += count0;
+ if (csbcpb->cpb.sha512.message_bit_length_lo < count0)
+ csbcpb->cpb.sha512.message_bit_length_hi++;
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, sctx->count[0],
+ nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA512_DIGEST_SIZE,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha512_ops));
+ atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo,
+ &(nx_ctx->stats->sha512_bytes));
+
+ memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+out:
+ return rc;
+}
+
+static int nx_sha512_export(struct shash_desc *desc, void *out)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct sha512_state *octx = out;
+
+ /* move message_bit_length (128 bits) into count and convert its value
+ * to bytes */
+ octx->count[0] = csbcpb->cpb.sha512.message_bit_length_lo >> 3 |
+ ((csbcpb->cpb.sha512.message_bit_length_hi & 7) << 61);
+ octx->count[1] = csbcpb->cpb.sha512.message_bit_length_hi >> 3;
+
+ octx->count[0] += sctx->count[0];
+ if (octx->count[0] < sctx->count[0])
+ octx->count[1]++;
+
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+ /* if no data has been processed yet, we need to export SHA512's
+ * initial data, in case this context gets imported into a software
+ * context */
+ if (csbcpb->cpb.sha512.message_bit_length_hi ||
+ csbcpb->cpb.sha512.message_bit_length_lo)
+ memcpy(octx->state, csbcpb->cpb.sha512.message_digest,
+ SHA512_DIGEST_SIZE);
+ else {
+ octx->state[0] = SHA512_H0;
+ octx->state[1] = SHA512_H1;
+ octx->state[2] = SHA512_H2;
+ octx->state[3] = SHA512_H3;
+ octx->state[4] = SHA512_H4;
+ octx->state[5] = SHA512_H5;
+ octx->state[6] = SHA512_H6;
+ octx->state[7] = SHA512_H7;
+ }
+
+ return 0;
+}
+
+static int nx_sha512_import(struct shash_desc *desc, const void *in)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ const struct sha512_state *ictx = in;
+
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+ sctx->count[0] = ictx->count[0] & 0x3f;
+ csbcpb->cpb.sha512.message_bit_length_lo = (ictx->count[0] & ~0x3f)
+ << 3;
+ csbcpb->cpb.sha512.message_bit_length_hi = ictx->count[1] << 3 |
+ ictx->count[0] >> 61;
+
+ if (csbcpb->cpb.sha512.message_bit_length_hi ||
+ csbcpb->cpb.sha512.message_bit_length_lo) {
+ memcpy(csbcpb->cpb.sha512.message_digest, ictx->state,
+ SHA512_DIGEST_SIZE);
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+ }
+
+ return 0;
+}
+
+struct shash_alg nx_shash_sha512_alg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .init = nx_sha512_init,
+ .update = nx_sha512_update,
+ .final = nx_sha512_final,
+ .export = nx_sha512_export,
+ .import = nx_sha512_import,
+ .descsize = sizeof(struct sha512_state),
+ .statesize = sizeof(struct sha512_state),
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "sha512-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_sha_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
new file mode 100644
index 0000000..d7f179c
--- /dev/null
+++ b/drivers/crypto/nx/nx.c
@@ -0,0 +1,716 @@
+/**
+ * Routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/hash.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <asm/pSeries_reconfig.h>
+#include <asm/abs_addr.h>
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+/**
+ * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure
+ *
+ * @nx_ctx: the crypto context handle
+ * @op: PFO operation struct to pass in
+ * @may_sleep: flag indicating the request can sleep
+ *
+ * Make the hcall, retrying while the hardware is busy. If we cannot yield
+ * the thread, limit the number of retries to 10 here.
+ */
+int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
+ struct vio_pfo_op *op,
+ u32 may_sleep)
+{
+ int rc, retries = 10;
+ struct vio_dev *viodev = nx_driver.viodev;
+
+ atomic_inc(&(nx_ctx->stats->sync_ops));
+
+ do {
+ rc = vio_h_cop_sync(viodev, op);
+ } while ((rc == -EBUSY && !may_sleep && retries--) ||
+ (rc == -EBUSY && may_sleep && cond_resched()));
+
+ if (rc) {
+ dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
+ "hcall rc: %ld\n", rc, op->hcall_err);
+ atomic_inc(&(nx_ctx->stats->errors));
+ atomic_set(&(nx_ctx->stats->last_error), op->hcall_err);
+ atomic_set(&(nx_ctx->stats->last_error_pid), current->pid);
+ }
+
+ return rc;
+}
+
+/**
+ * nx_build_sg_list - build an NX scatter list describing a single buffer
+ *
+ * @sg_head: pointer to the first scatter list element to build
+ * @start_addr: pointer to the linear buffer
+ * @len: length of the data at @start_addr
+ * @sgmax: the largest number of scatter list elements we're allowed to create
+ *
+ * This function will start writing nx_sg elements at @sg_head and keep
+ * writing them until all of the data from @start_addr is described or
+ * until sgmax elements have been written. Scatter list elements will be
+ * created such that none of the elements describes a buffer that crosses a 4K
+ * boundary.
+ */
+struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
+ u8 *start_addr,
+ unsigned int len,
+ u32 sgmax)
+{
+ unsigned int sg_len = 0;
+ struct nx_sg *sg;
+ u64 sg_addr = (u64)start_addr;
+ u64 end_addr;
+
+ /* determine the start and end for this address range - slightly
+ * different if this is in VMALLOC_REGION */
+ if (is_vmalloc_addr(start_addr))
+ sg_addr = phys_to_abs(page_to_phys(vmalloc_to_page(start_addr)))
+ + offset_in_page(sg_addr);
+ else
+ sg_addr = virt_to_abs(sg_addr);
+
+ end_addr = sg_addr + len;
+
+ /* each iteration will write one struct nx_sg element and add the
+ * length of data described by that element to sg_len. Once @len bytes
+ * have been described (or @sgmax elements have been written), the
+ * loop ends. min_t is used to ensure @end_addr falls on the same page
+ * as sg_addr, if not, we need to create another nx_sg element for the
+ * data on the next page */
+ for (sg = sg_head; sg_len < len; sg++) {
+ sg->addr = sg_addr;
+ sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
+ sg->len = sg_addr - sg->addr;
+ sg_len += sg->len;
+
+ if ((sg - sg_head) == sgmax) {
+ pr_err("nx: scatter/gather list overflow, pid: %d\n",
+ current->pid);
+ return NULL;
+ }
+ }
+
+ /* return the moved sg_head pointer */
+ return sg;
+}
+
+/**
+ * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist
+ *
+ * @nx_dst: pointer to the first nx_sg element to write
+ * @sglen: max number of nx_sg entries we're allowed to write
+ * @sg_src: pointer to the source linux scatterlist to walk
+ * @start: number of bytes to fast-forward past at the beginning of @sg_src
+ * @src_len: number of bytes to walk in @sg_src
+ */
+struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst,
+ unsigned int sglen,
+ struct scatterlist *sg_src,
+ unsigned int start,
+ unsigned int src_len)
+{
+ struct scatter_walk walk;
+ struct nx_sg *nx_sg = nx_dst;
+ unsigned int n, offset = 0, len = src_len;
+ char *dst;
+
+ /* we need to fast forward through @start bytes first */
+ for (;;) {
+ scatterwalk_start(&walk, sg_src);
+
+ if (start < offset + sg_src->length)
+ break;
+
+ offset += sg_src->length;
+ sg_src = scatterwalk_sg_next(sg_src);
+ }
+
+ /* start - offset is the number of bytes to advance in the scatterlist
+ * element we're currently looking at */
+ scatterwalk_advance(&walk, start - offset);
+
+ while (len && nx_sg) {
+ n = scatterwalk_clamp(&walk, len);
+ if (!n) {
+ scatterwalk_start(&walk, sg_next(walk.sg));
+ n = scatterwalk_clamp(&walk, len);
+ }
+ dst = scatterwalk_map(&walk);
+
+ nx_sg = nx_build_sg_list(nx_sg, dst, n, sglen);
+ len -= n;
+
+ scatterwalk_unmap(dst);
+ scatterwalk_advance(&walk, n);
+ scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len);
+ }
+
+ /* return the moved destination pointer */
+ return nx_sg;
+}
+
+/**
+ * nx_build_sg_lists - walk the input scatterlists and build arrays of NX
+ * scatterlists based on them.
+ *
+ * @nx_ctx: NX crypto context for the lists we're building
+ * @desc: the block cipher descriptor for the operation
+ * @dst: destination scatterlist
+ * @src: source scatterlist
+ * @nbytes: length of data described in the scatterlists
+ * @iv: destination for the iv data, if the algorithm requires it
+ *
+ * This is common code shared by all the AES algorithms. It uses the block
+ * cipher walk routines to traverse input and output scatterlists, building
+ * corresponding NX scatterlists
+ */
+int nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx,
+ struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ u8 *iv)
+{
+ struct nx_sg *nx_insg = nx_ctx->in_sg;
+ struct nx_sg *nx_outsg = nx_ctx->out_sg;
+ struct blkcipher_walk walk;
+ int rc;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+ if (rc)
+ goto out;
+
+ if (iv)
+ memcpy(iv, walk.iv, AES_BLOCK_SIZE);
+
+ while (walk.nbytes) {
+ nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+
+ rc = blkcipher_walk_done(desc, &walk, 0);
+ if (rc)
+ break;
+ }
+
+ if (walk.nbytes) {
+ nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+
+ rc = 0;
+ }
+
+ /* these lengths should be negative, which will indicate to phyp that
+ * the input and output parameters are scatterlists, not linear
+ * buffers */
+ nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg);
+out:
+ return rc;
+}
+
+/**
+ * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct
+ *
+ * @nx_ctx: the nx context to initialize
+ * @function: the function code for the op
+ */
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
+{
+ memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
+ nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;
+
+ nx_ctx->op.flags = function;
+ nx_ctx->op.csbcpb = virt_to_abs(nx_ctx->csbcpb);
+ nx_ctx->op.in = virt_to_abs(nx_ctx->in_sg);
+ nx_ctx->op.out = virt_to_abs(nx_ctx->out_sg);
+
+ if (nx_ctx->csbcpb_aead) {
+ nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT;
+
+ nx_ctx->op_aead.flags = function;
+ nx_ctx->op_aead.csbcpb = virt_to_abs(nx_ctx->csbcpb_aead);
+ nx_ctx->op_aead.in = virt_to_abs(nx_ctx->in_sg);
+ nx_ctx->op_aead.out = virt_to_abs(nx_ctx->out_sg);
+ }
+}
+
+static void nx_of_update_status(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ if (!strncmp(p->value, "okay", p->length)) {
+ props->status = NX_WAITING;
+ props->flags |= NX_OF_FLAG_STATUS_SET;
+ } else {
+ dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__,
+ (char *)p->value);
+ }
+}
+
+static void nx_of_update_sglen(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ if (p->length != sizeof(props->max_sg_len)) {
+ dev_err(dev, "%s: unexpected format for "
+ "ibm,max-sg-len property\n", __func__);
+ dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes "
+ "long, expected %zd bytes\n", __func__,
+ p->length, sizeof(props->max_sg_len));
+ return;
+ }
+
+ props->max_sg_len = *(u32 *)p->value;
+ props->flags |= NX_OF_FLAG_MAXSGLEN_SET;
+}
+
+static void nx_of_update_msc(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ struct msc_triplet *trip;
+ struct max_sync_cop *msc;
+ unsigned int bytes_so_far, i, lenp;
+
+ msc = (struct max_sync_cop *)p->value;
+ lenp = p->length;
+
+ /* You can't tell if the data read in for this property is sane by its
+ * size alone. This is because there are sizes embedded in the data
+ * structure. The best we can do is check lengths as we parse and bail
+ * as soon as a length error is detected. */
+ bytes_so_far = 0;
+
+ while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) {
+ bytes_so_far += sizeof(struct max_sync_cop);
+
+ trip = msc->trip;
+
+ for (i = 0;
+ ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
+ i < msc->triplets;
+ i++) {
+ if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+ dev_err(dev, "unknown function code/mode "
+ "combo: %d/%d (ignored)\n", msc->fc,
+ msc->mode);
+ goto next_loop;
+ }
+
+ switch (trip->keybitlen) {
+ case 128:
+ case 160:
+ props->ap[msc->fc][msc->mode][0].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][0].sglen =
+ trip->sglen;
+ break;
+ case 192:
+ props->ap[msc->fc][msc->mode][1].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][1].sglen =
+ trip->sglen;
+ break;
+ case 256:
+ if (msc->fc == NX_FC_AES) {
+ props->ap[msc->fc][msc->mode][2].
+ databytelen = trip->databytelen;
+ props->ap[msc->fc][msc->mode][2].sglen =
+ trip->sglen;
+ } else if (msc->fc == NX_FC_AES_HMAC ||
+ msc->fc == NX_FC_SHA) {
+ props->ap[msc->fc][msc->mode][1].
+ databytelen = trip->databytelen;
+ props->ap[msc->fc][msc->mode][1].sglen =
+ trip->sglen;
+ } else {
+ dev_warn(dev, "unknown function "
+ "code/key bit len combo"
+ ": (%u/256)\n", msc->fc);
+ }
+ break;
+ case 512:
+ props->ap[msc->fc][msc->mode][2].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][2].sglen =
+ trip->sglen;
+ break;
+ default:
+ dev_warn(dev, "unknown function code/key bit "
+ "len combo: (%u/%u)\n", msc->fc,
+ trip->keybitlen);
+ break;
+ }
+next_loop:
+ bytes_so_far += sizeof(struct msc_triplet);
+ trip++;
+ }
+
+ msc = (struct max_sync_cop *)trip;
+ }
+
+ props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET;
+}
+
+/**
+ * nx_of_init - read openFirmware values from the device tree
+ *
+ * @dev: device handle
+ * @props: pointer to struct to hold the properties values
+ *
+ * Called once at driver probe time, this function will read out the
+ * openFirmware properties we use at runtime. If all the OF properties are
+ * acceptable, when we exit this function props->flags will indicate that
+ * we're ready to register our crypto algorithms.
+ */
+static void nx_of_init(struct device *dev, struct nx_of *props)
+{
+ struct device_node *base_node = dev->of_node;
+ struct property *p;
+
+ p = of_find_property(base_node, "status", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'status' not found\n", __func__);
+ else
+ nx_of_update_status(dev, p, props);
+
+ p = of_find_property(base_node, "ibm,max-sg-len", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n",
+ __func__);
+ else
+ nx_of_update_sglen(dev, p, props);
+
+ p = of_find_property(base_node, "ibm,max-sync-cop", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n",
+ __func__);
+ else
+ nx_of_update_msc(dev, p, props);
+}
+
+/**
+ * nx_register_algs - register algorithms with the crypto API
+ *
+ * Called from nx_probe()
+ *
+ * If all OF properties are in an acceptable state, the driver flags will
+ * indicate that we're ready and we'll create our debugfs files and register
+ * out crypto algorithms.
+ */
+static int nx_register_algs(void)
+{
+ int rc = -1;
+
+ if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY)
+ goto out;
+
+ memset(&nx_driver.stats, 0, sizeof(struct nx_stats));
+
+ rc = NX_DEBUGFS_INIT(&nx_driver);
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&nx_ecb_aes_alg);
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&nx_cbc_aes_alg);
+ if (rc)
+ goto out_unreg_ecb;
+
+ rc = crypto_register_alg(&nx_ctr_aes_alg);
+ if (rc)
+ goto out_unreg_cbc;
+
+ rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+ if (rc)
+ goto out_unreg_ctr;
+
+ rc = crypto_register_alg(&nx_gcm_aes_alg);
+ if (rc)
+ goto out_unreg_ctr3686;
+
+ rc = crypto_register_alg(&nx_gcm4106_aes_alg);
+ if (rc)
+ goto out_unreg_gcm;
+
+ rc = crypto_register_alg(&nx_ccm_aes_alg);
+ if (rc)
+ goto out_unreg_gcm4106;
+
+ rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+ if (rc)
+ goto out_unreg_ccm;
+
+ rc = crypto_register_shash(&nx_shash_sha256_alg);
+ if (rc)
+ goto out_unreg_ccm4309;
+
+ rc = crypto_register_shash(&nx_shash_sha512_alg);
+ if (rc)
+ goto out_unreg_s256;
+
+ rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+ if (rc)
+ goto out_unreg_s512;
+
+ nx_driver.of.status = NX_OKAY;
+
+ goto out;
+
+out_unreg_s512:
+ crypto_unregister_shash(&nx_shash_sha512_alg);
+out_unreg_s256:
+ crypto_unregister_shash(&nx_shash_sha256_alg);
+out_unreg_ccm4309:
+ crypto_unregister_alg(&nx_ccm4309_aes_alg);
+out_unreg_ccm:
+ crypto_unregister_alg(&nx_ccm_aes_alg);
+out_unreg_gcm4106:
+ crypto_unregister_alg(&nx_gcm4106_aes_alg);
+out_unreg_gcm:
+ crypto_unregister_alg(&nx_gcm_aes_alg);
+out_unreg_ctr3686:
+ crypto_unregister_alg(&nx_ctr3686_aes_alg);
+out_unreg_ctr:
+ crypto_unregister_alg(&nx_ctr_aes_alg);
+out_unreg_cbc:
+ crypto_unregister_alg(&nx_cbc_aes_alg);
+out_unreg_ecb:
+ crypto_unregister_alg(&nx_ecb_aes_alg);
+out:
+ return rc;
+}
+
+/**
+ * nx_crypto_ctx_init - create and initialize a crypto api context
+ *
+ * @nx_ctx: the crypto api context
+ * @fc: function code for the context
+ * @mode: the function code specific mode for this context
+ */
+static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode)
+{
+ if (nx_driver.of.status != NX_OKAY) {
+ pr_err("Attempt to initialize NX crypto context while device "
+ "is not available!\n");
+ return -ENODEV;
+ }
+
+ /* we need an extra page for csbcpb_aead for these modes */
+ if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+ nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) +
+ sizeof(struct nx_csbcpb);
+ else
+ nx_ctx->kmem_len = (3 * NX_PAGE_SIZE) +
+ sizeof(struct nx_csbcpb);
+
+ nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL);
+ if (!nx_ctx->kmem)
+ return -ENOMEM;
+
+ /* the csbcpb and scatterlists must be 4K aligned pages */
+ nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem,
+ (u64)NX_PAGE_SIZE));
+ nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE);
+ nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE);
+
+ if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+ nx_ctx->csbcpb_aead =
+ (struct nx_csbcpb *)((u8 *)nx_ctx->out_sg +
+ NX_PAGE_SIZE);
+
+ /* give each context a pointer to global stats and their OF
+ * properties */
+ nx_ctx->stats = &nx_driver.stats;
+ memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode],
+ sizeof(struct alg_props) * 3);
+
+ return 0;
+}
+
+/* entry points from the crypto tfm initializers */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CCM);
+}
+
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_GCM);
+}
+
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CTR);
+}
+
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CBC);
+}
+
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_ECB);
+}
+
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA);
+}
+
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_XCBC_MAC);
+}
+
+/**
+ * nx_crypto_ctx_exit - destroy a crypto api context
+ *
+ * @tfm: the crypto transform pointer for the context
+ *
+ * As crypto API contexts are destroyed, this exit hook is called to free the
+ * memory associated with it.
+ */
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+ kzfree(nx_ctx->kmem);
+ nx_ctx->csbcpb = NULL;
+ nx_ctx->csbcpb_aead = NULL;
+ nx_ctx->in_sg = NULL;
+ nx_ctx->out_sg = NULL;
+}
+
+static int __devinit nx_probe(struct vio_dev *viodev,
+ const struct vio_device_id *id)
+{
+ dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
+ viodev->name, viodev->resource_id);
+
+ if (nx_driver.viodev) {
+ dev_err(&viodev->dev, "%s: Attempt to register more than one "
+ "instance of the hardware\n", __func__);
+ return -EINVAL;
+ }
+
+ nx_driver.viodev = viodev;
+
+ nx_of_init(&viodev->dev, &nx_driver.of);
+
+ return nx_register_algs();
+}
+
+static int __devexit nx_remove(struct vio_dev *viodev)
+{
+ dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
+ viodev->unit_address);
+
+ if (nx_driver.of.status == NX_OKAY) {
+ NX_DEBUGFS_FINI(&nx_driver);
+
+ crypto_unregister_alg(&nx_ccm_aes_alg);
+ crypto_unregister_alg(&nx_ccm4309_aes_alg);
+ crypto_unregister_alg(&nx_gcm_aes_alg);
+ crypto_unregister_alg(&nx_gcm4106_aes_alg);
+ crypto_unregister_alg(&nx_ctr_aes_alg);
+ crypto_unregister_alg(&nx_ctr3686_aes_alg);
+ crypto_unregister_alg(&nx_cbc_aes_alg);
+ crypto_unregister_alg(&nx_ecb_aes_alg);
+ crypto_unregister_shash(&nx_shash_sha256_alg);
+ crypto_unregister_shash(&nx_shash_sha512_alg);
+ crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+ }
+
+ return 0;
+}
+
+
+/* module wide initialization/cleanup */
+static int __init nx_init(void)
+{
+ return vio_register_driver(&nx_driver.viodriver);
+}
+
+static void __exit nx_fini(void)
+{
+ vio_unregister_driver(&nx_driver.viodriver);
+}
+
+static struct vio_device_id nx_crypto_driver_ids[] __devinitdata = {
+ { "ibm,sym-encryption-v1", "ibm,sym-encryption" },
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids);
+
+/* driver state structure */
+struct nx_crypto_driver nx_driver = {
+ .viodriver = {
+ .id_table = nx_crypto_driver_ids,
+ .probe = nx_probe,
+ .remove = nx_remove,
+ .name = NX_NAME,
+ },
+};
+
+module_init(nx_init);
+module_exit(nx_fini);
+
+MODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>");
+MODULE_DESCRIPTION(NX_STRING);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(NX_VERSION);
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
new file mode 100644
index 0000000..3232b18
--- /dev/null
+++ b/drivers/crypto/nx/nx.h
@@ -0,0 +1,193 @@
+
+#ifndef __NX_H__
+#define __NX_H__
+
+#define NX_NAME "nx-crypto"
+#define NX_STRING "IBM Power7+ Nest Accelerator Crypto Driver"
+#define NX_VERSION "1.0"
+
+static const char nx_driver_string[] = NX_STRING;
+static const char nx_driver_version[] = NX_VERSION;
+
+/* a scatterlist in the format PHYP is expecting */
+struct nx_sg {
+ u64 addr;
+ u32 rsvd;
+ u32 len;
+} __attribute((packed));
+
+#define NX_PAGE_SIZE (4096)
+#define NX_MAX_SG_ENTRIES (NX_PAGE_SIZE/(sizeof(struct nx_sg)))
+
+enum nx_status {
+ NX_DISABLED,
+ NX_WAITING,
+ NX_OKAY
+};
+
+/* msc_triplet and max_sync_cop are used only to assist in parsing the
+ * openFirmware property */
+struct msc_triplet {
+ u32 keybitlen;
+ u32 databytelen;
+ u32 sglen;
+} __packed;
+
+struct max_sync_cop {
+ u32 fc;
+ u32 mode;
+ u32 triplets;
+ struct msc_triplet trip[0];
+} __packed;
+
+struct alg_props {
+ u32 databytelen;
+ u32 sglen;
+};
+
+#define NX_OF_FLAG_MAXSGLEN_SET (1)
+#define NX_OF_FLAG_STATUS_SET (2)
+#define NX_OF_FLAG_MAXSYNCCOP_SET (4)
+#define NX_OF_FLAG_MASK_READY (NX_OF_FLAG_MAXSGLEN_SET | \
+ NX_OF_FLAG_STATUS_SET | \
+ NX_OF_FLAG_MAXSYNCCOP_SET)
+struct nx_of {
+ u32 flags;
+ u32 max_sg_len;
+ enum nx_status status;
+ struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3];
+};
+
+struct nx_stats {
+ atomic_t aes_ops;
+ atomic64_t aes_bytes;
+ atomic_t sha256_ops;
+ atomic64_t sha256_bytes;
+ atomic_t sha512_ops;
+ atomic64_t sha512_bytes;
+
+ atomic_t sync_ops;
+
+ atomic_t errors;
+ atomic_t last_error;
+ atomic_t last_error_pid;
+};
+
+struct nx_debugfs {
+ struct dentry *dfs_root;
+ struct dentry *dfs_aes_ops, *dfs_aes_bytes;
+ struct dentry *dfs_sha256_ops, *dfs_sha256_bytes;
+ struct dentry *dfs_sha512_ops, *dfs_sha512_bytes;
+ struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid;
+};
+
+struct nx_crypto_driver {
+ struct nx_stats stats;
+ struct nx_of of;
+ struct vio_dev *viodev;
+ struct vio_driver viodriver;
+ struct nx_debugfs dfs;
+};
+
+#define NX_GCM4106_NONCE_LEN (4)
+#define NX_GCM_CTR_OFFSET (12)
+struct nx_gcm_priv {
+ u8 iv[16];
+ u8 iauth_tag[16];
+ u8 nonce[NX_GCM4106_NONCE_LEN];
+};
+
+#define NX_CCM_AES_KEY_LEN (16)
+#define NX_CCM4309_AES_KEY_LEN (19)
+#define NX_CCM4309_NONCE_LEN (3)
+struct nx_ccm_priv {
+ u8 iv[16];
+ u8 b0[16];
+ u8 iauth_tag[16];
+ u8 oauth_tag[16];
+ u8 nonce[NX_CCM4309_NONCE_LEN];
+};
+
+struct nx_xcbc_priv {
+ u8 key[16];
+};
+
+struct nx_ctr_priv {
+ u8 iv[16];
+};
+
+struct nx_crypto_ctx {
+ void *kmem; /* unaligned, kmalloc'd buffer */
+ size_t kmem_len; /* length of kmem */
+ struct nx_csbcpb *csbcpb; /* aligned page given to phyp @ hcall time */
+ struct vio_pfo_op op; /* operation struct with hcall parameters */
+ struct nx_csbcpb *csbcpb_aead; /* secondary csbcpb used by AEAD algs */
+ struct vio_pfo_op op_aead;/* operation struct for csbcpb_aead */
+
+ struct nx_sg *in_sg; /* aligned pointer into kmem to an sg list */
+ struct nx_sg *out_sg; /* aligned pointer into kmem to an sg list */
+
+ struct alg_props *ap; /* pointer into props based on our key size */
+ struct alg_props props[3];/* openFirmware properties for requests */
+ struct nx_stats *stats; /* pointer into an nx_crypto_driver for stats
+ reporting */
+
+ union {
+ struct nx_gcm_priv gcm;
+ struct nx_ccm_priv ccm;
+ struct nx_xcbc_priv xcbc;
+ struct nx_ctr_priv ctr;
+ } priv;
+};
+
+/* prototypes */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function);
+int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
+ u32 may_sleep);
+struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int, u32);
+int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
+ struct scatterlist *, struct scatterlist *, unsigned int,
+ u8 *);
+struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
+ struct scatterlist *, unsigned int,
+ unsigned int);
+
+#ifdef CONFIG_DEBUG_FS
+#define NX_DEBUGFS_INIT(drv) nx_debugfs_init(drv)
+#define NX_DEBUGFS_FINI(drv) nx_debugfs_fini(drv)
+
+int nx_debugfs_init(struct nx_crypto_driver *);
+void nx_debugfs_fini(struct nx_crypto_driver *);
+#else
+#define NX_DEBUGFS_INIT(drv) (0)
+#define NX_DEBUGFS_FINI(drv) (0)
+#endif
+
+#define NX_PAGE_NUM(x) ((u64)(x) & 0xfffffffffffff000ULL)
+
+extern struct crypto_alg nx_cbc_aes_alg;
+extern struct crypto_alg nx_ecb_aes_alg;
+extern struct crypto_alg nx_gcm_aes_alg;
+extern struct crypto_alg nx_gcm4106_aes_alg;
+extern struct crypto_alg nx_ctr_aes_alg;
+extern struct crypto_alg nx_ctr3686_aes_alg;
+extern struct crypto_alg nx_ccm_aes_alg;
+extern struct crypto_alg nx_ccm4309_aes_alg;
+extern struct shash_alg nx_shash_aes_xcbc_alg;
+extern struct shash_alg nx_shash_sha512_alg;
+extern struct shash_alg nx_shash_sha256_alg;
+
+extern struct nx_crypto_driver nx_driver;
+
+#define SCATTERWALK_TO_SG 1
+#define SCATTERWALK_FROM_SG 0
+
+#endif
diff --git a/drivers/crypto/nx/nx_csbcpb.h b/drivers/crypto/nx/nx_csbcpb.h
new file mode 100644
index 0000000..a304f956
--- /dev/null
+++ b/drivers/crypto/nx/nx_csbcpb.h
@@ -0,0 +1,205 @@
+
+#ifndef __NX_CSBCPB_H__
+#define __NX_CSBCPB_H__
+
+struct cop_symcpb_aes_ecb {
+ u8 key[32];
+ u8 __rsvd[80];
+} __packed;
+
+struct cop_symcpb_aes_cbc {
+ u8 iv[16];
+ u8 key[32];
+ u8 cv[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gca {
+ u8 in_pat[16];
+ u8 key[32];
+ u8 out_pat[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gcm {
+ u8 in_pat_or_aad[16];
+ u8 iv_or_cnt[16];
+ u64 bit_length_aad;
+ u64 bit_length_data;
+ u8 in_s0[16];
+ u8 key[32];
+ u8 __rsvd1[16];
+ u8 out_pat_or_mac[16];
+ u8 out_s0[16];
+ u8 out_cnt[16];
+ u32 spbc;
+ u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_ctr {
+ u8 iv[16];
+ u8 key[32];
+ u8 cv[16];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_aes_cca {
+ u8 b0[16];
+ u8 b1[16];
+ u8 key[16];
+ u8 out_pat_or_b0[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_ccm {
+ u8 in_pat_or_b0[16];
+ u8 iv_or_ctr[16];
+ u8 in_s0[16];
+ u8 key[16];
+ u8 __rsvd1[48];
+ u8 out_pat_or_mac[16];
+ u8 out_s0[16];
+ u8 out_ctr[16];
+ u32 spbc;
+ u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_xcbc {
+ u8 cv[16];
+ u8 key[16];
+ u8 __rsvd1[16];
+ u8 out_cv_mac[16];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha256 {
+ u64 message_bit_length;
+ u64 __rsvd1;
+ u8 input_partial_digest[32];
+ u8 message_digest[32];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha512 {
+ u64 message_bit_length_hi;
+ u64 message_bit_length_lo;
+ u8 input_partial_digest[64];
+ u8 __rsvd1[32];
+ u8 message_digest[64];
+ u32 spbc;
+ u8 __rsvd2[76];
+} __packed;
+
+#define NX_FDM_INTERMEDIATE 0x01
+#define NX_FDM_CONTINUATION 0x02
+#define NX_FDM_ENDE_ENCRYPT 0x80
+
+#define NX_CPB_FDM(c) ((c)->cpb.hdr.fdm)
+#define NX_CPB_KS_DS(c) ((c)->cpb.hdr.ks_ds)
+
+#define NX_CPB_KEY_SIZE(c) (NX_CPB_KS_DS(c) >> 4)
+#define NX_CPB_SET_KEY_SIZE(c, x) NX_CPB_KS_DS(c) |= ((x) << 4)
+#define NX_CPB_SET_DIGEST_SIZE(c, x) NX_CPB_KS_DS(c) |= (x)
+
+struct cop_symcpb_header {
+ u8 mode;
+ u8 fdm;
+ u8 ks_ds;
+ u8 pad_byte;
+ u8 __rsvd[12];
+} __packed;
+
+struct cop_parameter_block {
+ struct cop_symcpb_header hdr;
+ union {
+ struct cop_symcpb_aes_ecb aes_ecb;
+ struct cop_symcpb_aes_cbc aes_cbc;
+ struct cop_symcpb_aes_gca aes_gca;
+ struct cop_symcpb_aes_gcm aes_gcm;
+ struct cop_symcpb_aes_cca aes_cca;
+ struct cop_symcpb_aes_ccm aes_ccm;
+ struct cop_symcpb_aes_ctr aes_ctr;
+ struct cop_symcpb_aes_xcbc aes_xcbc;
+ struct cop_symcpb_sha256 sha256;
+ struct cop_symcpb_sha512 sha512;
+ };
+} __packed;
+
+#define NX_CSB_VALID_BIT 0x80
+
+/* co-processor status block */
+struct cop_status_block {
+ u8 valid;
+ u8 crb_seq_number;
+ u8 completion_code;
+ u8 completion_extension;
+ u32 processed_byte_count;
+ u64 address;
+} __packed;
+
+/* Nest accelerator workbook section 4.4 */
+struct nx_csbcpb {
+ unsigned char __rsvd[112];
+ struct cop_status_block csb;
+ struct cop_parameter_block cpb;
+} __packed;
+
+/* nx_csbcpb related definitions */
+#define NX_MODE_AES_ECB 0
+#define NX_MODE_AES_CBC 1
+#define NX_MODE_AES_GMAC 2
+#define NX_MODE_AES_GCA 3
+#define NX_MODE_AES_GCM 4
+#define NX_MODE_AES_CCA 5
+#define NX_MODE_AES_CCM 6
+#define NX_MODE_AES_CTR 7
+#define NX_MODE_AES_XCBC_MAC 20
+#define NX_MODE_SHA 0
+#define NX_MODE_SHA_HMAC 1
+#define NX_MODE_AES_CBC_HMAC_ETA 8
+#define NX_MODE_AES_CBC_HMAC_ATE 9
+#define NX_MODE_AES_CBC_HMAC_EAA 10
+#define NX_MODE_AES_CTR_HMAC_ETA 12
+#define NX_MODE_AES_CTR_HMAC_ATE 13
+#define NX_MODE_AES_CTR_HMAC_EAA 14
+
+#define NX_FDM_CI_FULL 0
+#define NX_FDM_CI_FIRST 1
+#define NX_FDM_CI_LAST 2
+#define NX_FDM_CI_MIDDLE 3
+
+#define NX_FDM_PR_NONE 0
+#define NX_FDM_PR_PAD 1
+
+#define NX_KS_AES_128 1
+#define NX_KS_AES_192 2
+#define NX_KS_AES_256 3
+
+#define NX_DS_SHA256 2
+#define NX_DS_SHA512 3
+
+#define NX_FC_AES 0
+#define NX_FC_SHA 2
+#define NX_FC_AES_HMAC 6
+
+#define NX_MAX_FC (NX_FC_AES_HMAC + 1)
+#define NX_MAX_MODE (NX_MODE_AES_XCBC_MAC + 1)
+
+#define HCOP_FC_AES NX_FC_AES
+#define HCOP_FC_SHA NX_FC_SHA
+#define HCOP_FC_AES_HMAC NX_FC_AES_HMAC
+
+/* indices into the array of algorithm properties */
+#define NX_PROPS_AES_128 0
+#define NX_PROPS_AES_192 1
+#define NX_PROPS_AES_256 2
+#define NX_PROPS_SHA256 1
+#define NX_PROPS_SHA512 2
+
+#endif
diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c
new file mode 100644
index 0000000..7ab2e8d
--- /dev/null
+++ b/drivers/crypto/nx/nx_debugfs.c
@@ -0,0 +1,103 @@
+/**
+ * debugfs routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * debugfs
+ *
+ * For documentation on these attributes, please see:
+ *
+ * Documentation/ABI/testing/debugfs-pfo-nx-crypto
+ */
+
+int nx_debugfs_init(struct nx_crypto_driver *drv)
+{
+ struct nx_debugfs *dfs = &drv->dfs;
+
+ dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL);
+
+ dfs->dfs_aes_ops =
+ debugfs_create_u32("aes_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root, (u32 *)&drv->stats.aes_ops);
+ dfs->dfs_sha256_ops =
+ debugfs_create_u32("sha256_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.sha256_ops);
+ dfs->dfs_sha512_ops =
+ debugfs_create_u32("sha512_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.sha512_ops);
+ dfs->dfs_aes_bytes =
+ debugfs_create_u64("aes_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.aes_bytes);
+ dfs->dfs_sha256_bytes =
+ debugfs_create_u64("sha256_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.sha256_bytes);
+ dfs->dfs_sha512_bytes =
+ debugfs_create_u64("sha512_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.sha512_bytes);
+ dfs->dfs_errors =
+ debugfs_create_u32("errors",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root, (u32 *)&drv->stats.errors);
+ dfs->dfs_last_error =
+ debugfs_create_u32("last_error",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.last_error);
+ dfs->dfs_last_error_pid =
+ debugfs_create_u32("last_error_pid",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.last_error_pid);
+ return 0;
+}
+
+void
+nx_debugfs_fini(struct nx_crypto_driver *drv)
+{
+ debugfs_remove_recursive(drv->dfs.dfs_root);
+}
+
+#endif
diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig
new file mode 100644
index 0000000..b35e5c4
--- /dev/null
+++ b/drivers/crypto/ux500/Kconfig
@@ -0,0 +1,30 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+config CRYPTO_DEV_UX500_CRYP
+ tristate "UX500 crypto driver for CRYP block"
+ depends on CRYPTO_DEV_UX500
+ select CRYPTO_DES
+ help
+ This selects the crypto driver for the UX500_CRYP hardware. It supports
+ AES-ECB, CBC and CTR with keys sizes of 128, 192 and 256 bit sizes.
+
+config CRYPTO_DEV_UX500_HASH
+ tristate "UX500 crypto driver for HASH block"
+ depends on CRYPTO_DEV_UX500
+ select CRYPTO_HASH
+ select CRYPTO_HMAC
+ help
+ This selects the hash driver for the UX500_HASH hardware.
+ Depends on UX500/STM DMA if running in DMA mode.
+
+config CRYPTO_DEV_UX500_DEBUG
+ bool "Activate ux500 platform debug-mode for crypto and hash block"
+ depends on CRYPTO_DEV_UX500_CRYP || CRYPTO_DEV_UX500_HASH
+ default n
+ help
+ Say Y if you want to add debug prints to ux500_hash and
+ ux500_cryp devices.
diff --git a/drivers/crypto/ux500/Makefile b/drivers/crypto/ux500/Makefile
new file mode 100644
index 0000000..b9a365b
--- /dev/null
+++ b/drivers/crypto/ux500/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += hash/
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += cryp/
diff --git a/drivers/crypto/ux500/cryp/Makefile b/drivers/crypto/ux500/cryp/Makefile
new file mode 100644
index 0000000..e5d362a
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/Makefile
@@ -0,0 +1,13 @@
+#/*
+# * Copyright (C) ST-Ericsson SA 2010
+# * Author: shujuan.chen@stericsson.com for ST-Ericsson.
+# * License terms: GNU General Public License (GPL) version 2 */
+
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_cryp_core.o := -DDEBUG -O0
+CFLAGS_cryp.o := -DDEBUG -O0
+CFLAGS_cryp_irq.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += ux500_cryp.o
+ux500_cryp-objs := cryp.o cryp_irq.o cryp_core.o
diff --git a/drivers/crypto/ux500/cryp/cryp.c b/drivers/crypto/ux500/cryp/cryp.c
new file mode 100644
index 0000000..e208cea
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.c
@@ -0,0 +1,389 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+/**
+ * cryp_wait_until_done - wait until the device logic is not busy
+ */
+void cryp_wait_until_done(struct cryp_device_data *device_data)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+}
+
+/**
+ * cryp_check - This routine checks Peripheral and PCell Id
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_check(struct cryp_device_data *device_data)
+{
+ int peripheralid2 = 0;
+
+ if (NULL == device_data)
+ return -EINVAL;
+
+ peripheralid2 = readl_relaxed(&device_data->base->periphId2);
+
+ if (peripheralid2 != CRYP_PERIPHERAL_ID2_DB8500)
+ return -EPERM;
+
+ /* Check Peripheral and Pcell Id Register for CRYP */
+ if ((CRYP_PERIPHERAL_ID0 ==
+ readl_relaxed(&device_data->base->periphId0))
+ && (CRYP_PERIPHERAL_ID1 ==
+ readl_relaxed(&device_data->base->periphId1))
+ && (CRYP_PERIPHERAL_ID3 ==
+ readl_relaxed(&device_data->base->periphId3))
+ && (CRYP_PCELL_ID0 ==
+ readl_relaxed(&device_data->base->pcellId0))
+ && (CRYP_PCELL_ID1 ==
+ readl_relaxed(&device_data->base->pcellId1))
+ && (CRYP_PCELL_ID2 ==
+ readl_relaxed(&device_data->base->pcellId2))
+ && (CRYP_PCELL_ID3 ==
+ readl_relaxed(&device_data->base->pcellId3))) {
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+/**
+ * cryp_activity - This routine enables/disable the cryptography function.
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_crypen: Enable/Disable functionality
+ */
+void cryp_activity(struct cryp_device_data *device_data,
+ enum cryp_crypen cryp_crypen)
+{
+ CRYP_PUT_BITS(&device_data->base->cr,
+ cryp_crypen,
+ CRYP_CR_CRYPEN_POS,
+ CRYP_CR_CRYPEN_MASK);
+}
+
+/**
+ * cryp_flush_inoutfifo - Resets both the input and the output FIFOs
+ * @device_data: Pointer to the device data struct for base address.
+ */
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data)
+{
+ /*
+ * We always need to disble the hardware before trying to flush the
+ * FIFO. This is something that isn't written in the design
+ * specification, but we have been informed by the hardware designers
+ * that this must be done.
+ */
+ cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+ cryp_wait_until_done(device_data);
+
+ CRYP_SET_BITS(&device_data->base->cr, CRYP_CR_FFLUSH_MASK);
+ /*
+ * CRYP_SR_INFIFO_READY_MASK is the expected value on the status
+ * register when starting a new calculation, which means Input FIFO is
+ * not full and input FIFO is empty.
+ */
+ while (readl_relaxed(&device_data->base->sr) !=
+ CRYP_SR_INFIFO_READY_MASK)
+ cpu_relax();
+}
+
+/**
+ * cryp_set_configuration - This routine set the cr CRYP IP
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_config: Pointer to the configuration parameter
+ * @control_register: The control register to be written later on.
+ */
+int cryp_set_configuration(struct cryp_device_data *device_data,
+ struct cryp_config *cryp_config,
+ u32 *control_register)
+{
+ u32 cr_for_kse;
+
+ if (NULL == device_data || NULL == cryp_config)
+ return -EINVAL;
+
+ *control_register |= (cryp_config->keysize << CRYP_CR_KEYSIZE_POS);
+
+ /* Prepare key for decryption in AES_ECB and AES_CBC mode. */
+ if ((CRYP_ALGORITHM_DECRYPT == cryp_config->algodir) &&
+ ((CRYP_ALGO_AES_ECB == cryp_config->algomode) ||
+ (CRYP_ALGO_AES_CBC == cryp_config->algomode))) {
+ cr_for_kse = *control_register;
+ /*
+ * This seems a bit odd, but it is indeed needed to set this to
+ * encrypt even though it is a decryption that we are doing. It
+ * also mentioned in the design spec that you need to do this.
+ * After the keyprepartion for decrypting is done you should set
+ * algodir back to decryption, which is done outside this if
+ * statement.
+ *
+ * According to design specification we should set mode ECB
+ * during key preparation even though we might be running CBC
+ * when enter this function.
+ *
+ * Writing to KSE_ENABLED will drop CRYPEN when key preparation
+ * is done. Therefore we need to set CRYPEN again outside this
+ * if statement when running decryption.
+ */
+ cr_for_kse |= ((CRYP_ALGORITHM_ENCRYPT << CRYP_CR_ALGODIR_POS) |
+ (CRYP_ALGO_AES_ECB << CRYP_CR_ALGOMODE_POS) |
+ (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS) |
+ (KSE_ENABLED << CRYP_CR_KSE_POS));
+
+ writel_relaxed(cr_for_kse, &device_data->base->cr);
+ cryp_wait_until_done(device_data);
+ }
+
+ *control_register |=
+ ((cryp_config->algomode << CRYP_CR_ALGOMODE_POS) |
+ (cryp_config->algodir << CRYP_CR_ALGODIR_POS));
+
+ return 0;
+}
+
+/**
+ * cryp_configure_protection - set the protection bits in the CRYP logic.
+ * @device_data: Pointer to the device data struct for base address.
+ * @p_protect_config: Pointer to the protection mode and
+ * secure mode configuration
+ */
+int cryp_configure_protection(struct cryp_device_data *device_data,
+ struct cryp_protection_config *p_protect_config)
+{
+ if (NULL == p_protect_config)
+ return -EINVAL;
+
+ CRYP_WRITE_BIT(&device_data->base->cr,
+ (u32) p_protect_config->secure_access,
+ CRYP_CR_SECURE_MASK);
+ CRYP_PUT_BITS(&device_data->base->cr,
+ p_protect_config->privilege_access,
+ CRYP_CR_PRLG_POS,
+ CRYP_CR_PRLG_MASK);
+
+ return 0;
+}
+
+/**
+ * cryp_is_logic_busy - returns the busy status of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_is_logic_busy(struct cryp_device_data *device_data)
+{
+ return CRYP_TEST_BITS(&device_data->base->sr,
+ CRYP_SR_BUSY_MASK);
+}
+
+/**
+ * cryp_configure_for_dma - configures the CRYP IP for DMA operation
+ * @device_data: Pointer to the device data struct for base address.
+ * @dma_req: Specifies the DMA request type value.
+ */
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+ enum cryp_dma_req_type dma_req)
+{
+ CRYP_SET_BITS(&device_data->base->dmacr,
+ (u32) dma_req);
+}
+
+/**
+ * cryp_configure_key_values - configures the key values for CRYP operations
+ * @device_data: Pointer to the device data struct for base address.
+ * @key_reg_index: Key value index register
+ * @key_value: The key value struct
+ */
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+ enum cryp_key_reg_index key_reg_index,
+ struct cryp_key_value key_value)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+
+ switch (key_reg_index) {
+ case CRYP_KEY_REG_1:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_1_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_1_r);
+ break;
+ case CRYP_KEY_REG_2:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_2_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_2_r);
+ break;
+ case CRYP_KEY_REG_3:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_3_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_3_r);
+ break;
+ case CRYP_KEY_REG_4:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_4_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_4_r);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cryp_configure_init_vector - configures the initialization vector register
+ * @device_data: Pointer to the device data struct for base address.
+ * @init_vector_index: Specifies the index of the init vector.
+ * @init_vector_value: Specifies the value for the init vector.
+ */
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+ enum cryp_init_vector_index
+ init_vector_index,
+ struct cryp_init_vector_value
+ init_vector_value)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+
+ switch (init_vector_index) {
+ case CRYP_INIT_VECTOR_INDEX_0:
+ writel_relaxed(init_vector_value.init_value_left,
+ &device_data->base->init_vect_0_l);
+ writel_relaxed(init_vector_value.init_value_right,
+ &device_data->base->init_vect_0_r);
+ break;
+ case CRYP_INIT_VECTOR_INDEX_1:
+ writel_relaxed(init_vector_value.init_value_left,
+ &device_data->base->init_vect_1_l);
+ writel_relaxed(init_vector_value.init_value_right,
+ &device_data->base->init_vect_1_r);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cryp_save_device_context - Store hardware registers and
+ * other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx,
+ int cryp_mode)
+{
+ enum cryp_algo_mode algomode;
+ struct cryp_register *src_reg = device_data->base;
+ struct cryp_config *config =
+ (struct cryp_config *)device_data->current_ctx;
+
+ /*
+ * Always start by disable the hardware and wait for it to finish the
+ * ongoing calculations before trying to reprogram it.
+ */
+ cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+ cryp_wait_until_done(device_data);
+
+ if (cryp_mode == CRYP_MODE_DMA)
+ cryp_configure_for_dma(device_data, CRYP_DMA_DISABLE_BOTH);
+
+ if (CRYP_TEST_BITS(&src_reg->sr, CRYP_SR_IFEM_MASK) == 0)
+ ctx->din = readl_relaxed(&src_reg->din);
+
+ ctx->cr = readl_relaxed(&src_reg->cr) & CRYP_CR_CONTEXT_SAVE_MASK;
+
+ switch (config->keysize) {
+ case CRYP_KEY_SIZE_256:
+ ctx->key_4_l = readl_relaxed(&src_reg->key_4_l);
+ ctx->key_4_r = readl_relaxed(&src_reg->key_4_r);
+
+ case CRYP_KEY_SIZE_192:
+ ctx->key_3_l = readl_relaxed(&src_reg->key_3_l);
+ ctx->key_3_r = readl_relaxed(&src_reg->key_3_r);
+
+ case CRYP_KEY_SIZE_128:
+ ctx->key_2_l = readl_relaxed(&src_reg->key_2_l);
+ ctx->key_2_r = readl_relaxed(&src_reg->key_2_r);
+
+ default:
+ ctx->key_1_l = readl_relaxed(&src_reg->key_1_l);
+ ctx->key_1_r = readl_relaxed(&src_reg->key_1_r);
+ }
+
+ /* Save IV for CBC mode for both AES and DES. */
+ algomode = ((ctx->cr & CRYP_CR_ALGOMODE_MASK) >> CRYP_CR_ALGOMODE_POS);
+ if (algomode == CRYP_ALGO_TDES_CBC ||
+ algomode == CRYP_ALGO_DES_CBC ||
+ algomode == CRYP_ALGO_AES_CBC) {
+ ctx->init_vect_0_l = readl_relaxed(&src_reg->init_vect_0_l);
+ ctx->init_vect_0_r = readl_relaxed(&src_reg->init_vect_0_r);
+ ctx->init_vect_1_l = readl_relaxed(&src_reg->init_vect_1_l);
+ ctx->init_vect_1_r = readl_relaxed(&src_reg->init_vect_1_r);
+ }
+}
+
+/**
+ * cryp_restore_device_context - Restore hardware registers and
+ * other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx)
+{
+ struct cryp_register *reg = device_data->base;
+ struct cryp_config *config =
+ (struct cryp_config *)device_data->current_ctx;
+
+ /*
+ * Fall through for all items in switch statement. DES is captured in
+ * the default.
+ */
+ switch (config->keysize) {
+ case CRYP_KEY_SIZE_256:
+ writel_relaxed(ctx->key_4_l, &reg->key_4_l);
+ writel_relaxed(ctx->key_4_r, &reg->key_4_r);
+
+ case CRYP_KEY_SIZE_192:
+ writel_relaxed(ctx->key_3_l, &reg->key_3_l);
+ writel_relaxed(ctx->key_3_r, &reg->key_3_r);
+
+ case CRYP_KEY_SIZE_128:
+ writel_relaxed(ctx->key_2_l, &reg->key_2_l);
+ writel_relaxed(ctx->key_2_r, &reg->key_2_r);
+
+ default:
+ writel_relaxed(ctx->key_1_l, &reg->key_1_l);
+ writel_relaxed(ctx->key_1_r, &reg->key_1_r);
+ }
+
+ /* Restore IV for CBC mode for AES and DES. */
+ if (config->algomode == CRYP_ALGO_TDES_CBC ||
+ config->algomode == CRYP_ALGO_DES_CBC ||
+ config->algomode == CRYP_ALGO_AES_CBC) {
+ writel_relaxed(ctx->init_vect_0_l, &reg->init_vect_0_l);
+ writel_relaxed(ctx->init_vect_0_r, &reg->init_vect_0_r);
+ writel_relaxed(ctx->init_vect_1_l, &reg->init_vect_1_l);
+ writel_relaxed(ctx->init_vect_1_r, &reg->init_vect_1_r);
+ }
+}
diff --git a/drivers/crypto/ux500/cryp/cryp.h b/drivers/crypto/ux500/cryp/cryp.h
new file mode 100644
index 0000000..14cfd05
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.h
@@ -0,0 +1,308 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_H_
+#define _CRYP_H_
+
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+
+#define DEV_DBG_NAME "crypX crypX:"
+
+/* CRYP enable/disable */
+enum cryp_crypen {
+ CRYP_CRYPEN_DISABLE = 0,
+ CRYP_CRYPEN_ENABLE = 1
+};
+
+/* CRYP Start Computation enable/disable */
+enum cryp_start {
+ CRYP_START_DISABLE = 0,
+ CRYP_START_ENABLE = 1
+};
+
+/* CRYP Init Signal enable/disable */
+enum cryp_init {
+ CRYP_INIT_DISABLE = 0,
+ CRYP_INIT_ENABLE = 1
+};
+
+/* Cryp State enable/disable */
+enum cryp_state {
+ CRYP_STATE_DISABLE = 0,
+ CRYP_STATE_ENABLE = 1
+};
+
+/* Key preparation bit enable */
+enum cryp_key_prep {
+ KSE_DISABLED = 0,
+ KSE_ENABLED = 1
+};
+
+/* Key size for AES */
+#define CRYP_KEY_SIZE_128 (0)
+#define CRYP_KEY_SIZE_192 (1)
+#define CRYP_KEY_SIZE_256 (2)
+
+/* AES modes */
+enum cryp_algo_mode {
+ CRYP_ALGO_TDES_ECB,
+ CRYP_ALGO_TDES_CBC,
+ CRYP_ALGO_DES_ECB,
+ CRYP_ALGO_DES_CBC,
+ CRYP_ALGO_AES_ECB,
+ CRYP_ALGO_AES_CBC,
+ CRYP_ALGO_AES_CTR,
+ CRYP_ALGO_AES_XTS
+};
+
+/* Cryp Encryption or Decryption */
+enum cryp_algorithm_dir {
+ CRYP_ALGORITHM_ENCRYPT,
+ CRYP_ALGORITHM_DECRYPT
+};
+
+/* Hardware access method */
+enum cryp_mode {
+ CRYP_MODE_POLLING,
+ CRYP_MODE_INTERRUPT,
+ CRYP_MODE_DMA
+};
+
+/**
+ * struct cryp_config -
+ * @keysize: Key size for AES
+ * @algomode: AES modes
+ * @algodir: Cryp Encryption or Decryption
+ *
+ * CRYP configuration structure to be passed to set configuration
+ */
+struct cryp_config {
+ int keysize;
+ enum cryp_algo_mode algomode;
+ enum cryp_algorithm_dir algodir;
+};
+
+/**
+ * struct cryp_protection_config -
+ * @privilege_access: Privileged cryp state enable/disable
+ * @secure_access: Secure cryp state enable/disable
+ *
+ * Protection configuration structure for setting privilage access
+ */
+struct cryp_protection_config {
+ enum cryp_state privilege_access;
+ enum cryp_state secure_access;
+};
+
+/* Cryp status */
+enum cryp_status_id {
+ CRYP_STATUS_BUSY = 0x10,
+ CRYP_STATUS_OUTPUT_FIFO_FULL = 0x08,
+ CRYP_STATUS_OUTPUT_FIFO_NOT_EMPTY = 0x04,
+ CRYP_STATUS_INPUT_FIFO_NOT_FULL = 0x02,
+ CRYP_STATUS_INPUT_FIFO_EMPTY = 0x01
+};
+
+/* Cryp DMA interface */
+enum cryp_dma_req_type {
+ CRYP_DMA_DISABLE_BOTH,
+ CRYP_DMA_ENABLE_IN_DATA,
+ CRYP_DMA_ENABLE_OUT_DATA,
+ CRYP_DMA_ENABLE_BOTH_DIRECTIONS
+};
+
+enum cryp_dma_channel {
+ CRYP_DMA_RX = 0,
+ CRYP_DMA_TX
+};
+
+/* Key registers */
+enum cryp_key_reg_index {
+ CRYP_KEY_REG_1,
+ CRYP_KEY_REG_2,
+ CRYP_KEY_REG_3,
+ CRYP_KEY_REG_4
+};
+
+/* Key register left and right */
+struct cryp_key_value {
+ u32 key_value_left;
+ u32 key_value_right;
+};
+
+/* Cryp Initialization structure */
+enum cryp_init_vector_index {
+ CRYP_INIT_VECTOR_INDEX_0,
+ CRYP_INIT_VECTOR_INDEX_1
+};
+
+/* struct cryp_init_vector_value -
+ * @init_value_left
+ * @init_value_right
+ * */
+struct cryp_init_vector_value {
+ u32 init_value_left;
+ u32 init_value_right;
+};
+
+/**
+ * struct cryp_device_context - structure for a cryp context.
+ * @cr: control register
+ * @dmacr: DMA control register
+ * @imsc: Interrupt mask set/clear register
+ * @key_1_l: Key 1l register
+ * @key_1_r: Key 1r register
+ * @key_2_l: Key 2l register
+ * @key_2_r: Key 2r register
+ * @key_3_l: Key 3l register
+ * @key_3_r: Key 3r register
+ * @key_4_l: Key 4l register
+ * @key_4_r: Key 4r register
+ * @init_vect_0_l: Initialization vector 0l register
+ * @init_vect_0_r: Initialization vector 0r register
+ * @init_vect_1_l: Initialization vector 1l register
+ * @init_vect_1_r: Initialization vector 0r register
+ * @din: Data in register
+ * @dout: Data out register
+ *
+ * CRYP power management specifc structure.
+ */
+struct cryp_device_context {
+ u32 cr;
+ u32 dmacr;
+ u32 imsc;
+
+ u32 key_1_l;
+ u32 key_1_r;
+ u32 key_2_l;
+ u32 key_2_r;
+ u32 key_3_l;
+ u32 key_3_r;
+ u32 key_4_l;
+ u32 key_4_r;
+
+ u32 init_vect_0_l;
+ u32 init_vect_0_r;
+ u32 init_vect_1_l;
+ u32 init_vect_1_r;
+
+ u32 din;
+ u32 dout;
+};
+
+struct cryp_dma {
+ dma_cap_mask_t mask;
+ struct completion cryp_dma_complete;
+ struct dma_chan *chan_cryp2mem;
+ struct dma_chan *chan_mem2cryp;
+ struct stedma40_chan_cfg *cfg_cryp2mem;
+ struct stedma40_chan_cfg *cfg_mem2cryp;
+ int sg_src_len;
+ int sg_dst_len;
+ struct scatterlist *sg_src;
+ struct scatterlist *sg_dst;
+ int nents_src;
+ int nents_dst;
+};
+
+/**
+ * struct cryp_device_data - structure for a cryp device.
+ * @base: Pointer to the hardware base address.
+ * @dev: Pointer to the devices dev structure.
+ * @clk: Pointer to the device's clock control.
+ * @pwr_regulator: Pointer to the device's power control.
+ * @power_status: Current status of the power.
+ * @ctx_lock: Lock for current_ctx.
+ * @current_ctx: Pointer to the currently allocated context.
+ * @list_node: For inclusion into a klist.
+ * @dma: The dma structure holding channel configuration.
+ * @power_state: TRUE = power state on, FALSE = power state off.
+ * @power_state_spinlock: Spinlock for power_state.
+ * @restore_dev_ctx: TRUE = saved ctx, FALSE = no saved ctx.
+ */
+struct cryp_device_data {
+ struct cryp_register __iomem *base;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *pwr_regulator;
+ int power_status;
+ struct spinlock ctx_lock;
+ struct cryp_ctx *current_ctx;
+ struct klist_node list_node;
+ struct cryp_dma dma;
+ bool power_state;
+ struct spinlock power_state_spinlock;
+ bool restore_dev_ctx;
+};
+
+void cryp_wait_until_done(struct cryp_device_data *device_data);
+
+/* Initialization functions */
+
+int cryp_check(struct cryp_device_data *device_data);
+
+void cryp_activity(struct cryp_device_data *device_data,
+ enum cryp_crypen cryp_crypen);
+
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data);
+
+int cryp_set_configuration(struct cryp_device_data *device_data,
+ struct cryp_config *cryp_config,
+ u32 *control_register);
+
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+ enum cryp_dma_req_type dma_req);
+
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+ enum cryp_key_reg_index key_reg_index,
+ struct cryp_key_value key_value);
+
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+ enum cryp_init_vector_index
+ init_vector_index,
+ struct cryp_init_vector_value
+ init_vector_value);
+
+int cryp_configure_protection(struct cryp_device_data *device_data,
+ struct cryp_protection_config *p_protect_config);
+
+/* Power management funtions */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx,
+ int cryp_mode);
+
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx);
+
+/* Data transfer and status bits. */
+int cryp_is_logic_busy(struct cryp_device_data *device_data);
+
+int cryp_get_status(struct cryp_device_data *device_data);
+
+/**
+ * cryp_write_indata - This routine writes 32 bit data into the data input
+ * register of the cryptography IP.
+ * @device_data: Pointer to the device data struct for base address.
+ * @write_data: Data to write.
+ */
+int cryp_write_indata(struct cryp_device_data *device_data, u32 write_data);
+
+/**
+ * cryp_read_outdata - This routine reads the data from the data output
+ * register of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ * @read_data: Read the data from the output FIFO.
+ */
+int cryp_read_outdata(struct cryp_device_data *device_data, u32 *read_data);
+
+#endif /* _CRYP_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
new file mode 100644
index 0000000..7cac127
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -0,0 +1,1784 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/crypto.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/klist.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+#include <crypto/scatterwalk.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+#define CRYP_MAX_KEY_SIZE 32
+#define BYTES_PER_WORD 4
+
+static int cryp_mode;
+static atomic_t session_id;
+
+static struct stedma40_chan_cfg *mem_to_engine;
+static struct stedma40_chan_cfg *engine_to_mem;
+
+/**
+ * struct cryp_driver_data - data specific to the driver.
+ *
+ * @device_list: A list of registered devices to choose from.
+ * @device_allocation: A semaphore initialized with number of devices.
+ */
+struct cryp_driver_data {
+ struct klist device_list;
+ struct semaphore device_allocation;
+};
+
+/**
+ * struct cryp_ctx - Crypto context
+ * @config: Crypto mode.
+ * @key[CRYP_MAX_KEY_SIZE]: Key.
+ * @keylen: Length of key.
+ * @iv: Pointer to initialization vector.
+ * @indata: Pointer to indata.
+ * @outdata: Pointer to outdata.
+ * @datalen: Length of indata.
+ * @outlen: Length of outdata.
+ * @blocksize: Size of blocks.
+ * @updated: Updated flag.
+ * @dev_ctx: Device dependent context.
+ * @device: Pointer to the device.
+ */
+struct cryp_ctx {
+ struct cryp_config config;
+ u8 key[CRYP_MAX_KEY_SIZE];
+ u32 keylen;
+ u8 *iv;
+ const u8 *indata;
+ u8 *outdata;
+ u32 datalen;
+ u32 outlen;
+ u32 blocksize;
+ u8 updated;
+ struct cryp_device_context dev_ctx;
+ struct cryp_device_data *device;
+ u32 session_id;
+};
+
+static struct cryp_driver_data driver_data;
+
+/**
+ * uint8p_to_uint32_be - 4*uint8 to uint32 big endian
+ * @in: Data to convert.
+ */
+static inline u32 uint8p_to_uint32_be(u8 *in)
+{
+ u32 *data = (u32 *)in;
+
+ return cpu_to_be32p(data);
+}
+
+/**
+ * swap_bits_in_byte - mirror the bits in a byte
+ * @b: the byte to be mirrored
+ *
+ * The bits are swapped the following way:
+ * Byte b include bits 0-7, nibble 1 (n1) include bits 0-3 and
+ * nibble 2 (n2) bits 4-7.
+ *
+ * Nibble 1 (n1):
+ * (The "old" (moved) bit is replaced with a zero)
+ * 1. Move bit 6 and 7, 4 positions to the left.
+ * 2. Move bit 3 and 5, 2 positions to the left.
+ * 3. Move bit 1-4, 1 position to the left.
+ *
+ * Nibble 2 (n2):
+ * 1. Move bit 0 and 1, 4 positions to the right.
+ * 2. Move bit 2 and 4, 2 positions to the right.
+ * 3. Move bit 3-6, 1 position to the right.
+ *
+ * Combine the two nibbles to a complete and swapped byte.
+ */
+
+static inline u8 swap_bits_in_byte(u8 b)
+{
+#define R_SHIFT_4_MASK 0xc0 /* Bits 6 and 7, right shift 4 */
+#define R_SHIFT_2_MASK 0x28 /* (After right shift 4) Bits 3 and 5,
+ right shift 2 */
+#define R_SHIFT_1_MASK 0x1e /* (After right shift 2) Bits 1-4,
+ right shift 1 */
+#define L_SHIFT_4_MASK 0x03 /* Bits 0 and 1, left shift 4 */
+#define L_SHIFT_2_MASK 0x14 /* (After left shift 4) Bits 2 and 4,
+ left shift 2 */
+#define L_SHIFT_1_MASK 0x78 /* (After left shift 1) Bits 3-6,
+ left shift 1 */
+
+ u8 n1;
+ u8 n2;
+
+ /* Swap most significant nibble */
+ /* Right shift 4, bits 6 and 7 */
+ n1 = ((b & R_SHIFT_4_MASK) >> 4) | (b & ~(R_SHIFT_4_MASK >> 4));
+ /* Right shift 2, bits 3 and 5 */
+ n1 = ((n1 & R_SHIFT_2_MASK) >> 2) | (n1 & ~(R_SHIFT_2_MASK >> 2));
+ /* Right shift 1, bits 1-4 */
+ n1 = (n1 & R_SHIFT_1_MASK) >> 1;
+
+ /* Swap least significant nibble */
+ /* Left shift 4, bits 0 and 1 */
+ n2 = ((b & L_SHIFT_4_MASK) << 4) | (b & ~(L_SHIFT_4_MASK << 4));
+ /* Left shift 2, bits 2 and 4 */
+ n2 = ((n2 & L_SHIFT_2_MASK) << 2) | (n2 & ~(L_SHIFT_2_MASK << 2));
+ /* Left shift 1, bits 3-6 */
+ n2 = (n2 & L_SHIFT_1_MASK) << 1;
+
+ return n1 | n2;
+}
+
+static inline void swap_words_in_key_and_bits_in_byte(const u8 *in,
+ u8 *out, u32 len)
+{
+ unsigned int i = 0;
+ int j;
+ int index = 0;
+
+ j = len - BYTES_PER_WORD;
+ while (j >= 0) {
+ for (i = 0; i < BYTES_PER_WORD; i++) {
+ index = len - j - BYTES_PER_WORD + i;
+ out[j + i] =
+ swap_bits_in_byte(in[index]);
+ }
+ j -= BYTES_PER_WORD;
+ }
+}
+
+static void add_session_id(struct cryp_ctx *ctx)
+{
+ /*
+ * We never want 0 to be a valid value, since this is the default value
+ * for the software context.
+ */
+ if (unlikely(atomic_inc_and_test(&session_id)))
+ atomic_inc(&session_id);
+
+ ctx->session_id = atomic_read(&session_id);
+}
+
+static irqreturn_t cryp_interrupt_handler(int irq, void *param)
+{
+ struct cryp_ctx *ctx;
+ int i;
+ struct cryp_device_data *device_data;
+
+ if (param == NULL) {
+ BUG_ON(!param);
+ return IRQ_HANDLED;
+ }
+
+ /* The device is coming from the one found in hw_crypt_noxts. */
+ device_data = (struct cryp_device_data *)param;
+
+ ctx = device_data->current_ctx;
+
+ if (ctx == NULL) {
+ BUG_ON(!ctx);
+ return IRQ_HANDLED;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s] (len: %d) %s, ", __func__, ctx->outlen,
+ cryp_pending_irq_src(device_data, CRYP_IRQ_SRC_OUTPUT_FIFO) ?
+ "out" : "in");
+
+ if (cryp_pending_irq_src(device_data,
+ CRYP_IRQ_SRC_OUTPUT_FIFO)) {
+ if (ctx->outlen / ctx->blocksize > 0) {
+ for (i = 0; i < ctx->blocksize / 4; i++) {
+ *(ctx->outdata) = readl_relaxed(
+ &device_data->base->dout);
+ ctx->outdata += 4;
+ ctx->outlen -= 4;
+ }
+
+ if (ctx->outlen == 0) {
+ cryp_disable_irq_src(device_data,
+ CRYP_IRQ_SRC_OUTPUT_FIFO);
+ }
+ }
+ } else if (cryp_pending_irq_src(device_data,
+ CRYP_IRQ_SRC_INPUT_FIFO)) {
+ if (ctx->datalen / ctx->blocksize > 0) {
+ for (i = 0 ; i < ctx->blocksize / 4; i++) {
+ writel_relaxed(ctx->indata,
+ &device_data->base->din);
+ ctx->indata += 4;
+ ctx->datalen -= 4;
+ }
+
+ if (ctx->datalen == 0)
+ cryp_disable_irq_src(device_data,
+ CRYP_IRQ_SRC_INPUT_FIFO);
+
+ if (ctx->config.algomode == CRYP_ALGO_AES_XTS) {
+ CRYP_PUT_BITS(&device_data->base->cr,
+ CRYP_START_ENABLE,
+ CRYP_CR_START_POS,
+ CRYP_CR_START_MASK);
+
+ cryp_wait_until_done(device_data);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mode_is_aes(enum cryp_algo_mode mode)
+{
+ return CRYP_ALGO_AES_ECB == mode ||
+ CRYP_ALGO_AES_CBC == mode ||
+ CRYP_ALGO_AES_CTR == mode ||
+ CRYP_ALGO_AES_XTS == mode;
+}
+
+static int cfg_iv(struct cryp_device_data *device_data, u32 left, u32 right,
+ enum cryp_init_vector_index index)
+{
+ struct cryp_init_vector_value vector_value;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ vector_value.init_value_left = left;
+ vector_value.init_value_right = right;
+
+ return cryp_configure_init_vector(device_data,
+ index,
+ vector_value);
+}
+
+static int cfg_ivs(struct cryp_device_data *device_data, struct cryp_ctx *ctx)
+{
+ int i;
+ int status = 0;
+ int num_of_regs = ctx->blocksize / 8;
+ u32 iv[AES_BLOCK_SIZE / 4];
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ /*
+ * Since we loop on num_of_regs we need to have a check in case
+ * someone provides an incorrect blocksize which would force calling
+ * cfg_iv with i greater than 2 which is an error.
+ */
+ if (num_of_regs > 2) {
+ dev_err(device_data->dev, "[%s] Incorrect blocksize %d",
+ __func__, ctx->blocksize);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ctx->blocksize / 4; i++)
+ iv[i] = uint8p_to_uint32_be(ctx->iv + i*4);
+
+ for (i = 0; i < num_of_regs; i++) {
+ status = cfg_iv(device_data, iv[i*2], iv[i*2+1],
+ (enum cryp_init_vector_index) i);
+ if (status != 0)
+ return status;
+ }
+ return status;
+}
+
+static int set_key(struct cryp_device_data *device_data,
+ u32 left_key,
+ u32 right_key,
+ enum cryp_key_reg_index index)
+{
+ struct cryp_key_value key_value;
+ int cryp_error;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ key_value.key_value_left = left_key;
+ key_value.key_value_right = right_key;
+
+ cryp_error = cryp_configure_key_values(device_data,
+ index,
+ key_value);
+ if (cryp_error != 0)
+ dev_err(device_data->dev, "[%s]: "
+ "cryp_configure_key_values() failed!", __func__);
+
+ return cryp_error;
+}
+
+static int cfg_keys(struct cryp_ctx *ctx)
+{
+ int i;
+ int num_of_regs = ctx->keylen / 8;
+ u32 swapped_key[CRYP_MAX_KEY_SIZE / 4];
+ int cryp_error = 0;
+
+ dev_dbg(ctx->device->dev, "[%s]", __func__);
+
+ if (mode_is_aes(ctx->config.algomode)) {
+ swap_words_in_key_and_bits_in_byte((u8 *)ctx->key,
+ (u8 *)swapped_key,
+ ctx->keylen);
+ } else {
+ for (i = 0; i < ctx->keylen / 4; i++)
+ swapped_key[i] = uint8p_to_uint32_be(ctx->key + i*4);
+ }
+
+ for (i = 0; i < num_of_regs; i++) {
+ cryp_error = set_key(ctx->device,
+ *(((u32 *)swapped_key)+i*2),
+ *(((u32 *)swapped_key)+i*2+1),
+ (enum cryp_key_reg_index) i);
+
+ if (cryp_error != 0) {
+ dev_err(ctx->device->dev, "[%s]: set_key() failed!",
+ __func__);
+ return cryp_error;
+ }
+ }
+ return cryp_error;
+}
+
+static int cryp_setup_context(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ u32 control_register = CRYP_CR_DEFAULT;
+
+ switch (cryp_mode) {
+ case CRYP_MODE_INTERRUPT:
+ writel_relaxed(CRYP_IMSC_DEFAULT, &device_data->base->imsc);
+ break;
+
+ case CRYP_MODE_DMA:
+ writel_relaxed(CRYP_DMACR_DEFAULT, &device_data->base->dmacr);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ctx->updated == 0) {
+ cryp_flush_inoutfifo(device_data);
+ if (cfg_keys(ctx) != 0) {
+ dev_err(ctx->device->dev, "[%s]: cfg_keys failed!",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (ctx->iv &&
+ CRYP_ALGO_AES_ECB != ctx->config.algomode &&
+ CRYP_ALGO_DES_ECB != ctx->config.algomode &&
+ CRYP_ALGO_TDES_ECB != ctx->config.algomode) {
+ if (cfg_ivs(device_data, ctx) != 0)
+ return -EPERM;
+ }
+
+ cryp_set_configuration(device_data, &ctx->config,
+ &control_register);
+ add_session_id(ctx);
+ } else if (ctx->updated == 1 &&
+ ctx->session_id != atomic_read(&session_id)) {
+ cryp_flush_inoutfifo(device_data);
+ cryp_restore_device_context(device_data, &ctx->dev_ctx);
+
+ add_session_id(ctx);
+ control_register = ctx->dev_ctx.cr;
+ } else
+ control_register = ctx->dev_ctx.cr;
+
+ writel(control_register |
+ (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS),
+ &device_data->base->cr);
+
+ return 0;
+}
+
+static int cryp_get_device_data(struct cryp_ctx *ctx,
+ struct cryp_device_data **device_data)
+{
+ int ret;
+ struct klist_iter device_iterator;
+ struct klist_node *device_node;
+ struct cryp_device_data *local_device_data = NULL;
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ /* Wait until a device is available */
+ ret = down_interruptible(&driver_data.device_allocation);
+ if (ret)
+ return ret; /* Interrupted */
+
+ /* Select a device */
+ klist_iter_init(&driver_data.device_list, &device_iterator);
+
+ device_node = klist_next(&device_iterator);
+ while (device_node) {
+ local_device_data = container_of(device_node,
+ struct cryp_device_data, list_node);
+ spin_lock(&local_device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (local_device_data->current_ctx) {
+ device_node = klist_next(&device_iterator);
+ } else {
+ local_device_data->current_ctx = ctx;
+ ctx->device = local_device_data;
+ spin_unlock(&local_device_data->ctx_lock);
+ break;
+ }
+ spin_unlock(&local_device_data->ctx_lock);
+ }
+ klist_iter_exit(&device_iterator);
+
+ if (!device_node) {
+ /**
+ * No free device found.
+ * Since we allocated a device with down_interruptible, this
+ * should not be able to happen.
+ * Number of available devices, which are contained in
+ * device_allocation, is therefore decremented by not doing
+ * an up(device_allocation).
+ */
+ return -EBUSY;
+ }
+
+ *device_data = local_device_data;
+
+ return 0;
+}
+
+static void cryp_dma_setup_channel(struct cryp_device_data *device_data,
+ struct device *dev)
+{
+ dma_cap_zero(device_data->dma.mask);
+ dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+ device_data->dma.cfg_mem2cryp = mem_to_engine;
+ device_data->dma.chan_mem2cryp =
+ dma_request_channel(device_data->dma.mask,
+ stedma40_filter,
+ device_data->dma.cfg_mem2cryp);
+
+ device_data->dma.cfg_cryp2mem = engine_to_mem;
+ device_data->dma.chan_cryp2mem =
+ dma_request_channel(device_data->dma.mask,
+ stedma40_filter,
+ device_data->dma.cfg_cryp2mem);
+
+ init_completion(&device_data->dma.cryp_dma_complete);
+}
+
+static void cryp_dma_out_callback(void *data)
+{
+ struct cryp_ctx *ctx = (struct cryp_ctx *) data;
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ complete(&ctx->device->dma.cryp_dma_complete);
+}
+
+static int cryp_set_dma_transfer(struct cryp_ctx *ctx,
+ struct scatterlist *sg,
+ int len,
+ enum dma_data_direction direction)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *channel = NULL;
+ dma_cookie_t cookie;
+
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ if (unlikely(!IS_ALIGNED((u32)sg, 4))) {
+ dev_err(ctx->device->dev, "[%s]: Data in sg list isn't "
+ "aligned! Addr: 0x%08x", __func__, (u32)sg);
+ return -EFAULT;
+ }
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ channel = ctx->device->dma.chan_mem2cryp;
+ ctx->device->dma.sg_src = sg;
+ ctx->device->dma.sg_src_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg_src,
+ ctx->device->dma.nents_src,
+ direction);
+
+ if (!ctx->device->dma.sg_src_len) {
+ dev_dbg(ctx->device->dev,
+ "[%s]: Could not map the sg list (TO_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(TO_DEVICE)", __func__);
+
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg_src,
+ ctx->device->dma.sg_src_len,
+ direction, DMA_CTRL_ACK, NULL);
+ break;
+
+ case DMA_FROM_DEVICE:
+ channel = ctx->device->dma.chan_cryp2mem;
+ ctx->device->dma.sg_dst = sg;
+ ctx->device->dma.sg_dst_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg_dst,
+ ctx->device->dma.nents_dst,
+ direction);
+
+ if (!ctx->device->dma.sg_dst_len) {
+ dev_dbg(ctx->device->dev,
+ "[%s]: Could not map the sg list (FROM_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(FROM_DEVICE)", __func__);
+
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg_dst,
+ ctx->device->dma.sg_dst_len,
+ direction,
+ DMA_CTRL_ACK |
+ DMA_PREP_INTERRUPT, NULL);
+
+ desc->callback = cryp_dma_out_callback;
+ desc->callback_param = ctx;
+ break;
+
+ default:
+ dev_dbg(ctx->device->dev, "[%s]: Invalid DMA direction",
+ __func__);
+ return -EFAULT;
+ }
+
+ cookie = desc->tx_submit(desc);
+ dma_async_issue_pending(channel);
+
+ return 0;
+}
+
+static void cryp_dma_done(struct cryp_ctx *ctx)
+{
+ struct dma_chan *chan;
+
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ chan = ctx->device->dma.chan_mem2cryp;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
+ ctx->device->dma.sg_src_len, DMA_TO_DEVICE);
+
+ chan = ctx->device->dma.chan_cryp2mem;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
+ ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
+}
+
+static int cryp_dma_write(struct cryp_ctx *ctx, struct scatterlist *sg,
+ int len)
+{
+ int error = cryp_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+static int cryp_dma_read(struct cryp_ctx *ctx, struct scatterlist *sg, int len)
+{
+ int error = cryp_set_dma_transfer(ctx, sg, len, DMA_FROM_DEVICE);
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+static void cryp_polling_mode(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ int len = ctx->blocksize / BYTES_PER_WORD;
+ int remaining_length = ctx->datalen;
+ u32 *indata = (u32 *)ctx->indata;
+ u32 *outdata = (u32 *)ctx->outdata;
+
+ while (remaining_length > 0) {
+ writesl(&device_data->base->din, indata, len);
+ indata += len;
+ remaining_length -= (len * BYTES_PER_WORD);
+ cryp_wait_until_done(device_data);
+
+ readsl(&device_data->base->dout, outdata, len);
+ outdata += len;
+ cryp_wait_until_done(device_data);
+ }
+}
+
+static int cryp_disable_power(struct device *dev,
+ struct cryp_device_data *device_data,
+ bool save_device_context)
+{
+ int ret = 0;
+
+ dev_dbg(dev, "[%s]", __func__);
+
+ spin_lock(&device_data->power_state_spinlock);
+ if (!device_data->power_state)
+ goto out;
+
+ spin_lock(&device_data->ctx_lock);
+ if (save_device_context && device_data->current_ctx) {
+ cryp_save_device_context(device_data,
+ &device_data->current_ctx->dev_ctx,
+ cryp_mode);
+ device_data->restore_dev_ctx = true;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ clk_disable(device_data->clk);
+ ret = regulator_disable(device_data->pwr_regulator);
+ if (ret)
+ dev_err(dev, "[%s]: "
+ "regulator_disable() failed!",
+ __func__);
+
+ device_data->power_state = false;
+
+out:
+ spin_unlock(&device_data->power_state_spinlock);
+
+ return ret;
+}
+
+static int cryp_enable_power(
+ struct device *dev,
+ struct cryp_device_data *device_data,
+ bool restore_device_context)
+{
+ int ret = 0;
+
+ dev_dbg(dev, "[%s]", __func__);
+
+ spin_lock(&device_data->power_state_spinlock);
+ if (!device_data->power_state) {
+ ret = regulator_enable(device_data->pwr_regulator);
+ if (ret) {
+ dev_err(dev, "[%s]: regulator_enable() failed!",
+ __func__);
+ goto out;
+ }
+
+ ret = clk_enable(device_data->clk);
+ if (ret) {
+ dev_err(dev, "[%s]: clk_enable() failed!",
+ __func__);
+ regulator_disable(device_data->pwr_regulator);
+ goto out;
+ }
+ device_data->power_state = true;
+ }
+
+ if (device_data->restore_dev_ctx) {
+ spin_lock(&device_data->ctx_lock);
+ if (restore_device_context && device_data->current_ctx) {
+ device_data->restore_dev_ctx = false;
+ cryp_restore_device_context(device_data,
+ &device_data->current_ctx->dev_ctx);
+ }
+ spin_unlock(&device_data->ctx_lock);
+ }
+out:
+ spin_unlock(&device_data->power_state_spinlock);
+
+ return ret;
+}
+
+static int hw_crypt_noxts(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ int ret = 0;
+
+ const u8 *indata = ctx->indata;
+ u8 *outdata = ctx->outdata;
+ u32 datalen = ctx->datalen;
+ u32 outlen = datalen;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->outlen = ctx->datalen;
+
+ if (unlikely(!IS_ALIGNED((u32)indata, 4))) {
+ pr_debug(DEV_DBG_NAME " [%s]: Data isn't aligned! Addr: "
+ "0x%08x", __func__, (u32)indata);
+ return -EINVAL;
+ }
+
+ ret = cryp_setup_context(ctx, device_data);
+
+ if (ret)
+ goto out;
+
+ if (cryp_mode == CRYP_MODE_INTERRUPT) {
+ cryp_enable_irq_src(device_data, CRYP_IRQ_SRC_INPUT_FIFO |
+ CRYP_IRQ_SRC_OUTPUT_FIFO);
+
+ /*
+ * ctx->outlen is decremented in the cryp_interrupt_handler
+ * function. We had to add cpu_relax() (barrier) to make sure
+ * that gcc didn't optimze away this variable.
+ */
+ while (ctx->outlen > 0)
+ cpu_relax();
+ } else if (cryp_mode == CRYP_MODE_POLLING ||
+ cryp_mode == CRYP_MODE_DMA) {
+ /*
+ * The reason for having DMA in this if case is that if we are
+ * running cryp_mode = 2, then we separate DMA routines for
+ * handling cipher/plaintext > blocksize, except when
+ * running the normal CRYPTO_ALG_TYPE_CIPHER, then we still use
+ * the polling mode. Overhead of doing DMA setup eats up the
+ * benefits using it.
+ */
+ cryp_polling_mode(ctx, device_data);
+ } else {
+ dev_err(ctx->device->dev, "[%s]: Invalid operation mode!",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+ ctx->updated = 1;
+
+out:
+ ctx->indata = indata;
+ ctx->outdata = outdata;
+ ctx->datalen = datalen;
+ ctx->outlen = outlen;
+
+ return ret;
+}
+
+static int get_nents(struct scatterlist *sg, int nbytes)
+{
+ int nents = 0;
+
+ while (nbytes > 0) {
+ nbytes -= sg->length;
+ sg = scatterwalk_sg_next(sg);
+ nents++;
+ }
+
+ return nents;
+}
+
+static int ablk_dma_crypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ struct cryp_device_data *device_data;
+
+ int bytes_written = 0;
+ int bytes_read = 0;
+ int ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->datalen = areq->nbytes;
+ ctx->outlen = areq->nbytes;
+
+ ret = cryp_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ ret = cryp_setup_context(ctx, device_data);
+ if (ret)
+ goto out;
+
+ /* We have the device now, so store the nents in the dma struct. */
+ ctx->device->dma.nents_src = get_nents(areq->src, ctx->datalen);
+ ctx->device->dma.nents_dst = get_nents(areq->dst, ctx->outlen);
+
+ /* Enable DMA in- and output. */
+ cryp_configure_for_dma(device_data, CRYP_DMA_ENABLE_BOTH_DIRECTIONS);
+
+ bytes_written = cryp_dma_write(ctx, areq->src, ctx->datalen);
+ bytes_read = cryp_dma_read(ctx, areq->dst, bytes_written);
+
+ wait_for_completion(&ctx->device->dma.cryp_dma_complete);
+ cryp_dma_done(ctx);
+
+ cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+ ctx->updated = 1;
+
+out:
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx = NULL;
+ ctx->device = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+
+ if (unlikely(bytes_written != bytes_read))
+ return -EPERM;
+
+ return 0;
+}
+
+static int ablk_crypt(struct ablkcipher_request *areq)
+{
+ struct ablkcipher_walk walk;
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ struct cryp_device_data *device_data;
+ unsigned long src_paddr;
+ unsigned long dst_paddr;
+ int ret;
+ int nbytes;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ret = cryp_get_device_data(ctx, &device_data);
+ if (ret)
+ goto out;
+
+ ablkcipher_walk_init(&walk, areq->dst, areq->src, areq->nbytes);
+ ret = ablkcipher_walk_phys(areq, &walk);
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME "[%s]: ablkcipher_walk_phys() failed!",
+ __func__);
+ goto out;
+ }
+
+ while ((nbytes = walk.nbytes) > 0) {
+ ctx->iv = walk.iv;
+ src_paddr = (page_to_phys(walk.src.page) + walk.src.offset);
+ ctx->indata = phys_to_virt(src_paddr);
+
+ dst_paddr = (page_to_phys(walk.dst.page) + walk.dst.offset);
+ ctx->outdata = phys_to_virt(dst_paddr);
+
+ ctx->datalen = nbytes - (nbytes % ctx->blocksize);
+
+ ret = hw_crypt_noxts(ctx, device_data);
+ if (ret)
+ goto out;
+
+ nbytes -= ctx->datalen;
+ ret = ablkcipher_walk_done(areq, &walk, nbytes);
+ if (ret)
+ goto out;
+ }
+ ablkcipher_walk_complete(&walk);
+
+out:
+ /* Release the device */
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx = NULL;
+ ctx->device = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+
+ return ret;
+}
+
+static int aes_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ ctx->config.keysize = CRYP_KEY_SIZE_128;
+ break;
+
+ case AES_KEYSIZE_192:
+ ctx->config.keysize = CRYP_KEY_SIZE_192;
+ break;
+
+ case AES_KEYSIZE_256:
+ ctx->config.keysize = CRYP_KEY_SIZE_256;
+ break;
+
+ default:
+ pr_err(DEV_DBG_NAME "[%s]: Unknown keylen!", __func__);
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+
+ return 0;
+}
+
+static int des_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+ u32 tmp[DES_EXPKEY_WORDS];
+ int ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+ if (keylen != DES_KEY_SIZE) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = des_ekey(tmp, key);
+ if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+ __func__);
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+ return 0;
+}
+
+static int des3_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+ const u32 *K = (const u32 *)key;
+ u32 tmp[DES3_EDE_EXPKEY_WORDS];
+ int i, ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+ if (keylen != DES3_EDE_KEY_SIZE) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Checking key interdependency for weak key detection. */
+ if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+ !((K[2] ^ K[4]) | (K[3] ^ K[5]))) &&
+ (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+ __func__);
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++) {
+ ret = des_ekey(tmp, key + i*DES_KEY_SIZE);
+ if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: "
+ "CRYPTO_TFM_REQ_WEAK_KEY", __func__);
+ return -EINVAL;
+ }
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+ return 0;
+}
+
+static int cryp_blk_encrypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->config.algodir = CRYP_ALGORITHM_ENCRYPT;
+
+ /*
+ * DMA does not work for DES due to a hw bug */
+ if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+ return ablk_dma_crypt(areq);
+
+ /* For everything except DMA, we run the non DMA version. */
+ return ablk_crypt(areq);
+}
+
+static int cryp_blk_decrypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->config.algodir = CRYP_ALGORITHM_DECRYPT;
+
+ /* DMA does not work for DES due to a hw bug */
+ if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+ return ablk_dma_crypt(areq);
+
+ /* For everything except DMA, we run the non DMA version. */
+ return ablk_crypt(areq);
+}
+
+struct cryp_algo_template {
+ enum cryp_algo_mode algomode;
+ struct crypto_alg crypto;
+};
+
+static int cryp_cra_init(struct crypto_tfm *tfm)
+{
+ struct cryp_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct cryp_algo_template *cryp_alg = container_of(alg,
+ struct cryp_algo_template,
+ crypto);
+
+ ctx->config.algomode = cryp_alg->algomode;
+ ctx->blocksize = crypto_tfm_alg_blocksize(tfm);
+
+ return 0;
+}
+
+static struct cryp_algo_template cryp_algs[] = {
+ {
+ .algomode = CRYP_ALGO_AES_ECB,
+ .crypto = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_ECB,
+ .crypto = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_CBC,
+ .crypto = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_CTR,
+ .crypto = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_ECB,
+ .crypto = {
+ .cra_name = "des",
+ .cra_driver_name = "des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_ECB,
+ .crypto = {
+ .cra_name = "des3_ede",
+ .cra_driver_name = "des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_ECB,
+ .crypto = {
+ .cra_name = "ecb(des)",
+ .cra_driver_name = "ecb-des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_ECB,
+ .crypto = {
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des3_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_CBC,
+ .crypto = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_CBC,
+ .crypto = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des3_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ }
+ }
+ }
+ }
+};
+
+/**
+ * cryp_algs_register_all -
+ */
+static int cryp_algs_register_all(void)
+{
+ int ret;
+ int i;
+ int count;
+
+ pr_debug("[%s]", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(cryp_algs); i++) {
+ ret = crypto_register_alg(&cryp_algs[i].crypto);
+ if (ret) {
+ count = i;
+ pr_err("[%s] alg registration failed",
+ cryp_algs[i].crypto.cra_driver_name);
+ goto unreg;
+ }
+ }
+ return 0;
+unreg:
+ for (i = 0; i < count; i++)
+ crypto_unregister_alg(&cryp_algs[i].crypto);
+ return ret;
+}
+
+/**
+ * cryp_algs_unregister_all -
+ */
+static void cryp_algs_unregister_all(void)
+{
+ int i;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(cryp_algs); i++)
+ crypto_unregister_alg(&cryp_algs[i].crypto);
+}
+
+static int ux500_cryp_probe(struct platform_device *pdev)
+{
+ int ret;
+ int cryp_error = 0;
+ struct resource *res = NULL;
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+ struct cryp_protection_config prot = {
+ .privilege_access = CRYP_STATE_ENABLE
+ };
+ struct device *dev = &pdev->dev;
+
+ dev_dbg(dev, "[%s]", __func__);
+ device_data = kzalloc(sizeof(struct cryp_device_data), GFP_ATOMIC);
+ if (!device_data) {
+ dev_err(dev, "[%s]: kzalloc() failed!", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ device_data->dev = dev;
+ device_data->current_ctx = NULL;
+
+ /* Grab the DMA configuration from platform data. */
+ mem_to_engine = &((struct cryp_platform_data *)
+ dev->platform_data)->mem_to_engine;
+ engine_to_mem = &((struct cryp_platform_data *)
+ dev->platform_data)->engine_to_mem;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "[%s]: platform_get_resource() failed",
+ __func__);
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ dev_err(dev, "[%s]: request_mem_region() failed",
+ __func__);
+ ret = -EBUSY;
+ goto out_kfree;
+ }
+
+ device_data->base = ioremap(res->start, resource_size(res));
+ if (!device_data->base) {
+ dev_err(dev, "[%s]: ioremap failed!", __func__);
+ ret = -ENOMEM;
+ goto out_free_mem;
+ }
+
+ spin_lock_init(&device_data->ctx_lock);
+ spin_lock_init(&device_data->power_state_spinlock);
+
+ /* Enable power for CRYP hardware block */
+ device_data->pwr_regulator = regulator_get(&pdev->dev, "v-ape");
+ if (IS_ERR(device_data->pwr_regulator)) {
+ dev_err(dev, "[%s]: could not get cryp regulator", __func__);
+ ret = PTR_ERR(device_data->pwr_regulator);
+ device_data->pwr_regulator = NULL;
+ goto out_unmap;
+ }
+
+ /* Enable the clk for CRYP hardware block */
+ device_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(device_data->clk)) {
+ dev_err(dev, "[%s]: clk_get() failed!", __func__);
+ ret = PTR_ERR(device_data->clk);
+ goto out_regulator;
+ }
+
+ /* Enable device power (and clock) */
+ ret = cryp_enable_power(device_data->dev, device_data, false);
+ if (ret) {
+ dev_err(dev, "[%s]: cryp_enable_power() failed!", __func__);
+ goto out_clk;
+ }
+
+ cryp_error = cryp_check(device_data);
+ if (cryp_error != 0) {
+ dev_err(dev, "[%s]: cryp_init() failed!", __func__);
+ ret = -EINVAL;
+ goto out_power;
+ }
+
+ cryp_error = cryp_configure_protection(device_data, &prot);
+ if (cryp_error != 0) {
+ dev_err(dev, "[%s]: cryp_configure_protection() failed!",
+ __func__);
+ ret = -EINVAL;
+ goto out_power;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ dev_err(dev, "[%s]: IORESOURCE_IRQ unavailable",
+ __func__);
+ goto out_power;
+ }
+
+ ret = request_irq(res_irq->start,
+ cryp_interrupt_handler,
+ 0,
+ "cryp1",
+ device_data);
+ if (ret) {
+ dev_err(dev, "[%s]: Unable to request IRQ", __func__);
+ goto out_power;
+ }
+
+ if (cryp_mode == CRYP_MODE_DMA)
+ cryp_dma_setup_channel(device_data, dev);
+
+ platform_set_drvdata(pdev, device_data);
+
+ /* Put the new device into the device list... */
+ klist_add_tail(&device_data->list_node, &driver_data.device_list);
+
+ /* ... and signal that a new device is available. */
+ up(&driver_data.device_allocation);
+
+ atomic_set(&session_id, 1);
+
+ ret = cryp_algs_register_all();
+ if (ret) {
+ dev_err(dev, "[%s]: cryp_algs_register_all() failed!",
+ __func__);
+ goto out_power;
+ }
+
+ return 0;
+
+out_power:
+ cryp_disable_power(device_data->dev, device_data, false);
+
+out_clk:
+ clk_put(device_data->clk);
+
+out_regulator:
+ regulator_put(device_data->pwr_regulator);
+
+out_unmap:
+ iounmap(device_data->base);
+
+out_free_mem:
+ release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+ kfree(device_data);
+out:
+ return ret;
+}
+
+static int ux500_cryp_remove(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Try to decrease the number of available devices. */
+ if (down_trylock(&driver_data.device_allocation))
+ return -EBUSY;
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (device_data->current_ctx) {
+ /* The device is busy */
+ spin_unlock(&device_data->ctx_lock);
+ /* Return the device to the pool. */
+ up(&driver_data.device_allocation);
+ return -EBUSY;
+ }
+
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ cryp_algs_unregister_all();
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else {
+ disable_irq(res_irq->start);
+ free_irq(res_irq->start, device_data);
+ }
+
+ if (cryp_disable_power(&pdev->dev, device_data, false))
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+ __func__);
+
+ clk_put(device_data->clk);
+ regulator_put(device_data->pwr_regulator);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(device_data);
+
+ return 0;
+}
+
+static void ux500_cryp_shutdown(struct platform_device *pdev)
+{
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return;
+ }
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (!device_data->current_ctx) {
+ if (down_trylock(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+ "Shutting down anyway...", __func__);
+ /**
+ * (Allocate the device)
+ * Need to set this to non-null (dummy) value,
+ * to avoid usage if context switching.
+ */
+ device_data->current_ctx++;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ cryp_algs_unregister_all();
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else {
+ disable_irq(res_irq->start);
+ free_irq(res_irq->start, device_data);
+ }
+
+ if (cryp_disable_power(&pdev->dev, device_data, false))
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+ __func__);
+
+}
+
+static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct cryp_device_data *device_data;
+ struct resource *res_irq;
+ struct cryp_ctx *temp_ctx = NULL;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ /* Handle state? */
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else
+ disable_irq(res_irq->start);
+
+ spin_lock(&device_data->ctx_lock);
+ if (!device_data->current_ctx)
+ device_data->current_ctx++;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (device_data->current_ctx == ++temp_ctx) {
+ if (down_interruptible(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+ "failed", __func__);
+ ret = cryp_disable_power(&pdev->dev, device_data, false);
+
+ } else
+ ret = cryp_disable_power(&pdev->dev, device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power()", __func__);
+
+ return ret;
+}
+
+static int ux500_cryp_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct cryp_device_data *device_data;
+ struct resource *res_irq;
+ struct cryp_ctx *temp_ctx = NULL;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (device_data->current_ctx == ++temp_ctx)
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+
+ if (!device_data->current_ctx)
+ up(&driver_data.device_allocation);
+ else
+ ret = cryp_enable_power(&pdev->dev, device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: cryp_enable_power() failed!",
+ __func__);
+ else {
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res_irq)
+ enable_irq(res_irq->start);
+ }
+
+ return ret;
+}
+
+static struct platform_driver cryp_driver = {
+ .probe = ux500_cryp_probe,
+ .remove = ux500_cryp_remove,
+ .shutdown = ux500_cryp_shutdown,
+ .suspend = ux500_cryp_suspend,
+ .resume = ux500_cryp_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cryp1"
+ }
+};
+
+static int __init ux500_cryp_mod_init(void)
+{
+ pr_debug("[%s] is called!", __func__);
+ klist_init(&driver_data.device_list, NULL, NULL);
+ /* Initialize the semaphore to 0 devices (locked state) */
+ sema_init(&driver_data.device_allocation, 0);
+ return platform_driver_register(&cryp_driver);
+}
+
+static void __exit ux500_cryp_mod_fini(void)
+{
+ pr_debug("[%s] is called!", __func__);
+ platform_driver_unregister(&cryp_driver);
+ return;
+}
+
+module_init(ux500_cryp_mod_init);
+module_exit(ux500_cryp_mod_fini);
+
+module_param(cryp_mode, int, 0);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 CRYP crypto engine.");
+MODULE_ALIAS("aes-all");
+MODULE_ALIAS("des-all");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.c b/drivers/crypto/ux500/cryp/cryp_irq.c
new file mode 100644
index 0000000..08d291c
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.c
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/device.h>
+
+#include "cryp.h"
+#include "cryp_p.h"
+#include "cryp_irq.h"
+#include "cryp_irqp.h"
+
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ u32 i;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ i = readl_relaxed(&device_data->base->imsc);
+ i = i | irq_src;
+ writel_relaxed(i, &device_data->base->imsc);
+}
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ u32 i;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ i = readl_relaxed(&device_data->base->imsc);
+ i = i & ~irq_src;
+ writel_relaxed(i, &device_data->base->imsc);
+}
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ return (readl_relaxed(&device_data->base->mis) & irq_src) > 0;
+}
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.h b/drivers/crypto/ux500/cryp/cryp_irq.h
new file mode 100644
index 0000000..5a7837f
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_IRQ_H_
+#define _CRYP_IRQ_H_
+
+#include "cryp.h"
+
+enum cryp_irq_src_id {
+ CRYP_IRQ_SRC_INPUT_FIFO = 0x1,
+ CRYP_IRQ_SRC_OUTPUT_FIFO = 0x2,
+ CRYP_IRQ_SRC_ALL = 0x3
+};
+
+/**
+ * M0 Funtions
+ */
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+#endif /* _CRYP_IRQ_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_irqp.h b/drivers/crypto/ux500/cryp/cryp_irqp.h
new file mode 100644
index 0000000..8b339cc
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irqp.h
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __CRYP_IRQP_H_
+#define __CRYP_IRQP_H_
+
+#include "cryp_irq.h"
+
+/**
+ *
+ * CRYP Registers - Offset mapping
+ * +-----------------+
+ * 00h | CRYP_CR | Configuration register
+ * +-----------------+
+ * 04h | CRYP_SR | Status register
+ * +-----------------+
+ * 08h | CRYP_DIN | Data In register
+ * +-----------------+
+ * 0ch | CRYP_DOUT | Data out register
+ * +-----------------+
+ * 10h | CRYP_DMACR | DMA control register
+ * +-----------------+
+ * 14h | CRYP_IMSC | IMSC
+ * +-----------------+
+ * 18h | CRYP_RIS | Raw interrupt status
+ * +-----------------+
+ * 1ch | CRYP_MIS | Masked interrupt status.
+ * +-----------------+
+ * Key registers
+ * IVR registers
+ * Peripheral
+ * Cell IDs
+ *
+ * Refer data structure for other register map
+ */
+
+/**
+ * struct cryp_register
+ * @cr - Configuration register
+ * @status - Status register
+ * @din - Data input register
+ * @din_size - Data input size register
+ * @dout - Data output register
+ * @dout_size - Data output size register
+ * @dmacr - Dma control register
+ * @imsc - Interrupt mask set/clear register
+ * @ris - Raw interrupt status
+ * @mis - Masked interrupt statu register
+ * @key_1_l - Key register 1 L
+ * @key_1_r - Key register 1 R
+ * @key_2_l - Key register 2 L
+ * @key_2_r - Key register 2 R
+ * @key_3_l - Key register 3 L
+ * @key_3_r - Key register 3 R
+ * @key_4_l - Key register 4 L
+ * @key_4_r - Key register 4 R
+ * @init_vect_0_l - init vector 0 L
+ * @init_vect_0_r - init vector 0 R
+ * @init_vect_1_l - init vector 1 L
+ * @init_vect_1_r - init vector 1 R
+ * @cryp_unused1 - unused registers
+ * @itcr - Integration test control register
+ * @itip - Integration test input register
+ * @itop - Integration test output register
+ * @cryp_unused2 - unused registers
+ * @periphId0 - FE0 CRYP Peripheral Identication Register
+ * @periphId1 - FE4
+ * @periphId2 - FE8
+ * @periphId3 - FEC
+ * @pcellId0 - FF0 CRYP PCell Identication Register
+ * @pcellId1 - FF4
+ * @pcellId2 - FF8
+ * @pcellId3 - FFC
+ */
+struct cryp_register {
+ u32 cr; /* Configuration register */
+ u32 sr; /* Status register */
+ u32 din; /* Data input register */
+ u32 din_size; /* Data input size register */
+ u32 dout; /* Data output register */
+ u32 dout_size; /* Data output size register */
+ u32 dmacr; /* Dma control register */
+ u32 imsc; /* Interrupt mask set/clear register */
+ u32 ris; /* Raw interrupt status */
+ u32 mis; /* Masked interrupt statu register */
+
+ u32 key_1_l; /*Key register 1 L */
+ u32 key_1_r; /*Key register 1 R */
+ u32 key_2_l; /*Key register 2 L */
+ u32 key_2_r; /*Key register 2 R */
+ u32 key_3_l; /*Key register 3 L */
+ u32 key_3_r; /*Key register 3 R */
+ u32 key_4_l; /*Key register 4 L */
+ u32 key_4_r; /*Key register 4 R */
+
+ u32 init_vect_0_l; /*init vector 0 L */
+ u32 init_vect_0_r; /*init vector 0 R */
+ u32 init_vect_1_l; /*init vector 1 L */
+ u32 init_vect_1_r; /*init vector 1 R */
+
+ u32 cryp_unused1[(0x80 - 0x58) / sizeof(u32)]; /* unused registers */
+ u32 itcr; /*Integration test control register */
+ u32 itip; /*Integration test input register */
+ u32 itop; /*Integration test output register */
+ u32 cryp_unused2[(0xFE0 - 0x8C) / sizeof(u32)]; /* unused registers */
+
+ u32 periphId0; /* FE0 CRYP Peripheral Identication Register */
+ u32 periphId1; /* FE4 */
+ u32 periphId2; /* FE8 */
+ u32 periphId3; /* FEC */
+
+ u32 pcellId0; /* FF0 CRYP PCell Identication Register */
+ u32 pcellId1; /* FF4 */
+ u32 pcellId2; /* FF8 */
+ u32 pcellId3; /* FFC */
+};
+
+#endif
diff --git a/drivers/crypto/ux500/cryp/cryp_p.h b/drivers/crypto/ux500/cryp/cryp_p.h
new file mode 100644
index 0000000..6dcffe1
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_p.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_P_H_
+#define _CRYP_P_H_
+
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include "cryp.h"
+#include "cryp_irqp.h"
+
+/**
+ * Generic Macros
+ */
+#define CRYP_SET_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define CRYP_WRITE_BIT(reg_name, val, mask) \
+ writel_relaxed(((readl_relaxed(reg_name) & ~(mask)) |\
+ ((val) & (mask))), reg_name)
+
+#define CRYP_TEST_BITS(reg_name, val) \
+ (readl_relaxed(reg_name) & (val))
+
+#define CRYP_PUT_BITS(reg, val, shift, mask) \
+ writel_relaxed(((readl_relaxed(reg) & ~(mask)) | \
+ (((u32)val << shift) & (mask))), reg)
+
+/**
+ * CRYP specific Macros
+ */
+#define CRYP_PERIPHERAL_ID0 0xE3
+#define CRYP_PERIPHERAL_ID1 0x05
+
+#define CRYP_PERIPHERAL_ID2_DB8500 0x28
+#define CRYP_PERIPHERAL_ID3 0x00
+
+#define CRYP_PCELL_ID0 0x0D
+#define CRYP_PCELL_ID1 0xF0
+#define CRYP_PCELL_ID2 0x05
+#define CRYP_PCELL_ID3 0xB1
+
+/**
+ * CRYP register default values
+ */
+#define MAX_DEVICE_SUPPORT 2
+
+/* Priv set, keyrden set and datatype 8bits swapped set as default. */
+#define CRYP_CR_DEFAULT 0x0482
+#define CRYP_DMACR_DEFAULT 0x0
+#define CRYP_IMSC_DEFAULT 0x0
+#define CRYP_DIN_DEFAULT 0x0
+#define CRYP_DOUT_DEFAULT 0x0
+#define CRYP_KEY_DEFAULT 0x0
+#define CRYP_INIT_VECT_DEFAULT 0x0
+
+/**
+ * CRYP Control register specific mask
+ */
+#define CRYP_CR_SECURE_MASK BIT(0)
+#define CRYP_CR_PRLG_MASK BIT(1)
+#define CRYP_CR_ALGODIR_MASK BIT(2)
+#define CRYP_CR_ALGOMODE_MASK (BIT(5) | BIT(4) | BIT(3))
+#define CRYP_CR_DATATYPE_MASK (BIT(7) | BIT(6))
+#define CRYP_CR_KEYSIZE_MASK (BIT(9) | BIT(8))
+#define CRYP_CR_KEYRDEN_MASK BIT(10)
+#define CRYP_CR_KSE_MASK BIT(11)
+#define CRYP_CR_START_MASK BIT(12)
+#define CRYP_CR_INIT_MASK BIT(13)
+#define CRYP_CR_FFLUSH_MASK BIT(14)
+#define CRYP_CR_CRYPEN_MASK BIT(15)
+#define CRYP_CR_CONTEXT_SAVE_MASK (CRYP_CR_SECURE_MASK |\
+ CRYP_CR_PRLG_MASK |\
+ CRYP_CR_ALGODIR_MASK |\
+ CRYP_CR_ALGOMODE_MASK |\
+ CRYP_CR_DATATYPE_MASK |\
+ CRYP_CR_KEYSIZE_MASK |\
+ CRYP_CR_KEYRDEN_MASK |\
+ CRYP_CR_DATATYPE_MASK)
+
+
+#define CRYP_SR_INFIFO_READY_MASK (BIT(0) | BIT(1))
+#define CRYP_SR_IFEM_MASK BIT(0)
+#define CRYP_SR_BUSY_MASK BIT(4)
+
+/**
+ * Bit position used while setting bits in register
+ */
+#define CRYP_CR_PRLG_POS 1
+#define CRYP_CR_ALGODIR_POS 2
+#define CRYP_CR_ALGOMODE_POS 3
+#define CRYP_CR_DATATYPE_POS 6
+#define CRYP_CR_KEYSIZE_POS 8
+#define CRYP_CR_KEYRDEN_POS 10
+#define CRYP_CR_KSE_POS 11
+#define CRYP_CR_START_POS 12
+#define CRYP_CR_INIT_POS 13
+#define CRYP_CR_CRYPEN_POS 15
+
+#define CRYP_SR_BUSY_POS 4
+
+/**
+ * CRYP PCRs------PC_NAND control register
+ * BIT_MASK
+ */
+#define CRYP_DMA_REQ_MASK (BIT(1) | BIT(0))
+#define CRYP_DMA_REQ_MASK_POS 0
+
+
+struct cryp_system_context {
+ /* CRYP Register structure */
+ struct cryp_register *p_cryp_reg[MAX_DEVICE_SUPPORT];
+};
+
+#endif
diff --git a/drivers/crypto/ux500/hash/Makefile b/drivers/crypto/ux500/hash/Makefile
new file mode 100644
index 0000000..b2f90d9
--- /dev/null
+++ b/drivers/crypto/ux500/hash/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_hash_core.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += ux500_hash.o
+ux500_hash-objs := hash_core.o
diff --git a/drivers/crypto/ux500/hash/hash_alg.h b/drivers/crypto/ux500/hash/hash_alg.h
new file mode 100644
index 0000000..cd9351c
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_alg.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen (shujuan.chen@stericsson.com)
+ * Author: Joakim Bech (joakim.xx.bech@stericsson.com)
+ * Author: Berne Hebark (berne.hebark@stericsson.com))
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _HASH_ALG_H
+#define _HASH_ALG_H
+
+#include <linux/bitops.h>
+
+#define HASH_BLOCK_SIZE 64
+#define HASH_DMA_ALIGN_SIZE 4
+#define HASH_DMA_PERFORMANCE_MIN_SIZE 1024
+#define HASH_BYTES_PER_WORD 4
+
+/* Maximum value of the length's high word */
+#define HASH_HIGH_WORD_MAX_VAL 0xFFFFFFFFUL
+
+/* Power on Reset values HASH registers */
+#define HASH_RESET_CR_VALUE 0x0
+#define HASH_RESET_STR_VALUE 0x0
+
+/* Number of context swap registers */
+#define HASH_CSR_COUNT 52
+
+#define HASH_RESET_CSRX_REG_VALUE 0x0
+#define HASH_RESET_CSFULL_REG_VALUE 0x0
+#define HASH_RESET_CSDATAIN_REG_VALUE 0x0
+
+#define HASH_RESET_INDEX_VAL 0x0
+#define HASH_RESET_BIT_INDEX_VAL 0x0
+#define HASH_RESET_BUFFER_VAL 0x0
+#define HASH_RESET_LEN_HIGH_VAL 0x0
+#define HASH_RESET_LEN_LOW_VAL 0x0
+
+/* Control register bitfields */
+#define HASH_CR_RESUME_MASK 0x11FCF
+
+#define HASH_CR_SWITCHON_POS 31
+#define HASH_CR_SWITCHON_MASK BIT(31)
+
+#define HASH_CR_EMPTYMSG_POS 20
+#define HASH_CR_EMPTYMSG_MASK BIT(20)
+
+#define HASH_CR_DINF_POS 12
+#define HASH_CR_DINF_MASK BIT(12)
+
+#define HASH_CR_NBW_POS 8
+#define HASH_CR_NBW_MASK 0x00000F00UL
+
+#define HASH_CR_LKEY_POS 16
+#define HASH_CR_LKEY_MASK BIT(16)
+
+#define HASH_CR_ALGO_POS 7
+#define HASH_CR_ALGO_MASK BIT(7)
+
+#define HASH_CR_MODE_POS 6
+#define HASH_CR_MODE_MASK BIT(6)
+
+#define HASH_CR_DATAFORM_POS 4
+#define HASH_CR_DATAFORM_MASK (BIT(4) | BIT(5))
+
+#define HASH_CR_DMAE_POS 3
+#define HASH_CR_DMAE_MASK BIT(3)
+
+#define HASH_CR_INIT_POS 2
+#define HASH_CR_INIT_MASK BIT(2)
+
+#define HASH_CR_PRIVN_POS 1
+#define HASH_CR_PRIVN_MASK BIT(1)
+
+#define HASH_CR_SECN_POS 0
+#define HASH_CR_SECN_MASK BIT(0)
+
+/* Start register bitfields */
+#define HASH_STR_DCAL_POS 8
+#define HASH_STR_DCAL_MASK BIT(8)
+#define HASH_STR_DEFAULT 0x0
+
+#define HASH_STR_NBLW_POS 0
+#define HASH_STR_NBLW_MASK 0x0000001FUL
+
+#define HASH_NBLW_MAX_VAL 0x1F
+
+/* PrimeCell IDs */
+#define HASH_P_ID0 0xE0
+#define HASH_P_ID1 0x05
+#define HASH_P_ID2 0x38
+#define HASH_P_ID3 0x00
+#define HASH_CELL_ID0 0x0D
+#define HASH_CELL_ID1 0xF0
+#define HASH_CELL_ID2 0x05
+#define HASH_CELL_ID3 0xB1
+
+#define HASH_SET_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define HASH_CLEAR_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) & ~mask), reg_name)
+
+#define HASH_PUT_BITS(reg, val, shift, mask) \
+ writel_relaxed(((readl(reg) & ~(mask)) | \
+ (((u32)val << shift) & (mask))), reg)
+
+#define HASH_SET_DIN(val, len) writesl(&device_data->base->din, (val), (len))
+
+#define HASH_INITIALIZE \
+ HASH_PUT_BITS( \
+ &device_data->base->cr, \
+ 0x01, HASH_CR_INIT_POS, \
+ HASH_CR_INIT_MASK)
+
+#define HASH_SET_DATA_FORMAT(data_format) \
+ HASH_PUT_BITS( \
+ &device_data->base->cr, \
+ (u32) (data_format), HASH_CR_DATAFORM_POS, \
+ HASH_CR_DATAFORM_MASK)
+#define HASH_SET_NBLW(val) \
+ HASH_PUT_BITS( \
+ &device_data->base->str, \
+ (u32) (val), HASH_STR_NBLW_POS, \
+ HASH_STR_NBLW_MASK)
+#define HASH_SET_DCAL \
+ HASH_PUT_BITS( \
+ &device_data->base->str, \
+ 0x01, HASH_STR_DCAL_POS, \
+ HASH_STR_DCAL_MASK)
+
+/* Hardware access method */
+enum hash_mode {
+ HASH_MODE_CPU,
+ HASH_MODE_DMA
+};
+
+/**
+ * struct uint64 - Structure to handle 64 bits integers.
+ * @high_word: Most significant bits.
+ * @low_word: Least significant bits.
+ *
+ * Used to handle 64 bits integers.
+ */
+struct uint64 {
+ u32 high_word;
+ u32 low_word;
+};
+
+/**
+ * struct hash_register - Contains all registers in ux500 hash hardware.
+ * @cr: HASH control register (0x000).
+ * @din: HASH data input register (0x004).
+ * @str: HASH start register (0x008).
+ * @hx: HASH digest register 0..7 (0x00c-0x01C).
+ * @padding0: Reserved (0x02C).
+ * @itcr: Integration test control register (0x080).
+ * @itip: Integration test input register (0x084).
+ * @itop: Integration test output register (0x088).
+ * @padding1: Reserved (0x08C).
+ * @csfull: HASH context full register (0x0F8).
+ * @csdatain: HASH context swap data input register (0x0FC).
+ * @csrx: HASH context swap register 0..51 (0x100-0x1CC).
+ * @padding2: Reserved (0x1D0).
+ * @periphid0: HASH peripheral identification register 0 (0xFE0).
+ * @periphid1: HASH peripheral identification register 1 (0xFE4).
+ * @periphid2: HASH peripheral identification register 2 (0xFE8).
+ * @periphid3: HASH peripheral identification register 3 (0xFEC).
+ * @cellid0: HASH PCell identification register 0 (0xFF0).
+ * @cellid1: HASH PCell identification register 1 (0xFF4).
+ * @cellid2: HASH PCell identification register 2 (0xFF8).
+ * @cellid3: HASH PCell identification register 3 (0xFFC).
+ *
+ * The device communicates to the HASH via 32-bit-wide control registers
+ * accessible via the 32-bit width AMBA rev. 2.0 AHB Bus. Below is a structure
+ * with the registers used.
+ */
+struct hash_register {
+ u32 cr;
+ u32 din;
+ u32 str;
+ u32 hx[8];
+
+ u32 padding0[(0x080 - 0x02C) / sizeof(u32)];
+
+ u32 itcr;
+ u32 itip;
+ u32 itop;
+
+ u32 padding1[(0x0F8 - 0x08C) / sizeof(u32)];
+
+ u32 csfull;
+ u32 csdatain;
+ u32 csrx[HASH_CSR_COUNT];
+
+ u32 padding2[(0xFE0 - 0x1D0) / sizeof(u32)];
+
+ u32 periphid0;
+ u32 periphid1;
+ u32 periphid2;
+ u32 periphid3;
+
+ u32 cellid0;
+ u32 cellid1;
+ u32 cellid2;
+ u32 cellid3;
+};
+
+/**
+ * struct hash_state - Hash context state.
+ * @temp_cr: Temporary HASH Control Register.
+ * @str_reg: HASH Start Register.
+ * @din_reg: HASH Data Input Register.
+ * @csr[52]: HASH Context Swap Registers 0-39.
+ * @csfull: HASH Context Swap Registers 40 ie Status flags.
+ * @csdatain: HASH Context Swap Registers 41 ie Input data.
+ * @buffer: Working buffer for messages going to the hardware.
+ * @length: Length of the part of message hashed so far (floor(N/64) * 64).
+ * @index: Valid number of bytes in buffer (N % 64).
+ * @bit_index: Valid number of bits in buffer (N % 8).
+ *
+ * This structure is used between context switches, i.e. when ongoing jobs are
+ * interupted with new jobs. When this happens we need to store intermediate
+ * results in software.
+ *
+ * WARNING: "index" is the member of the structure, to be sure that "buffer"
+ * is aligned on a 4-bytes boundary. This is highly implementation dependent
+ * and MUST be checked whenever this code is ported on new platforms.
+ */
+struct hash_state {
+ u32 temp_cr;
+ u32 str_reg;
+ u32 din_reg;
+ u32 csr[52];
+ u32 csfull;
+ u32 csdatain;
+ u32 buffer[HASH_BLOCK_SIZE / sizeof(u32)];
+ struct uint64 length;
+ u8 index;
+ u8 bit_index;
+};
+
+/**
+ * enum hash_device_id - HASH device ID.
+ * @HASH_DEVICE_ID_0: Hash hardware with ID 0
+ * @HASH_DEVICE_ID_1: Hash hardware with ID 1
+ */
+enum hash_device_id {
+ HASH_DEVICE_ID_0 = 0,
+ HASH_DEVICE_ID_1 = 1
+};
+
+/**
+ * enum hash_data_format - HASH data format.
+ * @HASH_DATA_32_BITS: 32 bits data format
+ * @HASH_DATA_16_BITS: 16 bits data format
+ * @HASH_DATA_8_BITS: 8 bits data format.
+ * @HASH_DATA_1_BITS: 1 bit data format.
+ */
+enum hash_data_format {
+ HASH_DATA_32_BITS = 0x0,
+ HASH_DATA_16_BITS = 0x1,
+ HASH_DATA_8_BITS = 0x2,
+ HASH_DATA_1_BIT = 0x3
+};
+
+/**
+ * enum hash_algo - Enumeration for selecting between SHA1 or SHA2 algorithm.
+ * @HASH_ALGO_SHA1: Indicates that SHA1 is used.
+ * @HASH_ALGO_SHA2: Indicates that SHA2 (SHA256) is used.
+ */
+enum hash_algo {
+ HASH_ALGO_SHA1 = 0x0,
+ HASH_ALGO_SHA256 = 0x1
+};
+
+/**
+ * enum hash_op - Enumeration for selecting between HASH or HMAC mode.
+ * @HASH_OPER_MODE_HASH: Indicates usage of normal HASH mode.
+ * @HASH_OPER_MODE_HMAC: Indicates usage of HMAC.
+ */
+enum hash_op {
+ HASH_OPER_MODE_HASH = 0x0,
+ HASH_OPER_MODE_HMAC = 0x1
+};
+
+/**
+ * struct hash_config - Configuration data for the hardware.
+ * @data_format: Format of data entered into the hash data in register.
+ * @algorithm: Algorithm selection bit.
+ * @oper_mode: Operating mode selection bit.
+ */
+struct hash_config {
+ int data_format;
+ int algorithm;
+ int oper_mode;
+};
+
+/**
+ * struct hash_dma - Structure used for dma.
+ * @mask: DMA capabilities bitmap mask.
+ * @complete: Used to maintain state for a "completion".
+ * @chan_mem2hash: DMA channel.
+ * @cfg_mem2hash: DMA channel configuration.
+ * @sg_len: Scatterlist length.
+ * @sg: Scatterlist.
+ * @nents: Number of sg entries.
+ */
+struct hash_dma {
+ dma_cap_mask_t mask;
+ struct completion complete;
+ struct dma_chan *chan_mem2hash;
+ void *cfg_mem2hash;
+ int sg_len;
+ struct scatterlist *sg;
+ int nents;
+};
+
+/**
+ * struct hash_ctx - The context used for hash calculations.
+ * @key: The key used in the operation.
+ * @keylen: The length of the key.
+ * @state: The state of the current calculations.
+ * @config: The current configuration.
+ * @digestsize: The size of current digest.
+ * @device: Pointer to the device structure.
+ */
+struct hash_ctx {
+ u8 *key;
+ u32 keylen;
+ struct hash_config config;
+ int digestsize;
+ struct hash_device_data *device;
+};
+
+/**
+ * struct hash_ctx - The request context used for hash calculations.
+ * @state: The state of the current calculations.
+ * @dma_mode: Used in special cases (workaround), e.g. need to change to
+ * cpu mode, if not supported/working in dma mode.
+ * @updated: Indicates if hardware is initialized for new operations.
+ */
+struct hash_req_ctx {
+ struct hash_state state;
+ bool dma_mode;
+ u8 updated;
+};
+
+/**
+ * struct hash_device_data - structure for a hash device.
+ * @base: Pointer to the hardware base address.
+ * @list_node: For inclusion in klist.
+ * @dev: Pointer to the device dev structure.
+ * @ctx_lock: Spinlock for current_ctx.
+ * @current_ctx: Pointer to the currently allocated context.
+ * @power_state: TRUE = power state on, FALSE = power state off.
+ * @power_state_lock: Spinlock for power_state.
+ * @regulator: Pointer to the device's power control.
+ * @clk: Pointer to the device's clock control.
+ * @restore_dev_state: TRUE = saved state, FALSE = no saved state.
+ * @dma: Structure used for dma.
+ */
+struct hash_device_data {
+ struct hash_register __iomem *base;
+ struct klist_node list_node;
+ struct device *dev;
+ struct spinlock ctx_lock;
+ struct hash_ctx *current_ctx;
+ bool power_state;
+ struct spinlock power_state_lock;
+ struct regulator *regulator;
+ struct clk *clk;
+ bool restore_dev_state;
+ struct hash_state state; /* Used for saving and resuming state */
+ struct hash_dma dma;
+};
+
+int hash_check_hw(struct hash_device_data *device_data);
+
+int hash_setconfiguration(struct hash_device_data *device_data,
+ struct hash_config *config);
+
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx);
+
+void hash_get_digest(struct hash_device_data *device_data,
+ u8 *digest, int algorithm);
+
+int hash_hw_update(struct ahash_request *req);
+
+int hash_save_state(struct hash_device_data *device_data,
+ struct hash_state *state);
+
+int hash_resume_state(struct hash_device_data *device_data,
+ const struct hash_state *state);
+
+#endif
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
new file mode 100644
index 0000000..6dbb9ec
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -0,0 +1,2009 @@
+/*
+ * Cryptographic API.
+ * Support for Nomadik hardware crypto engine.
+
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/klist.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
+#include <linux/bitops.h>
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "hash_alg.h"
+
+#define DEV_DBG_NAME "hashX hashX:"
+
+static int hash_mode;
+module_param(hash_mode, int, 0);
+MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
+
+/**
+ * Pre-calculated empty message digests.
+ */
+static u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
+ 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
+ 0xaf, 0xd8, 0x07, 0x09
+};
+
+static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+
+/* HMAC-SHA1, no key */
+static u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
+ 0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08,
+ 0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63,
+ 0x70, 0x69, 0x0e, 0x1d
+};
+
+/* HMAC-SHA256, no key */
+static u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
+ 0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
+ 0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
+ 0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
+ 0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad
+};
+
+/**
+ * struct hash_driver_data - data specific to the driver.
+ *
+ * @device_list: A list of registered devices to choose from.
+ * @device_allocation: A semaphore initialized with number of devices.
+ */
+struct hash_driver_data {
+ struct klist device_list;
+ struct semaphore device_allocation;
+};
+
+static struct hash_driver_data driver_data;
+
+/* Declaration of functions */
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data: Structure for the hash device.
+ * @message: Last word of a message
+ * @index_bytes: The number of bytes in the last message
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+ const u32 *message, u8 index_bytes);
+
+/**
+ * release_hash_device - Releases a previously allocated hash device.
+ * @device_data: Structure for the hash device.
+ *
+ */
+static void release_hash_device(struct hash_device_data *device_data)
+{
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx->device = NULL;
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+}
+
+static void hash_dma_setup_channel(struct hash_device_data *device_data,
+ struct device *dev)
+{
+ struct hash_platform_data *platform_data = dev->platform_data;
+ dma_cap_zero(device_data->dma.mask);
+ dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+ device_data->dma.cfg_mem2hash = platform_data->mem_to_engine;
+ device_data->dma.chan_mem2hash =
+ dma_request_channel(device_data->dma.mask,
+ platform_data->dma_filter,
+ device_data->dma.cfg_mem2hash);
+
+ init_completion(&device_data->dma.complete);
+}
+
+static void hash_dma_callback(void *data)
+{
+ struct hash_ctx *ctx = (struct hash_ctx *) data;
+
+ complete(&ctx->device->dma.complete);
+}
+
+static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
+ int len, enum dma_data_direction direction)
+{
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *channel = NULL;
+ dma_cookie_t cookie;
+
+ if (direction != DMA_TO_DEVICE) {
+ dev_err(ctx->device->dev, "[%s] Invalid DMA direction",
+ __func__);
+ return -EFAULT;
+ }
+
+ sg->length = ALIGN(sg->length, HASH_DMA_ALIGN_SIZE);
+
+ channel = ctx->device->dma.chan_mem2hash;
+ ctx->device->dma.sg = sg;
+ ctx->device->dma.sg_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg, ctx->device->dma.nents,
+ direction);
+
+ if (!ctx->device->dma.sg_len) {
+ dev_err(ctx->device->dev,
+ "[%s]: Could not map the sg list (TO_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(TO_DEVICE)", __func__);
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg, ctx->device->dma.sg_len,
+ direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT, NULL);
+ if (!desc) {
+ dev_err(ctx->device->dev,
+ "[%s]: device_prep_slave_sg() failed!", __func__);
+ return -EFAULT;
+ }
+
+ desc->callback = hash_dma_callback;
+ desc->callback_param = ctx;
+
+ cookie = desc->tx_submit(desc);
+ dma_async_issue_pending(channel);
+
+ return 0;
+}
+
+static void hash_dma_done(struct hash_ctx *ctx)
+{
+ struct dma_chan *chan;
+
+ chan = ctx->device->dma.chan_mem2hash;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
+ ctx->device->dma.sg_len, DMA_TO_DEVICE);
+
+}
+
+static int hash_dma_write(struct hash_ctx *ctx,
+ struct scatterlist *sg, int len)
+{
+ int error = hash_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: hash_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+/**
+ * get_empty_message_digest - Returns a pre-calculated digest for
+ * the empty message.
+ * @device_data: Structure for the hash device.
+ * @zero_hash: Buffer to return the empty message digest.
+ * @zero_hash_size: Hash size of the empty message digest.
+ * @zero_digest: True if zero_digest returned.
+ */
+static int get_empty_message_digest(
+ struct hash_device_data *device_data,
+ u8 *zero_hash, u32 *zero_hash_size, bool *zero_digest)
+{
+ int ret = 0;
+ struct hash_ctx *ctx = device_data->current_ctx;
+ *zero_digest = false;
+
+ /**
+ * Caller responsible for ctx != NULL.
+ */
+
+ if (HASH_OPER_MODE_HASH == ctx->config.oper_mode) {
+ if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hash_sha1[0],
+ SHA1_DIGEST_SIZE);
+ *zero_hash_size = SHA1_DIGEST_SIZE;
+ *zero_digest = true;
+ } else if (HASH_ALGO_SHA256 ==
+ ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hash_sha256[0],
+ SHA256_DIGEST_SIZE);
+ *zero_hash_size = SHA256_DIGEST_SIZE;
+ *zero_digest = true;
+ } else {
+ dev_err(device_data->dev, "[%s] "
+ "Incorrect algorithm!"
+ , __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else if (HASH_OPER_MODE_HMAC == ctx->config.oper_mode) {
+ if (!ctx->keylen) {
+ if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hmac_sha1[0],
+ SHA1_DIGEST_SIZE);
+ *zero_hash_size = SHA1_DIGEST_SIZE;
+ *zero_digest = true;
+ } else if (HASH_ALGO_SHA256 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hmac_sha256[0],
+ SHA256_DIGEST_SIZE);
+ *zero_hash_size = SHA256_DIGEST_SIZE;
+ *zero_digest = true;
+ } else {
+ dev_err(device_data->dev, "[%s] "
+ "Incorrect algorithm!"
+ , __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ dev_dbg(device_data->dev, "[%s] Continue hash "
+ "calculation, since hmac key avalable",
+ __func__);
+ }
+ }
+out:
+
+ return ret;
+}
+
+/**
+ * hash_disable_power - Request to disable power and clock.
+ * @device_data: Structure for the hash device.
+ * @save_device_state: If true, saves the current hw state.
+ *
+ * This function request for disabling power (regulator) and clock,
+ * and could also save current hw state.
+ */
+static int hash_disable_power(
+ struct hash_device_data *device_data,
+ bool save_device_state)
+{
+ int ret = 0;
+ struct device *dev = device_data->dev;
+
+ spin_lock(&device_data->power_state_lock);
+ if (!device_data->power_state)
+ goto out;
+
+ if (save_device_state) {
+ hash_save_state(device_data,
+ &device_data->state);
+ device_data->restore_dev_state = true;
+ }
+
+ clk_disable(device_data->clk);
+ ret = regulator_disable(device_data->regulator);
+ if (ret)
+ dev_err(dev, "[%s] regulator_disable() failed!", __func__);
+
+ device_data->power_state = false;
+
+out:
+ spin_unlock(&device_data->power_state_lock);
+
+ return ret;
+}
+
+/**
+ * hash_enable_power - Request to enable power and clock.
+ * @device_data: Structure for the hash device.
+ * @restore_device_state: If true, restores a previous saved hw state.
+ *
+ * This function request for enabling power (regulator) and clock,
+ * and could also restore a previously saved hw state.
+ */
+static int hash_enable_power(
+ struct hash_device_data *device_data,
+ bool restore_device_state)
+{
+ int ret = 0;
+ struct device *dev = device_data->dev;
+
+ spin_lock(&device_data->power_state_lock);
+ if (!device_data->power_state) {
+ ret = regulator_enable(device_data->regulator);
+ if (ret) {
+ dev_err(dev, "[%s]: regulator_enable() failed!",
+ __func__);
+ goto out;
+ }
+ ret = clk_enable(device_data->clk);
+ if (ret) {
+ dev_err(dev, "[%s]: clk_enable() failed!",
+ __func__);
+ ret = regulator_disable(
+ device_data->regulator);
+ goto out;
+ }
+ device_data->power_state = true;
+ }
+
+ if (device_data->restore_dev_state) {
+ if (restore_device_state) {
+ device_data->restore_dev_state = false;
+ hash_resume_state(device_data,
+ &device_data->state);
+ }
+ }
+out:
+ spin_unlock(&device_data->power_state_lock);
+
+ return ret;
+}
+
+/**
+ * hash_get_device_data - Checks for an available hash device and return it.
+ * @hash_ctx: Structure for the hash context.
+ * @device_data: Structure for the hash device.
+ *
+ * This function check for an available hash device and return it to
+ * the caller.
+ * Note! Caller need to release the device, calling up().
+ */
+static int hash_get_device_data(struct hash_ctx *ctx,
+ struct hash_device_data **device_data)
+{
+ int ret;
+ struct klist_iter device_iterator;
+ struct klist_node *device_node;
+ struct hash_device_data *local_device_data = NULL;
+
+ /* Wait until a device is available */
+ ret = down_interruptible(&driver_data.device_allocation);
+ if (ret)
+ return ret; /* Interrupted */
+
+ /* Select a device */
+ klist_iter_init(&driver_data.device_list, &device_iterator);
+ device_node = klist_next(&device_iterator);
+ while (device_node) {
+ local_device_data = container_of(device_node,
+ struct hash_device_data, list_node);
+ spin_lock(&local_device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (local_device_data->current_ctx) {
+ device_node = klist_next(&device_iterator);
+ } else {
+ local_device_data->current_ctx = ctx;
+ ctx->device = local_device_data;
+ spin_unlock(&local_device_data->ctx_lock);
+ break;
+ }
+ spin_unlock(&local_device_data->ctx_lock);
+ }
+ klist_iter_exit(&device_iterator);
+
+ if (!device_node) {
+ /**
+ * No free device found.
+ * Since we allocated a device with down_interruptible, this
+ * should not be able to happen.
+ * Number of available devices, which are contained in
+ * device_allocation, is therefore decremented by not doing
+ * an up(device_allocation).
+ */
+ return -EBUSY;
+ }
+
+ *device_data = local_device_data;
+
+ return 0;
+}
+
+/**
+ * hash_hw_write_key - Writes the key to the hardware registries.
+ *
+ * @device_data: Structure for the hash device.
+ * @key: Key to be written.
+ * @keylen: The lengt of the key.
+ *
+ * Note! This function DOES NOT write to the NBLW registry, even though
+ * specified in the the hw design spec. Either due to incorrect info in the
+ * spec or due to a bug in the hw.
+ */
+static void hash_hw_write_key(struct hash_device_data *device_data,
+ const u8 *key, unsigned int keylen)
+{
+ u32 word = 0;
+ int nwords = 1;
+
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ while (keylen >= 4) {
+ u32 *key_word = (u32 *)key;
+
+ HASH_SET_DIN(key_word, nwords);
+ keylen -= 4;
+ key += 4;
+ }
+
+ /* Take care of the remaining bytes in the last word */
+ if (keylen) {
+ word = 0;
+ while (keylen) {
+ word |= (key[keylen - 1] << (8 * (keylen - 1)));
+ keylen--;
+ }
+
+ HASH_SET_DIN(&word, nwords);
+ }
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ HASH_SET_DCAL;
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+}
+
+/**
+ * init_hash_hw - Initialise the hash hardware for a new calculation.
+ * @device_data: Structure for the hash device.
+ * @ctx: The hash context.
+ *
+ * This function will enable the bits needed to clear and start a new
+ * calculation.
+ */
+static int init_hash_hw(struct hash_device_data *device_data,
+ struct hash_ctx *ctx)
+{
+ int ret = 0;
+
+ ret = hash_setconfiguration(device_data, &ctx->config);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_setconfiguration() "
+ "failed!", __func__);
+ return ret;
+ }
+
+ hash_begin(device_data, ctx);
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+ hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+ return ret;
+}
+
+/**
+ * hash_get_nents - Return number of entries (nents) in scatterlist (sg).
+ *
+ * @sg: Scatterlist.
+ * @size: Size in bytes.
+ * @aligned: True if sg data aligned to work in DMA mode.
+ *
+ */
+static int hash_get_nents(struct scatterlist *sg, int size, bool *aligned)
+{
+ int nents = 0;
+ bool aligned_data = true;
+
+ while (size > 0 && sg) {
+ nents++;
+ size -= sg->length;
+
+ /* hash_set_dma_transfer will align last nent */
+ if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE))
+ || (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) &&
+ size > 0))
+ aligned_data = false;
+
+ sg = sg_next(sg);
+ }
+
+ if (aligned)
+ *aligned = aligned_data;
+
+ if (size != 0)
+ return -EFAULT;
+
+ return nents;
+}
+
+/**
+ * hash_dma_valid_data - checks for dma valid sg data.
+ * @sg: Scatterlist.
+ * @datasize: Datasize in bytes.
+ *
+ * NOTE! This function checks for dma valid sg data, since dma
+ * only accept datasizes of even wordsize.
+ */
+static bool hash_dma_valid_data(struct scatterlist *sg, int datasize)
+{
+ bool aligned;
+
+ /* Need to include at least one nent, else error */
+ if (hash_get_nents(sg, datasize, &aligned) < 1)
+ return false;
+
+ return aligned;
+}
+
+/**
+ * hash_init - Common hash init function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ *
+ * Initialize structures.
+ */
+static int hash_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ if (!ctx->key)
+ ctx->keylen = 0;
+
+ memset(&req_ctx->state, 0, sizeof(struct hash_state));
+ req_ctx->updated = 0;
+ if (hash_mode == HASH_MODE_DMA) {
+ if (req->nbytes < HASH_DMA_ALIGN_SIZE) {
+ req_ctx->dma_mode = false; /* Don't use DMA */
+
+ pr_debug(DEV_DBG_NAME " [%s] DMA mode, but direct "
+ "to CPU mode for data size < %d",
+ __func__, HASH_DMA_ALIGN_SIZE);
+ } else {
+ if (req->nbytes >= HASH_DMA_PERFORMANCE_MIN_SIZE &&
+ hash_dma_valid_data(req->src,
+ req->nbytes)) {
+ req_ctx->dma_mode = true;
+ } else {
+ req_ctx->dma_mode = false;
+ pr_debug(DEV_DBG_NAME " [%s] DMA mode, but use"
+ " CPU mode for datalength < %d"
+ " or non-aligned data, except "
+ "in last nent", __func__,
+ HASH_DMA_PERFORMANCE_MIN_SIZE);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * hash_processblock - This function processes a single block of 512 bits (64
+ * bytes), word aligned, starting at message.
+ * @device_data: Structure for the hash device.
+ * @message: Block (512 bits) of message to be written to
+ * the HASH hardware.
+ *
+ */
+static void hash_processblock(
+ struct hash_device_data *device_data,
+ const u32 *message, int length)
+{
+ int len = length / HASH_BYTES_PER_WORD;
+ /*
+ * NBLW bits. Reset the number of bits in last word (NBLW).
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ /*
+ * Write message data to the HASH_DIN register.
+ */
+ HASH_SET_DIN(message, len);
+}
+
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data: Structure for the hash device.
+ * @message: Last word of a message.
+ * @index_bytes: The number of bytes in the last message.
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+ const u32 *message, u8 index_bytes)
+{
+ int nwords = 1;
+
+ /*
+ * Clear hash str register, only clear NBLW
+ * since DCAL will be reset by hardware.
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ /* Main loop */
+ while (index_bytes >= 4) {
+ HASH_SET_DIN(message, nwords);
+ index_bytes -= 4;
+ message++;
+ }
+
+ if (index_bytes)
+ HASH_SET_DIN(message, nwords);
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ /* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
+ HASH_SET_NBLW(index_bytes * 8);
+ dev_dbg(device_data->dev, "[%s] DIN=0x%08x NBLW=%d", __func__,
+ readl_relaxed(&device_data->base->din),
+ (int)(readl_relaxed(&device_data->base->str) &
+ HASH_STR_NBLW_MASK));
+ HASH_SET_DCAL;
+ dev_dbg(device_data->dev, "[%s] after dcal -> DIN=0x%08x NBLW=%d",
+ __func__, readl_relaxed(&device_data->base->din),
+ (int)(readl_relaxed(&device_data->base->str) &
+ HASH_STR_NBLW_MASK));
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+}
+
+/**
+ * hash_incrementlength - Increments the length of the current message.
+ * @ctx: Hash context
+ * @incr: Length of message processed already
+ *
+ * Overflow cannot occur, because conditions for overflow are checked in
+ * hash_hw_update.
+ */
+static void hash_incrementlength(struct hash_req_ctx *ctx, u32 incr)
+{
+ ctx->state.length.low_word += incr;
+
+ /* Check for wrap-around */
+ if (ctx->state.length.low_word < incr)
+ ctx->state.length.high_word++;
+}
+
+/**
+ * hash_setconfiguration - Sets the required configuration for the hash
+ * hardware.
+ * @device_data: Structure for the hash device.
+ * @config: Pointer to a configuration structure.
+ */
+int hash_setconfiguration(struct hash_device_data *device_data,
+ struct hash_config *config)
+{
+ int ret = 0;
+
+ if (config->algorithm != HASH_ALGO_SHA1 &&
+ config->algorithm != HASH_ALGO_SHA256)
+ return -EPERM;
+
+ /*
+ * DATAFORM bits. Set the DATAFORM bits to 0b11, which means the data
+ * to be written to HASH_DIN is considered as 32 bits.
+ */
+ HASH_SET_DATA_FORMAT(config->data_format);
+
+ /*
+ * ALGO bit. Set to 0b1 for SHA-1 and 0b0 for SHA-256
+ */
+ switch (config->algorithm) {
+ case HASH_ALGO_SHA1:
+ HASH_SET_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+ break;
+
+ case HASH_ALGO_SHA256:
+ HASH_CLEAR_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+ break;
+
+ default:
+ dev_err(device_data->dev, "[%s] Incorrect algorithm.",
+ __func__);
+ return -EPERM;
+ }
+
+ /*
+ * MODE bit. This bit selects between HASH or HMAC mode for the
+ * selected algorithm. 0b0 = HASH and 0b1 = HMAC.
+ */
+ if (HASH_OPER_MODE_HASH == config->oper_mode)
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_MODE_MASK);
+ else if (HASH_OPER_MODE_HMAC == config->oper_mode) {
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_MODE_MASK);
+ if (device_data->current_ctx->keylen > HASH_BLOCK_SIZE) {
+ /* Truncate key to blocksize */
+ dev_dbg(device_data->dev, "[%s] LKEY set", __func__);
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_LKEY_MASK);
+ } else {
+ dev_dbg(device_data->dev, "[%s] LKEY cleared",
+ __func__);
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_LKEY_MASK);
+ }
+ } else { /* Wrong hash mode */
+ ret = -EPERM;
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ }
+ return ret;
+}
+
+/**
+ * hash_begin - This routine resets some globals and initializes the hash
+ * hardware.
+ * @device_data: Structure for the hash device.
+ * @ctx: Hash context.
+ */
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx)
+{
+ /* HW and SW initializations */
+ /* Note: there is no need to initialize buffer and digest members */
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ /*
+ * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+ * prepare the initialize the HASH accelerator to compute the message
+ * digest of a new message.
+ */
+ HASH_INITIALIZE;
+
+ /*
+ * NBLW bits. Reset the number of bits in last word (NBLW).
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+}
+
+int hash_process_data(
+ struct hash_device_data *device_data,
+ struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
+ int msg_length, u8 *data_buffer, u8 *buffer, u8 *index)
+{
+ int ret = 0;
+ u32 count;
+
+ do {
+ if ((*index + msg_length) < HASH_BLOCK_SIZE) {
+ for (count = 0; count < msg_length; count++) {
+ buffer[*index + count] =
+ *(data_buffer + count);
+ }
+ *index += msg_length;
+ msg_length = 0;
+ } else {
+ if (req_ctx->updated) {
+
+ ret = hash_resume_state(device_data,
+ &device_data->state);
+ memmove(req_ctx->state.buffer,
+ device_data->state.buffer,
+ HASH_BLOCK_SIZE / sizeof(u32));
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_resume_state()"
+ " failed!", __func__);
+ goto out;
+ }
+ } else {
+ ret = init_hash_hw(device_data, ctx);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "init_hash_hw()"
+ " failed!", __func__);
+ goto out;
+ }
+ req_ctx->updated = 1;
+ }
+ /*
+ * If 'data_buffer' is four byte aligned and
+ * local buffer does not have any data, we can
+ * write data directly from 'data_buffer' to
+ * HW peripheral, otherwise we first copy data
+ * to a local buffer
+ */
+ if ((0 == (((u32)data_buffer) % 4))
+ && (0 == *index))
+ hash_processblock(device_data,
+ (const u32 *)
+ data_buffer, HASH_BLOCK_SIZE);
+ else {
+ for (count = 0; count <
+ (u32)(HASH_BLOCK_SIZE -
+ *index);
+ count++) {
+ buffer[*index + count] =
+ *(data_buffer + count);
+ }
+ hash_processblock(device_data,
+ (const u32 *)buffer,
+ HASH_BLOCK_SIZE);
+ }
+ hash_incrementlength(req_ctx, HASH_BLOCK_SIZE);
+ data_buffer += (HASH_BLOCK_SIZE - *index);
+
+ msg_length -= (HASH_BLOCK_SIZE - *index);
+ *index = 0;
+
+ ret = hash_save_state(device_data,
+ &device_data->state);
+
+ memmove(device_data->state.buffer,
+ req_ctx->state.buffer,
+ HASH_BLOCK_SIZE / sizeof(u32));
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_save_state()"
+ " failed!", __func__);
+ goto out;
+ }
+ }
+ } while (msg_length != 0);
+out:
+
+ return ret;
+}
+
+/**
+ * hash_dma_final - The hash dma final function for SHA1/SHA256.
+ * @req: The hash request for the job.
+ */
+static int hash_dma_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct hash_device_data *device_data;
+ u8 digest[SHA256_DIGEST_SIZE];
+ int bytes_written = 0;
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+ if (req_ctx->updated) {
+ ret = hash_resume_state(device_data, &device_data->state);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_resume_state() "
+ "failed!", __func__);
+ goto out;
+ }
+
+ }
+
+ if (!req_ctx->updated) {
+ ret = hash_setconfiguration(device_data, &ctx->config);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_setconfiguration() failed!",
+ __func__);
+ goto out;
+ }
+
+ /* Enable DMA input */
+ if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode) {
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_DMAE_MASK);
+ } else {
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_DMAE_MASK);
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_PRIVN_MASK);
+ }
+
+ HASH_INITIALIZE;
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+ hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+ /* Number of bits in last word = (nbytes * 8) % 32 */
+ HASH_SET_NBLW((req->nbytes * 8) % 32);
+ req_ctx->updated = 1;
+ }
+
+ /* Store the nents in the dma struct. */
+ ctx->device->dma.nents = hash_get_nents(req->src, req->nbytes, NULL);
+ if (!ctx->device->dma.nents) {
+ dev_err(device_data->dev, "[%s] "
+ "ctx->device->dma.nents = 0", __func__);
+ goto out;
+ }
+
+ bytes_written = hash_dma_write(ctx, req->src, req->nbytes);
+ if (bytes_written != req->nbytes) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_dma_write() failed!", __func__);
+ goto out;
+ }
+
+ wait_for_completion(&ctx->device->dma.complete);
+ hash_dma_done(ctx);
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+ unsigned int keylen = ctx->keylen;
+ u8 *key = ctx->key;
+
+ dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+ ctx->keylen);
+ hash_hw_write_key(device_data, key, keylen);
+ }
+
+ hash_get_digest(device_data, digest, ctx->config.algorithm);
+ memcpy(req->result, digest, ctx->digestsize);
+
+out:
+ release_hash_device(device_data);
+
+ /**
+ * Allocated in setkey, and only used in HMAC.
+ */
+ kfree(ctx->key);
+
+ return ret;
+}
+
+/**
+ * hash_hw_final - The final hash calculation function
+ * @req: The hash request for the job.
+ */
+int hash_hw_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct hash_device_data *device_data;
+ u8 digest[SHA256_DIGEST_SIZE];
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+ if (req_ctx->updated) {
+ ret = hash_resume_state(device_data, &device_data->state);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_resume_state() "
+ "failed!", __func__);
+ goto out;
+ }
+ } else if (req->nbytes == 0 && ctx->keylen == 0) {
+ u8 zero_hash[SHA256_DIGEST_SIZE];
+ u32 zero_hash_size = 0;
+ bool zero_digest = false;
+ /**
+ * Use a pre-calculated empty message digest
+ * (workaround since hw return zeroes, hw bug!?)
+ */
+ ret = get_empty_message_digest(device_data, &zero_hash[0],
+ &zero_hash_size, &zero_digest);
+ if (!ret && likely(zero_hash_size == ctx->digestsize) &&
+ zero_digest) {
+ memcpy(req->result, &zero_hash[0], ctx->digestsize);
+ goto out;
+ } else if (!ret && !zero_digest) {
+ dev_dbg(device_data->dev, "[%s] HMAC zero msg with "
+ "key, continue...", __func__);
+ } else {
+ dev_err(device_data->dev, "[%s] ret=%d, or wrong "
+ "digest size? %s", __func__, ret,
+ (zero_hash_size == ctx->digestsize) ?
+ "true" : "false");
+ /* Return error */
+ goto out;
+ }
+ } else if (req->nbytes == 0 && ctx->keylen > 0) {
+ dev_err(device_data->dev, "[%s] Empty message with "
+ "keylength > 0, NOT supported.", __func__);
+ goto out;
+ }
+
+ if (!req_ctx->updated) {
+ ret = init_hash_hw(device_data, ctx);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] init_hash_hw() "
+ "failed!", __func__);
+ goto out;
+ }
+ }
+
+ if (req_ctx->state.index) {
+ hash_messagepad(device_data, req_ctx->state.buffer,
+ req_ctx->state.index);
+ } else {
+ HASH_SET_DCAL;
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+ }
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+ unsigned int keylen = ctx->keylen;
+ u8 *key = ctx->key;
+
+ dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+ ctx->keylen);
+ hash_hw_write_key(device_data, key, keylen);
+ }
+
+ hash_get_digest(device_data, digest, ctx->config.algorithm);
+ memcpy(req->result, digest, ctx->digestsize);
+
+out:
+ release_hash_device(device_data);
+
+ /**
+ * Allocated in setkey, and only used in HMAC.
+ */
+ kfree(ctx->key);
+
+ return ret;
+}
+
+/**
+ * hash_hw_update - Updates current HASH computation hashing another part of
+ * the message.
+ * @req: Byte array containing the message to be hashed (caller
+ * allocated).
+ */
+int hash_hw_update(struct ahash_request *req)
+{
+ int ret = 0;
+ u8 index = 0;
+ u8 *buffer;
+ struct hash_device_data *device_data;
+ u8 *data_buffer;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct crypto_hash_walk walk;
+ int msg_length = crypto_hash_walk_first(req, &walk);
+
+ /* Empty message ("") is correct indata */
+ if (msg_length == 0)
+ return ret;
+
+ index = req_ctx->state.index;
+ buffer = (u8 *)req_ctx->state.buffer;
+
+ /* Check if ctx->state.length + msg_length
+ overflows */
+ if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
+ HASH_HIGH_WORD_MAX_VAL ==
+ req_ctx->state.length.high_word) {
+ pr_err(DEV_DBG_NAME " [%s] HASH_MSG_LENGTH_OVERFLOW!",
+ __func__);
+ return -EPERM;
+ }
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ /* Main loop */
+ while (0 != msg_length) {
+ data_buffer = walk.data;
+ ret = hash_process_data(device_data, ctx, req_ctx, msg_length,
+ data_buffer, buffer, &index);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_internal_hw_"
+ "update() failed!", __func__);
+ goto out;
+ }
+
+ msg_length = crypto_hash_walk_done(&walk, 0);
+ }
+
+ req_ctx->state.index = index;
+ dev_dbg(device_data->dev, "[%s] indata length=%d, bin=%d))",
+ __func__, req_ctx->state.index,
+ req_ctx->state.bit_index);
+
+out:
+ release_hash_device(device_data);
+
+ return ret;
+}
+
+/**
+ * hash_resume_state - Function that resumes the state of an calculation.
+ * @device_data: Pointer to the device structure.
+ * @device_state: The state to be restored in the hash hardware
+ */
+int hash_resume_state(struct hash_device_data *device_data,
+ const struct hash_state *device_state)
+{
+ u32 temp_cr;
+ s32 count;
+ int hash_mode = HASH_OPER_MODE_HASH;
+
+ if (NULL == device_state) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -EPERM;
+ }
+
+ /* Check correctness of index and length members */
+ if (device_state->index > HASH_BLOCK_SIZE
+ || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -EPERM;
+ }
+
+ /*
+ * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+ * prepare the initialize the HASH accelerator to compute the message
+ * digest of a new message.
+ */
+ HASH_INITIALIZE;
+
+ temp_cr = device_state->temp_cr;
+ writel_relaxed(temp_cr & HASH_CR_RESUME_MASK, &device_data->base->cr);
+
+ if (device_data->base->cr & HASH_CR_MODE_MASK)
+ hash_mode = HASH_OPER_MODE_HMAC;
+ else
+ hash_mode = HASH_OPER_MODE_HASH;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+ break;
+
+ writel_relaxed(device_state->csr[count],
+ &device_data->base->csrx[count]);
+ }
+
+ writel_relaxed(device_state->csfull, &device_data->base->csfull);
+ writel_relaxed(device_state->csdatain, &device_data->base->csdatain);
+
+ writel_relaxed(device_state->str_reg, &device_data->base->str);
+ writel_relaxed(temp_cr, &device_data->base->cr);
+
+ return 0;
+}
+
+/**
+ * hash_save_state - Function that saves the state of hardware.
+ * @device_data: Pointer to the device structure.
+ * @device_state: The strucure where the hardware state should be saved.
+ */
+int hash_save_state(struct hash_device_data *device_data,
+ struct hash_state *device_state)
+{
+ u32 temp_cr;
+ u32 count;
+ int hash_mode = HASH_OPER_MODE_HASH;
+
+ if (NULL == device_state) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -ENOTSUPP;
+ }
+
+ /* Write dummy value to force digest intermediate calculation. This
+ * actually makes sure that there isn't any ongoing calculation in the
+ * hardware.
+ */
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ temp_cr = readl_relaxed(&device_data->base->cr);
+
+ device_state->str_reg = readl_relaxed(&device_data->base->str);
+
+ device_state->din_reg = readl_relaxed(&device_data->base->din);
+
+ if (device_data->base->cr & HASH_CR_MODE_MASK)
+ hash_mode = HASH_OPER_MODE_HMAC;
+ else
+ hash_mode = HASH_OPER_MODE_HASH;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+ break;
+
+ device_state->csr[count] =
+ readl_relaxed(&device_data->base->csrx[count]);
+ }
+
+ device_state->csfull = readl_relaxed(&device_data->base->csfull);
+ device_state->csdatain = readl_relaxed(&device_data->base->csdatain);
+
+ device_state->temp_cr = temp_cr;
+
+ return 0;
+}
+
+/**
+ * hash_check_hw - This routine checks for peripheral Ids and PCell Ids.
+ * @device_data:
+ *
+ */
+int hash_check_hw(struct hash_device_data *device_data)
+{
+ /* Checking Peripheral Ids */
+ if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0)
+ && HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1)
+ && HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2)
+ && HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3)
+ && HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0)
+ && HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1)
+ && HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2)
+ && HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)
+ ) {
+ return 0;
+ }
+
+ dev_err(device_data->dev, "[%s] HASH_UNSUPPORTED_HW!",
+ __func__);
+ return -ENOTSUPP;
+}
+
+/**
+ * hash_get_digest - Gets the digest.
+ * @device_data: Pointer to the device structure.
+ * @digest: User allocated byte array for the calculated digest.
+ * @algorithm: The algorithm in use.
+ */
+void hash_get_digest(struct hash_device_data *device_data,
+ u8 *digest, int algorithm)
+{
+ u32 temp_hx_val, count;
+ int loop_ctr;
+
+ if (algorithm != HASH_ALGO_SHA1 && algorithm != HASH_ALGO_SHA256) {
+ dev_err(device_data->dev, "[%s] Incorrect algorithm %d",
+ __func__, algorithm);
+ return;
+ }
+
+ if (algorithm == HASH_ALGO_SHA1)
+ loop_ctr = SHA1_DIGEST_SIZE / sizeof(u32);
+ else
+ loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32);
+
+ dev_dbg(device_data->dev, "[%s] digest array:(0x%x)",
+ __func__, (u32) digest);
+
+ /* Copy result into digest array */
+ for (count = 0; count < loop_ctr; count++) {
+ temp_hx_val = readl_relaxed(&device_data->base->hx[count]);
+ digest[count * 4] = (u8) ((temp_hx_val >> 24) & 0xFF);
+ digest[count * 4 + 1] = (u8) ((temp_hx_val >> 16) & 0xFF);
+ digest[count * 4 + 2] = (u8) ((temp_hx_val >> 8) & 0xFF);
+ digest[count * 4 + 3] = (u8) ((temp_hx_val >> 0) & 0xFF);
+ }
+}
+
+/**
+ * hash_update - The hash update function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ */
+static int ahash_update(struct ahash_request *req)
+{
+ int ret = 0;
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode)
+ ret = hash_hw_update(req);
+ /* Skip update for DMA, all data will be passed to DMA in final */
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME " [%s] hash_hw_update() failed!",
+ __func__);
+ }
+
+ return ret;
+}
+
+/**
+ * hash_final - The hash final function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ */
+static int ahash_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ pr_debug(DEV_DBG_NAME " [%s] data size: %d", __func__, req->nbytes);
+
+ if ((hash_mode == HASH_MODE_DMA) && req_ctx->dma_mode)
+ ret = hash_dma_final(req);
+ else
+ ret = hash_hw_final(req);
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME " [%s] hash_hw/dma_final() failed",
+ __func__);
+ }
+
+ return ret;
+}
+
+static int hash_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen, int alg)
+{
+ int ret = 0;
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ /**
+ * Freed in final.
+ */
+ ctx->key = kmalloc(keylen, GFP_KERNEL);
+ if (!ctx->key) {
+ pr_err(DEV_DBG_NAME " [%s] Failed to allocate ctx->key "
+ "for %d\n", __func__, alg);
+ return -ENOMEM;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return ret;
+}
+
+static int ahash_sha1_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+ ctx->digestsize = SHA1_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int ahash_sha256_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA256;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+ ctx->digestsize = SHA256_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int ahash_sha1_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = ahash_sha1_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int ahash_sha256_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = ahash_sha256_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->digestsize = SHA1_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int hmac_sha256_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA256;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->digestsize = SHA256_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int hmac_sha1_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = hmac_sha1_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha256_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = hmac_sha256_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
+}
+
+static int hmac_sha256_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA256);
+}
+
+struct hash_algo_template {
+ struct hash_config conf;
+ struct ahash_alg hash;
+};
+
+static int hash_cra_init(struct crypto_tfm *tfm)
+{
+ struct hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct hash_algo_template *hash_alg;
+
+ hash_alg = container_of(__crypto_ahash_alg(alg),
+ struct hash_algo_template,
+ hash);
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct hash_req_ctx));
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = hash_alg->conf.algorithm;
+ ctx->config.oper_mode = hash_alg->conf.oper_mode;
+
+ ctx->digestsize = hash_alg->hash.halg.digestsize;
+
+ return 0;
+}
+
+static struct hash_algo_template hash_algs[] = {
+ {
+ .conf.algorithm = HASH_ALGO_SHA1,
+ .conf.oper_mode = HASH_OPER_MODE_HASH,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = ahash_sha1_digest,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA256,
+ .conf.oper_mode = HASH_OPER_MODE_HASH,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = ahash_sha256_digest,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA1,
+ .conf.oper_mode = HASH_OPER_MODE_HMAC,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = hmac_sha1_digest,
+ .setkey = hmac_sha1_setkey,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "hmac-sha1-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA256,
+ .conf.oper_mode = HASH_OPER_MODE_HMAC,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = hmac_sha256_digest,
+ .setkey = hmac_sha256_setkey,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "hmac-sha256-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ }
+};
+
+/**
+ * hash_algs_register_all -
+ */
+static int ahash_algs_register_all(struct hash_device_data *device_data)
+{
+ int ret;
+ int i;
+ int count;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algs); i++) {
+ ret = crypto_register_ahash(&hash_algs[i].hash);
+ if (ret) {
+ count = i;
+ dev_err(device_data->dev, "[%s] alg registration failed",
+ hash_algs[i].hash.halg.base.cra_driver_name);
+ goto unreg;
+ }
+ }
+ return 0;
+unreg:
+ for (i = 0; i < count; i++)
+ crypto_unregister_ahash(&hash_algs[i].hash);
+ return ret;
+}
+
+/**
+ * hash_algs_unregister_all -
+ */
+static void ahash_algs_unregister_all(struct hash_device_data *device_data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algs); i++)
+ crypto_unregister_ahash(&hash_algs[i].hash);
+}
+
+/**
+ * ux500_hash_probe - Function that probes the hash hardware.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res = NULL;
+ struct hash_device_data *device_data;
+ struct device *dev = &pdev->dev;
+
+ device_data = kzalloc(sizeof(struct hash_device_data), GFP_ATOMIC);
+ if (!device_data) {
+ dev_dbg(dev, "[%s] kzalloc() failed!", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ device_data->dev = dev;
+ device_data->current_ctx = NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(dev, "[%s] platform_get_resource() failed!", __func__);
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ dev_dbg(dev, "[%s] request_mem_region() failed!", __func__);
+ ret = -EBUSY;
+ goto out_kfree;
+ }
+
+ device_data->base = ioremap(res->start, resource_size(res));
+ if (!device_data->base) {
+ dev_err(dev, "[%s] ioremap() failed!",
+ __func__);
+ ret = -ENOMEM;
+ goto out_free_mem;
+ }
+ spin_lock_init(&device_data->ctx_lock);
+ spin_lock_init(&device_data->power_state_lock);
+
+ /* Enable power for HASH1 hardware block */
+ device_data->regulator = regulator_get(dev, "v-ape");
+ if (IS_ERR(device_data->regulator)) {
+ dev_err(dev, "[%s] regulator_get() failed!", __func__);
+ ret = PTR_ERR(device_data->regulator);
+ device_data->regulator = NULL;
+ goto out_unmap;
+ }
+
+ /* Enable the clock for HASH1 hardware block */
+ device_data->clk = clk_get(dev, NULL);
+ if (IS_ERR(device_data->clk)) {
+ dev_err(dev, "[%s] clk_get() failed!", __func__);
+ ret = PTR_ERR(device_data->clk);
+ goto out_regulator;
+ }
+
+ /* Enable device power (and clock) */
+ ret = hash_enable_power(device_data, false);
+ if (ret) {
+ dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+ goto out_clk;
+ }
+
+ ret = hash_check_hw(device_data);
+ if (ret) {
+ dev_err(dev, "[%s] hash_check_hw() failed!", __func__);
+ goto out_power;
+ }
+
+ if (hash_mode == HASH_MODE_DMA)
+ hash_dma_setup_channel(device_data, dev);
+
+ platform_set_drvdata(pdev, device_data);
+
+ /* Put the new device into the device list... */
+ klist_add_tail(&device_data->list_node, &driver_data.device_list);
+ /* ... and signal that a new device is available. */
+ up(&driver_data.device_allocation);
+
+ ret = ahash_algs_register_all(device_data);
+ if (ret) {
+ dev_err(dev, "[%s] ahash_algs_register_all() "
+ "failed!", __func__);
+ goto out_power;
+ }
+
+ dev_info(dev, "[%s] successfully probed\n", __func__);
+ return 0;
+
+out_power:
+ hash_disable_power(device_data, false);
+
+out_clk:
+ clk_put(device_data->clk);
+
+out_regulator:
+ regulator_put(device_data->regulator);
+
+out_unmap:
+ iounmap(device_data->base);
+
+out_free_mem:
+ release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+ kfree(device_data);
+out:
+ return ret;
+}
+
+/**
+ * ux500_hash_remove - Function that removes the hash device from the platform.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct hash_device_data *device_data;
+ struct device *dev = &pdev->dev;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Try to decrease the number of available devices. */
+ if (down_trylock(&driver_data.device_allocation))
+ return -EBUSY;
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (device_data->current_ctx) {
+ /* The device is busy */
+ spin_unlock(&device_data->ctx_lock);
+ /* Return the device to the pool. */
+ up(&driver_data.device_allocation);
+ return -EBUSY;
+ }
+
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ ahash_algs_unregister_all(device_data);
+
+ if (hash_disable_power(device_data, false))
+ dev_err(dev, "[%s]: hash_disable_power() failed",
+ __func__);
+
+ clk_put(device_data->clk);
+ regulator_put(device_data->regulator);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(device_data);
+
+ return 0;
+}
+
+/**
+ * ux500_hash_shutdown - Function that shutdown the hash device.
+ * @pdev: The platform device
+ */
+static void ux500_hash_shutdown(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ struct hash_device_data *device_data;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return;
+ }
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (!device_data->current_ctx) {
+ if (down_trylock(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+ "Shutting down anyway...", __func__);
+ /**
+ * (Allocate the device)
+ * Need to set this to non-null (dummy) value,
+ * to avoid usage if context switching.
+ */
+ device_data->current_ctx++;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ ahash_algs_unregister_all(device_data);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ if (hash_disable_power(device_data, false))
+ dev_err(&pdev->dev, "[%s] hash_disable_power() failed",
+ __func__);
+}
+
+/**
+ * ux500_hash_suspend - Function that suspends the hash device.
+ * @pdev: The platform device.
+ * @state: -
+ */
+static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct hash_device_data *device_data;
+ struct hash_ctx *temp_ctx = NULL;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (!device_data->current_ctx)
+ device_data->current_ctx++;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (device_data->current_ctx == ++temp_ctx) {
+ if (down_interruptible(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+ "failed", __func__);
+ ret = hash_disable_power(device_data, false);
+
+ } else
+ ret = hash_disable_power(device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: hash_disable_power()", __func__);
+
+ return ret;
+}
+
+/**
+ * ux500_hash_resume - Function that resume the hash device.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct hash_device_data *device_data;
+ struct hash_ctx *temp_ctx = NULL;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (device_data->current_ctx == ++temp_ctx)
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (!device_data->current_ctx)
+ up(&driver_data.device_allocation);
+ else
+ ret = hash_enable_power(device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: hash_enable_power() failed!",
+ __func__);
+
+ return ret;
+}
+
+static struct platform_driver hash_driver = {
+ .probe = ux500_hash_probe,
+ .remove = ux500_hash_remove,
+ .shutdown = ux500_hash_shutdown,
+ .suspend = ux500_hash_suspend,
+ .resume = ux500_hash_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "hash1",
+ }
+};
+
+/**
+ * ux500_hash_mod_init - The kernel module init function.
+ */
+static int __init ux500_hash_mod_init(void)
+{
+ klist_init(&driver_data.device_list, NULL, NULL);
+ /* Initialize the semaphore to 0 devices (locked state) */
+ sema_init(&driver_data.device_allocation, 0);
+
+ return platform_driver_register(&hash_driver);
+}
+
+/**
+ * ux500_hash_mod_fini - The kernel module exit function.
+ */
+static void __exit ux500_hash_mod_fini(void)
+{
+ platform_driver_unregister(&hash_driver);
+ return;
+}
+
+module_init(ux500_hash_mod_init);
+module_exit(ux500_hash_mod_fini);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 HASH engine.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("sha1-all");
+MODULE_ALIAS("sha256-all");
+MODULE_ALIAS("hmac-sha1-all");
+MODULE_ALIAS("hmac-sha256-all");
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 464fa21..f6b0a6e2 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -16,7 +16,7 @@ menuconfig PM_DEVFREQ
is attached to a single device and returns a "representative"
clock frequency of the device, which is also attached
to a device by 1-to-1. The device registering devfreq takes the
- responsiblity to "interpret" the representative frequency and
+ responsibility to "interpret" the representative frequency and
to set its every clock accordingly with the "target" callback
given to devfreq.
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..af75ddd 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_performance_func(struct devfreq *df,
unsigned long *freq)
@@ -25,8 +26,14 @@ static int devfreq_performance_func(struct devfreq *df,
return 0;
}
+static int performance_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_performance = {
.name = "performance",
+ .init = performance_init,
.get_target_freq = devfreq_performance_func,
.no_central_polling = true,
};
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..fec0cdb 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_powersave_func(struct devfreq *df,
unsigned long *freq)
@@ -22,8 +23,14 @@ static int devfreq_powersave_func(struct devfreq *df,
return 0;
}
+static int powersave_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_powersave = {
.name = "powersave",
+ .init = powersave_init,
.get_target_freq = devfreq_powersave_func,
.no_central_polling = true,
};
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 445fdf8..bf0d7e4 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -245,7 +245,9 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
dev_vdbg(chan2dev(&atchan->chan_common),
"descriptor %u complete\n", txd->cookie);
- dma_cookie_complete(txd);
+ /* mark the descriptor as complete for non cyclic cases only */
+ if (!atc_chan_is_cyclic(atchan))
+ dma_cookie_complete(txd);
/* move children to free_list */
list_splice_init(&desc->tx_list, &atchan->free_list);
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index e6f133b..f6e9b57 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -703,7 +703,9 @@ static void ep93xx_dma_tasklet(unsigned long data)
desc = ep93xx_dma_get_active(edmac);
if (desc) {
if (desc->complete) {
- dma_cookie_complete(&desc->txd);
+ /* mark descriptor complete for non cyclic case only */
+ if (!test_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags))
+ dma_cookie_complete(&desc->txd);
list_splice_init(&edmac->active, &list);
}
callback = desc->txd.callback;
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 2ee6e23..fa3fb21 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2322,7 +2322,8 @@ static void pl330_tasklet(unsigned long data)
/* Pick up ripe tomatoes */
list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
if (desc->status == DONE) {
- dma_cookie_complete(&desc->txd);
+ if (pch->cyclic)
+ dma_cookie_complete(&desc->txd);
list_move_tail(&desc->node, &list);
}
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e48ab31..5b73941 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -107,13 +107,13 @@ extern int edac_debug_level;
*
* CPU caches (L1 and L2)
* DMA engines
- * Core CPU swithces
+ * Core CPU switches
* Fabric switch units
* PCIe interface controllers
* other EDAC/ECC type devices that can be monitored for
* errors, etc.
*
- * It allows for a 2 level set of hiearchry. For example:
+ * It allows for a 2 level set of hierarchy. For example:
*
* cache could be composed of L1, L2 and L3 levels of cache.
* Each CPU core would have its own L1 cache, while sharing
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 4b15459..45b8f4b 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -56,7 +56,7 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
*
* The control structure is allocated in complete chunk
* from the OS. It is in turn sub allocated to the
- * various objects that compose the struture
+ * various objects that compose the structure
*
* The structure has a 'nr_instance' array within itself.
* Each instance represents a major component
@@ -118,7 +118,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
/* Calc the 'end' offset past the attributes array */
pvt = edac_align_ptr(&dev_attrib[count], sz_private);
} else {
- /* no attribute array specificed */
+ /* no attribute array specified */
pvt = edac_align_ptr(dev_attrib, sz_private);
}
@@ -394,7 +394,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
/* Reschedule the workq for the next time period to start again
* if the number of msec is for 1 sec, then adjust to the next
- * whole one second to save timers fireing all over the period
+ * whole one second to save timers firing all over the period
* between integral seconds
*/
if (edac_dev->poll_msec == 1000)
@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(edac_device_add_device);
* Remove sysfs entries for specified edac_device structure and
* then remove edac_device structure from global list
*
- * @pdev:
+ * @dev:
* Pointer to 'struct device' representing edac_device
* structure to remove.
*
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 85226cc..7f1dfcc 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -90,7 +90,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
#define MC_MAX_DOD 0x64
/*
- * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * OFFSETS for Device 3 Function 4, as indicated on Xeon 5500 datasheet:
* http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
*/
@@ -101,7 +101,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
#define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff)
#define DIMM0_COR_ERR(r) ((r) & 0x7fff)
-/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+/* OFFSETS for Device 3 Function 2, as indicated on Xeon 5500 datasheet */
#define MC_SSRCONTROL 0x48
#define SSR_MODE_DISABLE 0x00
#define SSR_MODE_ENABLE 0x01
@@ -398,7 +398,7 @@ static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = {
};
/****************************************************************************
- Anciliary status routines
+ Ancillary status routines
****************************************************************************/
/* MC_CONTROL bits */
@@ -1361,7 +1361,7 @@ static int i7core_get_onedevice(struct pci_dev **prev,
dev_descr->dev_id, *prev);
/*
- * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+ * On Xeon 55xx, the Intel QuickPath Arch Generic Non-core regs
* is at addr 8086:2c40, instead of 8086:2c41. So, we need
* to probe for the alternate address in case of failure
*/
@@ -2132,7 +2132,7 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
/*
* get_sdram_scrub_rate This routine convert current scrub rate value
- * into byte/sec bandwidth accourding to
+ * into byte/sec bandwidth according to
* SCRUBINTERVAL formula found in datasheet.
*/
static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index a203536..123204f 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -58,7 +58,7 @@ static int probed;
/*
* FIXME: For now, let's order by device function, as it makes
- * easier for driver's development proccess. This table should be
+ * easier for driver's development process. This table should be
* moved to pci_id.h when submitted upstream
*/
#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */
@@ -375,7 +375,7 @@ static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
/****************************************************************************
- Anciliary status routines
+ Ancillary status routines
****************************************************************************/
static inline int numrank(u32 mtr)
@@ -1430,7 +1430,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
type = "FATAL";
/*
- * According with Table 15-9 of the Intel Archictecture spec vol 3A,
+ * According with Table 15-9 of the Intel Architecture spec vol 3A,
* memory errors should fit in this mask:
* 000f 0000 1mmm cccc (binary)
* where:
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
new file mode 100644
index 0000000..29c5cf8
--- /dev/null
+++ b/drivers/extcon/Kconfig
@@ -0,0 +1,32 @@
+menuconfig EXTCON
+ tristate "External Connector Class (extcon) support"
+ help
+ Say Y here to enable external connector class (extcon) support.
+ This allows monitoring external connectors by userspace
+ via sysfs and uevent and supports external connectors with
+ multiple states; i.e., an extcon that may have multiple
+ cables attached. For example, an external connector of a device
+ may be used to connect an HDMI cable and a AC adaptor, and to
+ host USB ports. Many of 30-pin connectors including PDMI are
+ also good examples.
+
+if EXTCON
+
+comment "Extcon Device Drivers"
+
+config EXTCON_GPIO
+ tristate "GPIO extcon support"
+ depends on GENERIC_GPIO
+ help
+ Say Y here to enable GPIO based extcon support. Note that GPIO
+ extcon supports single state per extcon instance.
+
+config EXTCON_MAX8997
+ tristate "MAX8997 EXTCON Support"
+ depends on MFD_MAX8997
+ help
+ If you say yes here you get support for the MUIC device of
+ Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
+ detector and switch.
+
+endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
new file mode 100644
index 0000000..86020bd
--- /dev/null
+++ b/drivers/extcon/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for external connector class (extcon) devices
+#
+
+obj-$(CONFIG_EXTCON) += extcon_class.o
+obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o
+obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
diff --git a/drivers/misc/max8997-muic.c b/drivers/extcon/extcon-max8997.c
index 19591ea..23416e4 100644
--- a/drivers/misc/max8997-muic.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -1,7 +1,7 @@
/*
- * max8997-muic.c - MAX8997 muic driver for the Maxim 8997
+ * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
*
- * Copyright (C) 2011 Samsung Electrnoics
+ * Copyright (C) 2012 Samsung Electrnoics
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,6 @@
* 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>
@@ -30,6 +25,9 @@
#include <linux/kobject.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
+#include <linux/extcon.h>
+
+#define DEV_NAME "max8997-muic"
/* MAX8997-MUIC STATUS1 register */
#define STATUS1_ADC_SHIFT 0
@@ -95,7 +93,6 @@ static struct max8997_muic_irq muic_irqs[] = {
struct max8997_muic_info {
struct device *dev;
- struct max8997_dev *iodev;
struct i2c_client *muic;
struct max8997_muic_platform_data *muic_pdata;
@@ -106,12 +103,28 @@ struct max8997_muic_info {
int pre_adc;
struct mutex mutex;
+
+ struct extcon_dev *edev;
+};
+
+const char *max8997_extcon_cable[] = {
+ [0] = "USB",
+ [1] = "USB-Host",
+ [2] = "TA",
+ [3] = "Fast-charger",
+ [4] = "Slow-charger",
+ [5] = "Charge-downstream",
+ [6] = "MHL",
+ [7] = "Dock-desk",
+ [7] = "Dock-card",
+ [8] = "JIG",
+
+ NULL,
};
static int max8997_muic_handle_usb(struct max8997_muic_info *info,
enum max8997_muic_usb_type usb_type, bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
if (usb_type == MAX8997_USB_HOST) {
@@ -125,25 +138,25 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
}
}
- if (mdata->usb_callback)
- mdata->usb_callback(usb_type, attached);
+ switch (usb_type) {
+ case MAX8997_USB_HOST:
+ extcon_set_cable_state(info->edev, "USB-Host", attached);
+ break;
+ case MAX8997_USB_DEVICE:
+ extcon_set_cable_state(info->edev, "USB", attached);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
out:
return ret;
}
-static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
- bool attached)
-{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
-
- if (mdata->mhl_callback)
- mdata->mhl_callback(attached);
-}
-
static int max8997_muic_handle_dock(struct max8997_muic_info *info,
int adc, bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to AUDIO */
@@ -157,14 +170,13 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info,
switch (adc) {
case MAX8997_ADC_DESKDOCK:
- if (mdata->deskdock_callback)
- mdata->deskdock_callback(attached);
+ extcon_set_cable_state(info->edev, "Dock-desk", attached);
break;
case MAX8997_ADC_CARDOCK:
- if (mdata->cardock_callback)
- mdata->cardock_callback(attached);
+ extcon_set_cable_state(info->edev, "Dock-card", attached);
break;
default:
+ ret = -EINVAL;
break;
}
out:
@@ -174,7 +186,6 @@ out:
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to UART */
@@ -186,8 +197,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
goto out;
}
- if (mdata->uart_callback)
- mdata->uart_callback(attached);
+ extcon_set_cable_state(info->edev, "JIG", attached);
out:
return ret;
}
@@ -201,7 +211,7 @@ static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
break;
case MAX8997_ADC_MHL:
- max8997_muic_handle_mhl(info, false);
+ extcon_set_cable_state(info->edev, "MHL", false);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
@@ -230,7 +240,7 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
break;
case MAX8997_ADC_MHL:
- max8997_muic_handle_mhl(info, true);
+ extcon_set_cable_state(info->edev, "MHL", true);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
@@ -247,10 +257,40 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
ret = max8997_muic_handle_adc_detach(info);
break;
default:
- break;
+ ret = -EINVAL;
+ goto out;
}
info->pre_adc = adc;
+out:
+ return ret;
+}
+
+static int max8997_muic_handle_charger_type_detach(
+ struct max8997_muic_info *info)
+{
+ int ret = 0;
+
+ switch (info->pre_charger_type) {
+ case MAX8997_CHARGER_TYPE_USB:
+ extcon_set_cable_state(info->edev, "USB", false);
+ break;
+ case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+ extcon_set_cable_state(info->edev, "Charge-downstream", false);
+ break;
+ case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+ extcon_set_cable_state(info->edev, "TA", false);
+ break;
+ case MAX8997_CHARGER_TYPE_500MA:
+ extcon_set_cable_state(info->edev, "Slow-charger", false);
+ break;
+ case MAX8997_CHARGER_TYPE_1A:
+ extcon_set_cable_state(info->edev, "Fast-charger", false);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
return ret;
}
@@ -258,7 +298,6 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
enum max8997_muic_charger_type charger_type)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
u8 adc;
int ret;
@@ -270,30 +309,29 @@ static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
switch (charger_type) {
case MAX8997_CHARGER_TYPE_NONE:
- if (mdata->charger_callback)
- mdata->charger_callback(false, charger_type);
- if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
- max8997_muic_handle_usb(info,
- MAX8997_USB_DEVICE, false);
- }
+ ret = max8997_muic_handle_charger_type_detach(info);
break;
case MAX8997_CHARGER_TYPE_USB:
if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
max8997_muic_handle_usb(info,
MAX8997_USB_DEVICE, true);
}
- if (mdata->charger_callback)
- mdata->charger_callback(true, charger_type);
break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+ extcon_set_cable_state(info->edev, "Charge-downstream", true);
+ break;
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+ extcon_set_cable_state(info->edev, "TA", true);
+ break;
case MAX8997_CHARGER_TYPE_500MA:
+ extcon_set_cable_state(info->edev, "Slow-charger", true);
+ break;
case MAX8997_CHARGER_TYPE_1A:
- if (mdata->charger_callback)
- mdata->charger_callback(true, charger_type);
+ extcon_set_cable_state(info->edev, "Fast-charger", true);
break;
default:
- break;
+ ret = -EINVAL;
+ goto out;
}
info->pre_charger_type = charger_type;
@@ -305,18 +343,17 @@ static void max8997_muic_irq_work(struct work_struct *work)
{
struct max8997_muic_info *info = container_of(work,
struct max8997_muic_info, irq_work);
- struct max8997_platform_data *pdata =
- dev_get_platdata(info->iodev->dev);
- u8 status[3];
+ struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
+ u8 status[2];
u8 adc, chg_type;
- int irq_type = info->irq - pdata->irq_base;
+ int irq_type = info->irq - max8997->irq_base;
int ret;
mutex_lock(&info->mutex);
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
- 3, status);
+ 2, status);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
mutex_unlock(&info->mutex);
@@ -340,8 +377,8 @@ static void max8997_muic_irq_work(struct work_struct *work)
max8997_muic_handle_charger_type(info, chg_type);
break;
default:
- dev_info(info->dev, "misc interrupt: %s occurred\n",
- muic_irqs[irq_type].name);
+ dev_info(info->dev, "misc interrupt: irq %d occurred\n",
+ irq_type);
break;
}
@@ -387,21 +424,10 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info)
max8997_muic_handle_charger_type(info, chg_type);
}
-static void max8997_initialize_device(struct max8997_muic_info *info)
-{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
- int i;
-
- for (i = 0; i < mdata->num_init_data; i++) {
- max8997_write_reg(info->muic, mdata->init_data[i].addr,
- mdata->init_data[i].data);
- }
-}
-
static int __devinit max8997_muic_probe(struct platform_device *pdev)
{
- struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
+ struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
struct max8997_muic_info *info;
int ret, i;
@@ -412,16 +438,8 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev)
goto err_kfree;
}
- if (!pdata->muic_pdata) {
- dev_err(&pdev->dev, "failed to get platform_data\n");
- ret = -EINVAL;
- goto err_pdata;
- }
- info->muic_pdata = pdata->muic_pdata;
-
info->dev = &pdev->dev;
- info->iodev = iodev;
- info->muic = iodev->muic;
+ info->muic = max8997->muic;
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
@@ -440,24 +458,45 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev)
"failed: irq request (IRQ: %d,"
" error :%d)\n",
muic_irq->irq, ret);
-
- for (i = i - 1; i >= 0; i--)
- free_irq(muic_irq->irq, info);
-
goto err_irq;
}
}
+ /* External connector */
+ info->edev = kzalloc(sizeof(struct extcon_dev), GFP_KERNEL);
+ if (!info->edev) {
+ dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+ ret = -ENOMEM;
+ goto err_irq;
+ }
+ info->edev->name = DEV_NAME;
+ info->edev->supported_cable = max8997_extcon_cable;
+ ret = extcon_dev_register(info->edev, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ goto err_extcon;
+ }
+
/* Initialize registers according to platform data */
- max8997_initialize_device(info);
+ if (pdata->muic_pdata) {
+ struct max8997_muic_platform_data *mdata = info->muic_pdata;
+
+ for (i = 0; i < mdata->num_init_data; i++) {
+ max8997_write_reg(info->muic, mdata->init_data[i].addr,
+ mdata->init_data[i].data);
+ }
+ }
/* Initial device detection */
max8997_muic_detect_dev(info);
return ret;
+err_extcon:
+ kfree(info->edev);
err_irq:
-err_pdata:
+ while (--i >= 0)
+ free_irq(pdata->irq_base + muic_irqs[i].irq, info);
kfree(info);
err_kfree:
return ret;
@@ -466,14 +505,15 @@ err_kfree:
static int __devexit max8997_muic_remove(struct platform_device *pdev)
{
struct max8997_muic_info *info = platform_get_drvdata(pdev);
- struct max8997_platform_data *pdata =
- dev_get_platdata(info->iodev->dev);
+ struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
int i;
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
- free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+ free_irq(max8997->irq_base + muic_irqs[i].irq, info);
cancel_work_sync(&info->irq_work);
+ extcon_dev_unregister(info->edev);
+
kfree(info);
return 0;
@@ -481,7 +521,7 @@ static int __devexit max8997_muic_remove(struct platform_device *pdev)
static struct platform_driver max8997_muic_driver = {
.driver = {
- .name = "max8997-muic",
+ .name = DEV_NAME,
.owner = THIS_MODULE,
},
.probe = max8997_muic_probe,
@@ -490,6 +530,6 @@ static struct platform_driver max8997_muic_driver = {
module_platform_driver(max8997_muic_driver);
-MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
+MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
new file mode 100644
index 0000000..f598a70
--- /dev/null
+++ b/drivers/extcon/extcon_class.c
@@ -0,0 +1,832 @@
+/*
+ * drivers/extcon/extcon_class.c
+ *
+ * External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+
+/*
+ * extcon_cable_name suggests the standard cable names for commonly used
+ * cable types.
+ *
+ * However, please do not use extcon_cable_name directly for extcon_dev
+ * struct's supported_cable pointer unless your device really supports
+ * every single port-type of the following cable names. Please choose cable
+ * names that are actually used in your extcon device.
+ */
+const char *extcon_cable_name[] = {
+ [EXTCON_USB] = "USB",
+ [EXTCON_USB_HOST] = "USB-Host",
+ [EXTCON_TA] = "TA",
+ [EXTCON_FAST_CHARGER] = "Fast-charger",
+ [EXTCON_SLOW_CHARGER] = "Slow-charger",
+ [EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream",
+ [EXTCON_HDMI] = "HDMI",
+ [EXTCON_MHL] = "MHL",
+ [EXTCON_DVI] = "DVI",
+ [EXTCON_VGA] = "VGA",
+ [EXTCON_DOCK] = "Dock",
+ [EXTCON_LINE_IN] = "Line-in",
+ [EXTCON_LINE_OUT] = "Line-out",
+ [EXTCON_MIC_IN] = "Microphone",
+ [EXTCON_HEADPHONE_OUT] = "Headphone",
+ [EXTCON_SPDIF_IN] = "SPDIF-in",
+ [EXTCON_SPDIF_OUT] = "SPDIF-out",
+ [EXTCON_VIDEO_IN] = "Video-in",
+ [EXTCON_VIDEO_OUT] = "Video-out",
+ [EXTCON_MECHANICAL] = "Mechanical",
+
+ NULL,
+};
+
+struct class *extcon_class;
+#if defined(CONFIG_ANDROID)
+static struct class_compat *switch_class;
+#endif /* CONFIG_ANDROID */
+
+static LIST_HEAD(extcon_dev_list);
+static DEFINE_MUTEX(extcon_dev_list_lock);
+
+/**
+ * check_mutually_exclusive - Check if new_state violates mutually_exclusive
+ * condition.
+ * @edev: the extcon device
+ * @new_state: new cable attach status for @edev
+ *
+ * Returns 0 if nothing violates. Returns the index + 1 for the first
+ * violated condition.
+ */
+static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
+{
+ int i = 0;
+
+ if (!edev->mutually_exclusive)
+ return 0;
+
+ for (i = 0; edev->mutually_exclusive[i]; i++) {
+ int count = 0, j;
+ u32 correspondants = new_state & edev->mutually_exclusive[i];
+ u32 exp = 1;
+
+ for (j = 0; j < 32; j++) {
+ if (exp & correspondants)
+ count++;
+ if (count > 1)
+ return i + 1;
+ exp <<= 1;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int i, count = 0;
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ if (edev->print_state) {
+ int ret = edev->print_state(edev, buf);
+
+ if (ret >= 0)
+ return ret;
+ /* Use default if failed */
+ }
+
+ if (edev->max_supported == 0)
+ return sprintf(buf, "%u\n", edev->state);
+
+ for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
+ if (!edev->supported_cable[i])
+ break;
+ count += sprintf(buf + count, "%s=%d\n",
+ edev->supported_cable[i],
+ !!(edev->state & (1 << i)));
+ }
+
+ return count;
+}
+
+int extcon_set_state(struct extcon_dev *edev, u32 state);
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 state;
+ ssize_t ret = 0;
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ ret = sscanf(buf, "0x%x", &state);
+ if (ret == 0)
+ ret = -EINVAL;
+ else
+ ret = extcon_set_state(edev, state);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ /* Optional callback given by the user */
+ if (edev->print_name) {
+ int ret = edev->print_name(edev, buf);
+ if (ret >= 0)
+ return ret;
+ }
+
+ return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+static ssize_t cable_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_name);
+
+ return sprintf(buf, "%s\n",
+ cable->edev->supported_cable[cable->cable_index]);
+}
+
+static ssize_t cable_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_state);
+
+ return sprintf(buf, "%d\n",
+ extcon_get_cable_state_(cable->edev,
+ cable->cable_index));
+}
+
+static ssize_t cable_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_state);
+ int ret, state;
+
+ ret = sscanf(buf, "%d", &state);
+ if (ret == 0)
+ ret = -EINVAL;
+ else
+ ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
+ state);
+
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+/**
+ * extcon_update_state() - Update the cable attach states of the extcon device
+ * only for the masked bits.
+ * @edev: the extcon device
+ * @mask: the bit mask to designate updated bits.
+ * @state: new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ *
+ * Note that the notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+{
+ char name_buf[120];
+ char state_buf[120];
+ char *prop_buf;
+ char *envp[3];
+ int env_offset = 0;
+ int length;
+ unsigned long flags;
+
+ spin_lock_irqsave(&edev->lock, flags);
+
+ if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+ u32 old_state = edev->state;
+
+ if (check_mutually_exclusive(edev, (edev->state & ~mask) |
+ (state & mask))) {
+ spin_unlock_irqrestore(&edev->lock, flags);
+ return -EPERM;
+ }
+
+ edev->state &= ~mask;
+ edev->state |= state & mask;
+
+ raw_notifier_call_chain(&edev->nh, old_state, edev);
+
+ /* This could be in interrupt handler */
+ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+ if (prop_buf) {
+ length = name_show(edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(name_buf, sizeof(name_buf),
+ "NAME=%s", prop_buf);
+ envp[env_offset++] = name_buf;
+ }
+ length = state_show(edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(state_buf, sizeof(state_buf),
+ "STATE=%s", prop_buf);
+ envp[env_offset++] = state_buf;
+ }
+ envp[env_offset] = NULL;
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
+
+ kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+ free_page((unsigned long)prop_buf);
+ } else {
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
+
+ dev_err(edev->dev, "out of memory in extcon_set_state\n");
+ kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+ }
+ } else {
+ /* No changes */
+ spin_unlock_irqrestore(&edev->lock, flags);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(extcon_update_state);
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev: the extcon device
+ * @state: new cable attach status for @edev
+ *
+ * Note that notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+ return extcon_update_state(edev, 0xffffffff, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+/**
+ * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name to be searched.
+ *
+ * Note that accessing a cable state based on cable_index is faster than
+ * cable_name because using cable_name induces a loop with strncmp().
+ * Thus, when get/set_cable_state is repeatedly used, using cable_index
+ * is recommended.
+ */
+int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+{
+ int i;
+
+ if (edev->supported_cable) {
+ for (i = 0; edev->supported_cable[i]; i++) {
+ if (!strncmp(edev->supported_cable[i],
+ cable_name, CABLE_NAME_MAX))
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(extcon_find_cable_index);
+
+/**
+ * extcon_get_cable_state_() - Get the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @index: cable index that can be retrieved by extcon_find_cable_index().
+ */
+int extcon_get_cable_state_(struct extcon_dev *edev, int index)
+{
+ if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ return -EINVAL;
+
+ return !!(edev->state & (1 << index));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Get the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name.
+ *
+ * Note that this is slower than extcon_get_cable_state_.
+ */
+int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
+{
+ return extcon_get_cable_state_(edev, extcon_find_cable_index
+ (edev, cable_name));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state);
+
+/**
+ * extcon_get_cable_state_() - Set the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @index: cable index that can be retrieved by extcon_find_cable_index().
+ * @cable_state: the new cable status. The default semantics is
+ * true: attached / false: detached.
+ */
+int extcon_set_cable_state_(struct extcon_dev *edev,
+ int index, bool cable_state)
+{
+ u32 state;
+
+ if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ return -EINVAL;
+
+ state = cable_state ? (1 << index) : 0;
+ return extcon_update_state(edev, 1 << index, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Set the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name.
+ * @cable_state: the new cable status. The default semantics is
+ * true: attached / false: detached.
+ *
+ * Note that this is slower than extcon_set_cable_state_.
+ */
+int extcon_set_cable_state(struct extcon_dev *edev,
+ const char *cable_name, bool cable_state)
+{
+ return extcon_set_cable_state_(edev, extcon_find_cable_index
+ (edev, cable_name), cable_state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state);
+
+/**
+ * extcon_get_extcon_dev() - Get the extcon device instance from the name
+ * @extcon_name: The extcon name provided with extcon_dev_register()
+ */
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+ struct extcon_dev *sd;
+
+ mutex_lock(&extcon_dev_list_lock);
+ list_for_each_entry(sd, &extcon_dev_list, entry) {
+ if (!strcmp(sd->name, extcon_name))
+ goto out;
+ }
+ sd = NULL;
+out:
+ mutex_unlock(&extcon_dev_list_lock);
+ return sd;
+}
+EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
+
+static int _call_per_cable(struct notifier_block *nb, unsigned long val,
+ void *ptr)
+{
+ struct extcon_specific_cable_nb *obj = container_of(nb,
+ struct extcon_specific_cable_nb, internal_nb);
+ struct extcon_dev *edev = ptr;
+
+ if ((val & (1 << obj->cable_index)) !=
+ (edev->state & (1 << obj->cable_index))) {
+ bool cable_state = true;
+
+ obj->previous_value = val;
+
+ if (val & (1 << obj->cable_index))
+ cable_state = false;
+
+ return obj->user_nb->notifier_call(obj->user_nb,
+ cable_state, ptr);
+ }
+
+ return NOTIFY_OK;
+}
+
+/**
+ * extcon_register_interest() - Register a notifier for a state change of a
+ * specific cable, not a entier set of cables of a
+ * extcon device.
+ * @obj: an empty extcon_specific_cable_nb object to be returned.
+ * @extcon_name: the name of extcon device.
+ * @cable_name: the target cable name.
+ * @nb: the notifier block to get notified.
+ *
+ * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
+ * the struct for you.
+ *
+ * extcon_register_interest is a helper function for those who want to get
+ * notification for a single specific cable's status change. If a user wants
+ * to get notification for any changes of all cables of a extcon device,
+ * he/she should use the general extcon_register_notifier().
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+ const char *extcon_name, const char *cable_name,
+ struct notifier_block *nb)
+{
+ if (!obj || !extcon_name || !cable_name || !nb)
+ return -EINVAL;
+
+ obj->edev = extcon_get_extcon_dev(extcon_name);
+ if (!obj->edev)
+ return -ENODEV;
+
+ obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
+ if (obj->cable_index < 0)
+ return -ENODEV;
+
+ obj->user_nb = nb;
+
+ obj->internal_nb.notifier_call = _call_per_cable;
+
+ return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_unregister_interest() - Unregister the notifier registered by
+ * extcon_register_interest().
+ * @obj: the extcon_specific_cable_nb object returned by
+ * extcon_register_interest().
+ */
+int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
+{
+ if (!obj)
+ return -EINVAL;
+
+ return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_register_notifier() - Register a notifee to get notified by
+ * any attach status changes from the extcon.
+ * @edev: the extcon device.
+ * @nb: a notifier block to be registered.
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_register_notifier);
+
+/**
+ * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
+ * @edev: the extcon device.
+ * @nb: a registered notifier block to be unregistered.
+ */
+int extcon_unregister_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return raw_notifier_chain_unregister(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
+
+static struct device_attribute extcon_attrs[] = {
+ __ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
+ __ATTR_RO(name),
+ __ATTR_NULL,
+};
+
+static int create_extcon_class(void)
+{
+ if (!extcon_class) {
+ extcon_class = class_create(THIS_MODULE, "extcon");
+ if (IS_ERR(extcon_class))
+ return PTR_ERR(extcon_class);
+ extcon_class->dev_attrs = extcon_attrs;
+
+#if defined(CONFIG_ANDROID)
+ switch_class = class_compat_register("switch");
+ if (WARN(!switch_class, "cannot allocate"))
+ return -ENOMEM;
+#endif /* CONFIG_ANDROID */
+ }
+
+ return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+ mutex_lock(&extcon_dev_list_lock);
+ list_del(&edev->entry);
+ mutex_unlock(&extcon_dev_list_lock);
+
+ if (!skip && get_device(edev->dev)) {
+ int index;
+
+ if (edev->mutually_exclusive && edev->max_supported) {
+ for (index = 0; edev->mutually_exclusive[index];
+ index++)
+ kfree(edev->d_attrs_muex[index].attr.name);
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ }
+
+ for (index = 0; index < edev->max_supported; index++)
+ kfree(edev->cables[index].attr_g.name);
+
+ if (edev->max_supported) {
+ kfree(edev->extcon_dev_type.groups);
+ kfree(edev->cables);
+ }
+
+ device_unregister(edev->dev);
+ put_device(edev->dev);
+ }
+
+ kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ extcon_cleanup(edev, true);
+}
+
+static const char *muex_name = "mutually_exclusive";
+static void dummy_sysfs_dev_release(struct device *dev)
+{
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev : the new extcon device (should be allocated before calling)
+ * @dev : the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+ int ret, index = 0;
+
+ if (!extcon_class) {
+ ret = create_extcon_class();
+ if (ret < 0)
+ return ret;
+ }
+
+ if (edev->supported_cable) {
+ /* Get size of array */
+ for (index = 0; edev->supported_cable[index]; index++)
+ ;
+ edev->max_supported = index;
+ } else {
+ edev->max_supported = 0;
+ }
+
+ if (index > SUPPORTED_CABLE_MAX) {
+ dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+ return -EINVAL;
+ }
+
+ edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!edev->dev)
+ return -ENOMEM;
+ edev->dev->parent = dev;
+ edev->dev->class = extcon_class;
+ edev->dev->release = extcon_dev_release;
+
+ dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+
+ if (edev->max_supported) {
+ char buf[10];
+ char *str;
+ struct extcon_cable *cable;
+
+ edev->cables = kzalloc(sizeof(struct extcon_cable) *
+ edev->max_supported, GFP_KERNEL);
+ if (!edev->cables) {
+ ret = -ENOMEM;
+ goto err_sysfs_alloc;
+ }
+ for (index = 0; index < edev->max_supported; index++) {
+ cable = &edev->cables[index];
+
+ snprintf(buf, 10, "cable.%d", index);
+ str = kzalloc(sizeof(char) * (strlen(buf) + 1),
+ GFP_KERNEL);
+ if (!str) {
+ for (index--; index >= 0; index--) {
+ cable = &edev->cables[index];
+ kfree(cable->attr_g.name);
+ }
+ ret = -ENOMEM;
+
+ goto err_alloc_cables;
+ }
+ strcpy(str, buf);
+
+ cable->edev = edev;
+ cable->cable_index = index;
+ cable->attrs[0] = &cable->attr_name.attr;
+ cable->attrs[1] = &cable->attr_state.attr;
+ cable->attrs[2] = NULL;
+ cable->attr_g.name = str;
+ cable->attr_g.attrs = cable->attrs;
+
+ cable->attr_name.attr.name = "name";
+ cable->attr_name.attr.mode = 0444;
+ cable->attr_name.show = cable_name_show;
+
+ cable->attr_state.attr.name = "state";
+ cable->attr_state.attr.mode = 0644;
+ cable->attr_state.show = cable_state_show;
+ cable->attr_state.store = cable_state_store;
+ }
+ }
+
+ if (edev->max_supported && edev->mutually_exclusive) {
+ char buf[80];
+ char *name;
+
+ /* Count the size of mutually_exclusive array */
+ for (index = 0; edev->mutually_exclusive[index]; index++)
+ ;
+
+ edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
+ (index + 1), GFP_KERNEL);
+ if (!edev->attrs_muex) {
+ ret = -ENOMEM;
+ goto err_muex;
+ }
+
+ edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
+ index, GFP_KERNEL);
+ if (!edev->d_attrs_muex) {
+ ret = -ENOMEM;
+ kfree(edev->attrs_muex);
+ goto err_muex;
+ }
+
+ for (index = 0; edev->mutually_exclusive[index]; index++) {
+ sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
+ name = kzalloc(sizeof(char) * (strlen(buf) + 1),
+ GFP_KERNEL);
+ if (!name) {
+ for (index--; index >= 0; index--) {
+ kfree(edev->d_attrs_muex[index].attr.
+ name);
+ }
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ ret = -ENOMEM;
+ goto err_muex;
+ }
+ strcpy(name, buf);
+ edev->d_attrs_muex[index].attr.name = name;
+ edev->d_attrs_muex[index].attr.mode = 0000;
+ edev->attrs_muex[index] = &edev->d_attrs_muex[index]
+ .attr;
+ }
+ edev->attr_g_muex.name = muex_name;
+ edev->attr_g_muex.attrs = edev->attrs_muex;
+
+ }
+
+ if (edev->max_supported) {
+ edev->extcon_dev_type.groups =
+ kzalloc(sizeof(struct attribute_group *) *
+ (edev->max_supported + 2), GFP_KERNEL);
+ if (!edev->extcon_dev_type.groups) {
+ ret = -ENOMEM;
+ goto err_alloc_groups;
+ }
+
+ edev->extcon_dev_type.name = dev_name(edev->dev);
+ edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+ for (index = 0; index < edev->max_supported; index++)
+ edev->extcon_dev_type.groups[index] =
+ &edev->cables[index].attr_g;
+ if (edev->mutually_exclusive)
+ edev->extcon_dev_type.groups[index] =
+ &edev->attr_g_muex;
+
+ edev->dev->type = &edev->extcon_dev_type;
+ }
+
+ ret = device_register(edev->dev);
+ if (ret) {
+ put_device(edev->dev);
+ goto err_dev;
+ }
+#if defined(CONFIG_ANDROID)
+ if (switch_class)
+ ret = class_compat_create_link(switch_class, edev->dev,
+ dev);
+#endif /* CONFIG_ANDROID */
+
+ spin_lock_init(&edev->lock);
+
+ RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+
+ dev_set_drvdata(edev->dev, edev);
+ edev->state = 0;
+
+ mutex_lock(&extcon_dev_list_lock);
+ list_add(&edev->entry, &extcon_dev_list);
+ mutex_unlock(&extcon_dev_list_lock);
+
+ return 0;
+
+err_dev:
+ if (edev->max_supported)
+ kfree(edev->extcon_dev_type.groups);
+err_alloc_groups:
+ if (edev->max_supported && edev->mutually_exclusive) {
+ for (index = 0; edev->mutually_exclusive[index]; index++)
+ kfree(edev->d_attrs_muex[index].attr.name);
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ }
+err_muex:
+ for (index = 0; index < edev->max_supported; index++)
+ kfree(edev->cables[index].attr_g.name);
+err_alloc_cables:
+ if (edev->max_supported)
+ kfree(edev->cables);
+err_sysfs_alloc:
+ kfree(edev->dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev: the extcon device instance to be unregitered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+ extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+ return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+ class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c
new file mode 100644
index 0000000..fe7a07b
--- /dev/null
+++ b/drivers/extcon/extcon_gpio.c
@@ -0,0 +1,169 @@
+/*
+ * drivers/extcon/extcon_gpio.c
+ *
+ * Single-state GPIO extcon driver based on extcon class
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
+ * (originally switch class is supported)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/extcon.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/extcon/extcon_gpio.h>
+
+struct gpio_extcon_data {
+ struct extcon_dev edev;
+ unsigned gpio;
+ const char *state_on;
+ const char *state_off;
+ int irq;
+ struct delayed_work work;
+ unsigned long debounce_jiffies;
+};
+
+static void gpio_extcon_work(struct work_struct *work)
+{
+ int state;
+ struct gpio_extcon_data *data =
+ container_of(to_delayed_work(work), struct gpio_extcon_data,
+ work);
+
+ state = gpio_get_value(data->gpio);
+ extcon_set_state(&data->edev, state);
+}
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_extcon_data *extcon_data = dev_id;
+
+ schedule_delayed_work(&extcon_data->work,
+ extcon_data->debounce_jiffies);
+ return IRQ_HANDLED;
+}
+
+static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
+{
+ struct gpio_extcon_data *extcon_data =
+ container_of(edev, struct gpio_extcon_data, edev);
+ const char *state;
+ if (extcon_get_state(edev))
+ state = extcon_data->state_on;
+ else
+ state = extcon_data->state_off;
+
+ if (state)
+ return sprintf(buf, "%s\n", state);
+ return -EINVAL;
+}
+
+static int __devinit gpio_extcon_probe(struct platform_device *pdev)
+{
+ struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_extcon_data *extcon_data;
+ int ret = 0;
+
+ if (!pdata)
+ return -EBUSY;
+ if (!pdata->irq_flags) {
+ dev_err(&pdev->dev, "IRQ flag is not specified.\n");
+ return -EINVAL;
+ }
+
+ extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
+ GFP_KERNEL);
+ if (!extcon_data)
+ return -ENOMEM;
+
+ extcon_data->edev.name = pdata->name;
+ extcon_data->gpio = pdata->gpio;
+ extcon_data->state_on = pdata->state_on;
+ extcon_data->state_off = pdata->state_off;
+ if (pdata->state_on && pdata->state_off)
+ extcon_data->edev.print_state = extcon_gpio_print_state;
+ extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
+
+ ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
+ if (ret < 0)
+ goto err_extcon_dev_register;
+
+ ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
+ if (ret < 0)
+ goto err_request_gpio;
+
+ INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
+
+ extcon_data->irq = gpio_to_irq(extcon_data->gpio);
+ if (extcon_data->irq < 0) {
+ ret = extcon_data->irq;
+ goto err_detect_irq_num_failed;
+ }
+
+ ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
+ pdata->irq_flags, pdev->name,
+ extcon_data);
+ if (ret < 0)
+ goto err_request_irq;
+
+ /* Perform initial detection */
+ gpio_extcon_work(&extcon_data->work.work);
+
+ return 0;
+
+err_request_irq:
+err_detect_irq_num_failed:
+ gpio_free(extcon_data->gpio);
+err_request_gpio:
+ extcon_dev_unregister(&extcon_data->edev);
+err_extcon_dev_register:
+ devm_kfree(&pdev->dev, extcon_data);
+
+ return ret;
+}
+
+static int __devexit gpio_extcon_remove(struct platform_device *pdev)
+{
+ struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&extcon_data->work);
+ gpio_free(extcon_data->gpio);
+ extcon_dev_unregister(&extcon_data->edev);
+ devm_kfree(&pdev->dev, extcon_data);
+
+ return 0;
+}
+
+static struct platform_driver gpio_extcon_driver = {
+ .probe = gpio_extcon_probe,
+ .remove = __devexit_p(gpio_extcon_remove),
+ .driver = {
+ .name = "extcon-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(gpio_extcon_driver);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_DESCRIPTION("GPIO extcon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index cc595eb..f5552b3 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -676,6 +676,7 @@ void fw_card_release(struct kref *kref)
complete(&card->done);
}
+EXPORT_SYMBOL_GPL(fw_card_release);
void fw_core_remove_card(struct fw_card *card)
{
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index dea2dcc..db8a965 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,15 @@ void fw_send_response(struct fw_card *card,
}
EXPORT_SYMBOL(fw_send_response);
+/**
+ * fw_get_request_speed() - returns speed at which the @request was received
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+ return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
static void handle_exclusive_region_request(struct fw_card *card,
struct fw_packet *p,
struct fw_request *request,
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 9047f55..b5a2f61 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -120,21 +120,6 @@ int fw_compute_block_crc(__be32 *block);
void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
- kref_get(&card->kref);
-
- return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
- kref_put(&card->kref, fw_card_release);
-}
-
-
/* -cdev */
extern const struct file_operations fw_device_ops;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e03653d..eb80ba3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -91,6 +91,12 @@ config GPIO_IT8761E
help
Say yes here to support GPIO functionality of IT8761E super I/O chip.
+config GPIO_EM
+ tristate "Emma Mobile GPIO"
+ depends on ARM
+ help
+ Say yes here to support GPIO on Renesas Emma Mobile SoCs.
+
config GPIO_EP93XX
def_bool y
depends on ARCH_EP93XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 007f54b..708ffb2 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
@@ -36,7 +37,6 @@ obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
-obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o
obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 3dd2939..8950f62 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -83,8 +83,7 @@ EXPORT_SYMBOL(devm_gpio_request);
void devm_gpio_free(struct device *dev, unsigned int gpio)
{
- WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match,
+ WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
&gpio));
- gpio_free(gpio);
}
EXPORT_SYMBOL(devm_gpio_free);
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
new file mode 100644
index 0000000..150d976
--- /dev/null
+++ b/drivers/gpio/gpio-em.c
@@ -0,0 +1,418 @@
+/*
+ * Emma Mobile GPIO Support - GIO
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-em.h>
+
+struct em_gio_priv {
+ void __iomem *base0;
+ void __iomem *base1;
+ unsigned int irq_base;
+ spinlock_t sense_lock;
+ struct platform_device *pdev;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+};
+
+#define GIO_E1 0x00
+#define GIO_E0 0x04
+#define GIO_EM 0x04
+#define GIO_OL 0x08
+#define GIO_OH 0x0c
+#define GIO_I 0x10
+#define GIO_IIA 0x14
+#define GIO_IEN 0x18
+#define GIO_IDS 0x1c
+#define GIO_IIM 0x1c
+#define GIO_RAW 0x20
+#define GIO_MST 0x24
+#define GIO_IIR 0x28
+
+#define GIO_IDT0 0x40
+#define GIO_IDT1 0x44
+#define GIO_IDT2 0x48
+#define GIO_IDT3 0x4c
+#define GIO_RAWBL 0x50
+#define GIO_RAWBH 0x54
+#define GIO_IRBL 0x58
+#define GIO_IRBH 0x5c
+
+#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
+
+static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
+{
+ if (offs < GIO_IDT0)
+ return ioread32(p->base0 + offs);
+ else
+ return ioread32(p->base1 + (offs - GIO_IDT0));
+}
+
+static inline void em_gio_write(struct em_gio_priv *p, int offs,
+ unsigned long value)
+{
+ if (offs < GIO_IDT0)
+ iowrite32(value, p->base0 + offs);
+ else
+ iowrite32(value, p->base1 + (offs - GIO_IDT0));
+}
+
+static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
+{
+ struct irq_chip *chip = irq_data_get_irq_chip(d);
+ return container_of(chip, struct em_gio_priv, irq_chip);
+}
+
+static void em_gio_irq_disable(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_to_priv(d);
+
+ em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
+}
+
+static void em_gio_irq_enable(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_to_priv(d);
+
+ em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
+}
+
+#define GIO_ASYNC(x) (x + 8)
+
+static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
+ [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
+ [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
+ [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
+ [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
+};
+
+static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ struct em_gio_priv *p = irq_to_priv(d);
+ unsigned int reg, offset, shift;
+ unsigned long flags;
+ unsigned long tmp;
+
+ if (!value)
+ return -EINVAL;
+
+ offset = irqd_to_hwirq(d);
+
+ pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
+
+ /* 8 x 4 bit fields in 4 IDT registers */
+ reg = GIO_IDT(offset >> 3);
+ shift = (offset & 0x07) << 4;
+
+ spin_lock_irqsave(&p->sense_lock, flags);
+
+ /* disable the interrupt in IIA */
+ tmp = em_gio_read(p, GIO_IIA);
+ tmp &= ~BIT(offset);
+ em_gio_write(p, GIO_IIA, tmp);
+
+ /* change the sense setting in IDT */
+ tmp = em_gio_read(p, reg);
+ tmp &= ~(0xf << shift);
+ tmp |= value << shift;
+ em_gio_write(p, reg, tmp);
+
+ /* clear pending interrupts */
+ em_gio_write(p, GIO_IIR, BIT(offset));
+
+ /* enable the interrupt in IIA */
+ tmp = em_gio_read(p, GIO_IIA);
+ tmp |= BIT(offset);
+ em_gio_write(p, GIO_IIA, tmp);
+
+ spin_unlock_irqrestore(&p->sense_lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
+{
+ struct em_gio_priv *p = dev_id;
+ unsigned long pending;
+ unsigned int offset, irqs_handled = 0;
+
+ while ((pending = em_gio_read(p, GIO_MST))) {
+ offset = __ffs(pending);
+ em_gio_write(p, GIO_IIR, BIT(offset));
+ generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+ irqs_handled++;
+ }
+
+ return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
+{
+ return container_of(chip, struct em_gio_priv, gpio_chip);
+}
+
+static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
+ return 0;
+}
+
+static int em_gio_get(struct gpio_chip *chip, unsigned offset)
+{
+ return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
+}
+
+static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
+ unsigned shift, int value)
+{
+ /* upper 16 bits contains mask and lower 16 actual value */
+ em_gio_write(gpio_to_priv(chip), reg,
+ (1 << (shift + 16)) | (value << shift));
+}
+
+static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ /* output is split into two registers */
+ if (offset < 16)
+ __em_gio_set(chip, GIO_OL, offset, value);
+ else
+ __em_gio_set(chip, GIO_OH, offset - 16, value);
+}
+
+static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ em_gio_set(chip, offset, value);
+ em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
+ return 0;
+}
+
+static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
+}
+
+static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct em_gio_priv *p = h->host_data;
+
+ pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
+
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops em_gio_irq_domain_ops = {
+ .map = em_gio_irq_domain_map,
+};
+
+static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
+{
+ struct platform_device *pdev = p->pdev;
+ struct gpio_em_config *pdata = pdev->dev.platform_data;
+
+ p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
+ pdata->number_of_pins, numa_node_id());
+ if (IS_ERR_VALUE(p->irq_base)) {
+ dev_err(&pdev->dev, "cannot get irq_desc\n");
+ return -ENXIO;
+ }
+ pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
+ pdata->gpio_base, pdata->number_of_pins, p->irq_base);
+
+ p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
+ pdata->number_of_pins,
+ p->irq_base, 0,
+ &em_gio_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ irq_free_descs(p->irq_base, pdata->number_of_pins);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
+{
+ struct gpio_em_config *pdata = p->pdev->dev.platform_data;
+
+ irq_free_descs(p->irq_base, pdata->number_of_pins);
+ /* FIXME: irq domain wants to be freed! */
+}
+
+static int __devinit em_gio_probe(struct platform_device *pdev)
+{
+ struct gpio_em_config *pdata = pdev->dev.platform_data;
+ struct em_gio_priv *p;
+ struct resource *io[2], *irq[2];
+ struct gpio_chip *gpio_chip;
+ struct irq_chip *irq_chip;
+ const char *name = dev_name(&pdev->dev);
+ int ret;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+ spin_lock_init(&p->sense_lock);
+
+ io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
+ dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
+ if (!p->base0) {
+ dev_err(&pdev->dev, "failed to remap low I/O memory\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
+ p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
+ if (!p->base1) {
+ dev_err(&pdev->dev, "failed to remap high I/O memory\n");
+ ret = -ENXIO;
+ goto err2;
+ }
+
+ gpio_chip = &p->gpio_chip;
+ gpio_chip->direction_input = em_gio_direction_input;
+ gpio_chip->get = em_gio_get;
+ gpio_chip->direction_output = em_gio_direction_output;
+ gpio_chip->set = em_gio_set;
+ gpio_chip->to_irq = em_gio_to_irq;
+ gpio_chip->label = name;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->base = pdata->gpio_base;
+ gpio_chip->ngpio = pdata->number_of_pins;
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ irq_chip->irq_mask = em_gio_irq_disable;
+ irq_chip->irq_unmask = em_gio_irq_enable;
+ irq_chip->irq_enable = em_gio_irq_enable;
+ irq_chip->irq_disable = em_gio_irq_disable;
+ irq_chip->irq_set_type = em_gio_irq_set_type;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+
+ ret = em_gio_irq_domain_init(p);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ goto err3;
+ }
+
+ if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+ goto err4;
+ }
+
+ if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
+ dev_err(&pdev->dev, "failed to request high IRQ\n");
+ ret = -ENOENT;
+ goto err5;
+ }
+
+ ret = gpiochip_add(gpio_chip);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add GPIO controller\n");
+ goto err6;
+ }
+ return 0;
+
+err6:
+ free_irq(irq[1]->start, pdev);
+err5:
+ free_irq(irq[0]->start, pdev);
+err4:
+ em_gio_irq_domain_cleanup(p);
+err3:
+ iounmap(p->base1);
+err2:
+ iounmap(p->base0);
+err1:
+ kfree(p);
+err0:
+ return ret;
+}
+
+static int __devexit em_gio_remove(struct platform_device *pdev)
+{
+ struct em_gio_priv *p = platform_get_drvdata(pdev);
+ struct resource *irq[2];
+ int ret;
+
+ ret = gpiochip_remove(&p->gpio_chip);
+ if (ret)
+ return ret;
+
+ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ free_irq(irq[1]->start, pdev);
+ free_irq(irq[0]->start, pdev);
+ em_gio_irq_domain_cleanup(p);
+ iounmap(p->base1);
+ iounmap(p->base0);
+ kfree(p);
+ return 0;
+}
+
+static struct platform_driver em_gio_device_driver = {
+ .probe = em_gio_probe,
+ .remove = __devexit_p(em_gio_remove),
+ .driver = {
+ .name = "em_gio",
+ }
+};
+
+module_platform_driver(em_gio_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index fc3ace3..58a6a63 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -11,13 +11,17 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/slab.h>
@@ -56,6 +60,10 @@
int pxa_last_gpio;
+#ifdef CONFIG_OF
+static struct irq_domain *domain;
+#endif
+
struct pxa_gpio_chip {
struct gpio_chip chip;
void __iomem *regbase;
@@ -81,7 +89,6 @@ enum {
PXA3XX_GPIO,
PXA93X_GPIO,
MMP_GPIO = 0x10,
- MMP2_GPIO,
};
static DEFINE_SPINLOCK(gpio_lock);
@@ -475,22 +482,92 @@ static int pxa_gpio_nums(void)
gpio_type = MMP_GPIO;
} else if (cpu_is_mmp2()) {
count = 191;
- gpio_type = MMP2_GPIO;
+ gpio_type = MMP_GPIO;
}
#endif /* CONFIG_ARCH_MMP */
return count;
}
+static struct of_device_id pxa_gpio_dt_ids[] = {
+ { .compatible = "mrvl,pxa-gpio" },
+ { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+ {}
+};
+
+static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ return 0;
+}
+
+const struct irq_domain_ops pxa_irq_domain_ops = {
+ .map = pxa_irq_domain_map,
+};
+
+#ifdef CONFIG_OF
+static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
+{
+ int ret, nr_banks, nr_gpios, irq_base;
+ struct device_node *prev, *next, *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -EFAULT;
+ }
+ gpio_type = (int)of_id->data;
+
+ next = of_get_next_child(np, NULL);
+ prev = next;
+ if (!next) {
+ dev_err(&pdev->dev, "Failed to find child gpio node\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ for (nr_banks = 1; ; nr_banks++) {
+ next = of_get_next_child(np, prev);
+ if (!next)
+ break;
+ prev = next;
+ }
+ of_node_put(prev);
+ nr_gpios = nr_banks << 5;
+ pxa_last_gpio = nr_gpios - 1;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ goto err;
+ }
+ domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
+ &pxa_irq_domain_ops, NULL);
+ return 0;
+err:
+ iounmap(gpio_reg_base);
+ return ret;
+}
+#else
+#define pxa_gpio_probe_dt(pdev) (-1)
+#endif
+
static int __devinit pxa_gpio_probe(struct platform_device *pdev)
{
struct pxa_gpio_chip *c;
struct resource *res;
struct clk *clk;
struct pxa_gpio_platform_data *info;
- int gpio, irq, ret;
+ int gpio, irq, ret, use_of = 0;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
- pxa_last_gpio = pxa_gpio_nums();
+ ret = pxa_gpio_probe_dt(pdev);
+ if (ret < 0)
+ pxa_last_gpio = pxa_gpio_nums();
+ else
+ use_of = 1;
if (!pxa_last_gpio)
return -EINVAL;
@@ -545,25 +622,27 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
}
+ if (!use_of) {
#ifdef CONFIG_ARCH_PXA
- irq = gpio_to_irq(0);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
-
- irq = gpio_to_irq(1);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
-#endif
+ irq = gpio_to_irq(0);
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
- for (irq = gpio_to_irq(gpio_offset);
- irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq = gpio_to_irq(1);
irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
+#endif
+
+ for (irq = gpio_to_irq(gpio_offset);
+ irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
}
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
@@ -574,6 +653,7 @@ static struct platform_driver pxa_gpio_driver = {
.probe = pxa_gpio_probe,
.driver = {
.name = "pxa-gpio",
+ .of_match_table = pxa_gpio_dt_ids,
},
};
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 12f349b3..dc5184d 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -26,10 +26,10 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/mach/irq.h>
-#include <mach/gpio-tegra.h>
#include <mach/iomap.h>
#include <mach/suspend.h>
@@ -108,18 +108,29 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
tegra_gpio_writel(val, reg);
}
-void tegra_gpio_enable(int gpio)
+static void tegra_gpio_enable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
}
EXPORT_SYMBOL_GPL(tegra_gpio_enable);
-void tegra_gpio_disable(int gpio)
+static void tegra_gpio_disable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
}
EXPORT_SYMBOL_GPL(tegra_gpio_disable);
+int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(offset);
+}
+
+void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(offset);
+ tegra_gpio_disable(offset);
+}
+
static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
@@ -133,6 +144,7 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -141,6 +153,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
{
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -151,13 +164,14 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
static struct gpio_chip tegra_gpio_chip = {
.label = "tegra-gpio",
+ .request = tegra_gpio_request,
+ .free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.get = tegra_gpio_get,
.direction_output = tegra_gpio_direction_output,
.set = tegra_gpio_set,
.to_irq = tegra_gpio_to_irq,
.base = 0,
- .ngpio = TEGRA_NR_GPIOS,
};
static void tegra_gpio_irq_ack(struct irq_data *d)
@@ -224,6 +238,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
+ tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
+ tegra_gpio_enable(gpio);
+
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
__irq_set_handler_locked(d->irq, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -490,20 +507,6 @@ static int __init tegra_gpio_init(void)
}
postcore_initcall(tegra_gpio_init);
-void tegra_gpio_config(struct tegra_gpio_table *table, int num)
-{
- int i;
-
- for (i = 0; i < num; i++) {
- int gpio = table[i].gpio;
-
- if (table[i].enable)
- tegra_gpio_enable(gpio);
- else
- tegra_gpio_disable(gpio);
- }
-}
-
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 0ebb7d4..ef67e18 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1827,14 +1827,10 @@ void radeon_do_release(struct drm_device * dev)
r600_do_cleanup_cp(dev);
else
radeon_do_cleanup_cp(dev);
- if (dev_priv->me_fw) {
- release_firmware(dev_priv->me_fw);
- dev_priv->me_fw = NULL;
- }
- if (dev_priv->pfp_fw) {
- release_firmware(dev_priv->pfp_fw);
- dev_priv->pfp_fw = NULL;
- }
+ release_firmware(dev_priv->me_fw);
+ dev_priv->me_fw = NULL;
+ release_firmware(dev_priv->pfp_fw);
+ dev_priv->pfp_fw = NULL;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index c58a036..456a77c 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -551,7 +551,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
/* nothing to do if vm isn't bound */
if (vm->id == -1)
- return 0;;
+ return 0;
bo_va = radeon_bo_va(bo, vm);
if (bo_va == NULL) {
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index c7008b5..0519b05 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -91,7 +91,7 @@ int radeon_gem_set_domain(struct drm_gem_object *gobj,
}
if (!domain) {
/* Do nothings */
- printk(KERN_WARNING "Set domain withou domain !\n");
+ printk(KERN_WARNING "Set domain without domain !\n");
return 0;
}
if (domain == RADEON_GEM_DOMAIN_CPU) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ffddcba..034c80a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -32,9 +32,13 @@ config HID
If unsure, say Y.
config HID_BATTERY_STRENGTH
- bool
+ bool "Battery level reporting for HID devices"
depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
default n
+ ---help---
+ This option adds support of reporting battery strength (for HID devices
+ that support this feature) through power_supply class so that userspace
+ tools, such as upower, can display it.
config HIDRAW
bool "/dev/hidraw raw HID device support"
@@ -60,6 +64,18 @@ source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
depends on HID
+config HID_GENERIC
+ tristate "Generic HID driver"
+ depends on HID
+ default y
+ ---help---
+ Support for generic HID devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hid-generic.
+
+ If unsure, say Y.
+
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
depends on USB_HID
@@ -92,6 +108,12 @@ config HID_APPLE
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
MacBooks, MacBook Pros and Apple Aluminum.
+config HID_AUREAL
+ tristate "Aureal"
+ depends on USB_HID
+ ---help---
+ Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
+
config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID
@@ -448,7 +470,7 @@ config HID_PICOLCD_FB
select FB_SYS_FOPS
---help---
Provide access to PicoLCD's 256x64 monochrome display via a
- frambuffer device.
+ framebuffer device.
config HID_PICOLCD_BACKLIGHT
bool "Backlight control" if EXPERT
@@ -595,16 +617,10 @@ config THRUSTMASTER_FF
config HID_WACOM
tristate "Wacom Bluetooth devices support"
depends on BT_HIDP
- ---help---
- Support for Wacom Graphire Bluetooth tablet.
-
-config HID_WACOM_POWER_SUPPLY
- bool "Wacom Bluetooth devices power supply status support"
- depends on HID_WACOM
+ depends on LEDS_CLASS
select POWER_SUPPLY
---help---
- Say Y here if you want to enable power supply status monitoring for
- Wacom Bluetooth devices.
+ Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 22f1d16..ca6cc9f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -9,6 +9,8 @@ endif
obj-$(CONFIG_HID) += hid.o
+obj-$(CONFIG_HID_GENERIC) += hid-generic.o
+
hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-y := hid-lg.o
@@ -36,6 +38,7 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
+obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 299d238..fa10f84 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
}
- if (iso_layout) {
+ if (iso_layout) {
if (asc->quirks & APPLE_ISO_KEYBOARD) {
trans = apple_find_translation(apple_iso_keyboard, usage->code);
if (trans) {
@@ -458,6 +458,9 @@ static const struct hid_device_id apple_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_ISO_KEYBOARD },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
new file mode 100644
index 0000000..ba64b04
--- /dev/null
+++ b/drivers/hid/hid-aureal.c
@@ -0,0 +1,54 @@
+/*
+ * HID driver for Aureal Cy se W-01RN USB_V3.1 devices
+ *
+ * Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
+ * Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
+ *
+ * Based on HID sunplus driver by
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
+ dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
+ rdesc[53] = 0x65;
+ } return rdesc;
+}
+
+static const struct hid_device_id aureal_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, aureal_devices);
+
+static struct hid_driver aureal_driver = {
+ .name = "aureal",
+ .id_table = aureal_devices,
+ .report_fixup = aureal_report_fixup,
+};
+
+static int __init aureal_init(void)
+{
+ return hid_register_driver(&aureal_driver);
+}
+
+static void __exit aureal_exit(void)
+{
+ hid_unregister_driver(&aureal_driver);
+}
+
+module_init(aureal_init);
+module_exit(aureal_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 4da66b4..8e3a6b2 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
return -1;
}
- if (parser->global.logical_maximum < parser->global.logical_minimum) {
- hid_err(parser->device, "logical range invalid %d %d\n",
- parser->global.logical_minimum, parser->global.logical_maximum);
+ /* Handle both signed and unsigned cases properly */
+ if ((parser->global.logical_minimum < 0 &&
+ parser->global.logical_maximum <
+ parser->global.logical_minimum) ||
+ (parser->global.logical_minimum >= 0 &&
+ (__u32)parser->global.logical_maximum <
+ (__u32)parser->global.logical_minimum)) {
+ dbg_hid("logical range invalid 0x%x 0x%x\n",
+ parser->global.logical_minimum,
+ parser->global.logical_maximum);
return -1;
}
@@ -546,12 +553,11 @@ static void hid_free_report(struct hid_report *report)
}
/*
- * Free a device structure, all reports, and all fields.
+ * Close report. This function returns the device
+ * state to the point prior to hid_open_report().
*/
-
-static void hid_device_release(struct device *dev)
+static void hid_close_report(struct hid_device *device)
{
- struct hid_device *device = container_of(dev, struct hid_device, dev);
unsigned i, j;
for (i = 0; i < HID_REPORT_TYPES; i++) {
@@ -562,11 +568,34 @@ static void hid_device_release(struct device *dev)
if (report)
hid_free_report(report);
}
+ memset(report_enum, 0, sizeof(*report_enum));
+ INIT_LIST_HEAD(&report_enum->report_list);
}
kfree(device->rdesc);
+ device->rdesc = NULL;
+ device->rsize = 0;
+
kfree(device->collection);
- kfree(device);
+ device->collection = NULL;
+ device->collection_size = 0;
+ device->maxcollection = 0;
+ device->maxapplication = 0;
+
+ device->status &= ~HID_STAT_PARSED;
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_device_release(struct device *dev)
+{
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+
+ hid_close_report(hid);
+ kfree(hid->dev_rdesc);
+ kfree(hid);
}
/*
@@ -636,6 +665,60 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
return NULL;
}
+static void hid_scan_usage(struct hid_device *hid, u32 usage)
+{
+ if (usage == HID_DG_CONTACTID)
+ hid->group = HID_GROUP_MULTITOUCH;
+}
+
+/*
+ * Scan a report descriptor before the device is added to the bus.
+ * Sets device groups and other properties that determine what driver
+ * to load.
+ */
+static int hid_scan_report(struct hid_device *hid)
+{
+ unsigned int page = 0, delim = 0;
+ __u8 *start = hid->dev_rdesc;
+ __u8 *end = start + hid->dev_rsize;
+ unsigned int u, u_min = 0, u_max = 0;
+ struct hid_item item;
+
+ hid->group = HID_GROUP_GENERIC;
+ while ((start = fetch_item(start, end, &item)) != NULL) {
+ if (item.format != HID_ITEM_FORMAT_SHORT)
+ return -EINVAL;
+ if (item.type == HID_ITEM_TYPE_GLOBAL) {
+ if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
+ page = item_udata(&item) << 16;
+ } else if (item.type == HID_ITEM_TYPE_LOCAL) {
+ if (delim > 1)
+ break;
+ u = item_udata(&item);
+ if (item.size <= 2)
+ u += page;
+ switch (item.tag) {
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+ delim += !!u;
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE:
+ hid_scan_usage(hid, u);
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ u_min = u;
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ u_max = u;
+ for (u = u_min; u <= u_max; u++)
+ hid_scan_usage(hid, u);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
/**
* hid_parse_report - parse device report
*
@@ -643,15 +726,37 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
* @start: report start
* @size: report size
*
+ * Allocate the device report as read by the bus driver. This function should
+ * only be called from parse() in ll drivers.
+ */
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
+{
+ hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL);
+ if (!hid->dev_rdesc)
+ return -ENOMEM;
+ hid->dev_rsize = size;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/**
+ * hid_open_report - open a driver-specific device report
+ *
+ * @device: hid device
+ *
* Parse a report description into a hid_device structure. Reports are
* enumerated, fields are attached to these reports.
* 0 returned on success, otherwise nonzero error value.
+ *
+ * This function (or the equivalent hid_parse() macro) should only be
+ * called from probe() in drivers, before starting the device.
*/
-int hid_parse_report(struct hid_device *device, __u8 *start,
- unsigned size)
+int hid_open_report(struct hid_device *device)
{
struct hid_parser *parser;
struct hid_item item;
+ unsigned int size;
+ __u8 *start;
__u8 *end;
int ret;
static int (*dispatch_type[])(struct hid_parser *parser,
@@ -662,6 +767,14 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
hid_parser_reserved
};
+ if (WARN_ON(device->status & HID_STAT_PARSED))
+ return -EBUSY;
+
+ start = device->dev_rdesc;
+ if (WARN_ON(!start))
+ return -ENODEV;
+ size = device->dev_rsize;
+
if (device->driver->report_fixup)
start = device->driver->report_fixup(device, start, &size);
@@ -679,6 +792,15 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
parser->device = device;
end = start + size;
+
+ device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+ sizeof(struct hid_collection), GFP_KERNEL);
+ if (!device->collection) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
ret = -EINVAL;
while ((start = fetch_item(start, end, &item)) != NULL) {
@@ -704,6 +826,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
goto err;
}
vfree(parser);
+ device->status |= HID_STAT_PARSED;
return 0;
}
}
@@ -711,9 +834,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));
err:
vfree(parser);
+ hid_close_report(device);
return ret;
}
-EXPORT_SYMBOL_GPL(hid_parse_report);
+EXPORT_SYMBOL_GPL(hid_open_report);
/*
* Convert a signed n-bit integer to signed 32-bit integer. Common
@@ -1032,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return report;
}
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt)
{
struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1040,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
unsigned int a;
int rsize, csize = size;
u8 *cdata = data;
+ int ret = 0;
report = hid_get_report(report_enum, data);
if (!report)
- return;
+ goto out;
if (report_enum->numbered) {
cdata++;
@@ -1063,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- hidraw_report_event(hid, data, size);
+ if (hid->claimed & HID_CLAIMED_HIDRAW) {
+ ret = hidraw_report_event(hid, data, size);
+ if (ret)
+ goto out;
+ }
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
+out:
+ return ret;
}
EXPORT_SYMBOL_GPL(hid_report_raw_event);
@@ -1147,7 +1277,7 @@ nomem:
}
}
- hid_report_raw_event(hid, type, data, size, interrupt);
+ ret = hid_report_raw_event(hid, type, data, size, interrupt);
unlock:
up(&hid->driver_lock);
@@ -1158,7 +1288,8 @@ EXPORT_SYMBOL_GPL(hid_input_report);
static bool hid_match_one_id(struct hid_device *hdev,
const struct hid_device_id *id)
{
- return id->bus == hdev->bus &&
+ return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) &&
+ (id->group == HID_GROUP_ANY || id->group == hdev->group) &&
(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
(id->product == HID_ANY_ID || id->product == hdev->product);
}
@@ -1234,10 +1365,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
connect_mask & HID_CONNECT_HIDINPUT_FORCE))
hdev->claimed |= HID_CLAIMED_INPUT;
- if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
- /* this device should be handled by hid-multitouch, skip it */
- return -ENODEV;
- }
if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
!hdev->hiddev_connect(hdev,
@@ -1314,13 +1441,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
static const struct hid_device_id hid_have_special_driver[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1385,60 +1509,33 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
- { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1447,7 +1544,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1480,8 +1576,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
@@ -1513,15 +1607,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
- { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
@@ -1538,9 +1625,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1554,16 +1638,13 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
- { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
- { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
@@ -1578,16 +1659,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
@@ -1631,6 +1703,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
return -ENOMEM;
dynid->id.bus = bus;
+ dynid->id.group = HID_GROUP_ANY;
dynid->id.vendor = vendor;
dynid->id.product = product;
dynid->id.driver_data = driver_data;
@@ -1679,18 +1752,7 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- if ((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
- !strncmp(hdrv->name, "hid-multitouch", 14))
- return 1;
-
- if (!hid_match_device(hdev, hdrv))
- return 0;
-
- /* generic wants all that don't have specialized driver */
- if (!strncmp(hdrv->name, "generic-", 8) && !hid_ignore_special_drivers)
- return !hid_match_id(hdev, hid_have_special_driver);
-
- return 1;
+ return hid_match_device(hdev, hdrv) != NULL;
}
static int hid_device_probe(struct device *dev)
@@ -1707,23 +1769,22 @@ static int hid_device_probe(struct device *dev)
if (!hdev->driver) {
id = hid_match_device(hdev, hdrv);
if (id == NULL) {
- if (!((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
- !strncmp(hdrv->name, "hid-multitouch", 14))) {
- ret = -ENODEV;
- goto unlock;
- }
+ ret = -ENODEV;
+ goto unlock;
}
hdev->driver = hdrv;
if (hdrv->probe) {
ret = hdrv->probe(hdev, id);
} else { /* default probe */
- ret = hid_parse(hdev);
+ ret = hid_open_report(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
- if (ret)
+ if (ret) {
+ hid_close_report(hdev);
hdev->driver = NULL;
+ }
}
unlock:
up(&hdev->driver_lock);
@@ -1744,6 +1805,7 @@ static int hid_device_remove(struct device *dev)
hdrv->remove(hdev);
else /* default remove */
hid_hw_stop(hdev);
+ hid_close_report(hdev);
hdev->driver = NULL;
}
@@ -1751,6 +1813,23 @@ static int hid_device_remove(struct device *dev)
return 0;
}
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product);
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute hid_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
@@ -1768,8 +1847,8 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
return -ENOMEM;
- if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
- hdev->bus, hdev->vendor, hdev->product))
+ if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product))
return -ENOMEM;
return 0;
@@ -1777,6 +1856,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
static struct bus_type hid_bus_type = {
.name = "hid",
+ .dev_attrs = hid_dev_attrs,
.match = hid_bus_match,
.probe = hid_device_probe,
.remove = hid_device_remove,
@@ -2075,6 +2155,26 @@ int hid_add_device(struct hid_device *hdev)
&& (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
return -ENODEV;
+ /*
+ * Read the device report descriptor once and use as template
+ * for the driver-specific modifications.
+ */
+ ret = hdev->ll_driver->parse(hdev);
+ if (ret)
+ return ret;
+ if (!hdev->dev_rdesc)
+ return -ENODEV;
+
+ /*
+ * Scan generic devices for group information
+ */
+ if (hid_ignore_special_drivers ||
+ !hid_match_id(hdev, hid_have_special_driver)) {
+ ret = hid_scan_report(hdev);
+ if (ret)
+ hid_warn(hdev, "bad device descriptor (%d)\n", ret);
+ }
+
/* XXX hack, any other cleaner solution after the driver core
* is converted to allow more than 20 bytes as the device name? */
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
@@ -2103,7 +2203,6 @@ EXPORT_SYMBOL_GPL(hid_add_device);
struct hid_device *hid_allocate_device(void)
{
struct hid_device *hdev;
- unsigned int i;
int ret = -ENOMEM;
hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
@@ -2114,23 +2213,13 @@ struct hid_device *hid_allocate_device(void)
hdev->dev.release = hid_device_release;
hdev->dev.bus = &hid_bus_type;
- hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
- sizeof(struct hid_collection), GFP_KERNEL);
- if (hdev->collection == NULL)
- goto err;
- hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
- for (i = 0; i < HID_REPORT_TYPES; i++)
- INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+ hid_close_report(hdev);
init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list);
sema_init(&hdev->driver_lock, 1);
return hdev;
-err:
- put_device(&hdev->dev);
- return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(hid_allocate_device);
@@ -2141,6 +2230,9 @@ static void hid_remove_device(struct hid_device *hdev)
hid_debug_unregister(hdev);
hdev->status &= ~HID_STAT_ADDED;
}
+ kfree(hdev->dev_rdesc);
+ hdev->dev_rdesc = NULL;
+ hdev->dev_rsize = 0;
}
/**
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
new file mode 100644
index 0000000..a8b3148
--- /dev/null
+++ b/drivers/hid/hid-generic.c
@@ -0,0 +1,53 @@
+/*
+ * HID support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2007-2008 Oliver Neukum
+ * Copyright (c) 2006-2012 Jiri Kosina
+ * Copyright (c) 2012 Henrik Rydberg
+ */
+
+/*
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <linux/hid.h>
+
+static const struct hid_device_id hid_table[] = {
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, hid_table);
+
+static struct hid_driver hid_generic = {
+ .name = "hid-generic",
+ .id_table = hid_table,
+};
+
+static int __init hid_init(void)
+{
+ return hid_register_driver(&hid_generic);
+}
+
+static void __exit hid_exit(void)
+{
+ hid_unregister_driver(&hid_generic);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR("Henrik Rydberg");
+MODULE_DESCRIPTION("HID generic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 4066324..3d62781 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -430,6 +430,15 @@ cleanup:
return ret;
}
+static int mousevsc_hid_parse(struct hid_device *hid)
+{
+ struct hv_device *dev = hid_get_drvdata(hid);
+ struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+ return hid_parse_report(hid, input_dev->report_desc,
+ input_dev->report_desc_size);
+}
+
static int mousevsc_hid_open(struct hid_device *hid)
{
return 0;
@@ -449,6 +458,7 @@ static void mousevsc_hid_stop(struct hid_device *hid)
}
static struct hid_ll_driver mousevsc_ll_driver = {
+ .parse = mousevsc_hid_parse,
.open = mousevsc_hid_open,
.close = mousevsc_hid_close,
.start = mousevsc_hid_start,
@@ -506,13 +516,14 @@ static int mousevsc_probe(struct hv_device *device,
sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
+ hid_set_drvdata(hid_dev, device);
+
ret = hid_add_device(hid_dev);
if (ret)
goto probe_err1;
- ret = hid_parse_report(hid_dev, input_dev->report_desc,
- input_dev->report_desc_size);
+ ret = hid_parse(hid_dev);
if (ret) {
hid_err(hid_dev, "parse failed\n");
goto probe_err2;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e39aecb..9373f53 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -154,9 +154,15 @@
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
+#define USB_VENDOR_ID_AUREAL 0x0755
+#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
+
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
+#define USB_VENDOR_ID_BAANTO 0x2453
+#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+
#define USB_VENDOR_ID_BELKIN 0x050d
#define USB_DEVICE_ID_FLIP_KVM 0x3201
@@ -726,6 +732,7 @@
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
+#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
@@ -749,6 +756,7 @@
#define USB_DEVICE_ID_WALTOP_PID_0038 0x0038
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 002781c..132b001 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -225,7 +225,10 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
* Verify and convert units.
* See HID specification v1.11 6.2.2.7 Global Items for unit decoding
*/
- if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+ switch (code) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_Z:
if (field->unit == 0x11) { /* If centimeters */
/* Convert to millimeters */
unit_exponent += 1;
@@ -239,7 +242,13 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
} else {
return 0;
}
- } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+ break;
+
+ case ABS_RX:
+ case ABS_RY:
+ case ABS_RZ:
+ case ABS_TILT_X:
+ case ABS_TILT_Y:
if (field->unit == 0x14) { /* If degrees */
/* Convert to radians */
prev = logical_extents;
@@ -250,7 +259,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
} else if (field->unit != 0x12) { /* If not radians */
return 0;
}
- } else {
+ break;
+
+ default:
return 0;
}
@@ -623,6 +634,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_TOOL_RUBBER);
break;
+ case 0x3d: /* X Tilt */
+ map_abs_clear(ABS_TILT_X);
+ break;
+
+ case 0x3e: /* Y Tilt */
+ map_abs_clear(ABS_TILT_Y);
+ break;
+
case 0x33: /* Touch */
case 0x42: /* TipSwitch */
case 0x43: /* TipSwitch2 */
@@ -638,10 +657,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_STYLUS2);
break;
- case 0x51: /* ContactID */
- device->quirks |= HID_QUIRK_MULTITOUCH;
- goto unknown;
-
default: goto unknown;
}
break;
@@ -1208,13 +1223,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
- if (hid->quirks & HID_QUIRK_MULTITOUCH) {
- /* generic hid does not know how to handle multitouch devices */
- if (hidinput)
- goto out_cleanup;
- goto out_unwind;
- }
-
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index e7a7bd1..fc37ed6 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {
static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+ if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
hid_info(hdev,
"fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
- if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+ if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
hid_info(hdev,
"fixing up rel/abs in Logitech report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
- if ((quirks & LG_FF4) && *rsize >= 101 &&
+ if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&
rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
rdesc[47] == 0x05 && rdesc[48] == 0x09) {
hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 0, 0, 0, 0,183,184,185,186,187,
188,189,190,191,192,193,194, 0, 0, 0
};
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
unsigned int hid = usage->hid;
if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
lg_dinovo_mapping(hi, usage, bit, max))
return 1;
- if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+ if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
return 1;
if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* Special handling for Logitech Cordless Desktop */
if (field->application == HID_GD_MOUSE) {
- if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+ if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
(hid == 7 || hid == 8))
return -1;
} else {
- if ((quirks & LG_EXPANDED_KEYMAP) &&
+ if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
hid < ARRAY_SIZE(e_keymap) &&
e_keymap[hid] != 0) {
hid_map_usage(hi, usage, bit, max, EV_KEY,
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+ if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
(field->flags & HID_MAIN_ITEM_RELATIVE))
field->flags &= ~HID_MAIN_ITEM_RELATIVE;
- if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+ if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
usage->type == EV_REL || usage->type == EV_ABS))
clear_bit(usage->code, *bit);
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int lg_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+ if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
input_event(field->hidinput->input, usage->type, usage->code,
-value);
return 1;
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
- unsigned long quirks = id->driver_data;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ struct lg_drv_data *drv_data;
int ret;
- hid_set_drvdata(hdev, (void *)quirks);
+ drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
+ if (!drv_data) {
+ hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
+ return -ENOMEM;
+ }
+ drv_data->quirks = id->driver_data;
+
+ hid_set_drvdata(hdev, (void *)drv_data);
- if (quirks & LG_NOGET)
+ if (drv_data->quirks & LG_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
ret = hid_parse(hdev);
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
+ if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
connect_mask &= ~HID_CONNECT_FF;
ret = hid_hw_start(hdev, connect_mask);
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
- if (quirks & LG_FF)
+ if (drv_data->quirks & LG_FF)
lgff_init(hdev);
- if (quirks & LG_FF2)
+ if (drv_data->quirks & LG_FF2)
lg2ff_init(hdev);
- if (quirks & LG_FF3)
+ if (drv_data->quirks & LG_FF3)
lg3ff_init(hdev);
- if (quirks & LG_FF4)
+ if (drv_data->quirks & LG_FF4)
lg4ff_init(hdev);
return 0;
err_free:
+ kfree(drv_data);
return ret;
}
static void lg_remove(struct hid_device *hdev)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
- if(quirks & LG_FF4)
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+ if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev);
hid_hw_stop(hdev);
+ kfree(drv_data);
}
static const struct hid_device_id lg_devices[] = {
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 4b097286..d64cf8d 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -1,6 +1,11 @@
#ifndef __HID_LG_H
#define __HID_LG_H
+struct lg_drv_data {
+ unsigned long quirks;
+ void *device_props; /* Device specific properties */
+};
+
#ifdef CONFIG_LOGITECH_FF
int lgff_init(struct hid_device *hdev);
#else
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 6ecc9e2..f3390ee 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1,7 +1,8 @@
/*
- * Force feedback support for Logitech Speed Force Wireless
+ * Force feedback support for Logitech Gaming Wheels
*
- * http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ * Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
+ * Speed Force Wireless (WiiWheel)
*
* Copyright (c) 2010 Simon Wood <simon@mungewell.org>
*/
@@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
-static bool list_inited;
-
struct lg4ff_device_entry {
- char *device_id; /* Use name in respective kobject structure's address as the ID */
__u16 range;
__u16 min_range;
__u16 max_range;
- __u8 leds;
+#ifdef CONFIG_LEDS_CLASS
+ __u8 led_state;
+ struct led_classdev *led[5];
+#endif
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
};
-static struct lg4ff_device_entry device_list;
-
static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
FF_AUTOCENTER,
@@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
/* Read current range and display it in terminal */
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lg4ff_device_entry *uninitialized_var(entry);
- struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
size_t count;
- list_for_each(h, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
- break;
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return 0;
}
- if (h == &device_list.list) {
- dbg_hid("Device not found!");
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
return 0;
}
@@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
* according to the type of the wheel */
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct lg4ff_device_entry *uninitialized_var(entry);
- struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
__u16 range = simple_strtoul(buf, NULL, 10);
- list_for_each(h, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
- break;
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return 0;
}
- if (h == &device_list.list) {
- dbg_hid("Device not found!");
- return count;
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
+ return 0;
}
if (range == 0)
@@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
return count;
}
+#ifdef CONFIG_LEDS_CLASS
+static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
+{
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+
+ report->field[0]->value[0] = 0xf8;
+ report->field[0]->value[1] = 0x12;
+ report->field[0]->value[2] = leds;
+ report->field[0]->value[3] = 0x00;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+ struct lg4ff_device_entry *entry;
+ int i, state = 0;
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return;
+ }
+
+ entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+ if (!entry) {
+ hid_err(hid, "Device properties not found.");
+ return;
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (led_cdev != entry->led[i])
+ continue;
+ state = (entry->led_state >> i) & 1;
+ if (value == LED_OFF && state) {
+ entry->led_state &= ~(1 << i);
+ lg4ff_set_leds(hid, entry->led_state);
+ } else if (value != LED_OFF && !state) {
+ entry->led_state |= 1 << i;
+ lg4ff_set_leds(hid, entry->led_state);
+ }
+ break;
+ }
+}
+
+static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+ struct lg4ff_device_entry *entry;
+ int i, value = 0;
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return LED_OFF;
+ }
+
+ entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+ if (!entry) {
+ hid_err(hid, "Device properties not found.");
+ return LED_OFF;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (led_cdev == entry->led[i]) {
+ value = (entry->led_state >> i) & 1;
+ break;
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+#endif
+
int lg4ff_init(struct hid_device *hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
@@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)
struct hid_report *report;
struct hid_field *field;
struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
struct usb_device_descriptor *udesc;
int error, i, j;
__u16 bcdDevice, rev_maj, rev_min;
@@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)
dev->ff->set_autocenter(dev, 0);
}
- /* Initialize device_list if this is the first device to handle by lg4ff */
- if (!list_inited) {
- INIT_LIST_HEAD(&device_list.list);
- list_inited = 1;
+ /* Get private driver data */
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Cannot add device, private driver data not allocated\n");
+ return -1;
}
- /* Add the device to device_list */
+ /* Initialize device properties */
entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
if (!entry) {
- hid_err(hid, "Cannot add device, insufficient memory.\n");
- return -ENOMEM;
- }
- entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
- if (!entry->device_id) {
- hid_err(hid, "Cannot set device_id, insufficient memory.\n");
- kfree(entry);
+ hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
return -ENOMEM;
}
+ drv_data->device_props = entry;
+
entry->min_range = lg4ff_devices[i].min_range;
entry->max_range = lg4ff_devices[i].max_range;
entry->set_range = lg4ff_devices[i].set_range;
- list_add(&entry->list, &device_list.list);
/* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range);
@@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)
if (entry->set_range != NULL)
entry->set_range(hid, entry->range);
- hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
+#ifdef CONFIG_LEDS_CLASS
+ /* register led subsystem - G27 only */
+ entry->led_state = 0;
+ for (j = 0; j < 5; j++)
+ entry->led[j] = NULL;
+
+ if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
+ struct led_classdev *led;
+ size_t name_sz;
+ char *name;
+
+ lg4ff_set_leds(hid, 0);
+
+ name_sz = strlen(dev_name(&hid->dev)) + 8;
+
+ for (j = 0; j < 5; j++) {
+ led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+ if (!led) {
+ hid_err(hid, "can't allocate memory for LED %d\n", j);
+ goto err;
+ }
+
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = lg4ff_led_get_brightness;
+ led->brightness_set = lg4ff_led_set_brightness;
+
+ entry->led[j] = led;
+ error = led_classdev_register(&hid->dev, led);
+
+ if (error) {
+ hid_err(hid, "failed to register LED %d. Aborting.\n", j);
+err:
+ /* Deregister LEDs (if any) */
+ for (j = 0; j < 5; j++) {
+ led = entry->led[j];
+ entry->led[j] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ goto out; /* Let the driver continue without LEDs */
+ }
+ }
+ }
+out:
+#endif
+ hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
return 0;
}
int lg4ff_deinit(struct hid_device *hid)
{
- bool found = 0;
struct lg4ff_device_entry *entry;
- struct list_head *h, *g;
- list_for_each_safe(h, g, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
- list_del(h);
- kfree(entry->device_id);
- kfree(entry);
- found = 1;
- break;
- }
- }
+ struct lg_drv_data *drv_data;
+
+ device_remove_file(&hid->dev, &dev_attr_range);
- if (!found) {
- dbg_hid("Device entry not found!\n");
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Error while deinitializing device, no private driver data.\n");
+ return -1;
+ }
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Error while deinitializing device, no device properties data.\n");
return -1;
}
- device_remove_file(&hid->dev, &dev_attr_range);
+#ifdef CONFIG_LEDS_CLASS
+ {
+ int j;
+ struct led_classdev *led;
+
+ /* Deregister LEDs (if any) */
+ for (j = 0; j < 5; j++) {
+
+ led = entry->led[j];
+ entry->led[j] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+#endif
+
+ /* Deallocate memory */
+ kfree(entry);
+
dbg_hid("Device successfully unregistered\n");
return 0;
}
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 2b56efc..5e8a7ed 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -26,6 +26,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <asm/unaligned.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include "hid-logitech-dj.h"
@@ -155,6 +156,14 @@ static const char media_descriptor[] = {
/* Maximum size of all defined hid reports in bytes (including report id) */
#define MAX_REPORT_SIZE 8
+/* Make sure all descriptors are present here */
+#define MAX_RDESC_SIZE \
+ (sizeof(kbd_descriptor) + \
+ sizeof(mse_descriptor) + \
+ sizeof(consumer_descriptor) + \
+ sizeof(syscontrol_descriptor) + \
+ sizeof(media_descriptor))
+
/* Number of possible hid report types that can be created by this driver.
*
* Right now, RF report types have the same report types (or report id's)
@@ -265,8 +274,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
goto dj_device_allocate_fail;
}
- dj_dev->reports_supported = le32_to_cpu(
- dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+ dj_dev->reports_supported = get_unaligned_le32(
+ dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
dj_dev->hdev = dj_hiddev;
dj_dev->dj_receiver_dev = djrcv_dev;
dj_dev->device_index = dj_report->device_index;
@@ -473,9 +482,17 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
return 0;
}
+static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
+{
+ memcpy(*rdesc + *rsize, data, size);
+ *rsize += size;
+}
+
static int logi_dj_ll_parse(struct hid_device *hid)
{
struct dj_device *djdev = hid->driver_data;
+ unsigned int rsize = 0;
+ char *rdesc;
int retval;
dbg_hid("%s\n", __func__);
@@ -483,70 +500,38 @@ static int logi_dj_ll_parse(struct hid_device *hid)
djdev->hdev->version = 0x0111;
djdev->hdev->country = 0x00;
+ rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
+ if (!rdesc)
+ return -ENOMEM;
+
if (djdev->reports_supported & STD_KEYBOARD) {
dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) kbd_descriptor,
- sizeof(kbd_descriptor));
- if (retval) {
- dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
- " error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
}
if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: "
"%x\n", __func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) mse_descriptor,
- sizeof(mse_descriptor));
- if (retval) {
- dbg_hid("%s: sending a mouse descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
}
if (djdev->reports_supported & MULTIMEDIA) {
dbg_hid("%s: sending a multimedia report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) consumer_descriptor,
- sizeof(consumer_descriptor));
- if (retval) {
- dbg_hid("%s: sending a consumer_descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
}
if (djdev->reports_supported & POWER_KEYS) {
dbg_hid("%s: sending a power keys report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) syscontrol_descriptor,
- sizeof(syscontrol_descriptor));
- if (retval) {
- dbg_hid("%s: sending a syscontrol_descriptor, "
- "hid_parse failed error: %d\n",
- __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
}
if (djdev->reports_supported & MEDIA_CENTER) {
dbg_hid("%s: sending a media center report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) media_descriptor,
- sizeof(media_descriptor));
- if (retval) {
- dbg_hid("%s: sending a media_descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
}
if (djdev->reports_supported & KBD_LEDS) {
@@ -554,7 +539,10 @@ static int logi_dj_ll_parse(struct hid_device *hid)
__func__, djdev->reports_supported);
}
- return 0;
+ retval = hid_parse_report(hid, rdesc, rsize);
+ kfree(rdesc);
+
+ return retval;
}
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 1d5b941..6e3332a 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -70,9 +70,16 @@ struct mt_class {
bool is_indirect; /* true for touchpads */
};
+struct mt_fields {
+ unsigned usages[HID_MAX_FIELDS];
+ unsigned int length;
+};
+
struct mt_device {
struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */
+ struct mt_fields *fields; /* temporary placeholder for storing the
+ multitouch fields */
unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
@@ -110,6 +117,9 @@ struct mt_device {
#define MT_DEFAULT_MAXCONTACT 10
+#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
+#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
+
/*
* these device-dependent functions determine what slot corresponds
* to a valid contact that was just read.
@@ -275,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
}
-static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td,
+static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi)
{
- if (!test_bit(usage->hid, hi->input->absbit))
- td->last_slot_field = usage->hid;
+ struct mt_fields *f = td->fields;
+
+ if (f->length >= HID_MAX_FIELDS)
+ return;
+
+ f->usages[f->length++] = usage->hid;
}
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -330,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_GD_Y:
@@ -340,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
}
@@ -349,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_INRANGE:
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONFIDENCE:
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTID:
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
input_mt_init_slots(hi->input, td->maxcontacts);
- td->last_slot_field = usage->hid;
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
td->touches_by_report++;
return 1;
@@ -375,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_TOUCH_MAJOR);
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_HEIGHT:
@@ -385,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_height);
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_TIPPRESSURE:
@@ -396,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
@@ -635,6 +649,31 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
}
}
+static void mt_post_parse_default_settings(struct mt_device *td)
+{
+ __s32 quirks = td->mtclass.quirks;
+
+ /* unknown serial device needs special quirks */
+ if (td->touches_by_report == 1) {
+ quirks |= MT_QUIRK_ALWAYS_VALID;
+ quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
+ quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
+ quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+ }
+
+ td->mtclass.quirks = quirks;
+}
+
+static void mt_post_parse(struct mt_device *td)
+{
+ struct mt_fields *f = td->fields;
+
+ if (td->touches_by_report > 0) {
+ int field_count_per_touch = f->length / td->touches_by_report;
+ td->last_slot_field = f->usages[field_count_per_touch - 1];
+ }
+}
+
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
@@ -654,7 +693,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
- hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
@@ -666,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->maxcontact_report_id = -1;
hid_set_drvdata(hdev, td);
+ td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+ if (!td->fields) {
+ dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
ret = hid_parse(hdev);
if (ret != 0)
goto fail;
@@ -674,14 +719,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto fail;
- if (!id && td->touches_by_report == 1) {
- /* the device has been sent by hid-generic */
- mtclass = &td->mtclass;
- mtclass->quirks |= MT_QUIRK_ALWAYS_VALID;
- mtclass->quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
- mtclass->quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
- mtclass->quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
- }
+ mt_post_parse(td);
+
+ if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+ mt_post_parse_default_settings(td);
td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
GFP_KERNEL);
@@ -697,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
+ kfree(td->fields);
+ td->fields = NULL;
+
return 0;
fail:
+ kfree(td->fields);
kfree(td);
return ret;
}
@@ -727,50 +772,54 @@ static const struct hid_device_id mt_devices[] = {
/* 3M panels */
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M1968) },
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M2256) },
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M3266) },
/* ActionStar panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+ MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
USB_DEVICE_ID_ACTIONSTAR_1011) },
/* Atmel panels */
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+ MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
USB_DEVICE_ID_ATMEL_MULTITOUCH) },
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+ MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
+ /* Baanto multitouch devices */
+ { .driver_data = MT_CLS_DEFAULT,
+ MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
+ USB_DEVICE_ID_BAANTO_MT_190W2) },
/* Cando panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
/* Chunghwa Telecom touch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
+ MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
/* CVTouch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
USB_DEVICE_ID_CVTOUCH_SCREEN) },
/* Cypress panel */
@@ -780,225 +829,227 @@ static const struct hid_device_id mt_devices[] = {
/* eGalax devices (resistive) */
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
/* eGalax devices (capacitive) */
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
/* Elo TouchSystems IntelliTouch Plus panel */
{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_ELO,
+ MT_USB_DEVICE(USB_VENDOR_ID_ELO,
USB_DEVICE_ID_ELO_TS2515) },
/* GeneralTouch panel */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
/* Gametel game controller */
{ .driver_data = MT_CLS_DEFAULT,
- HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL,
+ MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
USB_DEVICE_ID_GAMETEL_MT_MODE) },
/* GoodTouch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
USB_DEVICE_ID_GOODTOUCH_000f) },
/* Hanvon panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
+ MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
/* Ideacom panel */
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+ MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
USB_DEVICE_ID_IDEACOM_IDC6650) },
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+ MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
USB_DEVICE_ID_IDEACOM_IDC6651) },
/* Ilitek dual touch panel */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
+ MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
/* IRTOUCH panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+ MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
/* LG Display panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_LG,
+ MT_USB_DEVICE(USB_VENDOR_ID_LG,
USB_DEVICE_ID_LG_MULTITOUCH) },
/* Lumio panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+ MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
USB_DEVICE_ID_CRYSTALTOUCH) },
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+ MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
/* MosArt panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
USB_DEVICE_ID_ASUS_T91MT)},
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+ MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
- HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT780) },
{ .driver_data = MT_CLS_PANASONIC,
- HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT880) },
/* PenMount panels */
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+ MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
USB_DEVICE_ID_PENMOUNT_PCI) },
/* PixArt optical touch screen */
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
/* PixCir-based panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+ MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
/* Quanta-based panels */
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
/* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
USB_DEVICE_ID_MTP)},
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
USB_DEVICE_ID_MTP_STM)},
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
USB_DEVICE_ID_MTP_SITRONIX)},
/* TopSeed panels */
{ .driver_data = MT_CLS_TOPSEED,
- HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
+ MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
/* Touch International panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
+ MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
/* Unitec panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
/* XAT */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XAT,
+ MT_USB_DEVICE(USB_VENDOR_ID_XAT,
USB_DEVICE_ID_XAT_CSR) },
/* Xiroku */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX2) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX2) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
+ /* Generic MT device */
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, mt_devices);
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 1f11289..3aba02b 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/usb.h>
#include "hid-ids.h"
@@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {
0xC0 /* End Collection */
};
+/*
+ * See TWHL850 description, device and HID report descriptors at
+ * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
+ */
+
+/* Size of the original descriptors of TWHL850 tablet */
+#define TWHL850_RDESC_ORIG_SIZE0 182
+#define TWHL850_RDESC_ORIG_SIZE1 161
+#define TWHL850_RDESC_ORIG_SIZE2 92
+
+/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
+static __u8 twhl850_rdesc_fixed0[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
+static __u8 twhl850_rdesc_fixed1[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
+static __u8 twhl850_rdesc_fixed2[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x06, /* Usage (Keyboard), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x03, /* Report ID (3), */
+ 0x05, 0x07, /* Usage Page (Keyboard), */
+ 0x14, /* Logical Minimum (0), */
+ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
+ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x18, /* Usage Minimum (None), */
+ 0x29, 0xFF, /* Usage Maximum (FFh), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x06, /* Report Count (6), */
+ 0x80, /* Input, */
+ 0xC0 /* End Collection */
+};
+
static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
+ struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
+ __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
switch (hdev->product) {
case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(wp1062_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
+ switch (iface_num) {
+ case 0:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
+ rdesc = twhl850_rdesc_fixed0;
+ *rsize = sizeof(twhl850_rdesc_fixed0);
+ }
+ break;
+ case 1:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
+ rdesc = twhl850_rdesc_fixed1;
+ *rsize = sizeof(twhl850_rdesc_fixed1);
+ }
+ break;
+ case 2:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
+ rdesc = twhl850_rdesc_fixed2;
+ *rsize = sizeof(twhl850_rdesc_fixed2);
+ }
+ break;
+ }
+ break;
}
return rdesc;
@@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 067e296..fe23a1e 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -24,15 +24,16 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/leds.h>
#include <linux/slab.h>
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
#include <linux/power_supply.h>
-#endif
#include "hid-ids.h"
#define PAD_DEVICE_ID 0x0F
+#define WAC_CMD_LED_CONTROL 0x20
+
struct wacom_data {
__u16 tool;
__u16 butstate;
@@ -41,16 +42,20 @@ struct wacom_data {
__u32 id;
__u32 serial;
unsigned char high_speed;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
- int battery_capacity;
+ __u8 battery_capacity;
+ __u8 power_raw;
+ __u8 ps_connected;
struct power_supply battery;
struct power_supply ac;
-#endif
+ __u8 led_selector;
+ struct led_classdev *leds[4];
};
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-/*percent of battery capacity, 0 means AC online*/
-static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+/*percent of battery capacity for Graphire
+ 8th value means AC online and show 100% capacity */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
@@ -64,13 +69,123 @@ static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_SCOPE,
};
+static void wacom_leds_set_brightness(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct device *dev = led_dev->dev->parent;
+ struct hid_device *hdev;
+ struct wacom_data *wdata;
+ unsigned char *buf;
+ __u8 led = 0;
+ int i;
+
+ hdev = container_of(dev, struct hid_device, dev);
+ wdata = hid_get_drvdata(hdev);
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev)
+ wdata->led_selector = i;
+ }
+
+ led = wdata->led_selector | 0x04;
+ buf = kzalloc(9, GFP_KERNEL);
+ if (buf) {
+ buf[0] = WAC_CMD_LED_CONTROL;
+ buf[1] = led;
+ buf[2] = value;
+ hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+ kfree(buf);
+ }
+
+ return;
+}
+
+static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
+{
+ struct wacom_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int value = 0;
+ int i;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ value = wdata->leds[i]->brightness;
+ break;
+ }
+ }
+
+ return value;
+}
+
+
+static int wacom_initialize_leds(struct hid_device *hdev)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct led_classdev *led;
+ struct device *dev = &hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 12;
+ char *name;
+ int i, ret;
+
+ wdata->led_selector = 0;
+
+ for (i = 0; i < 4; i++) {
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led) {
+ hid_warn(hdev,
+ "can't allocate memory for LED selector\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ name = (void *)&led[1];
+ snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 127;
+ led->brightness_get = wacom_leds_get_brightness;
+ led->brightness_set = wacom_leds_set_brightness;
+
+ wdata->leds[i] = led;
+
+ ret = led_classdev_register(dev, wdata->leds[i]);
+
+ if (ret) {
+ wdata->leds[i] = NULL;
+ kfree(led);
+ hid_warn(hdev, "can't register LED\n");
+ goto err;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static void wacom_destroy_leds(struct hid_device *hdev)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct led_classdev *led;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i]) {
+ led = wdata->leds[i];
+ wdata->leds[i] = NULL;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+
+}
+
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy,
struct wacom_data, battery);
- int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
@@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- /* show 100% battery capacity when charging */
- if (power_state == 0)
- val->intval = 100;
- else
- val->intval = power_state;
+ val->intval = wdata->battery_capacity;
break;
default:
ret = -EINVAL;
@@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
- int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
- if (power_state == 0)
- val->intval = 1;
- else
- val->intval = 0;
+ val->intval = wdata->ps_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy,
}
return ret;
}
-#endif
-
-static void wacom_set_features(struct hid_device *hdev)
-{
- int ret;
- __u8 rep_data[2];
-
- /*set high speed, tablet mode*/
- rep_data[0] = 0x03;
- rep_data[1] = 0x20;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
- return;
-}
-static void wacom_poke(struct hid_device *hdev, u8 speed)
+static void wacom_set_features(struct hid_device *hdev, u8 speed)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
int limit, ret;
- char rep_data[2];
-
- rep_data[0] = 0x03 ; rep_data[1] = 0x00;
- limit = 3;
- do {
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
- } while (ret < 0 && limit-- > 0);
-
- if (ret >= 0) {
- if (speed == 0)
- rep_data[0] = 0x05;
- else
- rep_data[0] = 0x06;
+ __u8 rep_data[2];
- rep_data[1] = 0x00;
+ switch (hdev->product) {
+ case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
+ rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
@@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
- wdata->high_speed = speed;
- return;
+ if (speed == 0)
+ rep_data[0] = 0x05;
+ else
+ rep_data[0] = 0x06;
+
+ rep_data[1] = 0x00;
+ limit = 3;
+ do {
+ ret = hdev->hid_output_raw_report(hdev,
+ rep_data, 2, HID_FEATURE_REPORT);
+ } while (ret < 0 && limit-- > 0);
+
+ if (ret >= 0) {
+ wdata->high_speed = speed;
+ return;
+ }
}
+
+ /*
+ * Note that if the raw queries fail, it's not a hard failure
+ * and it is safe to continue
+ */
+ hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+ rep_data[0], ret);
+ break;
+ case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+ if (speed == 1)
+ wdata->features &= ~0x20;
+ else
+ wdata->features |= 0x20;
+
+ rep_data[0] = 0x03;
+ rep_data[1] = wdata->features;
+
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+ HID_FEATURE_REPORT);
+ if (ret >= 0)
+ wdata->high_speed = speed;
+ break;
}
- /*
- * Note that if the raw queries fail, it's not a hard failure and it
- * is safe to continue
- */
- hid_warn(hdev, "failed to poke device, command %d, err %d\n",
- rep_data[0], ret);
return;
}
@@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev,
return -EINVAL;
if (new_speed == 0 || new_speed == 1) {
- wacom_poke(hdev, new_speed);
+ wacom_set_features(hdev, new_speed);
return strnlen(buf, PAGE_SIZE);
} else
return -EINVAL;
@@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev,
input_sync(input);
}
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
- /* Store current battery capacity */
+ /* Store current battery capacity and power supply state*/
rw = (data[7] >> 2 & 0x07);
- if (rw != wdata->battery_capacity)
- wdata->battery_capacity = rw;
-#endif
+ if (rw != wdata->power_raw) {
+ wdata->power_raw = rw;
+ wdata->battery_capacity = batcap_gr[rw];
+ if (rw == 7)
+ wdata->ps_connected = 1;
+ else
+ wdata->ps_connected = 0;
+ }
return 1;
}
@@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
{
__u16 x, y, pressure;
__u8 distance;
+ __u8 tilt_x, tilt_y;
switch (data[1]) {
case 0x80: /* Out of proximity report */
@@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
| (data[1] & 0x01);
distance = (data[9] >> 2) & 0x3f;
+ tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
+ tilt_y = data[8] & 0x7f;
input_report_key(input, BTN_TOUCH, pressure > 1);
@@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
input_report_abs(input, ABS_DISTANCE, distance);
+ input_report_abs(input, ABS_TILT_X, tilt_x);
+ input_report_abs(input, ABS_TILT_Y, tilt_y);
input_report_abs(input, ABS_MISC, wdata->id);
input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
input_report_key(input, wdata->tool, 1);
@@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
struct input_dev *input;
unsigned char *data = (unsigned char *) raw_data;
int i;
+ __u8 power_raw;
if (!(hdev->claimed & HID_CLAIMED_INPUT))
return 0;
@@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
- /* Check if this is a tablet report */
- if (data[0] != 0x03)
- return 0;
-
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
- return wacom_gr_parse_report(hdev, wdata, input, data);
+ if (data[0] == 0x03) {
+ return wacom_gr_parse_report(hdev, wdata, input, data);
+ } else {
+ hid_err(hdev, "Unknown report: %d,%d size:%d\n",
+ data[0], data[1], size);
+ return 0;
+ }
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
i = 1;
@@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
wacom_i4_parse_report(hdev, wdata, input, data + i);
+ power_raw = data[i+10];
+ if (power_raw != wdata->power_raw) {
+ wdata->power_raw = power_raw;
+ wdata->battery_capacity = batcap_i4[power_raw & 0x07];
+ wdata->ps_connected = power_raw & 0x08;
+ }
+
break;
default:
hid_err(hdev, "Unknown report: %d,%d size:%d\n",
@@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
+ input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
+ input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
break;
}
@@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev,
hid_warn(hdev,
"can't create sysfs speed attribute err: %d\n", ret);
- switch (hdev->product) {
- case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
- /* Set Wacom mode 2 with high reporting speed */
- wacom_poke(hdev, 1);
- break;
- case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+ wdata->features = 0;
+ wacom_set_features(hdev, 1);
+
+ if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
- wdata->features = 0;
- wacom_set_features(hdev);
- break;
+ ret = wacom_initialize_leds(hdev);
+ if (ret) {
+ hid_warn(hdev,
+ "can't create led attribute, err: %d\n", ret);
+ goto destroy_leds;
+ }
}
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
wdata->battery.properties = wacom_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
wdata->battery.get_property = wacom_battery_get_property;
@@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev,
}
power_supply_powers(&wdata->ac, &hdev->dev);
-#endif
return 0;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
err_ac:
power_supply_unregister(&wdata->battery);
err_battery:
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
-#endif
+destroy_leds:
+ wacom_destroy_leds(hdev);
err_free:
kfree(wdata);
return ret;
@@ -646,16 +778,14 @@ err_free:
static void wacom_remove(struct hid_device *hdev)
{
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
struct wacom_data *wdata = hid_get_drvdata(hdev);
-#endif
+
+ wacom_destroy_leds(hdev);
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
power_supply_unregister(&wdata->battery);
power_supply_unregister(&wdata->ac);
-#endif
kfree(hid_get_drvdata(hdev));
}
@@ -693,5 +823,5 @@ static void __exit wacom_exit(void)
module_init(wacom_init);
module_exit(wacom_exit);
+MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index 2cfd95c..745e4e9 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -502,28 +502,146 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-struct waltop_state {
- u8 pressure0;
- u8 pressure1;
+/*
+ * See Sirius Battery Free Tablet description, device and HID report descriptors
+ * at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
+ */
+
+/* Size of the original report descriptor of Sirius Battery Free Tablet */
+#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE 335
+
+/* Fixed Sirius Battery Free Tablet descriptor */
+static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x02, /* Report Size (2), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x80, /* Input, */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x3C, /* Usage (Invert), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x14, /* Logical Minimum (0), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
+ 0x26, 0xE0, 0x2E, /* Logical Maximum (12000), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xA4, /* Push, */
+ 0x55, 0xFE, /* Unit Exponent (-2), */
+ 0x65, 0x12, /* Unit (Radians), */
+ 0x35, 0x97, /* Physical Minimum (-105), */
+ 0x45, 0x69, /* Physical Maximum (105), */
+ 0x15, 0x97, /* Logical Minimum (-105), */
+ 0x25, 0x69, /* Logical Maximum (105), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x09, 0x3D, /* Usage (X Tilt), */
+ 0x09, 0x3E, /* Usage (Y Tilt), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x06, /* Usage (Keyboard), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0D, /* Report ID (13), */
+ 0x05, 0x07, /* Usage Page (Keyboard), */
+ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
+ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x18, /* Usage Minimum (None), */
+ 0x29, 0x65, /* Usage Maximum (KB Application), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x65, /* Logical Maximum (101), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x80, /* Input, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0C, /* Usage Page (Consumer), */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0C, /* Report ID (12), */
+ 0x09, 0xE9, /* Usage (Volume Inc), */
+ 0x09, 0xEA, /* Usage (Volume Dec), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x06, /* Report Size (6), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0 /* End Collection */
};
static int waltop_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
- struct waltop_state *s;
-
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (s == NULL) {
- hid_err(hdev, "can't allocate device state\n");
- ret = -ENOMEM;
- goto err;
- }
-
- s->pressure0 = 0;
- s->pressure1 = 0;
-
- hid_set_drvdata(hdev, s);
ret = hid_parse(hdev);
if (ret) {
@@ -539,7 +657,6 @@ static int waltop_probe(struct hid_device *hdev,
return 0;
err:
- kfree(s);
return ret;
}
@@ -583,6 +700,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
+ if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
+ rdesc = sirius_battery_free_tablet_rdesc_fixed;
+ *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
+ }
+ break;
}
return rdesc;
}
@@ -590,39 +713,72 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
- /* If this is a pen input report of a tablet with PID 0038 */
- if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
- report->type == HID_INPUT_REPORT &&
- report->id == 16 &&
- size == 8) {
- struct waltop_state *s = hid_get_drvdata(hdev);
-
+ /* If this is a pen input report */
+ if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
/*
- * Ignore maximum pressure reported when a barrel button is
- * pressed.
+ * Ignore reported pressure when a barrel button is pressed,
+ * because it is rarely correct.
*/
/* If a barrel button is pressed */
if ((data[1] & 0xF) > 1) {
- /* Use the last known pressure */
- data[6] = s->pressure0;
- data[7] = s->pressure1;
- } else {
- /* Remember reported pressure */
- s->pressure0 = data[6];
- s->pressure1 = data[7];
+ /* Report zero pressure */
+ data[6] = 0;
+ data[7] = 0;
}
}
+ /* If this is a pen input report of Sirius Battery Free Tablet */
+ if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
+ report->type == HID_INPUT_REPORT &&
+ report->id == 16 &&
+ size == 10) {
+ /*
+ * The tablet reports tilt as roughly sin(a)*21 (18 means 60
+ * degrees).
+ *
+ * This array stores angles as radians * 100, corresponding to
+ * reported values up to 60 degrees, as expected by userspace.
+ */
+ static const s8 tilt_to_radians[] = {
+ 0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
+ 50, 56, 62, 68, 74, 81, 88, 96, 105
+ };
+
+ s8 tilt_x = (s8)data[8];
+ s8 tilt_y = (s8)data[9];
+ s8 sign_x = tilt_x >= 0 ? 1 : -1;
+ s8 sign_y = tilt_y >= 0 ? 1 : -1;
+
+ tilt_x *= sign_x;
+ tilt_y *= sign_y;
+
+ /*
+ * Reverse the Y Tilt direction to match the HID standard and
+ * userspace expectations. See HID Usage Tables v1.12 16.3.2
+ * Tilt Orientation.
+ */
+ sign_y *= -1;
+
+ /*
+ * This effectively clamps reported tilt to 60 degrees - the
+ * range expected by userspace
+ */
+ if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
+ tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
+ if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
+ tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
+
+ data[8] = tilt_to_radians[tilt_x] * sign_x;
+ data[9] = tilt_to_radians[tilt_y] * sign_y;
+ }
+
return 0;
}
static void waltop_remove(struct hid_device *hdev)
{
- struct waltop_state *s = hid_get_drvdata(hdev);
-
hid_hw_stop(hdev);
- kfree(s);
}
static const struct hid_device_id waltop_devices[] = {
@@ -638,6 +794,8 @@ static const struct hid_device_id waltop_devices[] = {
USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+ USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ }
};
MODULE_DEVICE_TABLE(hid, waltop_devices);
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index cac3589..84e2fbe 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
/*
* Basic IR data is encoded into 3 bytes. The first two bytes are the
- * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+ * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
* of both.
* If data is packed, then the 3rd byte is put first and slightly
* reordered. This allows to interleave packed and non-packed data to
@@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
*/
if (packed) {
- x = ir[1] << 2;
- y = ir[2] << 2;
-
- x |= ir[0] & 0x3;
- y |= (ir[0] >> 2) & 0x3;
+ x = ir[1] | ((ir[0] & 0x03) << 8);
+ y = ir[2] | ((ir[0] & 0x0c) << 6);
} else {
- x = ir[0] << 2;
- y = ir[1] << 2;
-
- x |= (ir[2] >> 4) & 0x3;
- y |= (ir[2] >> 6) & 0x3;
+ x = ir[0] | ((ir[2] & 0x30) << 4);
+ y = ir[1] | ((ir[2] & 0xc0) << 2);
}
input_report_abs(wdata->ir, xid, x);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cf7d6d5..36fa77b 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
len = list->buffer[list->tail].len > count ?
count : list->buffer[list->tail].len;
- if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
- ret = -EFAULT;
- goto out;
+ if (list->buffer[list->tail].value) {
+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = len;
}
- ret = len;
kfree(list->buffer[list->tail].value);
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
.llseek = noop_llseek,
};
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
{
struct hidraw *dev = hid->hidraw;
struct hidraw_list *list;
+ int ret = 0;
list_for_each_entry(list, &dev->list, node) {
- list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+ if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
+ ret = -ENOMEM;
+ break;
+ }
list->buffer[list->head].len = len;
list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&dev->wait);
+ return ret;
}
EXPORT_SYMBOL_GPL(hidraw_report_event);
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5bf91db..482f936 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -28,6 +28,7 @@
#include <linux/input.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/string.h>
#include <linux/usb.h>
@@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)
!test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
- if (rc != 0)
+ if (rc != 0) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ if (rc == -ENOSPC)
+ set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ } else {
+ clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ }
}
spin_unlock_irqrestore(&usbhid->lock, flags);
return rc;
@@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)
if (time_after(jiffies, usbhid->stop_retry)) {
- /* Retries failed, so do a port reset */
- if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ /* Retries failed, so do a port reset unless we lack bandwidth*/
+ if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
+ && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+
schedule_work(&usbhid->reset_work);
goto done;
}
@@ -203,7 +211,7 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
return 0;
if ((kicked = (usbhid->outhead != usbhid->outtail))) {
- dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
r = usb_autopm_get_interface_async(usbhid->intf);
if (r < 0)
@@ -230,7 +238,7 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
return 0;
if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
- dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
r = usb_autopm_get_interface_async(usbhid->intf);
if (r < 0)
@@ -399,6 +407,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
* Output interrupt completion handler.
*/
+static int irq_out_pump_restart(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->outhead != usbhid->outtail)
+ return hid_submit_out(hid);
+ else
+ return -1;
+}
+
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
@@ -428,7 +446,7 @@ static void hid_irq_out(struct urb *urb)
else
usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
- if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) {
+ if (!irq_out_pump_restart(hid)) {
/* Successfully submitted next urb in queue */
spin_unlock_irqrestore(&usbhid->lock, flags);
return;
@@ -443,6 +461,15 @@ static void hid_irq_out(struct urb *urb)
/*
* Control pipe completion handler.
*/
+static int ctrl_pump_restart(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->ctrlhead != usbhid->ctrltail)
+ return hid_submit_ctrl(hid);
+ else
+ return -1;
+}
static void hid_ctrl(struct urb *urb)
{
@@ -476,7 +503,7 @@ static void hid_ctrl(struct urb *urb)
else
usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) {
+ if (!ctrl_pump_restart(hid)) {
/* Successfully submitted next urb in queue */
spin_unlock(&usbhid->lock);
return;
@@ -535,11 +562,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
- * no race because this is called under
+ * no race because the URB is blocked under
* spinlock
*/
- if (time_after(jiffies, usbhid->last_out + HZ * 5))
+ if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+ usb_block_urb(usbhid->urbout);
+ /* drop lock to not deadlock if the callback is called */
+ spin_unlock(&usbhid->lock);
usb_unlink_urb(usbhid->urbout);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbout);
+ /*
+ * if the unlinking has already completed
+ * the pump will have been stopped
+ * it must be restarted now
+ */
+ if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ if (!irq_out_pump_restart(hid))
+ set_bit(HID_OUT_RUNNING, &usbhid->iofl);
+
+
+ }
}
return;
}
@@ -583,11 +626,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
- * no race because this is called under
+ * no race because the URB is blocked under
* spinlock
*/
- if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+ if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
+ usb_block_urb(usbhid->urbctrl);
+ /* drop lock to not deadlock if the callback is called */
+ spin_unlock(&usbhid->lock);
usb_unlink_urb(usbhid->urbctrl);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbctrl);
+ /*
+ * if the unlinking has already completed
+ * the pump will have been stopped
+ * it must be restarted now
+ */
+ if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ if (!ctrl_pump_restart(hid))
+ set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ }
}
}
@@ -700,7 +757,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
int usbhid_open(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- int res;
+ int res = 0;
mutex_lock(&hid_open_mut);
if (!hid->open++) {
@@ -708,17 +765,27 @@ int usbhid_open(struct hid_device *hid)
/* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
- mutex_unlock(&hid_open_mut);
- return -EIO;
+ res = -EIO;
+ goto done;
}
usbhid->intf->needs_remote_wakeup = 1;
- if (hid_start_in(hid))
- hid_io_error(hid);
-
+ res = hid_start_in(hid);
+ if (res) {
+ if (res != -ENOSPC) {
+ hid_io_error(hid);
+ res = 0;
+ } else {
+ /* no use opening if resources are insufficient */
+ hid->open--;
+ res = -EBUSY;
+ usbhid->intf->needs_remote_wakeup = 0;
+ }
+ }
usb_autopm_put_interface(usbhid->intf);
}
+done:
mutex_unlock(&hid_open_mut);
- return 0;
+ return res;
}
void usbhid_close(struct hid_device *hid)
@@ -1347,7 +1414,34 @@ static int hid_post_reset(struct usb_interface *intf)
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_host_interface *interface = intf->cur_altsetting;
int status;
+ char *rdesc;
+
+ /* Fetch and examine the HID report descriptor. If this
+ * has changed, then rebind. Since usbcore's check of the
+ * configuration descriptors passed, we already know that
+ * the size of the HID report descriptor has not changed.
+ */
+ rdesc = kmalloc(hid->rsize, GFP_KERNEL);
+ if (!rdesc) {
+ dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+ return 1;
+ }
+ status = hid_get_class_descriptor(dev,
+ interface->desc.bInterfaceNumber,
+ HID_DT_REPORT, rdesc, hid->rsize);
+ if (status < 0) {
+ dbg_hid("reading report descriptor failed (post_reset)\n");
+ kfree(rdesc);
+ return 1;
+ }
+ status = memcmp(rdesc, hid->rdesc, hid->rsize);
+ kfree(rdesc);
+ if (status != 0) {
+ dbg_hid("report descriptor changed\n");
+ return 1;
+ }
spin_lock_irq(&usbhid->lock);
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
@@ -1504,28 +1598,15 @@ static struct usb_driver hid_driver = {
.supports_autosuspend = 1,
};
-static const struct hid_device_id hid_usb_table[] = {
- { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
- { }
-};
-
struct usb_interface *usbhid_find_interface(int minor)
{
return usb_find_interface(&hid_driver, minor);
}
-static struct hid_driver hid_usb_driver = {
- .name = "generic-usb",
- .id_table = hid_usb_table,
-};
-
static int __init hid_init(void)
{
int retval = -ENOMEM;
- retval = hid_register_driver(&hid_usb_driver);
- if (retval)
- goto hid_register_fail;
retval = usbhid_quirks_init(quirks_param);
if (retval)
goto usbhid_quirks_init_fail;
@@ -1538,8 +1619,6 @@ static int __init hid_init(void)
usb_register_fail:
usbhid_quirks_exit();
usbhid_quirks_init_fail:
- hid_unregister_driver(&hid_usb_driver);
-hid_register_fail:
return retval;
}
@@ -1547,7 +1626,6 @@ static void __exit hid_exit(void)
{
usb_deregister(&hid_driver);
usbhid_quirks_exit();
- hid_unregister_driver(&hid_usb_driver);
}
module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 782c639..0597ee6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -88,6 +88,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index b1ec0e2..14599e2 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/compat.h>
+#include <linux/vmalloc.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)
} else {
mutex_unlock(&list->hiddev->existancelock);
kfree(list->hiddev);
- kfree(list);
+ vfree(list);
return 0;
}
}
mutex_unlock(&list->hiddev->existancelock);
- kfree(list);
+ vfree(list);
return 0;
}
@@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
hid = usb_get_intfdata(intf);
hiddev = hid->hiddev;
- if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+ if (!(list = vzalloc(sizeof(struct hiddev_list))))
return -ENOMEM;
mutex_init(&list->thread_lock);
list->hiddev = hiddev;
@@ -322,7 +323,7 @@ bail_unlock:
mutex_unlock(&hiddev->existancelock);
bail:
file->private_data = NULL;
- kfree(list);
+ vfree(list);
return res;
}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index cb8f703..1883d7b 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
#define HID_STARTED 8
#define HID_REPORTED_IDLE 9
#define HID_KEYS_PRESSED 10
+#define HID_NO_BANDWIDTH 11
/*
* USB-specific HID struct, to be pointed to
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 0f6be45..bf16d72 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -92,9 +92,10 @@ static void usb_mouse_irq(struct urb *urb)
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- mouse->usbdev->bus->bus_name,
- mouse->usbdev->devpath, status);
+ dev_err(&mouse->usbdev->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ mouse->usbdev->bus->bus_name,
+ mouse->usbdev->devpath, status);
}
static int usb_mouse_open(struct input_dev *dev)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 9ffbfc5..2b8b8d4 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -46,40 +46,61 @@ struct vmbus_channel_message_table_entry {
*
* @icmsghdrp is of type &struct icmsg_hdr.
* @negop is of type &struct icmsg_negotiate.
- * Set up and fill in default negotiate response message. This response can
- * come from both the vmbus driver and the hv_utils driver. The current api
- * will respond properly to both Windows 2008 and Windows 2008-R2 operating
- * systems.
+ * Set up and fill in default negotiate response message.
+ *
+ * The max_fw_version specifies the maximum framework version that
+ * we can support and max _srv_version specifies the maximum service
+ * version we can support. A special value MAX_SRV_VER can be
+ * specified to indicate that we can handle the maximum version
+ * exposed by the host.
*
* Mainly used by Hyper-V drivers.
*/
void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
- struct icmsg_negotiate *negop, u8 *buf)
+ struct icmsg_negotiate *negop, u8 *buf,
+ int max_fw_version, int max_srv_version)
{
- if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- icmsghdrp->icmsgsize = 0x10;
-
- negop = (struct icmsg_negotiate *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- if (negop->icframe_vercnt == 2 &&
- negop->icversion_data[1].major == 3) {
- negop->icversion_data[0].major = 3;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 3;
- negop->icversion_data[1].minor = 0;
- } else {
- negop->icversion_data[0].major = 1;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 1;
- negop->icversion_data[1].minor = 0;
- }
+ int icframe_vercnt;
+ int icmsg_vercnt;
+ int i;
+
+ icmsghdrp->icmsgsize = 0x10;
+
+ negop = (struct icmsg_negotiate *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ icframe_vercnt = negop->icframe_vercnt;
+ icmsg_vercnt = negop->icmsg_vercnt;
+
+ /*
+ * Select the framework version number we will
+ * support.
+ */
+
+ for (i = 0; i < negop->icframe_vercnt; i++) {
+ if (negop->icversion_data[i].major <= max_fw_version)
+ icframe_vercnt = negop->icversion_data[i].major;
+ }
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
+ for (i = negop->icframe_vercnt;
+ (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
+ if (negop->icversion_data[i].major <= max_srv_version)
+ icmsg_vercnt = negop->icversion_data[i].major;
}
+
+ /*
+ * Respond with the maximum framework and service
+ * version numbers we can support.
+ */
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ negop->icversion_data[0].major = icframe_vercnt;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = icmsg_vercnt;
+ negop->icversion_data[1].minor = 0;
}
+
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
/*
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 15956bd..86f8885 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -252,7 +252,7 @@ void hv_cleanup(void)
*
* This involves a hypercall.
*/
-u16 hv_post_message(union hv_connection_id connection_id,
+int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size)
{
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 6186025..0012eed 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -394,7 +394,8 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer);
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
} else {
kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index dbb8b8e..d3ac6a4 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -70,7 +70,8 @@ static void shutdown_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
} else {
shutdown_msg =
(struct shutdown_msg_data *)&shut_txf_buf[
@@ -195,7 +196,8 @@ static void timesync_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
+ MAX_SRV_VER, MAX_SRV_VER);
} else {
timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
@@ -234,7 +236,8 @@ static void heartbeat_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL,
+ hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
} else {
heartbeat_msg =
(struct heartbeat_msg_data *)&hbeat_txf_buf[
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 699f0d8..b9426a6 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -495,7 +495,7 @@ extern int hv_init(void);
extern void hv_cleanup(void);
-extern u16 hv_post_message(union hv_connection_id connection_id,
+extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8deedc1..7cd9bf4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -318,7 +318,7 @@ config SENSORS_EXYNOS4_TMU
tristate "Temperature sensor on Samsung EXYNOS4"
depends on ARCH_EXYNOS4
help
- If you say yes here you get support for TMU (Thermal Managment
+ If you say yes here you get support for TMU (Thermal Management
Unit) on SAMSUNG EXYNOS4 series of SoC.
This driver can also be built as a module. If so, the module
@@ -1102,6 +1102,19 @@ config SENSORS_AMC6821
This driver can also be build as a module. If so, the module
will be called amc6821.
+config SENSORS_INA2XX
+ tristate "Texas Instruments INA219, INA226"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for INA219 and INA226 power
+ monitor chips.
+
+ The INA2xx driver is configured for the default configuration of
+ the part as described in the datasheet.
+ Default value for Rshunt is 10 mOhms.
+ This driver can also be built as a module. If so, the module
+ will be called ina2xx.
+
config SENSORS_THMC50
tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6d3f11f..e1eeac1 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 9140236..34ad5a2 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -107,15 +107,7 @@ struct acpi_power_meter_resource {
struct kobject *holders_dir;
};
-struct ro_sensor_template {
- char *label;
- ssize_t (*show)(struct device *dev,
- struct device_attribute *devattr,
- char *buf);
- int index;
-};
-
-struct rw_sensor_template {
+struct sensor_template {
char *label;
ssize_t (*show)(struct device *dev,
struct device_attribute *devattr,
@@ -469,52 +461,67 @@ static ssize_t show_name(struct device *dev,
return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
}
+#define RO_SENSOR_TEMPLATE(_label, _show, _index) \
+ { \
+ .label = _label, \
+ .show = _show, \
+ .index = _index, \
+ }
+
+#define RW_SENSOR_TEMPLATE(_label, _show, _set, _index) \
+ { \
+ .label = _label, \
+ .show = _show, \
+ .set = _set, \
+ .index = _index, \
+ }
+
/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */
-static struct ro_sensor_template meter_ro_attrs[] = {
-{POWER_AVERAGE_NAME, show_power, 0},
-{"power1_accuracy", show_accuracy, 0},
-{"power1_average_interval_min", show_val, 0},
-{"power1_average_interval_max", show_val, 1},
-{"power1_is_battery", show_val, 5},
-{NULL, NULL, 0},
+static struct sensor_template meter_attrs[] = {
+ RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
+ RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
+ RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
+ RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
+ RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
+ RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
+ set_avg_interval, 0),
+ {},
};
-static struct rw_sensor_template meter_rw_attrs[] = {
-{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_cap_attrs[] = {
+ RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
+ RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
+ RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
+ RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
+ {},
};
-static struct ro_sensor_template misc_cap_attrs[] = {
-{"power1_cap_min", show_val, 2},
-{"power1_cap_max", show_val, 3},
-{"power1_cap_hyst", show_val, 4},
-{POWER_ALARM_NAME, show_val, 6},
-{NULL, NULL, 0},
+static struct sensor_template ro_cap_attrs[] = {
+ RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
+ {},
};
-static struct ro_sensor_template ro_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, 0},
-{NULL, NULL, 0},
+static struct sensor_template rw_cap_attrs[] = {
+ RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
+ {},
};
-static struct rw_sensor_template rw_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, set_cap, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template trip_attrs[] = {
+ RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
+ RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
+ {},
};
-static struct rw_sensor_template trip_attrs[] = {
-{"power1_average_min", show_val, set_trip, 7},
-{"power1_average_max", show_val, set_trip, 8},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_attrs[] = {
+ RO_SENSOR_TEMPLATE("name", show_name, 0),
+ RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
+ RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
+ RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
+ {},
};
-static struct ro_sensor_template misc_attrs[] = {
-{"name", show_name, 0},
-{"power1_model_number", show_str, 0},
-{"power1_oem_info", show_str, 2},
-{"power1_serial_number", show_str, 1},
-{NULL, NULL, 0},
-};
+#undef RO_SENSOR_TEMPLATE
+#undef RW_SENSOR_TEMPLATE
/* Read power domain data */
static void remove_domain_devices(struct acpi_power_meter_resource *resource)
@@ -619,49 +626,24 @@ end:
}
/* Registration and deregistration */
-static int register_ro_attrs(struct acpi_power_meter_resource *resource,
- struct ro_sensor_template *ro)
+static int register_attrs(struct acpi_power_meter_resource *resource,
+ struct sensor_template *attrs)
{
struct device *dev = &resource->acpi_dev->dev;
struct sensor_device_attribute *sensors =
&resource->sensors[resource->num_sensors];
int res = 0;
- while (ro->label) {
- sensors->dev_attr.attr.name = ro->label;
+ while (attrs->label) {
+ sensors->dev_attr.attr.name = attrs->label;
sensors->dev_attr.attr.mode = S_IRUGO;
- sensors->dev_attr.show = ro->show;
- sensors->index = ro->index;
+ sensors->dev_attr.show = attrs->show;
+ sensors->index = attrs->index;
- sysfs_attr_init(&sensors->dev_attr.attr);
- res = device_create_file(dev, &sensors->dev_attr);
- if (res) {
- sensors->dev_attr.attr.name = NULL;
- goto error;
+ if (attrs->set) {
+ sensors->dev_attr.attr.mode |= S_IWUSR;
+ sensors->dev_attr.store = attrs->set;
}
- sensors++;
- resource->num_sensors++;
- ro++;
- }
-
-error:
- return res;
-}
-
-static int register_rw_attrs(struct acpi_power_meter_resource *resource,
- struct rw_sensor_template *rw)
-{
- struct device *dev = &resource->acpi_dev->dev;
- struct sensor_device_attribute *sensors =
- &resource->sensors[resource->num_sensors];
- int res = 0;
-
- while (rw->label) {
- sensors->dev_attr.attr.name = rw->label;
- sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
- sensors->dev_attr.show = rw->show;
- sensors->dev_attr.store = rw->set;
- sensors->index = rw->index;
sysfs_attr_init(&sensors->dev_attr.attr);
res = device_create_file(dev, &sensors->dev_attr);
@@ -671,7 +653,7 @@ static int register_rw_attrs(struct acpi_power_meter_resource *resource,
}
sensors++;
resource->num_sensors++;
- rw++;
+ attrs++;
}
error:
@@ -703,10 +685,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
return res;
if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
- res = register_ro_attrs(resource, meter_ro_attrs);
- if (res)
- goto error;
- res = register_rw_attrs(resource, meter_rw_attrs);
+ res = register_attrs(resource, meter_attrs);
if (res)
goto error;
}
@@ -718,28 +697,27 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
goto skip_unsafe_cap;
}
- if (resource->caps.configurable_cap) {
- res = register_rw_attrs(resource, rw_cap_attrs);
- if (res)
- goto error;
- } else {
- res = register_ro_attrs(resource, ro_cap_attrs);
- if (res)
- goto error;
- }
- res = register_ro_attrs(resource, misc_cap_attrs);
+ if (resource->caps.configurable_cap)
+ res = register_attrs(resource, rw_cap_attrs);
+ else
+ res = register_attrs(resource, ro_cap_attrs);
+
+ if (res)
+ goto error;
+
+ res = register_attrs(resource, misc_cap_attrs);
if (res)
goto error;
}
-skip_unsafe_cap:
+skip_unsafe_cap:
if (resource->caps.flags & POWER_METER_CAN_TRIP) {
- res = register_rw_attrs(resource, trip_attrs);
+ res = register_attrs(resource, trip_attrs);
if (res)
goto error;
}
- res = register_ro_attrs(resource, misc_attrs);
+ res = register_attrs(resource, misc_attrs);
if (res)
goto error;
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index f85ce70..cfec802 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -18,21 +18,14 @@
#include <linux/hwmon-sysfs.h>
/*
- * AD7314 power mode
- */
-#define AD7314_PD 0x2000
-
-/*
* AD7314 temperature masks
*/
-#define AD7314_TEMP_SIGN 0x200
#define AD7314_TEMP_MASK 0x7FE0
-#define AD7314_TEMP_OFFSET 5
+#define AD7314_TEMP_SHIFT 5
/*
* ADT7301 and ADT7302 temperature masks
*/
-#define ADT7301_TEMP_SIGN 0x2000
#define ADT7301_TEMP_MASK 0x3FFF
enum ad7314_variant {
@@ -73,7 +66,7 @@ static ssize_t ad7314_show_temperature(struct device *dev,
return ret;
switch (spi_get_device_id(chip->spi_dev)->driver_data) {
case ad7314:
- data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
+ data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
data = (data << 6) >> 6;
return sprintf(buf, "%d\n", 250 * data);
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index e8e18ca..6b13f1a 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -257,15 +257,4 @@ static struct pci_driver fam15h_power_driver = {
.remove = __devexit_p(fam15h_power_remove),
};
-static int __init fam15h_power_init(void)
-{
- return pci_register_driver(&fam15h_power_driver);
-}
-
-static void __exit fam15h_power_exit(void)
-{
- pci_unregister_driver(&fam15h_power_driver);
-}
-
-module_init(fam15h_power_init)
-module_exit(fam15h_power_exit)
+module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 0000000..7f3f4a3
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
@@ -0,0 +1,368 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * INA219:
+ * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina219
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* common register definitions */
+#define INA2XX_CONFIG 0x00
+#define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE 0x02 /* readonly */
+#define INA2XX_POWER 0x03 /* readonly */
+#define INA2XX_CURRENT 0x04 /* readonly */
+#define INA2XX_CALIBRATION 0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE 0x06
+#define INA226_ALERT_LIMIT 0x07
+#define INA226_DIE_ID 0xFF
+
+
+/* register count */
+#define INA219_REGISTERS 6
+#define INA226_REGISTERS 8
+
+#define INA2XX_MAX_REGISTERS 8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
+#define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE 15
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated;
+
+ int kind;
+ int registers;
+ u16 regs[INA2XX_MAX_REGISTERS];
+};
+
+int ina2xx_read_word(struct i2c_client *client, int reg)
+{
+ int val = i2c_smbus_read_word_data(client, reg);
+ if (unlikely(val < 0)) {
+ dev_dbg(&client->dev,
+ "Failed to read register: %d\n", reg);
+ return val;
+ }
+ return be16_to_cpu(val);
+}
+
+void ina2xx_write_word(struct i2c_client *client, int reg, int data)
+{
+ i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina2xx_data *data = i2c_get_clientdata(client);
+ struct ina2xx_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated +
+ HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+
+ int i;
+
+ dev_dbg(&client->dev, "Starting ina2xx update\n");
+
+ /* Read all registers */
+ for (i = 0; i < data->registers; i++) {
+ int rv = ina2xx_read_word(client, i);
+ if (rv < 0) {
+ ret = ERR_PTR(rv);
+ goto abort;
+ }
+ data->regs[i] = rv;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+{
+ /*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 & 2 -> conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA219_CALIBRATION_VALUE
+ */
+ int val = data->regs[reg];
+
+ switch (reg) {
+ case INA2XX_SHUNT_VOLTAGE:
+ /* LSB=10uV. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val, 100);
+ break;
+ case INA2XX_BUS_VOLTAGE:
+ /* LSB=4mV. Register is not right aligned, convert to mV. */
+ val = (val >> 3) * 4;
+ break;
+ case INA2XX_POWER:
+ /* LSB=20mW. Convert to uW */
+ val = val * 20 * 1000;
+ break;
+ case INA2XX_CURRENT:
+ /* LSB=1mA (selected). Is in mA */
+ break;
+ default:
+ /* programmer goofed */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+{
+ /*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 & 2 -> conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA226_CALIBRATION_VALUE
+ */
+ int val = data->regs[reg];
+
+ switch (reg) {
+ case INA2XX_SHUNT_VOLTAGE:
+ /* LSB=2.5uV. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val, 400);
+ break;
+ case INA2XX_BUS_VOLTAGE:
+ /* LSB=1.25mV. Convert to mV. */
+ val = val + DIV_ROUND_CLOSEST(val, 4);
+ break;
+ case INA2XX_POWER:
+ /* LSB=25mW. Convert to uW */
+ val = val * 25 * 1000;
+ break;
+ case INA2XX_CURRENT:
+ /* LSB=1mA (selected). Is in mA */
+ break;
+ default:
+ /* programmer goofed */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static ssize_t ina2xx_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ int value = 0;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ switch (data->kind) {
+ case ina219:
+ value = ina219_get_value(data, attr->index);
+ break;
+ case ina226:
+ value = ina226_get_value(data, attr->index);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/* shunt voltage */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+
+/* bus voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+
+/* calculated current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_CURRENT);
+
+/* calculated power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_POWER);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+ .attrs = ina2xx_attributes,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct ina2xx_data *data;
+ struct ina2xx_platform_data *pdata;
+ int ret = 0;
+ long shunt = 10000; /* default shunt value 10mOhms */
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (client->dev.platform_data) {
+ pdata =
+ (struct ina2xx_platform_data *)client->dev.platform_data;
+ shunt = pdata->shunt_uohms;
+ }
+
+ if (shunt <= 0)
+ return -ENODEV;
+
+ /* set the device type */
+ data->kind = id->driver_data;
+
+ switch (data->kind) {
+ case ina219:
+ /* device configuration */
+ ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+
+ /* set current LSB to 1mA, shunt is in uOhms */
+ /* (equation 13 in datasheet) */
+ ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
+ dev_info(&client->dev,
+ "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
+ data->registers = INA219_REGISTERS;
+ break;
+ case ina226:
+ /* device configuration */
+ ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
+
+ /* set current LSB to 1mA, shunt is in uOhms */
+ /* (equation 1 in datasheet)*/
+ ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
+ dev_info(&client->dev,
+ "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
+ data->registers = INA226_REGISTERS;
+ break;
+ default:
+ /* unknown device id */
+ return -ENODEV;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
+ if (ret)
+ return ret;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_err_hwmon;
+ }
+
+ return 0;
+
+out_err_hwmon:
+ sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+ return ret;
+}
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+ struct ina2xx_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+
+ return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+ { "ina219", ina219 },
+ { "ina226", ina226 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+ .driver = {
+ .name = "ina2xx",
+ },
+ .probe = ina2xx_probe,
+ .remove = ina2xx_remove,
+ .id_table = ina2xx_id,
+};
+
+static int __init ina2xx_init(void)
+{
+ return i2c_add_driver(&ina2xx_driver);
+}
+
+static void __exit ina2xx_exit(void)
+{
+ i2c_del_driver(&ina2xx_driver);
+}
+
+MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
+
+module_init(ina2xx_init);
+module_exit(ina2xx_exit);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0b204e4..e7701d9 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -19,6 +19,8 @@
* IT8726F Super I/O chip w/LPC interface
* IT8728F Super I/O chip w/LPC interface
* IT8758E Super I/O chip w/LPC interface
+ * IT8782F Super I/O chip w/LPC interface
+ * IT8783E/F Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
*
* Copyright (C) 2001 Chris Gauthron
@@ -59,7 +61,8 @@
#define DRVNAME "it87"
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
+ it8783 };
static unsigned short force_id;
module_param(force_id, ushort, 0);
@@ -137,13 +140,18 @@ static inline void superio_exit(void)
#define IT8721F_DEVID 0x8721
#define IT8726F_DEVID 0x8726
#define IT8728F_DEVID 0x8728
+#define IT8782F_DEVID 0x8782
+#define IT8783E_DEVID 0x8783
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO1_REG 0x25
#define IT87_SIO_GPIO3_REG 0x27
#define IT87_SIO_GPIO5_REG 0x29
+#define IT87_SIO_PINX1_REG 0x2a /* Pin selection */
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
+#define IT87_SIO_SPI_REG 0xef /* SPI function pin select */
#define IT87_SIO_VID_REG 0xfc /* VID value */
#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
@@ -210,6 +218,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_VIN_ENABLE 0x50
#define IT87_REG_TEMP_ENABLE 0x51
+#define IT87_REG_TEMP_EXTRA 0x55
#define IT87_REG_BEEP_ENABLE 0x5c
#define IT87_REG_CHIPID 0x58
@@ -226,9 +235,11 @@ struct it87_sio_data {
u8 beep_pin;
u8 internal; /* Internal sensors can be labeled */
/* Features skipped based on config or DMI */
+ u16 skip_in;
u8 skip_vid;
u8 skip_fan;
u8 skip_pwm;
+ u8 skip_temp;
};
/*
@@ -253,6 +264,7 @@ struct it87_data {
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[5]; /* Register values, possibly combined */
u16 fan_min[5]; /* Register values, possibly combined */
+ u8 has_temp; /* Bitfield, temp sensors enabled */
s8 temp[3]; /* Register value */
s8 temp_high[3]; /* Register value */
s8 temp_low[3]; /* Register value */
@@ -304,31 +316,23 @@ static inline int has_newer_autopwm(const struct it87_data *data)
|| data->type == it8728;
}
-static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+static int adc_lsb(const struct it87_data *data, int nr)
{
- long lsb;
-
- if (has_12mv_adc(data)) {
- if (data->in_scaled & (1 << nr))
- lsb = 24;
- else
- lsb = 12;
- } else
- lsb = 16;
+ int lsb = has_12mv_adc(data) ? 12 : 16;
+ if (data->in_scaled & (1 << nr))
+ lsb <<= 1;
+ return lsb;
+}
- val = DIV_ROUND_CLOSEST(val, lsb);
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+{
+ val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
return SENSORS_LIMIT(val, 0, 255);
}
static int in_from_reg(const struct it87_data *data, int nr, int val)
{
- if (has_12mv_adc(data)) {
- if (data->in_scaled & (1 << nr))
- return val * 24;
- else
- return val * 12;
- } else
- return val * 16;
+ return val * adc_lsb(data, nr);
}
static inline u8 FAN_TO_REG(long rpm, int div)
@@ -407,7 +411,9 @@ static inline int has_16bit_fans(const struct it87_data *data)
|| data->type == it8718
|| data->type == it8720
|| data->type == it8721
- || data->type == it8728;
+ || data->type == it8728
+ || data->type == it8782
+ || data->type == it8783;
}
static inline int has_old_autopwm(const struct it87_data *data)
@@ -1369,57 +1375,103 @@ static ssize_t show_name(struct device *dev, struct device_attribute
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static struct attribute *it87_attributes[] = {
+static struct attribute *it87_attributes_in[9][5] = {
+{
&sensor_dev_attr_in0_input.dev_attr.attr,
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in5_input.dev_attr.attr,
- &sensor_dev_attr_in6_input.dev_attr.attr,
- &sensor_dev_attr_in7_input.dev_attr.attr,
- &sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in3_min.dev_attr.attr,
- &sensor_dev_attr_in4_min.dev_attr.attr,
- &sensor_dev_attr_in5_min.dev_attr.attr,
- &sensor_dev_attr_in6_min.dev_attr.attr,
- &sensor_dev_attr_in7_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in3_max.dev_attr.attr,
- &sensor_dev_attr_in4_max.dev_attr.attr,
- &sensor_dev_attr_in5_max.dev_attr.attr,
- &sensor_dev_attr_in6_max.dev_attr.attr,
- &sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in5_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in6_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in7_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ NULL
+} };
+static const struct attribute_group it87_group_in[9] = {
+ { .attrs = it87_attributes_in[0] },
+ { .attrs = it87_attributes_in[1] },
+ { .attrs = it87_attributes_in[2] },
+ { .attrs = it87_attributes_in[3] },
+ { .attrs = it87_attributes_in[4] },
+ { .attrs = it87_attributes_in[5] },
+ { .attrs = it87_attributes_in[6] },
+ { .attrs = it87_attributes_in[7] },
+ { .attrs = it87_attributes_in[8] },
+};
+
+static struct attribute *it87_attributes_temp[3][6] = {
+{
&sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp2_min.dev_attr.attr,
- &sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp1_type.dev_attr.attr,
- &sensor_dev_attr_temp2_type.dev_attr.attr,
- &sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ NULL
+} , {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ NULL
+} , {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_temp[3] = {
+ { .attrs = it87_attributes_temp[0] },
+ { .attrs = it87_attributes_temp[1] },
+ { .attrs = it87_attributes_temp[2] },
+};
+static struct attribute *it87_attributes[] = {
&dev_attr_alarms.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_name.attr,
@@ -1430,7 +1482,7 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};
-static struct attribute *it87_attributes_beep[] = {
+static struct attribute *it87_attributes_in_beep[] = {
&sensor_dev_attr_in0_beep.dev_attr.attr,
&sensor_dev_attr_in1_beep.dev_attr.attr,
&sensor_dev_attr_in2_beep.dev_attr.attr,
@@ -1439,15 +1491,13 @@ static struct attribute *it87_attributes_beep[] = {
&sensor_dev_attr_in5_beep.dev_attr.attr,
&sensor_dev_attr_in6_beep.dev_attr.attr,
&sensor_dev_attr_in7_beep.dev_attr.attr,
+ NULL
+};
+static struct attribute *it87_attributes_temp_beep[] = {
&sensor_dev_attr_temp1_beep.dev_attr.attr,
&sensor_dev_attr_temp2_beep.dev_attr.attr,
&sensor_dev_attr_temp3_beep.dev_attr.attr,
- NULL
-};
-
-static const struct attribute_group it87_group_beep = {
- .attrs = it87_attributes_beep,
};
static struct attribute *it87_attributes_fan16[5][3+1] = { {
@@ -1651,6 +1701,12 @@ static int __init it87_find(unsigned short *address,
case IT8728F_DEVID:
sio_data->type = it8728;
break;
+ case IT8782F_DEVID:
+ sio_data->type = it8782;
+ break;
+ case IT8783E_DEVID:
+ sio_data->type = it8783;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -1686,16 +1742,86 @@ static int __init it87_find(unsigned short *address,
/* The IT8705F has a different LD number for GPIO */
superio_select(5);
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ } else if (sio_data->type == it8783) {
+ int reg25, reg27, reg2A, reg2C, regEF;
+
+ sio_data->skip_vid = 1; /* No VID */
+
+ superio_select(GPIO);
+
+ reg25 = superio_inb(IT87_SIO_GPIO1_REG);
+ reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+ reg2A = superio_inb(IT87_SIO_PINX1_REG);
+ reg2C = superio_inb(IT87_SIO_PINX2_REG);
+ regEF = superio_inb(IT87_SIO_SPI_REG);
+
+ /* Check if fan3 is there or not */
+ if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+ sio_data->skip_fan |= (1 << 2);
+ if ((reg25 & (1 << 4))
+ || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+ sio_data->skip_pwm |= (1 << 2);
+
+ /* Check if fan2 is there or not */
+ if (reg27 & (1 << 7))
+ sio_data->skip_fan |= (1 << 1);
+ if (reg27 & (1 << 3))
+ sio_data->skip_pwm |= (1 << 1);
+
+ /* VIN5 */
+ if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+ sio_data->skip_in |= (1 << 5); /* No VIN5 */
+
+ /* VIN6 */
+ if (reg27 & (1 << 1))
+ sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+ /*
+ * VIN7
+ * Does not depend on bit 2 of Reg2C, contrary to datasheet.
+ */
+ if (reg27 & (1 << 2)) {
+ /*
+ * The data sheet is a bit unclear regarding the
+ * internal voltage divider for VCCH5V. It says
+ * "This bit enables and switches VIN7 (pin 91) to the
+ * internal voltage divider for VCCH5V".
+ * This is different to other chips, where the internal
+ * voltage divider would connect VIN7 to an internal
+ * voltage source. Maybe that is the case here as well.
+ *
+ * Since we don't know for sure, re-route it if that is
+ * not the case, and ask the user to report if the
+ * resulting voltage is sane.
+ */
+ if (!(reg2C & (1 << 1))) {
+ reg2C |= (1 << 1);
+ superio_outb(IT87_SIO_PINX2_REG, reg2C);
+ pr_notice("Routing internal VCCH5V to in7.\n");
+ }
+ pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
+ pr_notice("Please report if it displays a reasonable voltage.\n");
+ }
+
+ if (reg2C & (1 << 0))
+ sio_data->internal |= (1 << 0);
+ if (reg2C & (1 << 1))
+ sio_data->internal |= (1 << 1);
+
+ sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+
} else {
int reg;
+ bool uart6;
superio_select(GPIO);
reg = superio_inb(IT87_SIO_GPIO3_REG);
- if (sio_data->type == it8721 || sio_data->type == it8728) {
+ if (sio_data->type == it8721 || sio_data->type == it8728 ||
+ sio_data->type == it8782) {
/*
- * The IT8721F/IT8758E doesn't have VID pins at all,
- * not sure about the IT8728F.
+ * IT8721F/IT8758E, and IT8782F don't have VID pins
+ * at all, not sure about the IT8728F.
*/
sio_data->skip_vid = 1;
} else {
@@ -1724,6 +1850,9 @@ static int __init it87_find(unsigned short *address,
sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
+
+ uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+
/*
* The IT8720F has no VIN7 pin, so VCCH should always be
* routed internally to VIN7 with an internal divider.
@@ -1733,8 +1862,12 @@ static int __init it87_find(unsigned short *address,
* configured, even though the IT8720F datasheet claims
* that the internal routing of VCCH to VIN7 is the default
* setting. So we force the internal routing in this case.
+ *
+ * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
+ * If UART6 is enabled, re-route VIN7 to the internal divider
+ * if that is not already the case.
*/
- if (sio_data->type == it8720 && !(reg & (1 << 1))) {
+ if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
reg |= (1 << 1);
superio_outb(IT87_SIO_PINX2_REG, reg);
pr_notice("Routing internal VCCH to in7\n");
@@ -1745,6 +1878,20 @@ static int __init it87_find(unsigned short *address,
sio_data->type == it8728)
sio_data->internal |= (1 << 1);
+ /*
+ * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
+ * While VIN7 can be routed to the internal voltage divider,
+ * VIN5 and VIN6 are not available if UART6 is enabled.
+ *
+ * Also, temp3 is not available if UART6 is enabled and TEMPIN3
+ * is the temperature source. Since we can not read the
+ * temperature source here, skip_temp is preliminary.
+ */
+ if (uart6) {
+ sio_data->skip_in |= (1 << 5) | (1 << 6);
+ sio_data->skip_temp |= (1 << 2);
+ }
+
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
}
if (sio_data->beep_pin)
@@ -1782,8 +1929,22 @@ static void it87_remove_files(struct device *dev)
int i;
sysfs_remove_group(&dev->kobj, &it87_group);
- if (sio_data->beep_pin)
- sysfs_remove_group(&dev->kobj, &it87_group_beep);
+ for (i = 0; i < 9; i++) {
+ if (sio_data->skip_in & (1 << i))
+ continue;
+ sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
+ if (it87_attributes_in_beep[i])
+ sysfs_remove_file(&dev->kobj,
+ it87_attributes_in_beep[i]);
+ }
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+ if (sio_data->beep_pin)
+ sysfs_remove_file(&dev->kobj,
+ it87_attributes_temp_beep[i]);
+ }
for (i = 0; i < 5; i++) {
if (!(data->has_fan & (1 << i)))
continue;
@@ -1823,22 +1984,22 @@ static int __devinit it87_probe(struct platform_device *pdev)
"it8720",
"it8721",
"it8728",
+ "it8782",
+ "it8783",
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) {
+ if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+ DRVNAME)) {
dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
(unsigned long)res->start,
(unsigned long)(res->start + IT87_EC_EXTENT - 1));
- err = -EBUSY;
- goto ERROR0;
+ return -EBUSY;
}
- data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto ERROR1;
- }
+ data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->addr = res->start;
data->type = sio_data->type;
@@ -1847,10 +2008,8 @@ static int __devinit it87_probe(struct platform_device *pdev)
/* Now, we do the remaining detection. */
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
- err = -ENODEV;
- goto ERROR2;
- }
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+ return -ENODEV;
platform_set_drvdata(pdev, data);
@@ -1867,6 +2026,18 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->in_scaled |= (1 << 7); /* in7 is VSB */
if (sio_data->internal & (1 << 2))
data->in_scaled |= (1 << 8); /* in8 is Vbat */
+ } else if (sio_data->type == it8782 || sio_data->type == it8783) {
+ if (sio_data->internal & (1 << 0))
+ data->in_scaled |= (1 << 3); /* in3 is VCC5V */
+ if (sio_data->internal & (1 << 1))
+ data->in_scaled |= (1 << 7); /* in7 is VCCH5V */
+ }
+
+ data->has_temp = 0x07;
+ if (sio_data->skip_temp & (1 << 2)) {
+ if (sio_data->type == it8782
+ && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+ data->has_temp &= ~(1 << 2);
}
/* Initialize the IT87 chip */
@@ -1875,12 +2046,34 @@ static int __devinit it87_probe(struct platform_device *pdev)
/* Register sysfs hooks */
err = sysfs_create_group(&dev->kobj, &it87_group);
if (err)
- goto ERROR2;
+ return err;
- if (sio_data->beep_pin) {
- err = sysfs_create_group(&dev->kobj, &it87_group_beep);
+ for (i = 0; i < 9; i++) {
+ if (sio_data->skip_in & (1 << i))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
if (err)
- goto ERROR4;
+ goto error;
+ if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
+ err = sysfs_create_file(&dev->kobj,
+ it87_attributes_in_beep[i]);
+ if (err)
+ goto error;
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
+ if (err)
+ goto error;
+ if (sio_data->beep_pin) {
+ err = sysfs_create_file(&dev->kobj,
+ it87_attributes_temp_beep[i]);
+ if (err)
+ goto error;
+ }
}
/* Do not create fan files for disabled fans */
@@ -1891,13 +2084,13 @@ static int __devinit it87_probe(struct platform_device *pdev)
continue;
err = sysfs_create_group(&dev->kobj, &fan_group[i]);
if (err)
- goto ERROR4;
+ goto error;
if (sio_data->beep_pin) {
err = sysfs_create_file(&dev->kobj,
it87_attributes_fan_beep[i]);
if (err)
- goto ERROR4;
+ goto error;
if (!fan_beep_need_rw)
continue;
@@ -1922,14 +2115,14 @@ static int __devinit it87_probe(struct platform_device *pdev)
err = sysfs_create_group(&dev->kobj,
&it87_group_pwm[i]);
if (err)
- goto ERROR4;
+ goto error;
if (!has_old_autopwm(data))
continue;
err = sysfs_create_group(&dev->kobj,
&it87_group_autopwm[i]);
if (err)
- goto ERROR4;
+ goto error;
}
}
@@ -1939,7 +2132,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->vid = sio_data->vid_value;
err = sysfs_create_group(&dev->kobj, &it87_group_vid);
if (err)
- goto ERROR4;
+ goto error;
}
/* Export labels for internal sensors */
@@ -1949,25 +2142,19 @@ static int __devinit it87_probe(struct platform_device *pdev)
err = sysfs_create_file(&dev->kobj,
it87_attributes_label[i]);
if (err)
- goto ERROR4;
+ goto error;
}
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
- goto ERROR4;
+ goto error;
}
return 0;
-ERROR4:
+error:
it87_remove_files(dev);
-ERROR2:
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-ERROR1:
- release_region(res->start, IT87_EC_EXTENT);
-ERROR0:
return err;
}
@@ -1978,10 +2165,6 @@ static int __devexit it87_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
it87_remove_files(&pdev->dev);
- release_region(data->addr, IT87_EC_EXTENT);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
@@ -2143,8 +2326,9 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
- /* IT8705F only supports three fans. */
- if (data->type != it87) {
+ /* IT8705F, IT8782F, and IT8783E/F only support three fans. */
+ if (data->type != it87 && data->type != it8782 &&
+ data->type != it8783) {
if (tmp & (1 << 4))
data->has_fan |= (1 << 3); /* fan4 enabled */
if (tmp & (1 << 5))
@@ -2233,6 +2417,8 @@ static struct it87_data *it87_update_device(struct device *dev)
}
}
for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
data->temp[i] =
it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] =
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 307bb32..7356b5e 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -225,15 +225,4 @@ static struct pci_driver k10temp_driver = {
.remove = __devexit_p(k10temp_remove),
};
-static int __init k10temp_init(void)
-{
- return pci_register_driver(&k10temp_driver);
-}
-
-static void __exit k10temp_exit(void)
-{
- pci_unregister_driver(&k10temp_driver);
-}
-
-module_init(k10temp_init)
-module_exit(k10temp_exit)
+module_pci_driver(k10temp_driver);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 5751019..35aac82 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -339,19 +339,8 @@ static struct pci_driver k8temp_driver = {
.remove = __devexit_p(k8temp_remove),
};
-static int __init k8temp_init(void)
-{
- return pci_register_driver(&k8temp_driver);
-}
-
-static void __exit k8temp_exit(void)
-{
- pci_unregister_driver(&k8temp_driver);
-}
+module_pci_driver(k8temp_driver);
MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
MODULE_DESCRIPTION("AMD K8 core temperature monitor");
MODULE_LICENSE("GPL");
-
-module_init(k8temp_init)
-module_exit(k8temp_exit)
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 9b382ec..6da9696 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -134,8 +134,7 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
return div64_u64(dividend, divisor);
}
-static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
- unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
{
struct ntc_thermistor_platform_data *pdata = data->pdata;
u64 mV = uV / 1000;
@@ -146,12 +145,12 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
if (mV == 0) {
if (pdata->connect == NTC_CONNECTED_POSITIVE)
- return UINT_MAX;
+ return INT_MAX;
return 0;
}
if (mV >= pmV)
return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
- 0 : UINT_MAX;
+ 0 : INT_MAX;
if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
N = div64_u64_safe(pdO * (pmV - mV), mV);
@@ -163,113 +162,109 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
else
N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
- return (unsigned int) N;
+ if (N > INT_MAX)
+ N = INT_MAX;
+ return N;
}
-static int lookup_comp(struct ntc_data *data,
- unsigned int ohm, int *i_low, int *i_high)
+static void lookup_comp(struct ntc_data *data, unsigned int ohm,
+ int *i_low, int *i_high)
{
- int start, end, mid = -1;
+ int start, end, mid;
+
+ /*
+ * Handle special cases: Resistance is higher than or equal to
+ * resistance in first table entry, or resistance is lower or equal
+ * to resistance in last table entry.
+ * In these cases, return i_low == i_high, either pointing to the
+ * beginning or to the end of the table depending on the condition.
+ */
+ if (ohm >= data->comp[0].ohm) {
+ *i_low = 0;
+ *i_high = 0;
+ return;
+ }
+ if (ohm <= data->comp[data->n_comp - 1].ohm) {
+ *i_low = data->n_comp - 1;
+ *i_high = data->n_comp - 1;
+ return;
+ }
/* Do a binary search on compensation table */
start = 0;
end = data->n_comp;
-
- while (end > start) {
+ while (start < end) {
mid = start + (end - start) / 2;
- if (data->comp[mid].ohm < ohm)
+ /*
+ * start <= mid < end
+ * data->comp[start].ohm > ohm >= data->comp[end].ohm
+ *
+ * We could check for "ohm == data->comp[mid].ohm" here, but
+ * that is a quite unlikely condition, and we would have to
+ * check again after updating start. Check it at the end instead
+ * for simplicity.
+ */
+ if (ohm >= data->comp[mid].ohm) {
end = mid;
- else if (data->comp[mid].ohm > ohm)
- start = mid + 1;
- else
- break;
- }
-
- if (mid == 0) {
- if (data->comp[mid].ohm > ohm) {
- *i_high = mid;
- *i_low = mid + 1;
- return 0;
- } else {
- *i_low = mid;
- *i_high = -1;
- return -EINVAL;
- }
- }
- if (mid == (data->n_comp - 1)) {
- if (data->comp[mid].ohm <= ohm) {
- *i_low = mid;
- *i_high = mid - 1;
- return 0;
} else {
- *i_low = -1;
- *i_high = mid;
- return -EINVAL;
+ start = mid + 1;
+ /*
+ * ohm >= data->comp[start].ohm might be true here,
+ * since we set start to mid + 1. In that case, we are
+ * done. We could keep going, but the condition is quite
+ * likely to occur, so it is worth checking for it.
+ */
+ if (ohm >= data->comp[start].ohm)
+ end = start;
}
+ /*
+ * start <= end
+ * data->comp[start].ohm >= ohm >= data->comp[end].ohm
+ */
}
-
- if (data->comp[mid].ohm <= ohm) {
- *i_low = mid;
- *i_high = mid - 1;
- } else {
- *i_low = mid + 1;
- *i_high = mid;
- }
-
- return 0;
+ /*
+ * start == end
+ * ohm >= data->comp[end].ohm
+ */
+ *i_low = end;
+ if (ohm == data->comp[end].ohm)
+ *i_high = end;
+ else
+ *i_high = end - 1;
}
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
{
int low, high;
- int ret;
+ int temp;
- ret = lookup_comp(data, ohm, &low, &high);
- if (ret) {
+ lookup_comp(data, ohm, &low, &high);
+ if (low == high) {
/* Unable to use linear approximation */
- if (low != -1)
- *temp = data->comp[low].temp_C * 1000;
- else if (high != -1)
- *temp = data->comp[high].temp_C * 1000;
- else
- return ret;
+ temp = data->comp[low].temp_C * 1000;
} else {
- *temp = data->comp[low].temp_C * 1000 +
+ temp = data->comp[low].temp_C * 1000 +
((data->comp[high].temp_C - data->comp[low].temp_C) *
1000 * ((int)ohm - (int)data->comp[low].ohm)) /
((int)data->comp[high].ohm - (int)data->comp[low].ohm);
}
-
- return 0;
+ return temp;
}
-static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+static int ntc_thermistor_get_ohm(struct ntc_data *data)
{
- int ret;
- int read_ohm, read_uV;
- unsigned int ohm = 0;
-
- if (data->pdata->read_ohm) {
- read_ohm = data->pdata->read_ohm();
- if (read_ohm < 0)
- return read_ohm;
- ohm = (unsigned int)read_ohm;
- }
+ int read_uV;
+
+ if (data->pdata->read_ohm)
+ return data->pdata->read_ohm();
if (data->pdata->read_uV) {
read_uV = data->pdata->read_uV();
if (read_uV < 0)
return read_uV;
- ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
- }
-
- ret = get_temp_mC(data, ohm, temp);
- if (ret) {
- dev_dbg(data->dev, "Sensor reading function not available.\n");
- return ret;
+ return get_ohm_of_thermistor(data, read_uV);
}
-
- return 0;
+ return -EINVAL;
}
static ssize_t ntc_show_name(struct device *dev,
@@ -290,12 +285,13 @@ static ssize_t ntc_show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ntc_data *data = dev_get_drvdata(dev);
- int temp, ret;
+ int ohm;
- ret = ntc_thermistor_read(data, &temp);
- if (ret)
- return ret;
- return sprintf(buf, "%d\n", temp);
+ ohm = ntc_thermistor_get_ohm(data);
+ if (ohm < 0)
+ return ohm;
+
+ return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
}
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -326,14 +322,14 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
/* Either one of the two is required. */
if (!pdata->read_uV && !pdata->read_ohm) {
- dev_err(&pdev->dev, "Both read_uV and read_ohm missing."
- "Need either one of the two.\n");
+ dev_err(&pdev->dev,
+ "Both read_uV and read_ohm missing. Need either one of the two.\n");
return -EINVAL;
}
if (pdata->read_uV && pdata->read_ohm) {
- dev_warn(&pdev->dev, "Only one of read_uV and read_ohm "
- "is needed; ignoring read_uV.\n");
+ dev_warn(&pdev->dev,
+ "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
pdata->read_uV = NULL;
}
@@ -344,12 +340,12 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
NTC_CONNECTED_POSITIVE) ||
(pdata->connect != NTC_CONNECTED_POSITIVE &&
pdata->connect != NTC_CONNECTED_GROUND))) {
- dev_err(&pdev->dev, "Required data to use read_uV not "
- "supplied.\n");
+ dev_err(&pdev->dev,
+ "Required data to use read_uV not supplied.\n");
return -EINVAL;
}
- data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -370,8 +366,7 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
pdev->id_entry->driver_data,
pdev->id_entry->name);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
platform_set_drvdata(pdev, data);
@@ -379,13 +374,13 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
if (ret) {
dev_err(data->dev, "unable to create sysfs files\n");
- goto err;
+ return ret;
}
data->hwmon_dev = hwmon_device_register(data->dev);
- if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+ if (IS_ERR(data->hwmon_dev)) {
dev_err(data->dev, "unable to register as hwmon device.\n");
- ret = -EINVAL;
+ ret = PTR_ERR(data->hwmon_dev);
goto err_after_sysfs;
}
@@ -395,8 +390,6 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
return 0;
err_after_sysfs:
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
-err:
- kfree(data);
return ret;
}
@@ -408,8 +401,6 @@ static int __devexit ntc_thermistor_remove(struct platform_device *pdev)
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d2c5095..94468a6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -351,7 +351,7 @@ config I2C_DAVINCI
For details please see http://www.ti.com/davinci
config I2C_DESIGNWARE_PLATFORM
- tristate "Synopsys DesignWare Platfrom"
+ tristate "Synopsys DesignWare Platform"
depends on HAVE_CLK
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dfb84b7..56bce9a 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -51,6 +51,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -470,6 +471,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx;
struct resource *res;
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+ struct pinctrl *pinctrl;
void __iomem *base;
resource_size_t res_size;
int irq, bitrate;
@@ -520,6 +522,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->base = base;
i2c_imx->res = res;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto fail3;
+ }
+
/* Get I2C clock */
i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
if (IS_ERR(i2c_imx->clk)) {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 76b8af4..7fa73ee 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/common.h>
@@ -325,10 +326,15 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
+ struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
int err, irq;
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index eb8ad53..99389d2 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -23,16 +23,61 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/of_i2c.h>
+
+#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
+#define I2C_PNX_SPEED_KHZ_DEFAULT 100
+#define I2C_PNX_REGION_SIZE 0x100
+
+enum {
+ mstatus_tdi = 0x00000001,
+ mstatus_afi = 0x00000002,
+ mstatus_nai = 0x00000004,
+ mstatus_drmi = 0x00000008,
+ mstatus_active = 0x00000020,
+ mstatus_scl = 0x00000040,
+ mstatus_sda = 0x00000080,
+ mstatus_rff = 0x00000100,
+ mstatus_rfe = 0x00000200,
+ mstatus_tff = 0x00000400,
+ mstatus_tfe = 0x00000800,
+};
-#include <mach/hardware.h>
-#include <mach/i2c.h>
+enum {
+ mcntrl_tdie = 0x00000001,
+ mcntrl_afie = 0x00000002,
+ mcntrl_naie = 0x00000004,
+ mcntrl_drmie = 0x00000008,
+ mcntrl_daie = 0x00000020,
+ mcntrl_rffie = 0x00000040,
+ mcntrl_tffie = 0x00000080,
+ mcntrl_reset = 0x00000100,
+ mcntrl_cdbmode = 0x00000400,
+};
-#define I2C_PNX_TIMEOUT 10 /* msec */
-#define I2C_PNX_SPEED_KHZ 100
-#define I2C_PNX_REGION_SIZE 0x100
+enum {
+ rw_bit = 1 << 0,
+ start_bit = 1 << 8,
+ stop_bit = 1 << 9,
+};
-static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
+
+static inline int wait_timeout(struct i2c_pnx_algo_data *data)
{
+ long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
mdelay(1);
@@ -41,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}
-static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+static inline int wait_reset(struct i2c_pnx_algo_data *data)
{
+ long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
mdelay(1);
@@ -54,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
struct timer_list *timer = &alg_data->mif.timer;
- unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
+ unsigned long expires = msecs_to_jiffies(alg_data->timeout);
if (expires <= 1)
expires = 2;
@@ -92,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr,
}
/* First, make sure bus is idle */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+ if (wait_timeout(alg_data)) {
/* Somebody else is monopolizing the bus */
dev_err(&alg_data->adapter.dev,
"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
@@ -185,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last) {
/* Wait until the STOP is seen. */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");
}
@@ -283,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last)
/* Wait until the STOP is seen. */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");
@@ -399,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data)
ctl |= mcntrl_reset;
iowrite32(ctl, I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
alg_data->mif.ret = -EIO;
complete(&alg_data->mif.complete);
}
@@ -414,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
/* If there is data in the fifo's after transfer,
* flush fifo's by reset.
*/
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
} else if (stat & mstatus_nai) {
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
}
}
@@ -568,14 +614,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
unsigned long freq;
- struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
-
- if (!i2c_pnx || !i2c_pnx->name) {
- dev_err(&pdev->dev, "%s: no platform data supplied\n",
- __func__);
- ret = -EINVAL;
- goto out;
- }
+ struct resource *res;
+ u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
if (!alg_data) {
@@ -585,14 +625,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, alg_data);
- strlcpy(alg_data->adapter.name, i2c_pnx->name,
- sizeof(alg_data->adapter.name));
alg_data->adapter.dev.parent = &pdev->dev;
alg_data->adapter.algo = &pnx_algorithm;
alg_data->adapter.algo_data = alg_data;
alg_data->adapter.nr = pdev->id;
- alg_data->i2c_pnx = i2c_pnx;
+ alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+#ifdef CONFIG_OF
+ alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
+ if (pdev->dev.of_node) {
+ of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &speed);
+ /*
+ * At this point, it is planned to add an OF timeout property.
+ * As soon as there is a consensus about how to call and handle
+ * this, sth. like the following can be put here:
+ *
+ * of_property_read_u32(pdev->dev.of_node, "timeout",
+ * &alg_data->timeout);
+ */
+ }
+#endif
alg_data->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(alg_data->clk)) {
ret = PTR_ERR(alg_data->clk);
@@ -603,17 +656,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
alg_data->mif.timer.function = i2c_pnx_timeout;
alg_data->mif.timer.data = (unsigned long)alg_data;
+ snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
+ "%s", pdev->name);
+
/* Register I/O resource */
- if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get mem resource.\n");
+ ret = -EBUSY;
+ goto out_clkget;
+ }
+ if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE,
pdev->name)) {
dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n",
- i2c_pnx->base);
- ret = -ENODEV;
+ res->start);
+ ret = -ENOMEM;
goto out_clkget;
}
- alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ alg_data->base = res->start;
+ alg_data->ioaddr = ioremap(res->start, I2C_PNX_REGION_SIZE);
if (!alg_data->ioaddr) {
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
ret = -ENOMEM;
@@ -637,20 +700,25 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/
- tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ tmp = (freq / speed) / 2 - 2;
if (tmp > 0x3FF)
tmp = 0x3FF;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));
iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
- if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+ if (wait_reset(alg_data)) {
ret = -ENODEV;
goto out_clock;
}
init_completion(&alg_data->mif.complete);
- ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+ alg_data->irq = platform_get_irq(pdev, 0);
+ if (alg_data->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
+ goto out_irq;
+ }
+ ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
0, pdev->name, alg_data);
if (ret)
goto out_clock;
@@ -662,39 +730,39 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
goto out_irq;
}
+ of_i2c_register_devices(&alg_data->adapter);
+
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
- alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
+ alg_data->adapter.name, res->start, alg_data->irq);
return 0;
out_irq:
- free_irq(i2c_pnx->irq, alg_data);
+ free_irq(alg_data->irq, alg_data);
out_clock:
clk_disable(alg_data->clk);
out_unmap:
iounmap(alg_data->ioaddr);
out_release:
- release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(res->start, I2C_PNX_REGION_SIZE);
out_clkget:
clk_put(alg_data->clk);
out_drvdata:
kfree(alg_data);
err_kzalloc:
platform_set_drvdata(pdev, NULL);
-out:
return ret;
}
static int __devexit i2c_pnx_remove(struct platform_device *pdev)
{
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
- struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
- free_irq(i2c_pnx->irq, alg_data);
+ free_irq(alg_data->irq, alg_data);
i2c_del_adapter(&alg_data->adapter);
clk_disable(alg_data->clk);
iounmap(alg_data->ioaddr);
- release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
clk_put(alg_data->clk);
kfree(alg_data);
platform_set_drvdata(pdev, NULL);
@@ -702,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id i2c_pnx_of_match[] = {
+ { .compatible = "nxp,pnx-i2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
+#endif
+
static struct platform_driver i2c_pnx_driver = {
.driver = {
.name = "pnx-i2c",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(i2c_pnx_of_match),
},
.probe = i2c_pnx_probe,
.remove = __devexit_p(i2c_pnx_remove),
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 7b397c6..31c47e1 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -227,6 +227,72 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev)
return 0;
}
+static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
+ struct pmac_i2c_bus *bus)
+{
+ struct i2c_client *newdev;
+ struct device_node *node;
+
+ for_each_child_of_node(adap->dev.of_node, node) {
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *reg;
+ char tmp[16];
+ u32 addr;
+ int len;
+
+ /* Get address & channel */
+ reg = of_get_property(node, "reg", &len);
+ if (!reg || (len < sizeof(int))) {
+ dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n",
+ node->full_name);
+ continue;
+ }
+ addr = be32_to_cpup(reg);
+
+ /* Multibus setup, check channel */
+ if (!pmac_i2c_match_adapter(node, adap))
+ continue;
+
+ dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
+ node->full_name);
+
+ /* Make up a modalias. Note: we to _NOT_ want the standard
+ * i2c drivers to match with any of our powermac stuff
+ * unless they have been specifically modified to handle
+ * it on a case by case basis. For example, for thermal
+ * control, things like lm75 etc... shall match with their
+ * corresponding windfarm drivers, _NOT_ the generic ones,
+ * so we force a prefix of AAPL, onto the modalias to
+ * make that happen
+ */
+ if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) {
+ dev_err(&adap->dev, "i2c-powermac: modalias failure"
+ " on %s\n", node->full_name);
+ continue;
+ }
+ snprintf(info.type, sizeof(info.type), "MAC,%s", tmp);
+
+ /* Fill out the rest of the info structure */
+ info.addr = (addr & 0xff) >> 1;
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
+
+ newdev = i2c_new_device(adap, &info);
+ if (!newdev) {
+ dev_err(&adap->dev, "i2c-powermac: Failure to register"
+ " %s\n", node->full_name);
+ of_node_put(node);
+ /* We do not dispose of the interrupt mapping on
+ * purpose. It's not necessary (interrupt cannot be
+ * re-used) and somebody else might have grabbed it
+ * via direct DT lookup so let's not bother
+ */
+ continue;
+ }
+ }
+}
static int __devinit i2c_powermac_probe(struct platform_device *dev)
{
@@ -272,6 +338,7 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
+ adapter->dev.of_node = dev->dev.of_node;
rc = i2c_add_adapter(adapter);
if (rc) {
printk(KERN_ERR "i2c-powermac: Adapter %s registration "
@@ -281,33 +348,10 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
- if (!strncmp(basename, "uni-n", 5)) {
- struct device_node *np;
- const u32 *prop;
- struct i2c_board_info info;
-
- /* Instantiate I2C motion sensor if present */
- np = of_find_node_by_name(NULL, "accelerometer");
- if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
- (prop = of_get_property(np, "reg", NULL))) {
- int i2c_bus;
- const char *tmp_bus;
-
- /* look for bus either using "reg" or by path */
- tmp_bus = strstr(np->full_name, "/i2c-bus@");
- if (tmp_bus)
- i2c_bus = *(tmp_bus + 9) - '0';
- else
- i2c_bus = ((*prop) >> 8) & 0x0f;
-
- if (pmac_i2c_get_channel(bus) == i2c_bus) {
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = ((*prop) & 0xff) >> 1;
- strlcpy(info.type, "ams", I2C_NAME_SIZE);
- i2c_new_device(adapter, &info);
- }
- }
- }
+ /* Cannot use of_i2c_register_devices() due to Apple device-tree
+ * funkyness
+ */
+ i2c_powermac_register_devices(adapter, bus);
return rc;
}
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
index c64ba73..b76a29d 100644
--- a/drivers/i2c/busses/i2c-s6000.c
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -3,7 +3,7 @@
*
* Description: Driver for S6000 Family I2C Interface
* Copyright (c) 2008 emlix GmbH
- * Author: Oskar Schirmer <os@emlix.com>
+ * Author: Oskar Schirmer <oskar@scara.com>
*
* Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
* Copyright (c) 2005-2007 Analog Devices, Inc.
diff --git a/drivers/i2c/busses/i2c-s6000.h b/drivers/i2c/busses/i2c-s6000.h
index ff23b81..4936f9f 100644
--- a/drivers/i2c/busses/i2c-s6000.h
+++ b/drivers/i2c/busses/i2c-s6000.h
@@ -6,7 +6,7 @@
* for more details.
*
* Copyright (C) 2008 Emlix GmbH <info@emlix.com>
- * Author: Oskar Schirmer <os@emlix.com>
+ * Author: Oskar Schirmer <oskar@scara.com>
*/
#ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
new file mode 100644
index 0000000..56eecef
--- /dev/null
+++ b/drivers/iio/Kconfig
@@ -0,0 +1,54 @@
+#
+# Industrial I/O subsytem configuration
+#
+
+menuconfig IIO
+ tristate "Industrial I/O support"
+ depends on GENERIC_HARDIRQS
+ help
+ The industrial I/O subsystem provides a unified framework for
+ drivers for many different types of embedded sensors using a
+ number of different physical interfaces (i2c, spi, etc). See
+ Documentation/iio for more information.
+
+if IIO
+
+config IIO_BUFFER
+ bool "Enable buffer support within IIO"
+ help
+ Provide core support for various buffer based data
+ acquisition methods.
+
+if IIO_BUFFER
+
+config IIO_KFIFO_BUF
+ select IIO_TRIGGER
+ tristate "Industrial I/O buffering based on kfifo"
+ help
+ A simple fifo based on kfifo. Use this if you want a fifo
+ rather than a ring buffer. Note that this currently provides
+ no buffer events so it is up to userspace to work out how
+ often to read from the buffer.
+
+endif # IIO_BUFFER
+
+config IIO_TRIGGER
+ boolean "Enable triggered sampling support"
+ help
+ Provides IIO core support for triggers. Currently these
+ are used to initialize capture of samples to push into
+ ring buffers. The triggers are effectively a 'capture
+ data now' interrupt.
+
+config IIO_CONSUMERS_PER_TRIGGER
+ int "Maximum number of consumers per trigger"
+ depends on IIO_TRIGGER
+ default "2"
+ help
+ This value controls the maximum number of consumers that a
+ given trigger may handle. Default is 2.
+
+source "drivers/iio/adc/Kconfig"
+source "drivers/iio/amplifiers/Kconfig"
+
+endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
new file mode 100644
index 0000000..e425afd
--- /dev/null
+++ b/drivers/iio/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the industrial I/O core.
+#
+
+obj-$(CONFIG_IIO) += industrialio.o
+industrialio-y := industrialio-core.o industrialio-event.o inkern.o
+industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
+industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+
+obj-y += adc/
+obj-y += amplifiers/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
new file mode 100644
index 0000000..9a0df81
--- /dev/null
+++ b/drivers/iio/adc/Kconfig
@@ -0,0 +1,16 @@
+#
+# ADC drivers
+#
+menu "Analog to digital converters"
+
+config AT91_ADC
+ tristate "Atmel AT91 ADC"
+ depends on ARCH_AT91
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select IIO_TRIGGER
+ select SYSFS
+ help
+ Say yes here to build support for Atmel AT91 ADC.
+
+endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
new file mode 100644
index 0000000..175c8d4
--- /dev/null
+++ b/drivers/iio/adc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO ADC drivers
+#
+
+obj-$(CONFIG_AT91_ADC) += at91_adc.o
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
new file mode 100644
index 0000000..f18a95d
--- /dev/null
+++ b/drivers/iio/adc/at91_adc.c
@@ -0,0 +1,802 @@
+/*
+ * Driver for the ADC present in the Atmel AT91 evaluation boards.
+ *
+ * Copyright 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <linux/platform_data/at91_adc.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include <mach/at91_adc.h>
+
+#define AT91_ADC_CHAN(st, ch) \
+ (st->registers->channel_base + (ch * 4))
+#define at91_adc_readl(st, reg) \
+ (readl_relaxed(st->reg_base + reg))
+#define at91_adc_writel(st, reg, val) \
+ (writel_relaxed(val, st->reg_base + reg))
+
+struct at91_adc_state {
+ struct clk *adc_clk;
+ u16 *buffer;
+ unsigned long channels_mask;
+ struct clk *clk;
+ bool done;
+ int irq;
+ bool irq_enabled;
+ u16 last_value;
+ struct mutex lock;
+ u8 num_channels;
+ void __iomem *reg_base;
+ struct at91_adc_reg_desc *registers;
+ u8 startup_time;
+ struct iio_trigger **trig;
+ struct at91_adc_trigger *trigger_list;
+ u32 trigger_number;
+ bool use_external;
+ u32 vref_mv;
+ wait_queue_head_t wq_data_avail;
+};
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_buffer *buffer = idev->buffer;
+ int i, j = 0;
+
+ for (i = 0; i < idev->masklength; i++) {
+ if (!test_bit(i, idev->active_scan_mask))
+ continue;
+ st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+ j++;
+ }
+
+ if (idev->scan_timestamp) {
+ s64 *timestamp = (s64 *)((u8 *)st->buffer +
+ ALIGN(j, sizeof(s64)));
+ *timestamp = pf->timestamp;
+ }
+
+ buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+
+ iio_trigger_notify_done(idev->trig);
+ st->irq_enabled = true;
+
+ /* Needed to ACK the DRDY interruption */
+ at91_adc_readl(st, AT91_ADC_LCDR);
+
+ enable_irq(st->irq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct at91_adc_state *st = iio_priv(idev);
+ u32 status = at91_adc_readl(st, st->registers->status_register);
+
+ if (!(status & st->registers->drdy_mask))
+ return IRQ_HANDLED;
+
+ if (iio_buffer_enabled(idev)) {
+ disable_irq_nosync(irq);
+ st->irq_enabled = false;
+ iio_trigger_poll(idev->trig, iio_get_time_ns());
+ } else {
+ st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+ st->done = true;
+ wake_up_interruptible(&st->wq_data_avail);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int at91_adc_channel_init(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_chan_spec *chan_array, *timestamp;
+ int bit, idx = 0;
+
+ idev->num_channels = bitmap_weight(&st->channels_mask,
+ st->num_channels) + 1;
+
+ chan_array = devm_kzalloc(&idev->dev,
+ ((idev->num_channels + 1) *
+ sizeof(struct iio_chan_spec)),
+ GFP_KERNEL);
+
+ if (!chan_array)
+ return -ENOMEM;
+
+ for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
+ struct iio_chan_spec *chan = chan_array + idx;
+
+ chan->type = IIO_VOLTAGE;
+ chan->indexed = 1;
+ chan->channel = bit;
+ chan->scan_index = idx;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 10;
+ chan->scan_type.storagebits = 16;
+ chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+ idx++;
+ }
+ timestamp = chan_array + idx;
+
+ timestamp->type = IIO_TIMESTAMP;
+ timestamp->channel = -1;
+ timestamp->scan_index = idx;
+ timestamp->scan_type.sign = 's';
+ timestamp->scan_type.realbits = 64;
+ timestamp->scan_type.storagebits = 64;
+
+ idev->channels = chan_array;
+ return idev->num_channels;
+}
+
+static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
+ struct at91_adc_trigger *triggers,
+ const char *trigger_name)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ u8 value = 0;
+ int i;
+
+ for (i = 0; i < st->trigger_number; i++) {
+ char *name = kasprintf(GFP_KERNEL,
+ "%s-dev%d-%s",
+ idev->name,
+ idev->id,
+ triggers[i].name);
+ if (!name)
+ return -ENOMEM;
+
+ if (strcmp(trigger_name, name) == 0) {
+ value = triggers[i].value;
+ kfree(name);
+ break;
+ }
+
+ kfree(name);
+ }
+
+ return value;
+}
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *idev = trig->private_data;
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_buffer *buffer = idev->buffer;
+ struct at91_adc_reg_desc *reg = st->registers;
+ u32 status = at91_adc_readl(st, reg->trigger_register);
+ u8 value;
+ u8 bit;
+
+ value = at91_adc_get_trigger_value_by_name(idev,
+ st->trigger_list,
+ idev->trig->name);
+ if (value == 0)
+ return -EINVAL;
+
+ if (state) {
+ st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
+ if (st->buffer == NULL)
+ return -ENOMEM;
+
+ at91_adc_writel(st, reg->trigger_register,
+ status | value);
+
+ for_each_set_bit(bit, buffer->scan_mask,
+ st->num_channels) {
+ struct iio_chan_spec const *chan = idev->channels + bit;
+ at91_adc_writel(st, AT91_ADC_CHER,
+ AT91_ADC_CH(chan->channel));
+ }
+
+ at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
+
+ } else {
+ at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
+
+ at91_adc_writel(st, reg->trigger_register,
+ status & ~value);
+
+ for_each_set_bit(bit, buffer->scan_mask,
+ st->num_channels) {
+ struct iio_chan_spec const *chan = idev->channels + bit;
+ at91_adc_writel(st, AT91_ADC_CHDR,
+ AT91_ADC_CH(chan->channel));
+ }
+ kfree(st->buffer);
+ }
+
+ return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &at91_adc_configure_trigger,
+};
+
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
+ struct at91_adc_trigger *trigger)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+ idev->id, trigger->name);
+ if (trig == NULL)
+ return NULL;
+
+ trig->dev.parent = idev->dev.parent;
+ trig->private_data = idev;
+ trig->ops = &at91_adc_trigger_ops;
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ return NULL;
+
+ return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int i, ret;
+
+ st->trig = devm_kzalloc(&idev->dev,
+ st->trigger_number * sizeof(st->trig),
+ GFP_KERNEL);
+
+ if (st->trig == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ for (i = 0; i < st->trigger_number; i++) {
+ if (st->trigger_list[i].is_external && !(st->use_external))
+ continue;
+
+ st->trig[i] = at91_adc_allocate_trigger(idev,
+ st->trigger_list + i);
+ if (st->trig[i] == NULL) {
+ dev_err(&idev->dev,
+ "Could not allocate trigger %d\n", i);
+ ret = -ENOMEM;
+ goto error_trigger;
+ }
+ }
+
+ return 0;
+
+error_trigger:
+ for (i--; i >= 0; i--) {
+ iio_trigger_unregister(st->trig[i]);
+ iio_trigger_free(st->trig[i]);
+ }
+error_ret:
+ return ret;
+}
+
+static void at91_adc_trigger_remove(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int i;
+
+ for (i = 0; i < st->trigger_number; i++) {
+ iio_trigger_unregister(st->trig[i]);
+ iio_trigger_free(st->trig[i]);
+ }
+}
+
+static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
+ .preenable = &iio_sw_buffer_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+};
+
+static int at91_adc_buffer_init(struct iio_dev *idev)
+{
+ int ret;
+
+ idev->buffer = iio_kfifo_allocate(idev);
+ if (!idev->buffer) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+ &at91_adc_trigger_handler,
+ IRQF_ONESHOT,
+ idev,
+ "%s-consumer%d",
+ idev->name,
+ idev->id);
+ if (idev->pollfunc == NULL) {
+ ret = -ENOMEM;
+ goto error_pollfunc;
+ }
+
+ idev->setup_ops = &at91_adc_buffer_ops;
+ idev->modes |= INDIO_BUFFER_TRIGGERED;
+
+ ret = iio_buffer_register(idev,
+ idev->channels,
+ idev->num_channels);
+ if (ret)
+ goto error_register;
+
+ return 0;
+
+error_register:
+ iio_dealloc_pollfunc(idev->pollfunc);
+error_pollfunc:
+ iio_kfifo_free(idev->buffer);
+error_ret:
+ return ret;
+}
+
+static void at91_adc_buffer_remove(struct iio_dev *idev)
+{
+ iio_buffer_unregister(idev);
+ iio_dealloc_pollfunc(idev->pollfunc);
+ iio_kfifo_free(idev->buffer);
+}
+
+static int at91_adc_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&st->lock);
+
+ at91_adc_writel(st, AT91_ADC_CHER,
+ AT91_ADC_CH(chan->channel));
+ at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+ at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
+
+ ret = wait_event_interruptible_timeout(st->wq_data_avail,
+ st->done,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ return -ETIMEDOUT;
+ else if (ret < 0)
+ return ret;
+
+ *val = st->last_value;
+
+ at91_adc_writel(st, AT91_ADC_CHDR,
+ AT91_ADC_CH(chan->channel));
+ at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+
+ st->last_value = 0;
+ st->done = false;
+ mutex_unlock(&st->lock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+ *val2 = 0;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int at91_adc_probe_dt(struct at91_adc_state *st,
+ struct platform_device *pdev)
+{
+ struct iio_dev *idev = iio_priv_to_dev(st);
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *trig_node;
+ int i = 0, ret;
+ u32 prop;
+
+ if (!node)
+ return -EINVAL;
+
+ st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
+
+ if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
+ dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->channels_mask = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
+ dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->num_channels = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
+ dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->startup_time = prop;
+
+
+ if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
+ dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->vref_mv = prop;
+
+ st->registers = devm_kzalloc(&idev->dev,
+ sizeof(struct at91_adc_reg_desc),
+ GFP_KERNEL);
+ if (!st->registers) {
+ dev_err(&idev->dev, "Could not allocate register memory.\n");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
+ dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->channel_base = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
+ dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->drdy_mask = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
+ dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->status_register = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
+ dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->trigger_register = prop;
+
+ st->trigger_number = of_get_child_count(node);
+ st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
+ sizeof(struct at91_adc_trigger),
+ GFP_KERNEL);
+ if (!st->trigger_list) {
+ dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ for_each_child_of_node(node, trig_node) {
+ struct at91_adc_trigger *trig = st->trigger_list + i;
+ const char *name;
+
+ if (of_property_read_string(trig_node, "trigger-name", &name)) {
+ dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ trig->name = name;
+
+ if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
+ dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ trig->value = prop;
+ trig->is_external = of_property_read_bool(trig_node, "trigger-external");
+ i++;
+ }
+
+ return 0;
+
+error_ret:
+ return ret;
+}
+
+static int at91_adc_probe_pdata(struct at91_adc_state *st,
+ struct platform_device *pdev)
+{
+ struct at91_adc_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ st->use_external = pdata->use_external_triggers;
+ st->vref_mv = pdata->vref;
+ st->channels_mask = pdata->channels_used;
+ st->num_channels = pdata->num_channels;
+ st->startup_time = pdata->startup_time;
+ st->trigger_number = pdata->trigger_number;
+ st->trigger_list = pdata->trigger_list;
+ st->registers = pdata->registers;
+
+ return 0;
+}
+
+static const struct iio_info at91_adc_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &at91_adc_read_raw,
+};
+
+static int __devinit at91_adc_probe(struct platform_device *pdev)
+{
+ unsigned int prsc, mstrclk, ticks, adc_clk;
+ int ret;
+ struct iio_dev *idev;
+ struct at91_adc_state *st;
+ struct resource *res;
+
+ idev = iio_device_alloc(sizeof(struct at91_adc_state));
+ if (idev == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st = iio_priv(idev);
+
+ if (pdev->dev.of_node)
+ ret = at91_adc_probe_dt(st, pdev);
+ else
+ ret = at91_adc_probe_pdata(st, pdev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "No platform data available.\n");
+ ret = -EINVAL;
+ goto error_free_device;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No resource defined\n");
+ ret = -ENXIO;
+ goto error_ret;
+ }
+
+ platform_set_drvdata(pdev, idev);
+
+ idev->dev.parent = &pdev->dev;
+ idev->name = dev_name(&pdev->dev);
+ idev->modes = INDIO_DIRECT_MODE;
+ idev->info = &at91_adc_info;
+
+ st->irq = platform_get_irq(pdev, 0);
+ if (st->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ ID is designated\n");
+ ret = -ENODEV;
+ goto error_free_device;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "AT91 adc registers")) {
+ dev_err(&pdev->dev, "Resources are unavailable.\n");
+ ret = -EBUSY;
+ goto error_free_device;
+ }
+
+ st->reg_base = ioremap(res->start, resource_size(res));
+ if (!st->reg_base) {
+ dev_err(&pdev->dev, "Failed to map registers.\n");
+ ret = -ENOMEM;
+ goto error_release_mem;
+ }
+
+ /*
+ * Disable all IRQs before setting up the handler
+ */
+ at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
+ at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
+ ret = request_irq(st->irq,
+ at91_adc_eoc_trigger,
+ 0,
+ pdev->dev.driver->name,
+ idev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
+ goto error_unmap_reg;
+ }
+
+ st->clk = clk_get(&pdev->dev, "adc_clk");
+ if (IS_ERR(st->clk)) {
+ dev_err(&pdev->dev, "Failed to get the clock.\n");
+ ret = PTR_ERR(st->clk);
+ goto error_free_irq;
+ }
+
+ ret = clk_prepare(st->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare the clock.\n");
+ goto error_free_clk;
+ }
+
+ ret = clk_enable(st->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable the clock.\n");
+ goto error_unprepare_clk;
+ }
+
+ st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+ if (IS_ERR(st->adc_clk)) {
+ dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
+ ret = PTR_ERR(st->clk);
+ goto error_disable_clk;
+ }
+
+ ret = clk_prepare(st->adc_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
+ goto error_free_adc_clk;
+ }
+
+ ret = clk_enable(st->adc_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
+ goto error_unprepare_adc_clk;
+ }
+
+ /*
+ * Prescaler rate computation using the formula from the Atmel's
+ * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
+ * specified by the electrical characteristics of the board.
+ */
+ mstrclk = clk_get_rate(st->clk);
+ adc_clk = clk_get_rate(st->adc_clk);
+ prsc = (mstrclk / (2 * adc_clk)) - 1;
+
+ if (!st->startup_time) {
+ dev_err(&pdev->dev, "No startup time available.\n");
+ ret = -EINVAL;
+ goto error_disable_adc_clk;
+ }
+
+ /*
+ * Number of ticks needed to cover the startup time of the ADC as
+ * defined in the electrical characteristics of the board, divided by 8.
+ * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
+ */
+ ticks = round_up((st->startup_time * adc_clk /
+ 1000000) - 1, 8) / 8;
+ at91_adc_writel(st, AT91_ADC_MR,
+ (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
+ (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+
+ /* Setup the ADC channels available on the board */
+ ret = at91_adc_channel_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
+ goto error_disable_adc_clk;
+ }
+
+ init_waitqueue_head(&st->wq_data_avail);
+ mutex_init(&st->lock);
+
+ ret = at91_adc_buffer_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+ goto error_disable_adc_clk;
+ }
+
+ ret = at91_adc_trigger_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+ goto error_unregister_buffer;
+ }
+
+ ret = iio_device_register(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_remove_triggers;
+ }
+
+ return 0;
+
+error_remove_triggers:
+ at91_adc_trigger_remove(idev);
+error_unregister_buffer:
+ at91_adc_buffer_remove(idev);
+error_disable_adc_clk:
+ clk_disable(st->adc_clk);
+error_unprepare_adc_clk:
+ clk_unprepare(st->adc_clk);
+error_free_adc_clk:
+ clk_put(st->adc_clk);
+error_disable_clk:
+ clk_disable(st->clk);
+error_unprepare_clk:
+ clk_unprepare(st->clk);
+error_free_clk:
+ clk_put(st->clk);
+error_free_irq:
+ free_irq(st->irq, idev);
+error_unmap_reg:
+ iounmap(st->reg_base);
+error_release_mem:
+ release_mem_region(res->start, resource_size(res));
+error_free_device:
+ iio_device_free(idev);
+error_ret:
+ return ret;
+}
+
+static int __devexit at91_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *idev = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct at91_adc_state *st = iio_priv(idev);
+
+ iio_device_unregister(idev);
+ at91_adc_trigger_remove(idev);
+ at91_adc_buffer_remove(idev);
+ clk_disable_unprepare(st->adc_clk);
+ clk_put(st->adc_clk);
+ clk_disable(st->clk);
+ clk_unprepare(st->clk);
+ clk_put(st->clk);
+ free_irq(st->irq, idev);
+ iounmap(st->reg_base);
+ release_mem_region(res->start, resource_size(res));
+ iio_device_free(idev);
+
+ return 0;
+}
+
+static const struct of_device_id at91_adc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9260-adc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
+
+static struct platform_driver at91_adc_driver = {
+ .probe = at91_adc_probe,
+ .remove = __devexit_p(at91_adc_remove),
+ .driver = {
+ .name = "at91_adc",
+ .of_match_table = of_match_ptr(at91_adc_dt_ids),
+ },
+};
+
+module_platform_driver(at91_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
new file mode 100644
index 0000000..05d707e
--- /dev/null
+++ b/drivers/iio/amplifiers/Kconfig
@@ -0,0 +1,17 @@
+#
+# Gain Amplifiers, etc.
+#
+menu "Amplifiers"
+
+config AD8366
+ tristate "Analog Devices AD8366 VGA"
+ depends on SPI
+ select BITREVERSE
+ help
+ Say yes here to build support for Analog Devices AD8366
+ SPI Dual-Digital Variable Gain Amplifier (VGA).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad8366.
+
+endmenu
diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile
new file mode 100644
index 0000000..a6ca366
--- /dev/null
+++ b/drivers/iio/amplifiers/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile iio/amplifiers
+#
+
+obj-$(CONFIG_AD8366) += ad8366.o
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
new file mode 100644
index 0000000..d8281cd
--- /dev/null
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -0,0 +1,222 @@
+/*
+ * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitrev.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+struct ad8366_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned char ch[2];
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned char data[2] ____cacheline_aligned;
+};
+
+static int ad8366_write(struct iio_dev *indio_dev,
+ unsigned char ch_a, char unsigned ch_b)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ch_a = bitrev8(ch_a & 0x3F);
+ ch_b = bitrev8(ch_b & 0x3F);
+
+ st->data[0] = ch_b >> 4;
+ st->data[1] = (ch_b << 4) | (ch_a >> 2);
+
+ ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
+ if (ret < 0)
+ dev_err(&indio_dev->dev, "write failed (%d)", ret);
+
+ return ret;
+}
+
+static int ad8366_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ int ret;
+ unsigned code;
+
+ mutex_lock(&indio_dev->mlock);
+ switch (m) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ code = st->ch[chan->channel];
+
+ /* Values in dB */
+ code = code * 253 + 4500;
+ *val = code / 1000;
+ *val2 = (code % 1000) * 1000;
+
+ ret = IIO_VAL_INT_PLUS_MICRO_DB;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+};
+
+static int ad8366_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ unsigned code;
+ int ret;
+
+ if (val < 0 || val2 < 0)
+ return -EINVAL;
+
+ /* Values in dB */
+ code = (((u8)val * 1000) + ((u32)val2 / 1000));
+
+ if (code > 20500 || code < 4500)
+ return -EINVAL;
+
+ code = (code - 4500) / 253;
+
+ mutex_lock(&indio_dev->mlock);
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ st->ch[chan->channel] = code;
+ ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static const struct iio_info ad8366_info = {
+ .read_raw = &ad8366_read_raw,
+ .write_raw = &ad8366_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define AD8366_CHAN(_channel) { \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .info_mask = IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT,\
+}
+
+static const struct iio_chan_spec ad8366_channels[] = {
+ AD8366_CHAN(0),
+ AD8366_CHAN(1),
+};
+
+static int __devinit ad8366_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad8366_state *st;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ spi_set_drvdata(spi, indio_dev);
+ st->spi = spi;
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->info = &ad8366_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad8366_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_disable_reg;
+
+ ad8366_write(indio_dev, 0 , 0);
+
+ return 0;
+
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int __devexit ad8366_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad8366_state *st = iio_priv(indio_dev);
+ struct regulator *reg = st->reg;
+
+ iio_device_unregister(indio_dev);
+
+ if (!IS_ERR(reg)) {
+ regulator_disable(reg);
+ regulator_put(reg);
+ }
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad8366_id[] = {
+ {"ad8366", 0},
+ {}
+};
+
+static struct spi_driver ad8366_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad8366_probe,
+ .remove = __devexit_p(ad8366_remove),
+ .id_table = ad8366_id,
+};
+
+module_spi_driver(ad8366_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_core.h b/drivers/iio/iio_core.h
index c9dfcba..f652e6a 100644
--- a/drivers/staging/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -12,6 +12,12 @@
#ifndef _IIO_CORE_H_
#define _IIO_CORE_H_
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+struct iio_chan_spec;
+struct iio_dev;
+
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
diff --git a/drivers/staging/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 6f7c56f..6f7c56f 100644
--- a/drivers/staging/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 386ba76..ac185b8 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -21,10 +21,10 @@
#include <linux/slab.h>
#include <linux/poll.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "sysfs.h"
-#include "buffer.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
@@ -105,7 +105,7 @@ static ssize_t iio_scan_el_show(struct device *dev,
char *buf)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
ret = test_bit(to_iio_dev_attr(attr)->address,
indio_dev->buffer->scan_mask);
@@ -124,13 +124,15 @@ static ssize_t iio_scan_el_store(struct device *dev,
const char *buf,
size_t len)
{
- int ret = 0;
+ int ret;
bool state;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- state = !(buf[0] == '0');
+ ret = strtobool(buf, &state);
+ if (ret < 0)
+ return ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
@@ -160,7 +162,7 @@ static ssize_t iio_scan_el_ts_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", indio_dev->buffer->scan_timestamp);
}
@@ -169,17 +171,21 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
const char *buf,
size_t len)
{
- int ret = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ int ret;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool state;
- state = !(buf[0] == '0');
+ ret = strtobool(buf, &state);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
+ indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -291,7 +297,7 @@ int iio_buffer_register(struct iio_dev *indio_dev,
goto error_cleanup_dynamic;
attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
- buffer->scan_index_timestamp =
+ indio_dev->scan_index_timestamp =
channels[i].scan_index;
}
if (indio_dev->masklength && buffer->scan_mask == NULL) {
@@ -346,7 +352,7 @@ ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
if (buffer->access->get_length)
@@ -364,7 +370,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
{
int ret;
ulong val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
ret = strict_strtoul(buf, 10, &val);
@@ -397,7 +403,7 @@ ssize_t iio_buffer_store_enable(struct device *dev,
int ret;
bool requested_state, current_state;
int previous_mode;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
mutex_lock(&indio_dev->mlock);
@@ -483,7 +489,7 @@ ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -503,30 +509,41 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
return NULL;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
+ bool timestamp)
{
- struct iio_buffer *buffer = indio_dev->buffer;
const struct iio_chan_spec *ch;
unsigned bytes = 0;
int length, i;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
/* How much space will the demuxed element take? */
- for_each_set_bit(i, buffer->scan_mask,
+ for_each_set_bit(i, mask,
indio_dev->masklength) {
ch = iio_find_channel_from_si(indio_dev, i);
- length = ch->scan_type.storagebits/8;
+ length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length);
bytes += length;
}
- if (buffer->scan_timestamp) {
+ if (timestamp) {
ch = iio_find_channel_from_si(indio_dev,
- buffer->scan_index_timestamp);
- length = ch->scan_type.storagebits/8;
+ indio_dev->scan_index_timestamp);
+ length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length);
bytes += length;
}
- buffer->access->set_bytes_per_datum(buffer, bytes);
+ return bytes;
+}
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer = indio_dev->buffer;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ /* How much space will the demuxed element take? */
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
+ buffer->scan_timestamp);
+ buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
/* What scan mask do we actually have ?*/
if (indio_dev->available_scan_masks)
@@ -638,19 +655,25 @@ int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
}
EXPORT_SYMBOL_GPL(iio_push_to_buffer);
+static void iio_buffer_demux_free(struct iio_buffer *buffer)
+{
+ struct iio_demux_table *p, *q;
+ list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+ list_del(&p->l);
+ kfree(p);
+ }
+}
+
int iio_update_demux(struct iio_dev *indio_dev)
{
const struct iio_chan_spec *ch;
struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
- struct iio_demux_table *p, *q;
+ struct iio_demux_table *p;
/* Clear out any old demux */
- list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
- list_del(&p->l);
- kfree(p);
- }
+ iio_buffer_demux_free(buffer);
kfree(buffer->demux_bounce);
buffer->demux_bounce = NULL;
@@ -704,7 +727,7 @@ int iio_update_demux(struct iio_dev *indio_dev)
goto error_clear_mux_table;
}
ch = iio_find_channel_from_si(indio_dev,
- buffer->scan_index_timestamp);
+ indio_dev->scan_index_timestamp);
length = ch->scan_type.storagebits/8;
if (out_loc % length)
out_loc += length - out_loc % length;
@@ -725,10 +748,8 @@ int iio_update_demux(struct iio_dev *indio_dev)
return 0;
error_clear_mux_table:
- list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
- list_del(&p->l);
- kfree(p);
- }
+ iio_buffer_demux_free(buffer);
+
return ret;
}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d303bfb..1ddd886 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -23,11 +23,11 @@
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/* IDA to assign each registered device a unique id*/
static DEFINE_IDA(iio_ida);
@@ -42,11 +42,6 @@ EXPORT_SYMBOL(iio_bus_type);
static struct dentry *iio_debugfs_dentry;
-static const char * const iio_data_type_name[] = {
- [IIO_RAW] = "raw",
- [IIO_PROCESSED] = "input",
-};
-
static const char * const iio_direction[] = {
[0] = "in",
[1] = "out",
@@ -68,6 +63,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_ANGL] = "angl",
[IIO_TIMESTAMP] = "timestamp",
[IIO_CAPACITANCE] = "capacitance",
+ [IIO_ALTVOLTAGE] = "altvoltage",
};
static const char * const iio_modifier_names[] = {
@@ -80,6 +76,8 @@ static const char * const iio_modifier_names[] = {
/* relies on pairs of these shared then separate */
static const char * const iio_chan_info_postfix[] = {
+ [IIO_CHAN_INFO_RAW] = "raw",
+ [IIO_CHAN_INFO_PROCESSED] = "input",
[IIO_CHAN_INFO_SCALE] = "scale",
[IIO_CHAN_INFO_OFFSET] = "offset",
[IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
@@ -90,6 +88,10 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
= "filter_low_pass_3db_frequency",
+ [IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
+ [IIO_CHAN_INFO_FREQUENCY] = "frequency",
+ [IIO_CHAN_INFO_PHASE] = "phase",
+ [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
};
const struct iio_chan_spec
@@ -151,14 +153,6 @@ static void __exit iio_exit(void)
}
#if defined(CONFIG_DEBUG_FS)
-static int iio_debugfs_open(struct inode *inode, struct file *file)
-{
- if (inode->i_private)
- file->private_data = inode->i_private;
-
- return 0;
-}
-
static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -217,7 +211,7 @@ static ssize_t iio_debugfs_write_reg(struct file *file,
}
static const struct file_operations iio_debugfs_reg_fops = {
- .open = iio_debugfs_open,
+ .open = simple_open,
.read = iio_debugfs_read_reg,
.write = iio_debugfs_write_reg,
};
@@ -234,15 +228,12 @@ static int iio_device_register_debugfs(struct iio_dev *indio_dev)
if (indio_dev->info->debugfs_reg_access == NULL)
return 0;
- if (IS_ERR(iio_debugfs_dentry))
+ if (!iio_debugfs_dentry)
return 0;
indio_dev->debugfs_dentry =
debugfs_create_dir(dev_name(&indio_dev->dev),
iio_debugfs_dentry);
- if (IS_ERR(indio_dev->debugfs_dentry))
- return PTR_ERR(indio_dev->debugfs_dentry);
-
if (indio_dev->debugfs_dentry == NULL) {
dev_warn(indio_dev->dev.parent,
"Failed to create debugfs directory\n");
@@ -274,13 +265,13 @@ static ssize_t iio_read_channel_ext_info(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
const struct iio_chan_spec_ext_info *ext_info;
ext_info = &this_attr->c->ext_info[this_attr->address];
- return ext_info->read(indio_dev, this_attr->c, buf);
+ return ext_info->read(indio_dev, ext_info->private, this_attr->c, buf);
}
static ssize_t iio_write_channel_ext_info(struct device *dev,
@@ -288,42 +279,50 @@ static ssize_t iio_write_channel_ext_info(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
const struct iio_chan_spec_ext_info *ext_info;
ext_info = &this_attr->c->ext_info[this_attr->address];
- return ext_info->write(indio_dev, this_attr->c, buf, len);
+ return ext_info->write(indio_dev, ext_info->private,
+ this_attr->c, buf, len);
}
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val, val2;
+ bool scale_db = false;
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
&val, &val2, this_attr->address);
if (ret < 0)
return ret;
- if (ret == IIO_VAL_INT)
+ switch (ret) {
+ case IIO_VAL_INT:
return sprintf(buf, "%d\n", val);
- else if (ret == IIO_VAL_INT_PLUS_MICRO) {
+ case IIO_VAL_INT_PLUS_MICRO_DB:
+ scale_db = true;
+ case IIO_VAL_INT_PLUS_MICRO:
if (val2 < 0)
- return sprintf(buf, "-%d.%06u\n", val, -val2);
+ return sprintf(buf, "-%d.%06u%s\n", val, -val2,
+ scale_db ? " dB" : "");
else
- return sprintf(buf, "%d.%06u\n", val, val2);
- } else if (ret == IIO_VAL_INT_PLUS_NANO) {
+ return sprintf(buf, "%d.%06u%s\n", val, val2,
+ scale_db ? " dB" : "");
+ case IIO_VAL_INT_PLUS_NANO:
if (val2 < 0)
return sprintf(buf, "-%d.%09u\n", val, -val2);
else
return sprintf(buf, "%d.%09u\n", val, val2);
- } else
+ default:
return 0;
+ }
}
static ssize_t iio_write_channel_info(struct device *dev,
@@ -331,7 +330,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, integer = 0, fract = 0, fract_mult = 100000;
bool integer_part = true, negative = false;
@@ -575,25 +574,12 @@ error_ret:
static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
- int ret, i, attrcount = 0;
+ int ret, attrcount = 0;
+ int i;
const struct iio_chan_spec_ext_info *ext_info;
if (chan->channel < 0)
return 0;
-
- ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val],
- chan,
- &iio_read_channel_info,
- (chan->output ?
- &iio_write_channel_info : NULL),
- 0,
- 0,
- &indio_dev->dev,
- &indio_dev->channel_attr_list);
- if (ret)
- goto error_ret;
- attrcount++;
-
for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
chan,
@@ -652,7 +638,7 @@ static ssize_t iio_show_dev_name(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%s\n", indio_dev->name);
}
@@ -738,7 +724,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
static void iio_dev_release(struct device *device)
{
- struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(device);
cdev_del(&indio_dev->chrdev);
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
iio_device_unregister_trigger_consumer(indio_dev);
@@ -752,7 +738,7 @@ static struct device_type iio_dev_type = {
.release = iio_dev_release,
};
-struct iio_dev *iio_allocate_device(int sizeof_priv)
+struct iio_dev *iio_device_alloc(int sizeof_priv)
{
struct iio_dev *dev;
size_t alloc_size;
@@ -788,16 +774,16 @@ struct iio_dev *iio_allocate_device(int sizeof_priv)
return dev;
}
-EXPORT_SYMBOL(iio_allocate_device);
+EXPORT_SYMBOL(iio_device_alloc);
-void iio_free_device(struct iio_dev *dev)
+void iio_device_free(struct iio_dev *dev)
{
if (dev) {
ida_simple_remove(&iio_ida, dev->id);
kfree(dev);
}
}
-EXPORT_SYMBOL(iio_free_device);
+EXPORT_SYMBOL(iio_device_free);
/**
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
diff --git a/drivers/staging/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 5fdf739..b49059d 100644
--- a/drivers/staging/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -20,10 +20,10 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/**
* struct iio_event_interface - chrdev interface for an event line
@@ -186,7 +186,7 @@ static ssize_t iio_ev_state_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
bool val;
@@ -205,7 +205,7 @@ static ssize_t iio_ev_state_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val = indio_dev->info->read_event_config(indio_dev,
this_attr->address);
@@ -220,7 +220,7 @@ static ssize_t iio_ev_value_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val, ret;
@@ -237,7 +237,7 @@ static ssize_t iio_ev_value_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long val;
int ret;
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 47ecadd..0f582df 100644
--- a/drivers/staging/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -15,11 +15,11 @@
#include <linux/list.h>
#include <linux/slab.h>
-#include "iio.h"
-#include "trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
-#include "trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
/* RFC - Question of approach
* Make the common case (single sensor single trigger)
@@ -310,7 +310,7 @@ static ssize_t iio_trigger_read_current(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (indio_dev->trig)
return sprintf(buf, "%s\n", indio_dev->trig->name);
@@ -329,7 +329,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_trigger *oldtrig = indio_dev->trig;
struct iio_trigger *trig;
int ret;
@@ -360,9 +360,9 @@ static ssize_t iio_trigger_write_current(struct device *dev,
indio_dev->trig = trig;
if (oldtrig && indio_dev->trig != oldtrig)
- iio_put_trigger(oldtrig);
+ iio_trigger_put(oldtrig);
if (indio_dev->trig)
- iio_get_trigger(indio_dev->trig);
+ iio_trigger_get(indio_dev->trig);
return len;
}
@@ -426,7 +426,7 @@ static void iio_trig_subirqunmask(struct irq_data *d)
trig->subirqs[d->irq - trig->subirq_base].enabled = true;
}
-struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
+struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
{
va_list vargs;
struct iio_trigger *trig;
@@ -472,14 +472,14 @@ struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
}
return trig;
}
-EXPORT_SYMBOL(iio_allocate_trigger);
+EXPORT_SYMBOL(iio_trigger_alloc);
-void iio_free_trigger(struct iio_trigger *trig)
+void iio_trigger_free(struct iio_trigger *trig)
{
if (trig)
put_device(&trig->dev);
}
-EXPORT_SYMBOL(iio_free_trigger);
+EXPORT_SYMBOL(iio_trigger_free);
void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
@@ -491,7 +491,7 @@ void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
{
/* Clean up and associated but not attached triggers references */
if (indio_dev->trig)
- iio_put_trigger(indio_dev->trig);
+ iio_trigger_put(indio_dev->trig);
}
int iio_triggered_buffer_postenable(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/inkern.c b/drivers/iio/inkern.c
index ef07a02..9226458 100644
--- a/drivers/staging/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -11,11 +11,11 @@
#include <linux/slab.h>
#include <linux/mutex.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "machine.h"
-#include "driver.h"
-#include "consumer.h"
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
struct iio_map_internal {
struct iio_dev *indio_dev;
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 9f3bd59..6bf9d05 100644
--- a/drivers/staging/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -5,8 +5,7 @@
#include <linux/workqueue.h>
#include <linux/kfifo.h>
#include <linux/mutex.h>
-
-#include "kfifo_buf.h"
+#include <linux/iio/kfifo_buf.h>
struct iio_kfifo {
struct iio_buffer buffer;
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index eb0add31..a0f29c1 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -51,6 +51,7 @@ source "drivers/infiniband/hw/cxgb3/Kconfig"
source "drivers/infiniband/hw/cxgb4/Kconfig"
source "drivers/infiniband/hw/mlx4/Kconfig"
source "drivers/infiniband/hw/nes/Kconfig"
+source "drivers/infiniband/hw/ocrdma/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index a3b2d8e..bf846a1 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
obj-$(CONFIG_INFINIBAND_CXGB4) += hw/cxgb4/
obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/
obj-$(CONFIG_INFINIBAND_NES) += hw/nes/
+obj-$(CONFIG_INFINIBAND_OCRDMA) += hw/ocrdma/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 59fbd70..55d5642 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1219,13 +1219,13 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
}
if (!conn_id) {
ret = -ENOMEM;
- goto out;
+ goto err1;
}
mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
ret = cma_acquire_dev(conn_id);
if (ret)
- goto release_conn_id;
+ goto err2;
conn_id->cm_id.ib = cm_id;
cm_id->context = conn_id;
@@ -1237,31 +1237,33 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
*/
atomic_inc(&conn_id->refcount);
ret = conn_id->id.event_handler(&conn_id->id, &event);
- if (!ret) {
- /*
- * Acquire mutex to prevent user executing rdma_destroy_id()
- * while we're accessing the cm_id.
- */
- mutex_lock(&lock);
- if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
- ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
- mutex_unlock(&lock);
- mutex_unlock(&conn_id->handler_mutex);
- cma_deref_id(conn_id);
- goto out;
- }
+ if (ret)
+ goto err3;
+
+ /*
+ * Acquire mutex to prevent user executing rdma_destroy_id()
+ * while we're accessing the cm_id.
+ */
+ mutex_lock(&lock);
+ if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
+ ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
+ mutex_unlock(&lock);
+ mutex_unlock(&conn_id->handler_mutex);
+ mutex_unlock(&listen_id->handler_mutex);
cma_deref_id(conn_id);
+ return 0;
+err3:
+ cma_deref_id(conn_id);
/* Destroy the CM ID by returning a non-zero value. */
conn_id->cm_id.ib = NULL;
-
-release_conn_id:
+err2:
cma_exch(conn_id, RDMA_CM_DESTROYING);
mutex_unlock(&conn_id->handler_mutex);
- rdma_destroy_id(&conn_id->id);
-
-out:
+err1:
mutex_unlock(&listen_id->handler_mutex);
+ if (conn_id)
+ rdma_destroy_id(&conn_id->id);
return ret;
}
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 71f0c0f..a841123 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -269,7 +269,7 @@ void ib_umem_release(struct ib_umem *umem)
} else
down_write(&mm->mmap_sem);
- current->mm->locked_vm -= diff;
+ current->mm->pinned_vm -= diff;
up_write(&mm->mmap_sem);
mmput(mm);
kfree(umem);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 4d27e4c3..f9d0d7c 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -41,13 +41,18 @@
#include "uverbs.h"
-static struct lock_class_key pd_lock_key;
-static struct lock_class_key mr_lock_key;
-static struct lock_class_key cq_lock_key;
-static struct lock_class_key qp_lock_key;
-static struct lock_class_key ah_lock_key;
-static struct lock_class_key srq_lock_key;
-static struct lock_class_key xrcd_lock_key;
+struct uverbs_lock_class {
+ struct lock_class_key key;
+ char name[16];
+};
+
+static struct uverbs_lock_class pd_lock_class = { .name = "PD-uobj" };
+static struct uverbs_lock_class mr_lock_class = { .name = "MR-uobj" };
+static struct uverbs_lock_class cq_lock_class = { .name = "CQ-uobj" };
+static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" };
+static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" };
+static struct uverbs_lock_class srq_lock_class = { .name = "SRQ-uobj" };
+static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" };
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
do { \
@@ -83,13 +88,13 @@ static struct lock_class_key xrcd_lock_key;
*/
static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
- struct ib_ucontext *context, struct lock_class_key *key)
+ struct ib_ucontext *context, struct uverbs_lock_class *c)
{
uobj->user_handle = user_handle;
uobj->context = context;
kref_init(&uobj->ref);
init_rwsem(&uobj->mutex);
- lockdep_set_class(&uobj->mutex, key);
+ lockdep_set_class_and_name(&uobj->mutex, &c->key, c->name);
uobj->live = 0;
}
@@ -522,7 +527,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, 0, file->ucontext, &pd_lock_key);
+ init_uobj(uobj, 0, file->ucontext, &pd_lock_class);
down_write(&uobj->mutex);
pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
@@ -750,7 +755,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
goto err_tree_mutex_unlock;
}
- init_uobj(&obj->uobject, 0, file->ucontext, &xrcd_lock_key);
+ init_uobj(&obj->uobject, 0, file->ucontext, &xrcd_lock_class);
down_write(&obj->uobject.mutex);
@@ -947,7 +952,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, 0, file->ucontext, &mr_lock_key);
+ init_uobj(uobj, 0, file->ucontext, &mr_lock_class);
down_write(&uobj->mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -1115,7 +1120,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key);
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_class);
down_write(&obj->uobject.mutex);
if (cmd.comp_channel >= 0) {
@@ -1399,6 +1404,9 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
+ if (cmd.qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
+ return -EPERM;
+
INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
@@ -1407,7 +1415,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key);
+ init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_class);
down_write(&obj->uevent.uobject.mutex);
if (cmd.qp_type == IB_QPT_XRC_TGT) {
@@ -1418,13 +1426,6 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
}
device = xrcd->device;
} else {
- pd = idr_read_pd(cmd.pd_handle, file->ucontext);
- scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0);
- if (!pd || !scq) {
- ret = -EINVAL;
- goto err_put;
- }
-
if (cmd.qp_type == IB_QPT_XRC_INI) {
cmd.max_recv_wr = cmd.max_recv_sge = 0;
} else {
@@ -1435,13 +1436,24 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
goto err_put;
}
}
- rcq = (cmd.recv_cq_handle == cmd.send_cq_handle) ?
- scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1);
- if (!rcq) {
- ret = -EINVAL;
- goto err_put;
+
+ if (cmd.recv_cq_handle != cmd.send_cq_handle) {
+ rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext, 0);
+ if (!rcq) {
+ ret = -EINVAL;
+ goto err_put;
+ }
}
}
+
+ scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, !!rcq);
+ rcq = rcq ?: scq;
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ if (!pd || !scq) {
+ ret = -EINVAL;
+ goto err_put;
+ }
+
device = pd->device;
}
@@ -1585,7 +1597,7 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key);
+ init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_class);
down_write(&obj->uevent.uobject.mutex);
xrcd = idr_read_xrcd(cmd.pd_handle, file->ucontext, &xrcd_uobj);
@@ -2272,7 +2284,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key);
+ init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_class);
down_write(&uobj->mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -2476,30 +2488,30 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext, &srq_lock_key);
+ init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext, &srq_lock_class);
down_write(&obj->uevent.uobject.mutex);
- pd = idr_read_pd(cmd->pd_handle, file->ucontext);
- if (!pd) {
- ret = -EINVAL;
- goto err;
- }
-
if (cmd->srq_type == IB_SRQT_XRC) {
- attr.ext.xrc.cq = idr_read_cq(cmd->cq_handle, file->ucontext, 0);
- if (!attr.ext.xrc.cq) {
- ret = -EINVAL;
- goto err_put_pd;
- }
-
attr.ext.xrc.xrcd = idr_read_xrcd(cmd->xrcd_handle, file->ucontext, &xrcd_uobj);
if (!attr.ext.xrc.xrcd) {
ret = -EINVAL;
- goto err_put_cq;
+ goto err;
}
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
atomic_inc(&obj->uxrcd->refcnt);
+
+ attr.ext.xrc.cq = idr_read_cq(cmd->cq_handle, file->ucontext, 0);
+ if (!attr.ext.xrc.cq) {
+ ret = -EINVAL;
+ goto err_put_xrcd;
+ }
+ }
+
+ pd = idr_read_pd(cmd->pd_handle, file->ucontext);
+ if (!pd) {
+ ret = -EINVAL;
+ goto err_put_cq;
}
attr.event_handler = ib_uverbs_srq_event_handler;
@@ -2576,17 +2588,17 @@ err_destroy:
ib_destroy_srq(srq);
err_put:
- if (cmd->srq_type == IB_SRQT_XRC) {
- atomic_dec(&obj->uxrcd->refcnt);
- put_uobj_read(xrcd_uobj);
- }
+ put_pd_read(pd);
err_put_cq:
if (cmd->srq_type == IB_SRQT_XRC)
put_cq_read(attr.ext.xrc.cq);
-err_put_pd:
- put_pd_read(pd);
+err_put_xrcd:
+ if (cmd->srq_type == IB_SRQT_XRC) {
+ atomic_dec(&obj->uxrcd->refcnt);
+ put_uobj_read(xrcd_uobj);
+ }
err:
put_uobj_write(&obj->uevent.uobject);
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 575b780..30f199e 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -479,6 +479,7 @@ static const struct {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
+ [IB_QPT_RAW_PACKET] = IB_QP_PORT,
[IB_QPT_UC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
@@ -1183,23 +1184,33 @@ EXPORT_SYMBOL(ib_dealloc_fmr);
int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
{
+ int ret;
+
if (!qp->device->attach_mcast)
return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
return -EINVAL;
- return qp->device->attach_mcast(qp, gid, lid);
+ ret = qp->device->attach_mcast(qp, gid, lid);
+ if (!ret)
+ atomic_inc(&qp->usecnt);
+ return ret;
}
EXPORT_SYMBOL(ib_attach_mcast);
int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
{
+ int ret;
+
if (!qp->device->detach_mcast)
return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
return -EINVAL;
- return qp->device->detach_mcast(qp, gid, lid);
+ ret = qp->device->detach_mcast(qp, gid, lid);
+ if (!ret)
+ atomic_dec(&qp->usecnt);
+ return ret;
}
EXPORT_SYMBOL(ib_detach_mcast);
diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile
index 46b878c..e11cf72 100644
--- a/drivers/infiniband/hw/cxgb4/Makefile
+++ b/drivers/infiniband/hw/cxgb4/Makefile
@@ -2,4 +2,4 @@ ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
-iw_cxgb4-y := device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o
+iw_cxgb4-y := device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 92b4c2b..55ab284e 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1362,7 +1362,10 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
ep = lookup_tid(t, tid);
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- BUG_ON(!ep);
+ if (!ep) {
+ printk(KERN_WARNING MOD "Abort rpl to freed endpoint\n");
+ return 0;
+ }
mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
case ABORTING:
@@ -1410,6 +1413,24 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
return 0;
}
+ /*
+ * Log interesting failures.
+ */
+ switch (status) {
+ case CPL_ERR_CONN_RESET:
+ case CPL_ERR_CONN_TIMEDOUT:
+ break;
+ default:
+ printk(KERN_INFO MOD "Active open failure - "
+ "atid %u status %u errno %d %pI4:%u->%pI4:%u\n",
+ atid, status, status2errno(status),
+ &ep->com.local_addr.sin_addr.s_addr,
+ ntohs(ep->com.local_addr.sin_port),
+ &ep->com.remote_addr.sin_addr.s_addr,
+ ntohs(ep->com.remote_addr.sin_port));
+ break;
+ }
+
connect_reply_upcall(ep, status2errno(status));
state_set(&ep->com, DEAD);
@@ -1593,7 +1614,7 @@ static int import_ep(struct c4iw_ep *ep, __be32 peer_ip, struct dst_entry *dst,
n, n->dev, 0);
if (!ep->l2t)
goto out;
- ep->mtu = dst_mtu(ep->dst);
+ ep->mtu = dst_mtu(dst);
ep->tx_chan = cxgb4_port_chan(n->dev);
ep->smac_idx = (cxgb4_port_viid(n->dev) & 0x7F) << 1;
step = cdev->rdev.lldi.ntxq /
@@ -2656,6 +2677,12 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
unsigned int tid = GET_TID(req);
ep = lookup_tid(t, tid);
+ if (!ep) {
+ printk(KERN_WARNING MOD
+ "Abort on non-existent endpoint, tid %d\n", tid);
+ kfree_skb(skb);
+ return 0;
+ }
if (is_neg_adv_abort(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
ep->hwtid);
@@ -2667,11 +2694,8 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
/*
* Wake up any threads in rdma_init() or rdma_fini().
- * However, this is not needed if com state is just
- * MPA_REQ_SENT
*/
- if (ep->com.state != MPA_REQ_SENT)
- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
sched(dev, skb);
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 6d0df6e..cb4ecd7 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
#include <rdma/ib_verbs.h>
@@ -44,6 +45,12 @@ MODULE_DESCRIPTION("Chelsio T4 RDMA Driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
+struct uld_ctx {
+ struct list_head entry;
+ struct cxgb4_lld_info lldi;
+ struct c4iw_dev *dev;
+};
+
static LIST_HEAD(uld_ctx_list);
static DEFINE_MUTEX(dev_mutex);
@@ -115,7 +122,7 @@ static int qp_release(struct inode *inode, struct file *file)
printk(KERN_INFO "%s null qpd?\n", __func__);
return 0;
}
- kfree(qpd->buf);
+ vfree(qpd->buf);
kfree(qpd);
return 0;
}
@@ -139,7 +146,7 @@ static int qp_open(struct inode *inode, struct file *file)
spin_unlock_irq(&qpd->devp->lock);
qpd->bufsize = count * 128;
- qpd->buf = kmalloc(qpd->bufsize, GFP_KERNEL);
+ qpd->buf = vmalloc(qpd->bufsize);
if (!qpd->buf) {
ret = -ENOMEM;
goto err1;
@@ -240,6 +247,81 @@ static const struct file_operations stag_debugfs_fops = {
.llseek = default_llseek,
};
+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};
+
+static int stats_show(struct seq_file *seq, void *v)
+{
+ struct c4iw_dev *dev = seq->private;
+
+ seq_printf(seq, " Object: %10s %10s %10s %10s\n", "Total", "Current",
+ "Max", "Fail");
+ seq_printf(seq, " PDID: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.pd.total, dev->rdev.stats.pd.cur,
+ dev->rdev.stats.pd.max, dev->rdev.stats.pd.fail);
+ seq_printf(seq, " QID: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.qid.total, dev->rdev.stats.qid.cur,
+ dev->rdev.stats.qid.max, dev->rdev.stats.qid.fail);
+ seq_printf(seq, " TPTMEM: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.stag.total, dev->rdev.stats.stag.cur,
+ dev->rdev.stats.stag.max, dev->rdev.stats.stag.fail);
+ seq_printf(seq, " PBLMEM: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.pbl.total, dev->rdev.stats.pbl.cur,
+ dev->rdev.stats.pbl.max, dev->rdev.stats.pbl.fail);
+ seq_printf(seq, " RQTMEM: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.rqt.total, dev->rdev.stats.rqt.cur,
+ dev->rdev.stats.rqt.max, dev->rdev.stats.rqt.fail);
+ seq_printf(seq, " OCQPMEM: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.ocqp.total, dev->rdev.stats.ocqp.cur,
+ dev->rdev.stats.ocqp.max, dev->rdev.stats.ocqp.fail);
+ seq_printf(seq, " DB FULL: %10llu\n", dev->rdev.stats.db_full);
+ seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);
+ seq_printf(seq, " DB DROP: %10llu\n", dev->rdev.stats.db_drop);
+ seq_printf(seq, " DB State: %s Transitions %llu\n",
+ db_state_str[dev->db_state],
+ dev->rdev.stats.db_state_transitions);
+ return 0;
+}
+
+static int stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, stats_show, inode->i_private);
+}
+
+static ssize_t stats_clear(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct c4iw_dev *dev = ((struct seq_file *)file->private_data)->private;
+
+ mutex_lock(&dev->rdev.stats.lock);
+ dev->rdev.stats.pd.max = 0;
+ dev->rdev.stats.pd.fail = 0;
+ dev->rdev.stats.qid.max = 0;
+ dev->rdev.stats.qid.fail = 0;
+ dev->rdev.stats.stag.max = 0;
+ dev->rdev.stats.stag.fail = 0;
+ dev->rdev.stats.pbl.max = 0;
+ dev->rdev.stats.pbl.fail = 0;
+ dev->rdev.stats.rqt.max = 0;
+ dev->rdev.stats.rqt.fail = 0;
+ dev->rdev.stats.ocqp.max = 0;
+ dev->rdev.stats.ocqp.fail = 0;
+ dev->rdev.stats.db_full = 0;
+ dev->rdev.stats.db_empty = 0;
+ dev->rdev.stats.db_drop = 0;
+ dev->rdev.stats.db_state_transitions = 0;
+ mutex_unlock(&dev->rdev.stats.lock);
+ return count;
+}
+
+static const struct file_operations stats_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = stats_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = stats_clear,
+};
+
static int setup_debugfs(struct c4iw_dev *devp)
{
struct dentry *de;
@@ -256,6 +338,12 @@ static int setup_debugfs(struct c4iw_dev *devp)
(void *)devp, &stag_debugfs_fops);
if (de && de->d_inode)
de->d_inode->i_size = 4096;
+
+ de = debugfs_create_file("stats", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &stats_debugfs_fops);
+ if (de && de->d_inode)
+ de->d_inode->i_size = 4096;
+
return 0;
}
@@ -269,9 +357,13 @@ void c4iw_release_dev_ucontext(struct c4iw_rdev *rdev,
list_for_each_safe(pos, nxt, &uctx->qpids) {
entry = list_entry(pos, struct c4iw_qid_list, entry);
list_del_init(&entry->entry);
- if (!(entry->qid & rdev->qpmask))
- c4iw_put_resource(&rdev->resource.qid_fifo, entry->qid,
- &rdev->resource.qid_fifo_lock);
+ if (!(entry->qid & rdev->qpmask)) {
+ c4iw_put_resource(&rdev->resource.qid_table,
+ entry->qid);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.qid.cur -= rdev->qpmask + 1;
+ mutex_unlock(&rdev->stats.lock);
+ }
kfree(entry);
}
@@ -332,6 +424,13 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
goto err1;
}
+ rdev->stats.pd.total = T4_MAX_NUM_PD;
+ rdev->stats.stag.total = rdev->lldi.vr->stag.size;
+ rdev->stats.pbl.total = rdev->lldi.vr->pbl.size;
+ rdev->stats.rqt.total = rdev->lldi.vr->rq.size;
+ rdev->stats.ocqp.total = rdev->lldi.vr->ocq.size;
+ rdev->stats.qid.total = rdev->lldi.vr->qp.size;
+
err = c4iw_init_resource(rdev, c4iw_num_stags(rdev), T4_MAX_NUM_PD);
if (err) {
printk(KERN_ERR MOD "error %d initializing resources\n", err);
@@ -370,12 +469,6 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev)
c4iw_destroy_resource(&rdev->resource);
}
-struct uld_ctx {
- struct list_head entry;
- struct cxgb4_lld_info lldi;
- struct c4iw_dev *dev;
-};
-
static void c4iw_dealloc(struct uld_ctx *ctx)
{
c4iw_rdev_close(&ctx->dev->rdev);
@@ -440,6 +533,8 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
idr_init(&devp->qpidr);
idr_init(&devp->mmidr);
spin_lock_init(&devp->lock);
+ mutex_init(&devp->rdev.stats.lock);
+ mutex_init(&devp->db_mutex);
if (c4iw_debugfs_root) {
devp->debugfs_root = debugfs_create_dir(
@@ -585,11 +680,234 @@ static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
return 0;
}
+static int disable_qp_db(int id, void *p, void *data)
+{
+ struct c4iw_qp *qp = p;
+
+ t4_disable_wq_db(&qp->wq);
+ return 0;
+}
+
+static void stop_queues(struct uld_ctx *ctx)
+{
+ spin_lock_irq(&ctx->dev->lock);
+ if (ctx->dev->db_state == NORMAL) {
+ ctx->dev->rdev.stats.db_state_transitions++;
+ ctx->dev->db_state = FLOW_CONTROL;
+ idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
+ }
+ spin_unlock_irq(&ctx->dev->lock);
+}
+
+static int enable_qp_db(int id, void *p, void *data)
+{
+ struct c4iw_qp *qp = p;
+
+ t4_enable_wq_db(&qp->wq);
+ return 0;
+}
+
+static void resume_queues(struct uld_ctx *ctx)
+{
+ spin_lock_irq(&ctx->dev->lock);
+ if (ctx->dev->qpcnt <= db_fc_threshold &&
+ ctx->dev->db_state == FLOW_CONTROL) {
+ ctx->dev->db_state = NORMAL;
+ ctx->dev->rdev.stats.db_state_transitions++;
+ idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+ }
+ spin_unlock_irq(&ctx->dev->lock);
+}
+
+struct qp_list {
+ unsigned idx;
+ struct c4iw_qp **qps;
+};
+
+static int add_and_ref_qp(int id, void *p, void *data)
+{
+ struct qp_list *qp_listp = data;
+ struct c4iw_qp *qp = p;
+
+ c4iw_qp_add_ref(&qp->ibqp);
+ qp_listp->qps[qp_listp->idx++] = qp;
+ return 0;
+}
+
+static int count_qps(int id, void *p, void *data)
+{
+ unsigned *countp = data;
+ (*countp)++;
+ return 0;
+}
+
+static void deref_qps(struct qp_list qp_list)
+{
+ int idx;
+
+ for (idx = 0; idx < qp_list.idx; idx++)
+ c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);
+}
+
+static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
+{
+ int idx;
+ int ret;
+
+ for (idx = 0; idx < qp_list->idx; idx++) {
+ struct c4iw_qp *qp = qp_list->qps[idx];
+
+ ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
+ qp->wq.sq.qid,
+ t4_sq_host_wq_pidx(&qp->wq),
+ t4_sq_wq_size(&qp->wq));
+ if (ret) {
+ printk(KERN_ERR MOD "%s: Fatal error - "
+ "DB overflow recovery failed - "
+ "error syncing SQ qid %u\n",
+ pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
+ return;
+ }
+
+ ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
+ qp->wq.rq.qid,
+ t4_rq_host_wq_pidx(&qp->wq),
+ t4_rq_wq_size(&qp->wq));
+
+ if (ret) {
+ printk(KERN_ERR MOD "%s: Fatal error - "
+ "DB overflow recovery failed - "
+ "error syncing RQ qid %u\n",
+ pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
+ return;
+ }
+
+ /* Wait for the dbfifo to drain */
+ while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(10));
+ }
+ }
+}
+
+static void recover_queues(struct uld_ctx *ctx)
+{
+ int count = 0;
+ struct qp_list qp_list;
+ int ret;
+
+ /* lock out kernel db ringers */
+ mutex_lock(&ctx->dev->db_mutex);
+
+ /* put all queues in to recovery mode */
+ spin_lock_irq(&ctx->dev->lock);
+ ctx->dev->db_state = RECOVERY;
+ ctx->dev->rdev.stats.db_state_transitions++;
+ idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
+ spin_unlock_irq(&ctx->dev->lock);
+
+ /* slow everybody down */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(1000));
+
+ /* Wait for the dbfifo to completely drain. */
+ while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(10));
+ }
+
+ /* flush the SGE contexts */
+ ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);
+ if (ret) {
+ printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
+ pci_name(ctx->lldi.pdev));
+ goto out;
+ }
+
+ /* Count active queues so we can build a list of queues to recover */
+ spin_lock_irq(&ctx->dev->lock);
+ idr_for_each(&ctx->dev->qpidr, count_qps, &count);
+
+ qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);
+ if (!qp_list.qps) {
+ printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
+ pci_name(ctx->lldi.pdev));
+ spin_unlock_irq(&ctx->dev->lock);
+ goto out;
+ }
+ qp_list.idx = 0;
+
+ /* add and ref each qp so it doesn't get freed */
+ idr_for_each(&ctx->dev->qpidr, add_and_ref_qp, &qp_list);
+
+ spin_unlock_irq(&ctx->dev->lock);
+
+ /* now traverse the list in a safe context to recover the db state*/
+ recover_lost_dbs(ctx, &qp_list);
+
+ /* we're almost done! deref the qps and clean up */
+ deref_qps(qp_list);
+ kfree(qp_list.qps);
+
+ /* Wait for the dbfifo to completely drain again */
+ while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(10));
+ }
+
+ /* resume the queues */
+ spin_lock_irq(&ctx->dev->lock);
+ if (ctx->dev->qpcnt > db_fc_threshold)
+ ctx->dev->db_state = FLOW_CONTROL;
+ else {
+ ctx->dev->db_state = NORMAL;
+ idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+ }
+ ctx->dev->rdev.stats.db_state_transitions++;
+ spin_unlock_irq(&ctx->dev->lock);
+
+out:
+ /* start up kernel db ringers again */
+ mutex_unlock(&ctx->dev->db_mutex);
+}
+
+static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
+{
+ struct uld_ctx *ctx = handle;
+
+ switch (control) {
+ case CXGB4_CONTROL_DB_FULL:
+ stop_queues(ctx);
+ mutex_lock(&ctx->dev->rdev.stats.lock);
+ ctx->dev->rdev.stats.db_full++;
+ mutex_unlock(&ctx->dev->rdev.stats.lock);
+ break;
+ case CXGB4_CONTROL_DB_EMPTY:
+ resume_queues(ctx);
+ mutex_lock(&ctx->dev->rdev.stats.lock);
+ ctx->dev->rdev.stats.db_empty++;
+ mutex_unlock(&ctx->dev->rdev.stats.lock);
+ break;
+ case CXGB4_CONTROL_DB_DROP:
+ recover_queues(ctx);
+ mutex_lock(&ctx->dev->rdev.stats.lock);
+ ctx->dev->rdev.stats.db_drop++;
+ mutex_unlock(&ctx->dev->rdev.stats.lock);
+ break;
+ default:
+ printk(KERN_WARNING MOD "%s: unknown control cmd %u\n",
+ pci_name(ctx->lldi.pdev), control);
+ break;
+ }
+ return 0;
+}
+
static struct cxgb4_uld_info c4iw_uld_info = {
.name = DRV_NAME,
.add = c4iw_uld_add,
.rx_handler = c4iw_uld_rx_handler,
.state_change = c4iw_uld_state_change,
+ .control = c4iw_uld_control,
};
static int __init c4iw_init_module(void)
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index 397cb36..cf2f6b4 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -84,7 +84,7 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
struct c4iw_qp *qhp;
u32 cqid;
- spin_lock(&dev->lock);
+ spin_lock_irq(&dev->lock);
qhp = get_qhp(dev, CQE_QPID(err_cqe));
if (!qhp) {
printk(KERN_ERR MOD "BAD AE qpid 0x%x opcode %d "
@@ -93,7 +93,7 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
CQE_WRID_LOW(err_cqe));
- spin_unlock(&dev->lock);
+ spin_unlock_irq(&dev->lock);
goto out;
}
@@ -109,13 +109,13 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
CQE_WRID_LOW(err_cqe));
- spin_unlock(&dev->lock);
+ spin_unlock_irq(&dev->lock);
goto out;
}
c4iw_qp_add_ref(&qhp->ibqp);
atomic_inc(&chp->refcnt);
- spin_unlock(&dev->lock);
+ spin_unlock_irq(&dev->lock);
/* Bad incoming write */
if (RQ_TYPE(err_cqe) &&
diff --git a/drivers/infiniband/hw/cxgb4/id_table.c b/drivers/infiniband/hw/cxgb4/id_table.c
new file mode 100644
index 0000000..f95e5df
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/id_table.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011 Chelsio Communications. 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/random.h>
+#include "iw_cxgb4.h"
+
+#define RANDOM_SKIP 16
+
+/*
+ * Trivial bitmap-based allocator. If the random flag is set, the
+ * allocator is designed to:
+ * - pseudo-randomize the id returned such that it is not trivially predictable.
+ * - avoid reuse of recently used id (at the expense of predictability)
+ */
+u32 c4iw_id_alloc(struct c4iw_id_table *alloc)
+{
+ unsigned long flags;
+ u32 obj;
+
+ spin_lock_irqsave(&alloc->lock, flags);
+
+ obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last);
+ if (obj >= alloc->max)
+ obj = find_first_zero_bit(alloc->table, alloc->max);
+
+ if (obj < alloc->max) {
+ if (alloc->flags & C4IW_ID_TABLE_F_RANDOM)
+ alloc->last += random32() % RANDOM_SKIP;
+ else
+ alloc->last = obj + 1;
+ if (alloc->last >= alloc->max)
+ alloc->last = 0;
+ set_bit(obj, alloc->table);
+ obj += alloc->start;
+ } else
+ obj = -1;
+
+ spin_unlock_irqrestore(&alloc->lock, flags);
+ return obj;
+}
+
+void c4iw_id_free(struct c4iw_id_table *alloc, u32 obj)
+{
+ unsigned long flags;
+
+ obj -= alloc->start;
+ BUG_ON((int)obj < 0);
+
+ spin_lock_irqsave(&alloc->lock, flags);
+ clear_bit(obj, alloc->table);
+ spin_unlock_irqrestore(&alloc->lock, flags);
+}
+
+int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,
+ u32 reserved, u32 flags)
+{
+ int i;
+
+ alloc->start = start;
+ alloc->flags = flags;
+ if (flags & C4IW_ID_TABLE_F_RANDOM)
+ alloc->last = random32() % RANDOM_SKIP;
+ else
+ alloc->last = 0;
+ alloc->max = num;
+ spin_lock_init(&alloc->lock);
+ alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof(long),
+ GFP_KERNEL);
+ if (!alloc->table)
+ return -ENOMEM;
+
+ bitmap_zero(alloc->table, num);
+ if (!(alloc->flags & C4IW_ID_TABLE_F_EMPTY))
+ for (i = 0; i < reserved; ++i)
+ set_bit(i, alloc->table);
+
+ return 0;
+}
+
+void c4iw_id_table_free(struct c4iw_id_table *alloc)
+{
+ kfree(alloc->table);
+}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 1357c5b..9beb3a9 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -45,7 +45,6 @@
#include <linux/kref.h>
#include <linux/timer.h>
#include <linux/io.h>
-#include <linux/kfifo.h>
#include <asm/byteorder.h>
@@ -79,13 +78,22 @@ static inline void *cplhdr(struct sk_buff *skb)
return skb->data;
}
+#define C4IW_ID_TABLE_F_RANDOM 1 /* Pseudo-randomize the id's returned */
+#define C4IW_ID_TABLE_F_EMPTY 2 /* Table is initially empty */
+
+struct c4iw_id_table {
+ u32 flags;
+ u32 start; /* logical minimal id */
+ u32 last; /* hint for find */
+ u32 max;
+ spinlock_t lock;
+ unsigned long *table;
+};
+
struct c4iw_resource {
- struct kfifo tpt_fifo;
- spinlock_t tpt_fifo_lock;
- struct kfifo qid_fifo;
- spinlock_t qid_fifo_lock;
- struct kfifo pdid_fifo;
- spinlock_t pdid_fifo_lock;
+ struct c4iw_id_table tpt_table;
+ struct c4iw_id_table qid_table;
+ struct c4iw_id_table pdid_table;
};
struct c4iw_qid_list {
@@ -103,6 +111,27 @@ enum c4iw_rdev_flags {
T4_FATAL_ERROR = (1<<0),
};
+struct c4iw_stat {
+ u64 total;
+ u64 cur;
+ u64 max;
+ u64 fail;
+};
+
+struct c4iw_stats {
+ struct mutex lock;
+ struct c4iw_stat qid;
+ struct c4iw_stat pd;
+ struct c4iw_stat stag;
+ struct c4iw_stat pbl;
+ struct c4iw_stat rqt;
+ struct c4iw_stat ocqp;
+ u64 db_full;
+ u64 db_empty;
+ u64 db_drop;
+ u64 db_state_transitions;
+};
+
struct c4iw_rdev {
struct c4iw_resource resource;
unsigned long qpshift;
@@ -117,6 +146,7 @@ struct c4iw_rdev {
struct cxgb4_lld_info lldi;
unsigned long oc_mw_pa;
void __iomem *oc_mw_kva;
+ struct c4iw_stats stats;
};
static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -175,6 +205,12 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
return wr_waitp->ret;
}
+enum db_state {
+ NORMAL = 0,
+ FLOW_CONTROL = 1,
+ RECOVERY = 2
+};
+
struct c4iw_dev {
struct ib_device ibdev;
struct c4iw_rdev rdev;
@@ -183,7 +219,10 @@ struct c4iw_dev {
struct idr qpidr;
struct idr mmidr;
spinlock_t lock;
+ struct mutex db_mutex;
struct dentry *debugfs_root;
+ enum db_state db_state;
+ int qpcnt;
};
static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -211,29 +250,57 @@ static inline struct c4iw_mr *get_mhp(struct c4iw_dev *rhp, u32 mmid)
return idr_find(&rhp->mmidr, mmid);
}
-static inline int insert_handle(struct c4iw_dev *rhp, struct idr *idr,
- void *handle, u32 id)
+static inline int _insert_handle(struct c4iw_dev *rhp, struct idr *idr,
+ void *handle, u32 id, int lock)
{
int ret;
int newid;
do {
- if (!idr_pre_get(idr, GFP_KERNEL))
+ if (!idr_pre_get(idr, lock ? GFP_KERNEL : GFP_ATOMIC))
return -ENOMEM;
- spin_lock_irq(&rhp->lock);
+ if (lock)
+ spin_lock_irq(&rhp->lock);
ret = idr_get_new_above(idr, handle, id, &newid);
- BUG_ON(newid != id);
- spin_unlock_irq(&rhp->lock);
+ BUG_ON(!ret && newid != id);
+ if (lock)
+ spin_unlock_irq(&rhp->lock);
} while (ret == -EAGAIN);
return ret;
}
-static inline void remove_handle(struct c4iw_dev *rhp, struct idr *idr, u32 id)
+static inline int insert_handle(struct c4iw_dev *rhp, struct idr *idr,
+ void *handle, u32 id)
+{
+ return _insert_handle(rhp, idr, handle, id, 1);
+}
+
+static inline int insert_handle_nolock(struct c4iw_dev *rhp, struct idr *idr,
+ void *handle, u32 id)
+{
+ return _insert_handle(rhp, idr, handle, id, 0);
+}
+
+static inline void _remove_handle(struct c4iw_dev *rhp, struct idr *idr,
+ u32 id, int lock)
{
- spin_lock_irq(&rhp->lock);
+ if (lock)
+ spin_lock_irq(&rhp->lock);
idr_remove(idr, id);
- spin_unlock_irq(&rhp->lock);
+ if (lock)
+ spin_unlock_irq(&rhp->lock);
+}
+
+static inline void remove_handle(struct c4iw_dev *rhp, struct idr *idr, u32 id)
+{
+ _remove_handle(rhp, idr, id, 1);
+}
+
+static inline void remove_handle_nolock(struct c4iw_dev *rhp,
+ struct idr *idr, u32 id)
+{
+ _remove_handle(rhp, idr, id, 0);
}
struct c4iw_pd {
@@ -353,6 +420,8 @@ struct c4iw_qp_attributes {
struct c4iw_ep *llp_stream_handle;
u8 layer_etype;
u8 ecode;
+ u16 sq_db_inc;
+ u16 rq_db_inc;
};
struct c4iw_qp {
@@ -427,6 +496,8 @@ static inline void insert_mmap(struct c4iw_ucontext *ucontext,
enum c4iw_qp_attr_mask {
C4IW_QP_ATTR_NEXT_STATE = 1 << 0,
+ C4IW_QP_ATTR_SQ_DB = 1<<1,
+ C4IW_QP_ATTR_RQ_DB = 1<<2,
C4IW_QP_ATTR_ENABLE_RDMA_READ = 1 << 7,
C4IW_QP_ATTR_ENABLE_RDMA_WRITE = 1 << 8,
C4IW_QP_ATTR_ENABLE_RDMA_BIND = 1 << 9,
@@ -480,6 +551,23 @@ static inline int c4iw_convert_state(enum ib_qp_state ib_state)
}
}
+static inline int to_ib_qp_state(int c4iw_qp_state)
+{
+ switch (c4iw_qp_state) {
+ case C4IW_QP_STATE_IDLE:
+ return IB_QPS_INIT;
+ case C4IW_QP_STATE_RTS:
+ return IB_QPS_RTS;
+ case C4IW_QP_STATE_CLOSING:
+ return IB_QPS_SQD;
+ case C4IW_QP_STATE_TERMINATE:
+ return IB_QPS_SQE;
+ case C4IW_QP_STATE_ERROR:
+ return IB_QPS_ERR;
+ }
+ return IB_QPS_ERR;
+}
+
static inline u32 c4iw_ib_to_tpt_access(int a)
{
return (a & IB_ACCESS_REMOTE_WRITE ? FW_RI_MEM_ACCESS_REM_WRITE : 0) |
@@ -693,14 +781,20 @@ static inline int compute_wscale(int win)
return wscale;
}
+u32 c4iw_id_alloc(struct c4iw_id_table *alloc);
+void c4iw_id_free(struct c4iw_id_table *alloc, u32 obj);
+int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,
+ u32 reserved, u32 flags);
+void c4iw_id_table_free(struct c4iw_id_table *alloc);
+
typedef int (*c4iw_handler_func)(struct c4iw_dev *dev, struct sk_buff *skb);
int c4iw_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
struct l2t_entry *l2t);
void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qpid,
struct c4iw_dev_ucontext *uctx);
-u32 c4iw_get_resource(struct kfifo *fifo, spinlock_t *lock);
-void c4iw_put_resource(struct kfifo *fifo, u32 entry, spinlock_t *lock);
+u32 c4iw_get_resource(struct c4iw_id_table *id_table);
+void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry);
int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid);
int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
int c4iw_pblpool_create(struct c4iw_rdev *rdev);
@@ -769,6 +863,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd,
struct ib_udata *udata);
int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
+int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr);
struct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn);
u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size);
void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
@@ -797,5 +893,7 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe);
extern struct cxgb4_client t4c_client;
extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS];
extern int c4iw_max_read_depth;
+extern int db_fc_threshold;
+
#endif
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 40c8353..57e07c6 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -131,10 +131,14 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
stag_idx = (*stag) >> 8;
if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
- stag_idx = c4iw_get_resource(&rdev->resource.tpt_fifo,
- &rdev->resource.tpt_fifo_lock);
+ stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
if (!stag_idx)
return -ENOMEM;
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.stag.cur += 32;
+ if (rdev->stats.stag.cur > rdev->stats.stag.max)
+ rdev->stats.stag.max = rdev->stats.stag.cur;
+ mutex_unlock(&rdev->stats.lock);
*stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff);
}
PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
@@ -165,9 +169,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
(rdev->lldi.vr->stag.start >> 5),
sizeof(tpt), &tpt);
- if (reset_tpt_entry)
- c4iw_put_resource(&rdev->resource.tpt_fifo, stag_idx,
- &rdev->resource.tpt_fifo_lock);
+ if (reset_tpt_entry) {
+ c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.stag.cur -= 32;
+ mutex_unlock(&rdev->stats.lock);
+ }
return err;
}
@@ -686,8 +693,8 @@ int c4iw_dealloc_mw(struct ib_mw *mw)
mhp = to_c4iw_mw(mw);
rhp = mhp->rhp;
mmid = (mw->rkey) >> 8;
- deallocate_window(&rhp->rdev, mhp->attr.stag);
remove_handle(rhp, &rhp->mmidr, mmid);
+ deallocate_window(&rhp->rdev, mhp->attr.stag);
kfree(mhp);
PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __func__, mw, mmid, mhp);
return 0;
@@ -789,12 +796,12 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
mhp = to_c4iw_mr(ib_mr);
rhp = mhp->rhp;
mmid = mhp->attr.stag >> 8;
+ remove_handle(rhp, &rhp->mmidr, mmid);
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr);
if (mhp->attr.pbl_size)
c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
mhp->attr.pbl_size << 3);
- remove_handle(rhp, &rhp->mmidr, mmid);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
if (mhp->umem)
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index be1c18f..e084fdc 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -188,8 +188,10 @@ static int c4iw_deallocate_pd(struct ib_pd *pd)
php = to_c4iw_pd(pd);
rhp = php->rhp;
PDBG("%s ibpd %p pdid 0x%x\n", __func__, pd, php->pdid);
- c4iw_put_resource(&rhp->rdev.resource.pdid_fifo, php->pdid,
- &rhp->rdev.resource.pdid_fifo_lock);
+ c4iw_put_resource(&rhp->rdev.resource.pdid_table, php->pdid);
+ mutex_lock(&rhp->rdev.stats.lock);
+ rhp->rdev.stats.pd.cur--;
+ mutex_unlock(&rhp->rdev.stats.lock);
kfree(php);
return 0;
}
@@ -204,14 +206,12 @@ static struct ib_pd *c4iw_allocate_pd(struct ib_device *ibdev,
PDBG("%s ibdev %p\n", __func__, ibdev);
rhp = (struct c4iw_dev *) ibdev;
- pdid = c4iw_get_resource(&rhp->rdev.resource.pdid_fifo,
- &rhp->rdev.resource.pdid_fifo_lock);
+ pdid = c4iw_get_resource(&rhp->rdev.resource.pdid_table);
if (!pdid)
return ERR_PTR(-EINVAL);
php = kzalloc(sizeof(*php), GFP_KERNEL);
if (!php) {
- c4iw_put_resource(&rhp->rdev.resource.pdid_fifo, pdid,
- &rhp->rdev.resource.pdid_fifo_lock);
+ c4iw_put_resource(&rhp->rdev.resource.pdid_table, pdid);
return ERR_PTR(-ENOMEM);
}
php->pdid = pdid;
@@ -222,6 +222,11 @@ static struct ib_pd *c4iw_allocate_pd(struct ib_device *ibdev,
return ERR_PTR(-EFAULT);
}
}
+ mutex_lock(&rhp->rdev.stats.lock);
+ rhp->rdev.stats.pd.cur++;
+ if (rhp->rdev.stats.pd.cur > rhp->rdev.stats.pd.max)
+ rhp->rdev.stats.pd.max = rhp->rdev.stats.pd.cur;
+ mutex_unlock(&rhp->rdev.stats.lock);
PDBG("%s pdid 0x%0x ptr 0x%p\n", __func__, pdid, php);
return &php->ibpd;
}
@@ -438,6 +443,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
(1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_QP) |
(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
(1ull << IB_USER_VERBS_CMD_POLL_CQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
(1ull << IB_USER_VERBS_CMD_POST_SEND) |
@@ -460,6 +466,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
dev->ibdev.destroy_ah = c4iw_ah_destroy;
dev->ibdev.create_qp = c4iw_create_qp;
dev->ibdev.modify_qp = c4iw_ib_modify_qp;
+ dev->ibdev.query_qp = c4iw_ib_query_qp;
dev->ibdev.destroy_qp = c4iw_destroy_qp;
dev->ibdev.create_cq = c4iw_create_cq;
dev->ibdev.destroy_cq = c4iw_destroy_cq;
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 5f940ae..45aedf1 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -34,10 +34,19 @@
#include "iw_cxgb4.h"
+static int db_delay_usecs = 1;
+module_param(db_delay_usecs, int, 0644);
+MODULE_PARM_DESC(db_delay_usecs, "Usecs to delay awaiting db fifo to drain");
+
static int ocqp_support = 1;
module_param(ocqp_support, int, 0644);
MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)");
+int db_fc_threshold = 2000;
+module_param(db_fc_threshold, int, 0644);
+MODULE_PARM_DESC(db_fc_threshold, "QP count/threshold that triggers automatic "
+ "db flow control mode (default = 2000)");
+
static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
{
unsigned long flag;
@@ -1128,6 +1137,35 @@ out:
return ret;
}
+/*
+ * Called by the library when the qp has user dbs disabled due to
+ * a DB_FULL condition. This function will single-thread all user
+ * DB rings to avoid overflowing the hw db-fifo.
+ */
+static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc)
+{
+ int delay = db_delay_usecs;
+
+ mutex_lock(&qhp->rhp->db_mutex);
+ do {
+
+ /*
+ * The interrupt threshold is dbfifo_int_thresh << 6. So
+ * make sure we don't cross that and generate an interrupt.
+ */
+ if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) <
+ (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) {
+ writel(V_QID(qid) | V_PIDX(inc), qhp->wq.db);
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(delay));
+ delay = min(delay << 1, 2000);
+ } while (1);
+ mutex_unlock(&qhp->rhp->db_mutex);
+ return 0;
+}
+
int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
enum c4iw_qp_attr_mask mask,
struct c4iw_qp_attributes *attrs,
@@ -1176,6 +1214,15 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
qhp->attr = newattr;
}
+ if (mask & C4IW_QP_ATTR_SQ_DB) {
+ ret = ring_kernel_db(qhp, qhp->wq.sq.qid, attrs->sq_db_inc);
+ goto out;
+ }
+ if (mask & C4IW_QP_ATTR_RQ_DB) {
+ ret = ring_kernel_db(qhp, qhp->wq.rq.qid, attrs->rq_db_inc);
+ goto out;
+ }
+
if (!(mask & C4IW_QP_ATTR_NEXT_STATE))
goto out;
if (qhp->attr.state == attrs->next_state)
@@ -1352,6 +1399,14 @@ out:
return ret;
}
+static int enable_qp_db(int id, void *p, void *data)
+{
+ struct c4iw_qp *qp = p;
+
+ t4_enable_wq_db(&qp->wq);
+ return 0;
+}
+
int c4iw_destroy_qp(struct ib_qp *ib_qp)
{
struct c4iw_dev *rhp;
@@ -1369,7 +1424,16 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
wait_event(qhp->wait, !qhp->ep);
- remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+ spin_lock_irq(&rhp->lock);
+ remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+ rhp->qpcnt--;
+ BUG_ON(rhp->qpcnt < 0);
+ if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) {
+ rhp->rdev.stats.db_state_transitions++;
+ rhp->db_state = NORMAL;
+ idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
+ }
+ spin_unlock_irq(&rhp->lock);
atomic_dec(&qhp->refcnt);
wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
@@ -1383,6 +1447,14 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
return 0;
}
+static int disable_qp_db(int id, void *p, void *data)
+{
+ struct c4iw_qp *qp = p;
+
+ t4_disable_wq_db(&qp->wq);
+ return 0;
+}
+
struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
struct ib_udata *udata)
{
@@ -1469,7 +1541,16 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
init_waitqueue_head(&qhp->wait);
atomic_set(&qhp->refcnt, 1);
- ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
+ spin_lock_irq(&rhp->lock);
+ if (rhp->db_state != NORMAL)
+ t4_disable_wq_db(&qhp->wq);
+ if (++rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
+ rhp->rdev.stats.db_state_transitions++;
+ rhp->db_state = FLOW_CONTROL;
+ idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
+ }
+ ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
+ spin_unlock_irq(&rhp->lock);
if (ret)
goto err2;
@@ -1613,6 +1694,15 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
C4IW_QP_ATTR_ENABLE_RDMA_WRITE |
C4IW_QP_ATTR_ENABLE_RDMA_BIND) : 0;
+ /*
+ * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for
+ * ringing the queue db when we're in DB_FULL mode.
+ */
+ attrs.sq_db_inc = attr->sq_psn;
+ attrs.rq_db_inc = attr->rq_psn;
+ mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0;
+ mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0;
+
return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0);
}
@@ -1621,3 +1711,14 @@ struct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn)
PDBG("%s ib_dev %p qpn 0x%x\n", __func__, dev, qpn);
return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn);
}
+
+int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+ struct c4iw_qp *qhp = to_c4iw_qp(ibqp);
+
+ memset(attr, 0, sizeof *attr);
+ memset(init_attr, 0, sizeof *init_attr);
+ attr->qp_state = to_ib_qp_state(qhp->attr.state);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c
index 407ff39..cdef4d7 100644
--- a/drivers/infiniband/hw/cxgb4/resource.c
+++ b/drivers/infiniband/hw/cxgb4/resource.c
@@ -30,96 +30,25 @@
* SOFTWARE.
*/
/* Crude resource management */
-#include <linux/kernel.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/kfifo.h>
#include <linux/spinlock.h>
-#include <linux/errno.h>
#include <linux/genalloc.h>
#include <linux/ratelimit.h>
#include "iw_cxgb4.h"
-#define RANDOM_SIZE 16
-
-static int __c4iw_init_resource_fifo(struct kfifo *fifo,
- spinlock_t *fifo_lock,
- u32 nr, u32 skip_low,
- u32 skip_high,
- int random)
-{
- u32 i, j, entry = 0, idx;
- u32 random_bytes;
- u32 rarray[16];
- spin_lock_init(fifo_lock);
-
- if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
- return -ENOMEM;
-
- for (i = 0; i < skip_low + skip_high; i++)
- kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
- if (random) {
- j = 0;
- random_bytes = random32();
- for (i = 0; i < RANDOM_SIZE; i++)
- rarray[i] = i + skip_low;
- for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
- if (j >= RANDOM_SIZE) {
- j = 0;
- random_bytes = random32();
- }
- idx = (random_bytes >> (j * 2)) & 0xF;
- kfifo_in(fifo,
- (unsigned char *) &rarray[idx],
- sizeof(u32));
- rarray[idx] = i;
- j++;
- }
- for (i = 0; i < RANDOM_SIZE; i++)
- kfifo_in(fifo,
- (unsigned char *) &rarray[i],
- sizeof(u32));
- } else
- for (i = skip_low; i < nr - skip_high; i++)
- kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
-
- for (i = 0; i < skip_low + skip_high; i++)
- if (kfifo_out_locked(fifo, (unsigned char *) &entry,
- sizeof(u32), fifo_lock))
- break;
- return 0;
-}
-
-static int c4iw_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
- u32 nr, u32 skip_low, u32 skip_high)
-{
- return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
- skip_high, 0);
-}
-
-static int c4iw_init_resource_fifo_random(struct kfifo *fifo,
- spinlock_t *fifo_lock,
- u32 nr, u32 skip_low, u32 skip_high)
-{
- return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
- skip_high, 1);
-}
-
-static int c4iw_init_qid_fifo(struct c4iw_rdev *rdev)
+static int c4iw_init_qid_table(struct c4iw_rdev *rdev)
{
u32 i;
- spin_lock_init(&rdev->resource.qid_fifo_lock);
-
- if (kfifo_alloc(&rdev->resource.qid_fifo, rdev->lldi.vr->qp.size *
- sizeof(u32), GFP_KERNEL))
+ if (c4iw_id_table_alloc(&rdev->resource.qid_table,
+ rdev->lldi.vr->qp.start,
+ rdev->lldi.vr->qp.size,
+ rdev->lldi.vr->qp.size, 0))
return -ENOMEM;
for (i = rdev->lldi.vr->qp.start;
- i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
+ i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
if (!(i & rdev->qpmask))
- kfifo_in(&rdev->resource.qid_fifo,
- (unsigned char *) &i, sizeof(u32));
+ c4iw_id_free(&rdev->resource.qid_table, i);
return 0;
}
@@ -127,44 +56,42 @@ static int c4iw_init_qid_fifo(struct c4iw_rdev *rdev)
int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid)
{
int err = 0;
- err = c4iw_init_resource_fifo_random(&rdev->resource.tpt_fifo,
- &rdev->resource.tpt_fifo_lock,
- nr_tpt, 1, 0);
+ err = c4iw_id_table_alloc(&rdev->resource.tpt_table, 0, nr_tpt, 1,
+ C4IW_ID_TABLE_F_RANDOM);
if (err)
goto tpt_err;
- err = c4iw_init_qid_fifo(rdev);
+ err = c4iw_init_qid_table(rdev);
if (err)
goto qid_err;
- err = c4iw_init_resource_fifo(&rdev->resource.pdid_fifo,
- &rdev->resource.pdid_fifo_lock,
- nr_pdid, 1, 0);
+ err = c4iw_id_table_alloc(&rdev->resource.pdid_table, 0,
+ nr_pdid, 1, 0);
if (err)
goto pdid_err;
return 0;
-pdid_err:
- kfifo_free(&rdev->resource.qid_fifo);
-qid_err:
- kfifo_free(&rdev->resource.tpt_fifo);
-tpt_err:
+ pdid_err:
+ c4iw_id_table_free(&rdev->resource.qid_table);
+ qid_err:
+ c4iw_id_table_free(&rdev->resource.tpt_table);
+ tpt_err:
return -ENOMEM;
}
/*
* returns 0 if no resource available
*/
-u32 c4iw_get_resource(struct kfifo *fifo, spinlock_t *lock)
+u32 c4iw_get_resource(struct c4iw_id_table *id_table)
{
u32 entry;
- if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
- return entry;
- else
+ entry = c4iw_id_alloc(id_table);
+ if (entry == (u32)(-1))
return 0;
+ return entry;
}
-void c4iw_put_resource(struct kfifo *fifo, u32 entry, spinlock_t *lock)
+void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry)
{
PDBG("%s entry 0x%x\n", __func__, entry);
- kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock);
+ c4iw_id_free(id_table, entry);
}
u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
@@ -181,10 +108,12 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
qid = entry->qid;
kfree(entry);
} else {
- qid = c4iw_get_resource(&rdev->resource.qid_fifo,
- &rdev->resource.qid_fifo_lock);
+ qid = c4iw_get_resource(&rdev->resource.qid_table);
if (!qid)
goto out;
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.qid.cur += rdev->qpmask + 1;
+ mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc(sizeof *entry, GFP_KERNEL);
if (!entry)
@@ -213,6 +142,10 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
out:
mutex_unlock(&uctx->lock);
PDBG("%s qid 0x%x\n", __func__, qid);
+ mutex_lock(&rdev->stats.lock);
+ if (rdev->stats.qid.cur > rdev->stats.qid.max)
+ rdev->stats.qid.max = rdev->stats.qid.cur;
+ mutex_unlock(&rdev->stats.lock);
return qid;
}
@@ -245,10 +178,12 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
qid = entry->qid;
kfree(entry);
} else {
- qid = c4iw_get_resource(&rdev->resource.qid_fifo,
- &rdev->resource.qid_fifo_lock);
+ qid = c4iw_get_resource(&rdev->resource.qid_table);
if (!qid)
goto out;
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.qid.cur += rdev->qpmask + 1;
+ mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc(sizeof *entry, GFP_KERNEL);
if (!entry)
@@ -277,6 +212,10 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
out:
mutex_unlock(&uctx->lock);
PDBG("%s qid 0x%x\n", __func__, qid);
+ mutex_lock(&rdev->stats.lock);
+ if (rdev->stats.qid.cur > rdev->stats.qid.max)
+ rdev->stats.qid.max = rdev->stats.qid.cur;
+ mutex_unlock(&rdev->stats.lock);
return qid;
}
@@ -297,9 +236,9 @@ void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
void c4iw_destroy_resource(struct c4iw_resource *rscp)
{
- kfifo_free(&rscp->tpt_fifo);
- kfifo_free(&rscp->qid_fifo);
- kfifo_free(&rscp->pdid_fifo);
+ c4iw_id_table_free(&rscp->tpt_table);
+ c4iw_id_table_free(&rscp->qid_table);
+ c4iw_id_table_free(&rscp->pdid_table);
}
/*
@@ -312,15 +251,23 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
- if (!addr)
- printk_ratelimited(KERN_WARNING MOD "%s: Out of PBL memory\n",
- pci_name(rdev->lldi.pdev));
+ mutex_lock(&rdev->stats.lock);
+ if (addr) {
+ rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
+ if (rdev->stats.pbl.cur > rdev->stats.pbl.max)
+ rdev->stats.pbl.max = rdev->stats.pbl.cur;
+ } else
+ rdev->stats.pbl.fail++;
+ mutex_unlock(&rdev->stats.lock);
return (u32)addr;
}
void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
}
@@ -377,12 +324,23 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
if (!addr)
printk_ratelimited(KERN_WARNING MOD "%s: Out of RQT memory\n",
pci_name(rdev->lldi.pdev));
+ mutex_lock(&rdev->stats.lock);
+ if (addr) {
+ rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
+ if (rdev->stats.rqt.cur > rdev->stats.rqt.max)
+ rdev->stats.rqt.max = rdev->stats.rqt.cur;
+ } else
+ rdev->stats.rqt.fail++;
+ mutex_unlock(&rdev->stats.lock);
return (u32)addr;
}
void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
}
@@ -433,12 +391,22 @@ u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+ if (addr) {
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.ocqp.cur += roundup(size, 1 << MIN_OCQP_SHIFT);
+ if (rdev->stats.ocqp.cur > rdev->stats.ocqp.max)
+ rdev->stats.ocqp.max = rdev->stats.ocqp.cur;
+ mutex_unlock(&rdev->stats.lock);
+ }
return (u32)addr;
}
void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.ocqp.cur -= roundup(size, 1 << MIN_OCQP_SHIFT);
+ mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
}
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index c0221ee..16f26ab 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -62,6 +62,10 @@ struct t4_status_page {
__be16 pidx;
u8 qp_err; /* flit 1 - sw owns */
u8 db_off;
+ u8 pad;
+ u16 host_wq_pidx;
+ u16 host_cidx;
+ u16 host_pidx;
};
#define T4_EQ_ENTRY_SIZE 64
@@ -375,6 +379,16 @@ static inline void t4_rq_consume(struct t4_wq *wq)
wq->rq.cidx = 0;
}
+static inline u16 t4_rq_host_wq_pidx(struct t4_wq *wq)
+{
+ return wq->rq.queue[wq->rq.size].status.host_wq_pidx;
+}
+
+static inline u16 t4_rq_wq_size(struct t4_wq *wq)
+{
+ return wq->rq.size * T4_RQ_NUM_SLOTS;
+}
+
static inline int t4_sq_onchip(struct t4_sq *sq)
{
return sq->flags & T4_SQ_ONCHIP;
@@ -412,6 +426,16 @@ static inline void t4_sq_consume(struct t4_wq *wq)
wq->sq.cidx = 0;
}
+static inline u16 t4_sq_host_wq_pidx(struct t4_wq *wq)
+{
+ return wq->sq.queue[wq->sq.size].status.host_wq_pidx;
+}
+
+static inline u16 t4_sq_wq_size(struct t4_wq *wq)
+{
+ return wq->sq.size * T4_SQ_NUM_SLOTS;
+}
+
static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc)
{
wmb();
diff --git a/drivers/infiniband/hw/cxgb4/user.h b/drivers/infiniband/hw/cxgb4/user.h
index e6669d5..32b754c 100644
--- a/drivers/infiniband/hw/cxgb4/user.h
+++ b/drivers/infiniband/hw/cxgb4/user.h
@@ -32,7 +32,7 @@
#ifndef __C4IW_USER_H__
#define __C4IW_USER_H__
-#define C4IW_UVERBS_ABI_VERSION 1
+#define C4IW_UVERBS_ABI_VERSION 2
/*
* Make sure that all structs defined in this file remain laid out so
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 1d7aea1..7cc3054 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -596,8 +596,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
ipath_format_hwerrors(hwerrs,
ipath_6110_hwerror_msgs,
- sizeof(ipath_6110_hwerror_msgs) /
- sizeof(ipath_6110_hwerror_msgs[0]),
+ ARRAY_SIZE(ipath_6110_hwerror_msgs),
msg, msgl);
if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index c0a03ac..26dfbc8 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -209,8 +209,7 @@ void ipath_format_hwerrors(u64 hwerrs,
{
int i;
const int glen =
- sizeof(ipath_generic_hwerror_msgs) /
- sizeof(ipath_generic_hwerror_msgs[0]);
+ ARRAY_SIZE(ipath_generic_hwerror_msgs);
for (i=0; i<glen; i++) {
if (hwerrs & ipath_generic_hwerror_msgs[i].mask) {
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 77c8cb4..6d4ef71c 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -50,7 +50,7 @@ static void mlx4_ib_cq_event(struct mlx4_cq *cq, enum mlx4_event type)
struct ib_cq *ibcq;
if (type != MLX4_EVENT_TYPE_CQ_ERROR) {
- printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+ pr_warn("Unexpected event type %d "
"on CQ %06x\n", type, cq->cqn);
return;
}
@@ -222,6 +222,9 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
uar = &dev->priv_uar;
}
+ if (dev->eq_table)
+ vector = dev->eq_table[vector % ibdev->num_comp_vectors];
+
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
cq->db.dma, &cq->mcq, vector, 0);
if (err)
@@ -463,7 +466,7 @@ static void dump_cqe(void *cqe)
{
__be32 *buf = cqe;
- printk(KERN_DEBUG "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ pr_debug("CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
be32_to_cpu(buf[0]), be32_to_cpu(buf[1]), be32_to_cpu(buf[2]),
be32_to_cpu(buf[3]), be32_to_cpu(buf[4]), be32_to_cpu(buf[5]),
be32_to_cpu(buf[6]), be32_to_cpu(buf[7]));
@@ -473,7 +476,7 @@ static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe,
struct ib_wc *wc)
{
if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) {
- printk(KERN_DEBUG "local QP operation err "
+ pr_debug("local QP operation err "
"(QPN %06x, WQE index %x, vendor syndrome %02x, "
"opcode = %02x)\n",
be32_to_cpu(cqe->my_qpn), be16_to_cpu(cqe->wqe_index),
@@ -576,7 +579,7 @@ repoll:
if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_OPCODE_NOP &&
is_send)) {
- printk(KERN_WARNING "Completion for NOP opcode detected!\n");
+ pr_warn("Completion for NOP opcode detected!\n");
return -EINVAL;
}
@@ -606,7 +609,7 @@ repoll:
mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev,
be32_to_cpu(cqe->vlan_my_qpn));
if (unlikely(!mqp)) {
- printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n",
+ pr_warn("CQ %06x with entry for unknown QPN %06x\n",
cq->mcq.cqn, be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK);
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index b948b6d..ee1c577 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -789,7 +789,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
list_del(&ge->list);
kfree(ge);
} else
- printk(KERN_WARNING "could not find mgid entry\n");
+ pr_warn("could not find mgid entry\n");
mutex_unlock(&mqp->mutex);
@@ -902,7 +902,7 @@ static void update_gids_task(struct work_struct *work)
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox)) {
- printk(KERN_WARNING "update gid table failed %ld\n", PTR_ERR(mailbox));
+ pr_warn("update gid table failed %ld\n", PTR_ERR(mailbox));
return;
}
@@ -913,7 +913,7 @@ static void update_gids_task(struct work_struct *work)
1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
MLX4_CMD_NATIVE);
if (err)
- printk(KERN_WARNING "set port command failed\n");
+ pr_warn("set port command failed\n");
else {
memcpy(gw->dev->iboe.gid_table[gw->port - 1], gw->gids, sizeof gw->gids);
event.device = &gw->dev->ib_dev;
@@ -1076,18 +1076,98 @@ static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event
return NOTIFY_DONE;
}
+static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
+{
+ char name[32];
+ int eq_per_port = 0;
+ int added_eqs = 0;
+ int total_eqs = 0;
+ int i, j, eq;
+
+ /* Init eq table */
+ ibdev->eq_table = NULL;
+ ibdev->eq_added = 0;
+
+ /* Legacy mode? */
+ if (dev->caps.comp_pool == 0)
+ return;
+
+ eq_per_port = rounddown_pow_of_two(dev->caps.comp_pool/
+ dev->caps.num_ports);
+
+ /* Init eq table */
+ added_eqs = 0;
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ added_eqs += eq_per_port;
+
+ total_eqs = dev->caps.num_comp_vectors + added_eqs;
+
+ ibdev->eq_table = kzalloc(total_eqs * sizeof(int), GFP_KERNEL);
+ if (!ibdev->eq_table)
+ return;
+
+ ibdev->eq_added = added_eqs;
+
+ eq = 0;
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) {
+ for (j = 0; j < eq_per_port; j++) {
+ sprintf(name, "mlx4-ib-%d-%d@%s",
+ i, j, dev->pdev->bus->name);
+ /* Set IRQ for specific name (per ring) */
+ if (mlx4_assign_eq(dev, name, &ibdev->eq_table[eq])) {
+ /* Use legacy (same as mlx4_en driver) */
+ pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq);
+ ibdev->eq_table[eq] =
+ (eq % dev->caps.num_comp_vectors);
+ }
+ eq++;
+ }
+ }
+
+ /* Fill the reset of the vector with legacy EQ */
+ for (i = 0, eq = added_eqs; i < dev->caps.num_comp_vectors; i++)
+ ibdev->eq_table[eq++] = i;
+
+ /* Advertise the new number of EQs to clients */
+ ibdev->ib_dev.num_comp_vectors = total_eqs;
+}
+
+static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
+{
+ int i;
+ int total_eqs;
+
+ /* Reset the advertised EQ number */
+ ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
+
+ /* Free only the added eqs */
+ for (i = 0; i < ibdev->eq_added; i++) {
+ /* Don't free legacy eqs if used */
+ if (ibdev->eq_table[i] <= dev->caps.num_comp_vectors)
+ continue;
+ mlx4_release_eq(dev, ibdev->eq_table[i]);
+ }
+
+ total_eqs = dev->caps.num_comp_vectors + ibdev->eq_added;
+ memset(ibdev->eq_table, 0, total_eqs * sizeof(int));
+ kfree(ibdev->eq_table);
+
+ ibdev->eq_table = NULL;
+ ibdev->eq_added = 0;
+}
+
static void *mlx4_ib_add(struct mlx4_dev *dev)
{
struct mlx4_ib_dev *ibdev;
int num_ports = 0;
- int i;
+ int i, j;
int err;
struct mlx4_ib_iboe *iboe;
- printk_once(KERN_INFO "%s", mlx4_ib_version);
+ pr_info_once("%s", mlx4_ib_version);
if (mlx4_is_mfunc(dev)) {
- printk(KERN_WARNING "IB not yet supported in SRIOV\n");
+ pr_warn("IB not yet supported in SRIOV\n");
return NULL;
}
@@ -1210,6 +1290,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
(1ull << IB_USER_VERBS_CMD_CLOSE_XRCD);
}
+ mlx4_ib_alloc_eqs(dev, ibdev);
+
spin_lock_init(&iboe->lock);
if (init_node_data(ibdev))
@@ -1241,9 +1323,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
goto err_reg;
}
- for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
+ for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) {
if (device_create_file(&ibdev->ib_dev.dev,
- mlx4_class_attributes[i]))
+ mlx4_class_attributes[j]))
goto err_notif;
}
@@ -1253,7 +1335,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
err_notif:
if (unregister_netdevice_notifier(&ibdev->iboe.nb))
- printk(KERN_WARNING "failure unregistering notifier\n");
+ pr_warn("failure unregistering notifier\n");
flush_workqueue(wq);
err_reg:
@@ -1288,7 +1370,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
ib_unregister_device(&ibdev->ib_dev);
if (ibdev->iboe.nb.notifier_call) {
if (unregister_netdevice_notifier(&ibdev->iboe.nb))
- printk(KERN_WARNING "failure unregistering notifier\n");
+ pr_warn("failure unregistering notifier\n");
ibdev->iboe.nb.notifier_call = NULL;
}
iounmap(ibdev->uar_map);
@@ -1298,6 +1380,8 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
mlx4_CLOSE_PORT(dev, p);
+ mlx4_ib_free_eqs(dev, ibdev);
+
mlx4_uar_free(dev, &ibdev->priv_uar);
mlx4_pd_free(dev, ibdev->priv_pdn);
ib_dealloc_device(&ibdev->ib_dev);
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index ed80345..e62297c 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -202,6 +202,8 @@ struct mlx4_ib_dev {
bool ib_active;
struct mlx4_ib_iboe iboe;
int counters[MLX4_MAX_PORTS];
+ int *eq_table;
+ int eq_added;
};
static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev)
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index dca55b1..bbaf617 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -338,7 +338,7 @@ int mlx4_ib_unmap_fmr(struct list_head *fmr_list)
err = mlx4_SYNC_TPT(mdev);
if (err)
- printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when "
+ pr_warn("SYNC_TPT error %d when "
"unmapping FMRs\n", err);
return 0;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 3a78489..ceb3332 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -84,6 +84,11 @@ enum {
MLX4_IB_CACHE_LINE_SIZE = 64,
};
+enum {
+ MLX4_RAW_QP_MTU = 7,
+ MLX4_RAW_QP_MSGMAX = 31,
+};
+
static const __be32 mlx4_ib_opcode[] = {
[IB_WR_SEND] = cpu_to_be32(MLX4_OPCODE_SEND),
[IB_WR_LSO] = cpu_to_be32(MLX4_OPCODE_LSO),
@@ -256,7 +261,7 @@ static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type)
event.event = IB_EVENT_QP_ACCESS_ERR;
break;
default:
- printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+ pr_warn("Unexpected event type %d "
"on QP %06x\n", type, qp->qpn);
return;
}
@@ -573,7 +578,12 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (sqpn) {
qpn = sqpn;
} else {
- err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn);
+ /* Raw packet QPNs must be aligned to 8 bits. If not, the WQE
+ * BlueFlame setup flow wrongly causes VLAN insertion. */
+ if (init_attr->qp_type == IB_QPT_RAW_PACKET)
+ err = mlx4_qp_reserve_range(dev->dev, 1, 1 << 8, &qpn);
+ else
+ err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn);
if (err)
goto err_wrid;
}
@@ -715,7 +725,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
if (qp->state != IB_QPS_RESET)
if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
- printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n",
+ pr_warn("modify QP %06x to RESET failed.\n",
qp->mqp.qpn);
get_cqs(qp, &send_cq, &recv_cq);
@@ -791,6 +801,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
case IB_QPT_RC:
case IB_QPT_UC:
case IB_QPT_UD:
+ case IB_QPT_RAW_PACKET:
{
qp = kzalloc(sizeof *qp, GFP_KERNEL);
if (!qp)
@@ -872,7 +883,8 @@ static int to_mlx4_st(enum ib_qp_type type)
case IB_QPT_XRC_INI:
case IB_QPT_XRC_TGT: return MLX4_QP_ST_XRC;
case IB_QPT_SMI:
- case IB_QPT_GSI: return MLX4_QP_ST_MLX;
+ case IB_QPT_GSI:
+ case IB_QPT_RAW_PACKET: return MLX4_QP_ST_MLX;
default: return -1;
}
}
@@ -946,7 +958,7 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
if (ah->ah_flags & IB_AH_GRH) {
if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len[port]) {
- printk(KERN_ERR "sgid_index (%u) too large. max is %d\n",
+ pr_err("sgid_index (%u) too large. max is %d\n",
ah->grh.sgid_index, dev->dev->caps.gid_table_len[port] - 1);
return -1;
}
@@ -1042,6 +1054,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI)
context->mtu_msgmax = (IB_MTU_4096 << 5) | 11;
+ else if (ibqp->qp_type == IB_QPT_RAW_PACKET)
+ context->mtu_msgmax = (MLX4_RAW_QP_MTU << 5) | MLX4_RAW_QP_MSGMAX;
else if (ibqp->qp_type == IB_QPT_UD) {
if (qp->flags & MLX4_IB_QP_LSO)
context->mtu_msgmax = (IB_MTU_4096 << 5) |
@@ -1050,7 +1064,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
} else if (attr_mask & IB_QP_PATH_MTU) {
if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
- printk(KERN_ERR "path MTU (%u) is invalid\n",
+ pr_err("path MTU (%u) is invalid\n",
attr->path_mtu);
goto out;
}
@@ -1200,7 +1214,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (cur_state == IB_QPS_INIT &&
new_state == IB_QPS_RTR &&
(ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI ||
- ibqp->qp_type == IB_QPT_UD)) {
+ ibqp->qp_type == IB_QPT_UD ||
+ ibqp->qp_type == IB_QPT_RAW_PACKET)) {
context->pri_path.sched_queue = (qp->port - 1) << 6;
if (is_qp0(dev, qp))
context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE;
@@ -1266,7 +1281,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (is_qp0(dev, qp)) {
if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR)
if (mlx4_INIT_PORT(dev->dev, qp->port))
- printk(KERN_WARNING "INIT_PORT failed for port %d\n",
+ pr_warn("INIT_PORT failed for port %d\n",
qp->port);
if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR &&
@@ -1319,6 +1334,11 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto out;
}
+ if ((attr_mask & IB_QP_PORT) && (ibqp->qp_type == IB_QPT_RAW_PACKET) &&
+ (rdma_port_get_link_layer(&dev->ib_dev, attr->port_num) !=
+ IB_LINK_LAYER_ETHERNET))
+ goto out;
+
if (attr_mask & IB_QP_PKEY_INDEX) {
int p = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
if (attr->pkey_index >= dev->dev->caps.pkey_table_len[p])
@@ -1424,6 +1444,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
if (is_eth) {
u8 *smac;
+ u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
+
+ mlx->sched_prio = cpu_to_be16(pcp);
memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
/* FIXME: cache smac value? */
@@ -1434,10 +1457,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
if (!is_vlan) {
sqp->ud_header.eth.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
} else {
- u16 pcp;
-
sqp->ud_header.vlan.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
- pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp);
}
} else {
@@ -1460,16 +1480,16 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf);
if (0) {
- printk(KERN_ERR "built UD header of size %d:\n", header_size);
+ pr_err("built UD header of size %d:\n", header_size);
for (i = 0; i < header_size / 4; ++i) {
if (i % 8 == 0)
- printk(" [%02x] ", i * 4);
- printk(" %08x",
- be32_to_cpu(((__be32 *) sqp->header_buf)[i]));
+ pr_err(" [%02x] ", i * 4);
+ pr_cont(" %08x",
+ be32_to_cpu(((__be32 *) sqp->header_buf)[i]));
if ((i + 1) % 8 == 0)
- printk("\n");
+ pr_cont("\n");
}
- printk("\n");
+ pr_err("\n");
}
/*
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 39542f3..60c5fb0 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -59,7 +59,7 @@ static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
event.event = IB_EVENT_SRQ_ERR;
break;
default:
- printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+ pr_warn("Unexpected event type %d "
"on SRQ %06x\n", type, srq->srqn);
return;
}
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 71edfbb..020e95c 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2884,7 +2884,8 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
ibevent.device = nesqp->ibqp.device;
ibevent.event = nesqp->terminate_eventtype;
ibevent.element.qp = &nesqp->ibqp;
- nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ if (nesqp->ibqp.event_handler)
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
}
@@ -3320,6 +3321,10 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nesqp->private_data_len = conn_param->private_data_len;
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+ /* space for rdma0 read msg */
+ if (conn_param->ord == 0)
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(1);
+
nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
conn_param->private_data_len);
diff --git a/drivers/infiniband/hw/ocrdma/Kconfig b/drivers/infiniband/hw/ocrdma/Kconfig
new file mode 100644
index 0000000..b5b6056
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/Kconfig
@@ -0,0 +1,8 @@
+config INFINIBAND_OCRDMA
+ tristate "Emulex One Connect HCA support"
+ depends on ETHERNET && NETDEVICES && PCI && (IPV6 || IPV6=n)
+ select NET_VENDOR_EMULEX
+ select BE2NET
+ ---help---
+ This driver provides low-level InfiniBand over Ethernet
+ support for Emulex One Connect host channel adapters (HCAs).
diff --git a/drivers/infiniband/hw/ocrdma/Makefile b/drivers/infiniband/hw/ocrdma/Makefile
new file mode 100644
index 0000000..06a5bed
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Idrivers/net/ethernet/emulex/benet
+
+obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma.o
+
+ocrdma-y := ocrdma_main.o ocrdma_verbs.o ocrdma_hw.o ocrdma_ah.o
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
new file mode 100644
index 0000000..85a69c9
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -0,0 +1,393 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_H__
+#define __OCRDMA_H__
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include <be_roce.h>
+#include "ocrdma_sli.h"
+
+#define OCRDMA_ROCE_DEV_VERSION "1.0.0"
+#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
+
+#define ocrdma_err(format, arg...) printk(KERN_ERR format, ##arg)
+
+#define OCRDMA_MAX_AH 512
+
+#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
+
+struct ocrdma_dev_attr {
+ u8 fw_ver[32];
+ u32 vendor_id;
+ u32 device_id;
+ u16 max_pd;
+ u16 max_cq;
+ u16 max_cqe;
+ u16 max_qp;
+ u16 max_wqe;
+ u16 max_rqe;
+ u32 max_inline_data;
+ int max_send_sge;
+ int max_recv_sge;
+ int max_mr;
+ u64 max_mr_size;
+ u32 max_num_mr_pbl;
+ int max_fmr;
+ int max_map_per_fmr;
+ int max_pages_per_frmr;
+ u16 max_ord_per_qp;
+ u16 max_ird_per_qp;
+
+ int device_cap_flags;
+ u8 cq_overflow_detect;
+ u8 srq_supported;
+
+ u32 wqe_size;
+ u32 rqe_size;
+ u32 ird_page_size;
+ u8 local_ca_ack_delay;
+ u8 ird;
+ u8 num_ird_pages;
+};
+
+struct ocrdma_pbl {
+ void *va;
+ dma_addr_t pa;
+};
+
+struct ocrdma_queue_info {
+ void *va;
+ dma_addr_t dma;
+ u32 size;
+ u16 len;
+ u16 entry_size; /* Size of an element in the queue */
+ u16 id; /* qid, where to ring the doorbell. */
+ u16 head, tail;
+ bool created;
+ atomic_t used; /* Number of valid elements in the queue */
+};
+
+struct ocrdma_eq {
+ struct ocrdma_queue_info q;
+ u32 vector;
+ int cq_cnt;
+ struct ocrdma_dev *dev;
+ char irq_name[32];
+};
+
+struct ocrdma_mq {
+ struct ocrdma_queue_info sq;
+ struct ocrdma_queue_info cq;
+ bool rearm_cq;
+};
+
+struct mqe_ctx {
+ struct mutex lock; /* for serializing mailbox commands on MQ */
+ wait_queue_head_t cmd_wait;
+ u32 tag;
+ u16 cqe_status;
+ u16 ext_status;
+ bool cmd_done;
+};
+
+struct ocrdma_dev {
+ struct ib_device ibdev;
+ struct ocrdma_dev_attr attr;
+
+ struct mutex dev_lock; /* provides syncronise access to device data */
+ spinlock_t flush_q_lock ____cacheline_aligned;
+
+ struct ocrdma_cq **cq_tbl;
+ struct ocrdma_qp **qp_tbl;
+
+ struct ocrdma_eq meq;
+ struct ocrdma_eq *qp_eq_tbl;
+ int eq_cnt;
+ u16 base_eqid;
+ u16 max_eq;
+
+ union ib_gid *sgid_tbl;
+ /* provided synchronization to sgid table for
+ * updating gid entries triggered by notifier.
+ */
+ spinlock_t sgid_lock;
+
+ int gsi_qp_created;
+ struct ocrdma_cq *gsi_sqcq;
+ struct ocrdma_cq *gsi_rqcq;
+
+ struct {
+ struct ocrdma_av *va;
+ dma_addr_t pa;
+ u32 size;
+ u32 num_ah;
+ /* provide synchronization for av
+ * entry allocations.
+ */
+ spinlock_t lock;
+ u32 ahid;
+ struct ocrdma_pbl pbl;
+ } av_tbl;
+
+ void *mbx_cmd;
+ struct ocrdma_mq mq;
+ struct mqe_ctx mqe_ctx;
+
+ struct be_dev_info nic_info;
+
+ struct list_head entry;
+ struct rcu_head rcu;
+ int id;
+};
+
+struct ocrdma_cq {
+ struct ib_cq ibcq;
+ struct ocrdma_dev *dev;
+ struct ocrdma_cqe *va;
+ u32 phase;
+ u32 getp; /* pointer to pending wrs to
+ * return to stack, wrap arounds
+ * at max_hw_cqe
+ */
+ u32 max_hw_cqe;
+ bool phase_change;
+ bool armed, solicited;
+ bool arm_needed;
+
+ spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization
+ * to cq polling
+ */
+ /* syncronizes cq completion handler invoked from multiple context */
+ spinlock_t comp_handler_lock ____cacheline_aligned;
+ u16 id;
+ u16 eqn;
+
+ struct ocrdma_ucontext *ucontext;
+ dma_addr_t pa;
+ u32 len;
+ atomic_t use_cnt;
+
+ /* head of all qp's sq and rq for which cqes need to be flushed
+ * by the software.
+ */
+ struct list_head sq_head, rq_head;
+};
+
+struct ocrdma_pd {
+ struct ib_pd ibpd;
+ struct ocrdma_dev *dev;
+ struct ocrdma_ucontext *uctx;
+ atomic_t use_cnt;
+ u32 id;
+ int num_dpp_qp;
+ u32 dpp_page;
+ bool dpp_enabled;
+};
+
+struct ocrdma_ah {
+ struct ib_ah ibah;
+ struct ocrdma_dev *dev;
+ struct ocrdma_av *av;
+ u16 sgid_index;
+ u32 id;
+};
+
+struct ocrdma_qp_hwq_info {
+ u8 *va; /* virtual address */
+ u32 max_sges;
+ u32 head, tail;
+ u32 entry_size;
+ u32 max_cnt;
+ u32 max_wqe_idx;
+ u32 free_delta;
+ u16 dbid; /* qid, where to ring the doorbell. */
+ u32 len;
+ dma_addr_t pa;
+};
+
+struct ocrdma_srq {
+ struct ib_srq ibsrq;
+ struct ocrdma_dev *dev;
+ u8 __iomem *db;
+ /* provide synchronization to multiple context(s) posting rqe */
+ spinlock_t q_lock ____cacheline_aligned;
+
+ struct ocrdma_qp_hwq_info rq;
+ struct ocrdma_pd *pd;
+ atomic_t use_cnt;
+ u32 id;
+ u64 *rqe_wr_id_tbl;
+ u32 *idx_bit_fields;
+ u32 bit_fields_len;
+};
+
+struct ocrdma_qp {
+ struct ib_qp ibqp;
+ struct ocrdma_dev *dev;
+
+ u8 __iomem *sq_db;
+ /* provide synchronization to multiple context(s) posting wqe, rqe */
+ spinlock_t q_lock ____cacheline_aligned;
+ struct ocrdma_qp_hwq_info sq;
+ struct {
+ uint64_t wrid;
+ uint16_t dpp_wqe_idx;
+ uint16_t dpp_wqe;
+ uint8_t signaled;
+ uint8_t rsvd[3];
+ } *wqe_wr_id_tbl;
+ u32 max_inline_data;
+ struct ocrdma_cq *sq_cq;
+ /* list maintained per CQ to flush SQ errors */
+ struct list_head sq_entry;
+
+ u8 __iomem *rq_db;
+ struct ocrdma_qp_hwq_info rq;
+ u64 *rqe_wr_id_tbl;
+ struct ocrdma_cq *rq_cq;
+ struct ocrdma_srq *srq;
+ /* list maintained per CQ to flush RQ errors */
+ struct list_head rq_entry;
+
+ enum ocrdma_qp_state state; /* QP state */
+ int cap_flags;
+ u32 max_ord, max_ird;
+
+ u32 id;
+ struct ocrdma_pd *pd;
+
+ enum ib_qp_type qp_type;
+
+ int sgid_idx;
+ u32 qkey;
+ bool dpp_enabled;
+ u8 *ird_q_va;
+};
+
+#define OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp) \
+ (((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) && \
+ (qp->id < 64)) ? 24 : 16)
+
+struct ocrdma_hw_mr {
+ struct ocrdma_dev *dev;
+ u32 lkey;
+ u8 fr_mr;
+ u8 remote_atomic;
+ u8 remote_rd;
+ u8 remote_wr;
+ u8 local_rd;
+ u8 local_wr;
+ u8 mw_bind;
+ u8 rsvd;
+ u64 len;
+ struct ocrdma_pbl *pbl_table;
+ u32 num_pbls;
+ u32 num_pbes;
+ u32 pbl_size;
+ u32 pbe_size;
+ u64 fbo;
+ u64 va;
+};
+
+struct ocrdma_mr {
+ struct ib_mr ibmr;
+ struct ib_umem *umem;
+ struct ocrdma_hw_mr hwmr;
+ struct ocrdma_pd *pd;
+};
+
+struct ocrdma_ucontext {
+ struct ib_ucontext ibucontext;
+ struct ocrdma_dev *dev;
+
+ struct list_head mm_head;
+ struct mutex mm_list_lock; /* protects list entries of mm type */
+ struct {
+ u32 *va;
+ dma_addr_t pa;
+ u32 len;
+ } ah_tbl;
+};
+
+struct ocrdma_mm {
+ struct {
+ u64 phy_addr;
+ unsigned long len;
+ } key;
+ struct list_head entry;
+};
+
+static inline struct ocrdma_dev *get_ocrdma_dev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct ocrdma_dev, ibdev);
+}
+
+static inline struct ocrdma_ucontext *get_ocrdma_ucontext(struct ib_ucontext
+ *ibucontext)
+{
+ return container_of(ibucontext, struct ocrdma_ucontext, ibucontext);
+}
+
+static inline struct ocrdma_pd *get_ocrdma_pd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct ocrdma_pd, ibpd);
+}
+
+static inline struct ocrdma_cq *get_ocrdma_cq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct ocrdma_cq, ibcq);
+}
+
+static inline struct ocrdma_qp *get_ocrdma_qp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct ocrdma_qp, ibqp);
+}
+
+static inline struct ocrdma_mr *get_ocrdma_mr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct ocrdma_mr, ibmr);
+}
+
+static inline struct ocrdma_ah *get_ocrdma_ah(struct ib_ah *ibah)
+{
+ return container_of(ibah, struct ocrdma_ah, ibah);
+}
+
+static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct ocrdma_srq, ibsrq);
+}
+
+#endif
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_abi.h b/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
new file mode 100644
index 0000000..a411a4e
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
@@ -0,0 +1,134 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_ABI_H__
+#define __OCRDMA_ABI_H__
+
+struct ocrdma_alloc_ucontext_resp {
+ u32 dev_id;
+ u32 wqe_size;
+ u32 max_inline_data;
+ u32 dpp_wqe_size;
+ u64 ah_tbl_page;
+ u32 ah_tbl_len;
+ u32 rsvd;
+ u8 fw_ver[32];
+ u32 rqe_size;
+ u64 rsvd1;
+} __packed;
+
+/* user kernel communication data structures. */
+struct ocrdma_alloc_pd_ureq {
+ u64 rsvd1;
+} __packed;
+
+struct ocrdma_alloc_pd_uresp {
+ u32 id;
+ u32 dpp_enabled;
+ u32 dpp_page_addr_hi;
+ u32 dpp_page_addr_lo;
+ u64 rsvd1;
+} __packed;
+
+struct ocrdma_create_cq_ureq {
+ u32 dpp_cq;
+ u32 rsvd;
+} __packed;
+
+#define MAX_CQ_PAGES 8
+struct ocrdma_create_cq_uresp {
+ u32 cq_id;
+ u32 page_size;
+ u32 num_pages;
+ u32 max_hw_cqe;
+ u64 page_addr[MAX_CQ_PAGES];
+ u64 db_page_addr;
+ u32 db_page_size;
+ u32 phase_change;
+ u64 rsvd1;
+ u64 rsvd2;
+} __packed;
+
+#define MAX_QP_PAGES 8
+#define MAX_UD_AV_PAGES 8
+
+struct ocrdma_create_qp_ureq {
+ u8 enable_dpp_cq;
+ u8 rsvd;
+ u16 dpp_cq_id;
+ u32 rsvd1;
+};
+
+struct ocrdma_create_qp_uresp {
+ u16 qp_id;
+ u16 sq_dbid;
+ u16 rq_dbid;
+ u16 resv0;
+ u32 sq_page_size;
+ u32 rq_page_size;
+ u32 num_sq_pages;
+ u32 num_rq_pages;
+ u64 sq_page_addr[MAX_QP_PAGES];
+ u64 rq_page_addr[MAX_QP_PAGES];
+ u64 db_page_addr;
+ u32 db_page_size;
+ u32 dpp_credit;
+ u32 dpp_offset;
+ u32 rsvd1;
+ u32 num_wqe_allocated;
+ u32 num_rqe_allocated;
+ u32 free_wqe_delta;
+ u32 free_rqe_delta;
+ u32 db_sq_offset;
+ u32 db_rq_offset;
+ u32 db_shift;
+ u64 rsvd2;
+ u64 rsvd3;
+} __packed;
+
+struct ocrdma_create_srq_uresp {
+ u16 rq_dbid;
+ u16 resv0;
+ u32 resv1;
+
+ u32 rq_page_size;
+ u32 num_rq_pages;
+
+ u64 rq_page_addr[MAX_QP_PAGES];
+ u64 db_page_addr;
+
+ u32 db_page_size;
+ u32 num_rqe_allocated;
+ u32 db_rq_offset;
+ u32 db_shift;
+
+ u32 free_rqe_delta;
+ u32 rsvd2;
+ u64 rsvd3;
+} __packed;
+
+#endif /* __OCRDMA_ABI_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
new file mode 100644
index 0000000..a877a8e
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -0,0 +1,172 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#include <net/neighbour.h>
+#include <net/netevent.h>
+
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+
+#include "ocrdma.h"
+#include "ocrdma_verbs.h"
+#include "ocrdma_ah.h"
+#include "ocrdma_hw.h"
+
+static inline int set_av_attr(struct ocrdma_ah *ah,
+ struct ib_ah_attr *attr, int pdid)
+{
+ int status = 0;
+ u16 vlan_tag; bool vlan_enabled = false;
+ struct ocrdma_dev *dev = ah->dev;
+ struct ocrdma_eth_vlan eth;
+ struct ocrdma_grh grh;
+ int eth_sz;
+
+ memset(&eth, 0, sizeof(eth));
+ memset(&grh, 0, sizeof(grh));
+
+ ah->sgid_index = attr->grh.sgid_index;
+
+ vlan_tag = rdma_get_vlan_id(&attr->grh.dgid);
+ if (vlan_tag && (vlan_tag < 0x1000)) {
+ eth.eth_type = cpu_to_be16(0x8100);
+ eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
+ vlan_tag |= (attr->sl & 7) << 13;
+ eth.vlan_tag = cpu_to_be16(vlan_tag);
+ eth_sz = sizeof(struct ocrdma_eth_vlan);
+ vlan_enabled = true;
+ } else {
+ eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
+ eth_sz = sizeof(struct ocrdma_eth_basic);
+ }
+ memcpy(&eth.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN);
+ status = ocrdma_resolve_dgid(dev, &attr->grh.dgid, &eth.dmac[0]);
+ if (status)
+ return status;
+ status = ocrdma_query_gid(&dev->ibdev, 1, attr->grh.sgid_index,
+ (union ib_gid *)&grh.sgid[0]);
+ if (status)
+ return status;
+
+ grh.tclass_flow = cpu_to_be32((6 << 28) |
+ (attr->grh.traffic_class << 24) |
+ attr->grh.flow_label);
+ /* 0x1b is next header value in GRH */
+ grh.pdid_hoplimit = cpu_to_be32((pdid << 16) |
+ (0x1b << 8) | attr->grh.hop_limit);
+
+ memcpy(&grh.dgid[0], attr->grh.dgid.raw, sizeof(attr->grh.dgid.raw));
+ memcpy(&ah->av->eth_hdr, &eth, eth_sz);
+ memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
+ if (vlan_enabled)
+ ah->av->valid |= OCRDMA_AV_VLAN_VALID;
+ return status;
+}
+
+struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
+{
+ u32 *ahid_addr;
+ int status;
+ struct ocrdma_ah *ah;
+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+ struct ocrdma_dev *dev = pd->dev;
+
+ if (!(attr->ah_flags & IB_AH_GRH))
+ return ERR_PTR(-EINVAL);
+
+ ah = kzalloc(sizeof *ah, GFP_ATOMIC);
+ if (!ah)
+ return ERR_PTR(-ENOMEM);
+ ah->dev = pd->dev;
+
+ status = ocrdma_alloc_av(dev, ah);
+ if (status)
+ goto av_err;
+ status = set_av_attr(ah, attr, pd->id);
+ if (status)
+ goto av_conf_err;
+
+ /* if pd is for the user process, pass the ah_id to user space */
+ if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
+ ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
+ *ahid_addr = ah->id;
+ }
+ return &ah->ibah;
+
+av_conf_err:
+ ocrdma_free_av(dev, ah);
+av_err:
+ kfree(ah);
+ return ERR_PTR(status);
+}
+
+int ocrdma_destroy_ah(struct ib_ah *ibah)
+{
+ struct ocrdma_ah *ah = get_ocrdma_ah(ibah);
+ ocrdma_free_av(ah->dev, ah);
+ kfree(ah);
+ return 0;
+}
+
+int ocrdma_query_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+ struct ocrdma_ah *ah = get_ocrdma_ah(ibah);
+ struct ocrdma_av *av = ah->av;
+ struct ocrdma_grh *grh;
+ attr->ah_flags |= IB_AH_GRH;
+ if (ah->av->valid & Bit(1)) {
+ grh = (struct ocrdma_grh *)((u8 *)ah->av +
+ sizeof(struct ocrdma_eth_vlan));
+ attr->sl = be16_to_cpu(av->eth_hdr.vlan_tag) >> 13;
+ } else {
+ grh = (struct ocrdma_grh *)((u8 *)ah->av +
+ sizeof(struct ocrdma_eth_basic));
+ attr->sl = 0;
+ }
+ memcpy(&attr->grh.dgid.raw[0], &grh->dgid[0], sizeof(grh->dgid));
+ attr->grh.sgid_index = ah->sgid_index;
+ attr->grh.hop_limit = be32_to_cpu(grh->pdid_hoplimit) & 0xff;
+ attr->grh.traffic_class = be32_to_cpu(grh->tclass_flow) >> 24;
+ attr->grh.flow_label = be32_to_cpu(grh->tclass_flow) & 0x00ffffffff;
+ return 0;
+}
+
+int ocrdma_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+ /* modify_ah is unsupported */
+ return -ENOSYS;
+}
+
+int ocrdma_process_mad(struct ib_device *ibdev,
+ int process_mad_flags,
+ u8 port_num,
+ struct ib_wc *in_wc,
+ struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ return IB_MAD_RESULT_SUCCESS;
+}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
new file mode 100644
index 0000000..8ac49e7
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
@@ -0,0 +1,42 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_AH_H__
+#define __OCRDMA_AH_H__
+
+struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
+int ocrdma_destroy_ah(struct ib_ah *);
+int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
+int ocrdma_modify_ah(struct ib_ah *, struct ib_ah_attr *);
+
+int ocrdma_process_mad(struct ib_device *,
+ int process_mad_flags,
+ u8 port_num,
+ struct ib_wc *in_wc,
+ struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad);
+#endif /* __OCRDMA_AH_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
new file mode 100644
index 0000000..9b204b1
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -0,0 +1,2640 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) CNA Adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/log2.h>
+#include <linux/dma-mapping.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+
+#include "ocrdma.h"
+#include "ocrdma_hw.h"
+#include "ocrdma_verbs.h"
+#include "ocrdma_ah.h"
+
+enum mbx_status {
+ OCRDMA_MBX_STATUS_FAILED = 1,
+ OCRDMA_MBX_STATUS_ILLEGAL_FIELD = 3,
+ OCRDMA_MBX_STATUS_OOR = 100,
+ OCRDMA_MBX_STATUS_INVALID_PD = 101,
+ OCRDMA_MBX_STATUS_PD_INUSE = 102,
+ OCRDMA_MBX_STATUS_INVALID_CQ = 103,
+ OCRDMA_MBX_STATUS_INVALID_QP = 104,
+ OCRDMA_MBX_STATUS_INVALID_LKEY = 105,
+ OCRDMA_MBX_STATUS_ORD_EXCEEDS = 106,
+ OCRDMA_MBX_STATUS_IRD_EXCEEDS = 107,
+ OCRDMA_MBX_STATUS_SENDQ_WQE_EXCEEDS = 108,
+ OCRDMA_MBX_STATUS_RECVQ_RQE_EXCEEDS = 109,
+ OCRDMA_MBX_STATUS_SGE_SEND_EXCEEDS = 110,
+ OCRDMA_MBX_STATUS_SGE_WRITE_EXCEEDS = 111,
+ OCRDMA_MBX_STATUS_SGE_RECV_EXCEEDS = 112,
+ OCRDMA_MBX_STATUS_INVALID_STATE_CHANGE = 113,
+ OCRDMA_MBX_STATUS_MW_BOUND = 114,
+ OCRDMA_MBX_STATUS_INVALID_VA = 115,
+ OCRDMA_MBX_STATUS_INVALID_LENGTH = 116,
+ OCRDMA_MBX_STATUS_INVALID_FBO = 117,
+ OCRDMA_MBX_STATUS_INVALID_ACC_RIGHTS = 118,
+ OCRDMA_MBX_STATUS_INVALID_PBE_SIZE = 119,
+ OCRDMA_MBX_STATUS_INVALID_PBL_ENTRY = 120,
+ OCRDMA_MBX_STATUS_INVALID_PBL_SHIFT = 121,
+ OCRDMA_MBX_STATUS_INVALID_SRQ_ID = 129,
+ OCRDMA_MBX_STATUS_SRQ_ERROR = 133,
+ OCRDMA_MBX_STATUS_RQE_EXCEEDS = 134,
+ OCRDMA_MBX_STATUS_MTU_EXCEEDS = 135,
+ OCRDMA_MBX_STATUS_MAX_QP_EXCEEDS = 136,
+ OCRDMA_MBX_STATUS_SRQ_LIMIT_EXCEEDS = 137,
+ OCRDMA_MBX_STATUS_SRQ_SIZE_UNDERUNS = 138,
+ OCRDMA_MBX_STATUS_QP_BOUND = 130,
+ OCRDMA_MBX_STATUS_INVALID_CHANGE = 139,
+ OCRDMA_MBX_STATUS_ATOMIC_OPS_UNSUP = 140,
+ OCRDMA_MBX_STATUS_INVALID_RNR_NAK_TIMER = 141,
+ OCRDMA_MBX_STATUS_MW_STILL_BOUND = 142,
+ OCRDMA_MBX_STATUS_PKEY_INDEX_INVALID = 143,
+ OCRDMA_MBX_STATUS_PKEY_INDEX_EXCEEDS = 144
+};
+
+enum additional_status {
+ OCRDMA_MBX_ADDI_STATUS_INSUFFICIENT_RESOURCES = 22
+};
+
+enum cqe_status {
+ OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_PRIVILEDGES = 1,
+ OCRDMA_MBX_CQE_STATUS_INVALID_PARAMETER = 2,
+ OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_RESOURCES = 3,
+ OCRDMA_MBX_CQE_STATUS_QUEUE_FLUSHING = 4,
+ OCRDMA_MBX_CQE_STATUS_DMA_FAILED = 5
+};
+
+static inline void *ocrdma_get_eqe(struct ocrdma_eq *eq)
+{
+ return (u8 *)eq->q.va + (eq->q.tail * sizeof(struct ocrdma_eqe));
+}
+
+static inline void ocrdma_eq_inc_tail(struct ocrdma_eq *eq)
+{
+ eq->q.tail = (eq->q.tail + 1) & (OCRDMA_EQ_LEN - 1);
+}
+
+static inline void *ocrdma_get_mcqe(struct ocrdma_dev *dev)
+{
+ struct ocrdma_mcqe *cqe = (struct ocrdma_mcqe *)
+ ((u8 *) dev->mq.cq.va +
+ (dev->mq.cq.tail * sizeof(struct ocrdma_mcqe)));
+
+ if (!(le32_to_cpu(cqe->valid_ae_cmpl_cons) & OCRDMA_MCQE_VALID_MASK))
+ return NULL;
+ return cqe;
+}
+
+static inline void ocrdma_mcq_inc_tail(struct ocrdma_dev *dev)
+{
+ dev->mq.cq.tail = (dev->mq.cq.tail + 1) & (OCRDMA_MQ_CQ_LEN - 1);
+}
+
+static inline struct ocrdma_mqe *ocrdma_get_mqe(struct ocrdma_dev *dev)
+{
+ return (struct ocrdma_mqe *)((u8 *) dev->mq.sq.va +
+ (dev->mq.sq.head *
+ sizeof(struct ocrdma_mqe)));
+}
+
+static inline void ocrdma_mq_inc_head(struct ocrdma_dev *dev)
+{
+ dev->mq.sq.head = (dev->mq.sq.head + 1) & (OCRDMA_MQ_LEN - 1);
+ atomic_inc(&dev->mq.sq.used);
+}
+
+static inline void *ocrdma_get_mqe_rsp(struct ocrdma_dev *dev)
+{
+ return (void *)((u8 *) dev->mq.sq.va +
+ (dev->mqe_ctx.tag * sizeof(struct ocrdma_mqe)));
+}
+
+enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps)
+{
+ switch (qps) {
+ case OCRDMA_QPS_RST:
+ return IB_QPS_RESET;
+ case OCRDMA_QPS_INIT:
+ return IB_QPS_INIT;
+ case OCRDMA_QPS_RTR:
+ return IB_QPS_RTR;
+ case OCRDMA_QPS_RTS:
+ return IB_QPS_RTS;
+ case OCRDMA_QPS_SQD:
+ case OCRDMA_QPS_SQ_DRAINING:
+ return IB_QPS_SQD;
+ case OCRDMA_QPS_SQE:
+ return IB_QPS_SQE;
+ case OCRDMA_QPS_ERR:
+ return IB_QPS_ERR;
+ };
+ return IB_QPS_ERR;
+}
+
+static enum ocrdma_qp_state get_ocrdma_qp_state(enum ib_qp_state qps)
+{
+ switch (qps) {
+ case IB_QPS_RESET:
+ return OCRDMA_QPS_RST;
+ case IB_QPS_INIT:
+ return OCRDMA_QPS_INIT;
+ case IB_QPS_RTR:
+ return OCRDMA_QPS_RTR;
+ case IB_QPS_RTS:
+ return OCRDMA_QPS_RTS;
+ case IB_QPS_SQD:
+ return OCRDMA_QPS_SQD;
+ case IB_QPS_SQE:
+ return OCRDMA_QPS_SQE;
+ case IB_QPS_ERR:
+ return OCRDMA_QPS_ERR;
+ };
+ return OCRDMA_QPS_ERR;
+}
+
+static int ocrdma_get_mbx_errno(u32 status)
+{
+ int err_num = -EFAULT;
+ u8 mbox_status = (status & OCRDMA_MBX_RSP_STATUS_MASK) >>
+ OCRDMA_MBX_RSP_STATUS_SHIFT;
+ u8 add_status = (status & OCRDMA_MBX_RSP_ASTATUS_MASK) >>
+ OCRDMA_MBX_RSP_ASTATUS_SHIFT;
+
+ switch (mbox_status) {
+ case OCRDMA_MBX_STATUS_OOR:
+ case OCRDMA_MBX_STATUS_MAX_QP_EXCEEDS:
+ err_num = -EAGAIN;
+ break;
+
+ case OCRDMA_MBX_STATUS_INVALID_PD:
+ case OCRDMA_MBX_STATUS_INVALID_CQ:
+ case OCRDMA_MBX_STATUS_INVALID_SRQ_ID:
+ case OCRDMA_MBX_STATUS_INVALID_QP:
+ case OCRDMA_MBX_STATUS_INVALID_CHANGE:
+ case OCRDMA_MBX_STATUS_MTU_EXCEEDS:
+ case OCRDMA_MBX_STATUS_INVALID_RNR_NAK_TIMER:
+ case OCRDMA_MBX_STATUS_PKEY_INDEX_INVALID:
+ case OCRDMA_MBX_STATUS_PKEY_INDEX_EXCEEDS:
+ case OCRDMA_MBX_STATUS_ILLEGAL_FIELD:
+ case OCRDMA_MBX_STATUS_INVALID_PBL_ENTRY:
+ case OCRDMA_MBX_STATUS_INVALID_LKEY:
+ case OCRDMA_MBX_STATUS_INVALID_VA:
+ case OCRDMA_MBX_STATUS_INVALID_LENGTH:
+ case OCRDMA_MBX_STATUS_INVALID_FBO:
+ case OCRDMA_MBX_STATUS_INVALID_ACC_RIGHTS:
+ case OCRDMA_MBX_STATUS_INVALID_PBE_SIZE:
+ case OCRDMA_MBX_STATUS_ATOMIC_OPS_UNSUP:
+ case OCRDMA_MBX_STATUS_SRQ_ERROR:
+ case OCRDMA_MBX_STATUS_SRQ_SIZE_UNDERUNS:
+ err_num = -EINVAL;
+ break;
+
+ case OCRDMA_MBX_STATUS_PD_INUSE:
+ case OCRDMA_MBX_STATUS_QP_BOUND:
+ case OCRDMA_MBX_STATUS_MW_STILL_BOUND:
+ case OCRDMA_MBX_STATUS_MW_BOUND:
+ err_num = -EBUSY;
+ break;
+
+ case OCRDMA_MBX_STATUS_RECVQ_RQE_EXCEEDS:
+ case OCRDMA_MBX_STATUS_SGE_RECV_EXCEEDS:
+ case OCRDMA_MBX_STATUS_RQE_EXCEEDS:
+ case OCRDMA_MBX_STATUS_SRQ_LIMIT_EXCEEDS:
+ case OCRDMA_MBX_STATUS_ORD_EXCEEDS:
+ case OCRDMA_MBX_STATUS_IRD_EXCEEDS:
+ case OCRDMA_MBX_STATUS_SENDQ_WQE_EXCEEDS:
+ case OCRDMA_MBX_STATUS_SGE_SEND_EXCEEDS:
+ case OCRDMA_MBX_STATUS_SGE_WRITE_EXCEEDS:
+ err_num = -ENOBUFS;
+ break;
+
+ case OCRDMA_MBX_STATUS_FAILED:
+ switch (add_status) {
+ case OCRDMA_MBX_ADDI_STATUS_INSUFFICIENT_RESOURCES:
+ err_num = -EAGAIN;
+ break;
+ }
+ default:
+ err_num = -EFAULT;
+ }
+ return err_num;
+}
+
+static int ocrdma_get_mbx_cqe_errno(u16 cqe_status)
+{
+ int err_num = -EINVAL;
+
+ switch (cqe_status) {
+ case OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_PRIVILEDGES:
+ err_num = -EPERM;
+ break;
+ case OCRDMA_MBX_CQE_STATUS_INVALID_PARAMETER:
+ err_num = -EINVAL;
+ break;
+ case OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_RESOURCES:
+ case OCRDMA_MBX_CQE_STATUS_QUEUE_FLUSHING:
+ err_num = -EAGAIN;
+ break;
+ case OCRDMA_MBX_CQE_STATUS_DMA_FAILED:
+ err_num = -EIO;
+ break;
+ }
+ return err_num;
+}
+
+void ocrdma_ring_cq_db(struct ocrdma_dev *dev, u16 cq_id, bool armed,
+ bool solicited, u16 cqe_popped)
+{
+ u32 val = cq_id & OCRDMA_DB_CQ_RING_ID_MASK;
+
+ val |= ((cq_id & OCRDMA_DB_CQ_RING_ID_EXT_MASK) <<
+ OCRDMA_DB_CQ_RING_ID_EXT_MASK_SHIFT);
+
+ if (armed)
+ val |= (1 << OCRDMA_DB_CQ_REARM_SHIFT);
+ if (solicited)
+ val |= (1 << OCRDMA_DB_CQ_SOLICIT_SHIFT);
+ val |= (cqe_popped << OCRDMA_DB_CQ_NUM_POPPED_SHIFT);
+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_CQ_OFFSET);
+}
+
+static void ocrdma_ring_mq_db(struct ocrdma_dev *dev)
+{
+ u32 val = 0;
+
+ val |= dev->mq.sq.id & OCRDMA_MQ_ID_MASK;
+ val |= 1 << OCRDMA_MQ_NUM_MQE_SHIFT;
+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_MQ_OFFSET);
+}
+
+static void ocrdma_ring_eq_db(struct ocrdma_dev *dev, u16 eq_id,
+ bool arm, bool clear_int, u16 num_eqe)
+{
+ u32 val = 0;
+
+ val |= eq_id & OCRDMA_EQ_ID_MASK;
+ val |= ((eq_id & OCRDMA_EQ_ID_EXT_MASK) << OCRDMA_EQ_ID_EXT_MASK_SHIFT);
+ if (arm)
+ val |= (1 << OCRDMA_REARM_SHIFT);
+ if (clear_int)
+ val |= (1 << OCRDMA_EQ_CLR_SHIFT);
+ val |= (1 << OCRDMA_EQ_TYPE_SHIFT);
+ val |= (num_eqe << OCRDMA_NUM_EQE_SHIFT);
+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_EQ_OFFSET);
+}
+
+static void ocrdma_init_mch(struct ocrdma_mbx_hdr *cmd_hdr,
+ u8 opcode, u8 subsys, u32 cmd_len)
+{
+ cmd_hdr->subsys_op = (opcode | (subsys << OCRDMA_MCH_SUBSYS_SHIFT));
+ cmd_hdr->timeout = 20; /* seconds */
+ cmd_hdr->cmd_len = cmd_len - sizeof(struct ocrdma_mbx_hdr);
+}
+
+static void *ocrdma_init_emb_mqe(u8 opcode, u32 cmd_len)
+{
+ struct ocrdma_mqe *mqe;
+
+ mqe = kzalloc(sizeof(struct ocrdma_mqe), GFP_KERNEL);
+ if (!mqe)
+ return NULL;
+ mqe->hdr.spcl_sge_cnt_emb |=
+ (OCRDMA_MQE_EMBEDDED << OCRDMA_MQE_HDR_EMB_SHIFT) &
+ OCRDMA_MQE_HDR_EMB_MASK;
+ mqe->hdr.pyld_len = cmd_len - sizeof(struct ocrdma_mqe_hdr);
+
+ ocrdma_init_mch(&mqe->u.emb_req.mch, opcode, OCRDMA_SUBSYS_ROCE,
+ mqe->hdr.pyld_len);
+ return mqe;
+}
+
+static void ocrdma_free_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q)
+{
+ dma_free_coherent(&dev->nic_info.pdev->dev, q->size, q->va, q->dma);
+}
+
+static int ocrdma_alloc_q(struct ocrdma_dev *dev,
+ struct ocrdma_queue_info *q, u16 len, u16 entry_size)
+{
+ memset(q, 0, sizeof(*q));
+ q->len = len;
+ q->entry_size = entry_size;
+ q->size = len * entry_size;
+ q->va = dma_alloc_coherent(&dev->nic_info.pdev->dev, q->size,
+ &q->dma, GFP_KERNEL);
+ if (!q->va)
+ return -ENOMEM;
+ memset(q->va, 0, q->size);
+ return 0;
+}
+
+static void ocrdma_build_q_pages(struct ocrdma_pa *q_pa, int cnt,
+ dma_addr_t host_pa, int hw_page_size)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ q_pa[i].lo = (u32) (host_pa & 0xffffffff);
+ q_pa[i].hi = (u32) upper_32_bits(host_pa);
+ host_pa += hw_page_size;
+ }
+}
+
+static void ocrdma_assign_eq_vect_gen2(struct ocrdma_dev *dev,
+ struct ocrdma_eq *eq)
+{
+ /* assign vector and update vector id for next EQ */
+ eq->vector = dev->nic_info.msix.start_vector;
+ dev->nic_info.msix.start_vector += 1;
+}
+
+static void ocrdma_free_eq_vect_gen2(struct ocrdma_dev *dev)
+{
+ /* this assumes that EQs are freed in exactly reverse order
+ * as its allocation.
+ */
+ dev->nic_info.msix.start_vector -= 1;
+}
+
+static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q,
+ int queue_type)
+{
+ u8 opcode = 0;
+ int status;
+ struct ocrdma_delete_q_req *cmd = dev->mbx_cmd;
+
+ switch (queue_type) {
+ case QTYPE_MCCQ:
+ opcode = OCRDMA_CMD_DELETE_MQ;
+ break;
+ case QTYPE_CQ:
+ opcode = OCRDMA_CMD_DELETE_CQ;
+ break;
+ case QTYPE_EQ:
+ opcode = OCRDMA_CMD_DELETE_EQ;
+ break;
+ default:
+ BUG();
+ }
+ memset(cmd, 0, sizeof(*cmd));
+ ocrdma_init_mch(&cmd->req, opcode, OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ cmd->id = q->id;
+
+ status = be_roce_mcc_cmd(dev->nic_info.netdev,
+ cmd, sizeof(*cmd), NULL, NULL);
+ if (!status)
+ q->created = false;
+ return status;
+}
+
+static int ocrdma_mbx_create_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
+{
+ int status;
+ struct ocrdma_create_eq_req *cmd = dev->mbx_cmd;
+ struct ocrdma_create_eq_rsp *rsp = dev->mbx_cmd;
+
+ memset(cmd, 0, sizeof(*cmd));
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_EQ, OCRDMA_SUBSYS_COMMON,
+ sizeof(*cmd));
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)
+ cmd->req.rsvd_version = 0;
+ else
+ cmd->req.rsvd_version = 2;
+
+ cmd->num_pages = 4;
+ cmd->valid = OCRDMA_CREATE_EQ_VALID;
+ cmd->cnt = 4 << OCRDMA_CREATE_EQ_CNT_SHIFT;
+
+ ocrdma_build_q_pages(&cmd->pa[0], cmd->num_pages, eq->q.dma,
+ PAGE_SIZE_4K);
+ status = be_roce_mcc_cmd(dev->nic_info.netdev, cmd, sizeof(*cmd), NULL,
+ NULL);
+ if (!status) {
+ eq->q.id = rsp->vector_eqid & 0xffff;
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)
+ ocrdma_assign_eq_vect_gen2(dev, eq);
+ else {
+ eq->vector = (rsp->vector_eqid >> 16) & 0xffff;
+ dev->nic_info.msix.start_vector += 1;
+ }
+ eq->q.created = true;
+ }
+ return status;
+}
+
+static int ocrdma_create_eq(struct ocrdma_dev *dev,
+ struct ocrdma_eq *eq, u16 q_len)
+{
+ int status;
+
+ status = ocrdma_alloc_q(dev, &eq->q, OCRDMA_EQ_LEN,
+ sizeof(struct ocrdma_eqe));
+ if (status)
+ return status;
+
+ status = ocrdma_mbx_create_eq(dev, eq);
+ if (status)
+ goto mbx_err;
+ eq->dev = dev;
+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
+
+ return 0;
+mbx_err:
+ ocrdma_free_q(dev, &eq->q);
+ return status;
+}
+
+static int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
+{
+ int irq;
+
+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)
+ irq = dev->nic_info.pdev->irq;
+ else
+ irq = dev->nic_info.msix.vector_list[eq->vector];
+ return irq;
+}
+
+static void _ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
+{
+ if (eq->q.created) {
+ ocrdma_mbx_delete_q(dev, &eq->q, QTYPE_EQ);
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)
+ ocrdma_free_eq_vect_gen2(dev);
+ ocrdma_free_q(dev, &eq->q);
+ }
+}
+
+static void ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
+{
+ int irq;
+
+ /* disarm EQ so that interrupts are not generated
+ * during freeing and EQ delete is in progress.
+ */
+ ocrdma_ring_eq_db(dev, eq->q.id, false, false, 0);
+
+ irq = ocrdma_get_irq(dev, eq);
+ free_irq(irq, eq);
+ _ocrdma_destroy_eq(dev, eq);
+}
+
+static void ocrdma_destroy_qp_eqs(struct ocrdma_dev *dev)
+{
+ int i;
+
+ /* deallocate the data path eqs */
+ for (i = 0; i < dev->eq_cnt; i++)
+ ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]);
+}
+
+static int ocrdma_mbx_mq_cq_create(struct ocrdma_dev *dev,
+ struct ocrdma_queue_info *cq,
+ struct ocrdma_queue_info *eq)
+{
+ struct ocrdma_create_cq_cmd *cmd = dev->mbx_cmd;
+ struct ocrdma_create_cq_cmd_rsp *rsp = dev->mbx_cmd;
+ int status;
+
+ memset(cmd, 0, sizeof(*cmd));
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_CQ,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ cmd->pgsz_pgcnt = PAGES_4K_SPANNED(cq->va, cq->size);
+ cmd->ev_cnt_flags = OCRDMA_CREATE_CQ_DEF_FLAGS;
+ cmd->eqn = (eq->id << OCRDMA_CREATE_CQ_EQID_SHIFT);
+
+ ocrdma_build_q_pages(&cmd->pa[0], cmd->pgsz_pgcnt,
+ cq->dma, PAGE_SIZE_4K);
+ status = be_roce_mcc_cmd(dev->nic_info.netdev,
+ cmd, sizeof(*cmd), NULL, NULL);
+ if (!status) {
+ cq->id = (rsp->cq_id & OCRDMA_CREATE_CQ_RSP_CQ_ID_MASK);
+ cq->created = true;
+ }
+ return status;
+}
+
+static u32 ocrdma_encoded_q_len(int q_len)
+{
+ u32 len_encoded = fls(q_len); /* log2(len) + 1 */
+
+ if (len_encoded == 16)
+ len_encoded = 0;
+ return len_encoded;
+}
+
+static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
+ struct ocrdma_queue_info *mq,
+ struct ocrdma_queue_info *cq)
+{
+ int num_pages, status;
+ struct ocrdma_create_mq_req *cmd = dev->mbx_cmd;
+ struct ocrdma_create_mq_rsp *rsp = dev->mbx_cmd;
+ struct ocrdma_pa *pa;
+
+ memset(cmd, 0, sizeof(*cmd));
+ num_pages = PAGES_4K_SPANNED(mq->va, mq->size);
+
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ cmd->v0.pages = num_pages;
+ cmd->v0.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
+ cmd->v0.async_cqid_valid = (cq->id << 1);
+ cmd->v0.cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
+ cmd->v0.cqid_ringsize |=
+ (cq->id << OCRDMA_CREATE_MQ_V0_CQ_ID_SHIFT);
+ cmd->v0.valid = OCRDMA_CREATE_MQ_VALID;
+ pa = &cmd->v0.pa[0];
+ } else {
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ cmd->req.rsvd_version = 1;
+ cmd->v1.cqid_pages = num_pages;
+ cmd->v1.cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);
+ cmd->v1.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
+ cmd->v1.async_event_bitmap = Bit(20);
+ cmd->v1.async_cqid_ringsize = cq->id;
+ cmd->v1.async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
+ cmd->v1.valid = OCRDMA_CREATE_MQ_VALID;
+ pa = &cmd->v1.pa[0];
+ }
+ ocrdma_build_q_pages(pa, num_pages, mq->dma, PAGE_SIZE_4K);
+ status = be_roce_mcc_cmd(dev->nic_info.netdev,
+ cmd, sizeof(*cmd), NULL, NULL);
+ if (!status) {
+ mq->id = rsp->id;
+ mq->created = true;
+ }
+ return status;
+}
+
+static int ocrdma_create_mq(struct ocrdma_dev *dev)
+{
+ int status;
+
+ /* Alloc completion queue for Mailbox queue */
+ status = ocrdma_alloc_q(dev, &dev->mq.cq, OCRDMA_MQ_CQ_LEN,
+ sizeof(struct ocrdma_mcqe));
+ if (status)
+ goto alloc_err;
+
+ status = ocrdma_mbx_mq_cq_create(dev, &dev->mq.cq, &dev->meq.q);
+ if (status)
+ goto mbx_cq_free;
+
+ memset(&dev->mqe_ctx, 0, sizeof(dev->mqe_ctx));
+ init_waitqueue_head(&dev->mqe_ctx.cmd_wait);
+ mutex_init(&dev->mqe_ctx.lock);
+
+ /* Alloc Mailbox queue */
+ status = ocrdma_alloc_q(dev, &dev->mq.sq, OCRDMA_MQ_LEN,
+ sizeof(struct ocrdma_mqe));
+ if (status)
+ goto mbx_cq_destroy;
+ status = ocrdma_mbx_create_mq(dev, &dev->mq.sq, &dev->mq.cq);
+ if (status)
+ goto mbx_q_free;
+ ocrdma_ring_cq_db(dev, dev->mq.cq.id, true, false, 0);
+ return 0;
+
+mbx_q_free:
+ ocrdma_free_q(dev, &dev->mq.sq);
+mbx_cq_destroy:
+ ocrdma_mbx_delete_q(dev, &dev->mq.cq, QTYPE_CQ);
+mbx_cq_free:
+ ocrdma_free_q(dev, &dev->mq.cq);
+alloc_err:
+ return status;
+}
+
+static void ocrdma_destroy_mq(struct ocrdma_dev *dev)
+{
+ struct ocrdma_queue_info *mbxq, *cq;
+
+ /* mqe_ctx lock synchronizes with any other pending cmds. */
+ mutex_lock(&dev->mqe_ctx.lock);
+ mbxq = &dev->mq.sq;
+ if (mbxq->created) {
+ ocrdma_mbx_delete_q(dev, mbxq, QTYPE_MCCQ);
+ ocrdma_free_q(dev, mbxq);
+ }
+ mutex_unlock(&dev->mqe_ctx.lock);
+
+ cq = &dev->mq.cq;
+ if (cq->created) {
+ ocrdma_mbx_delete_q(dev, cq, QTYPE_CQ);
+ ocrdma_free_q(dev, cq);
+ }
+}
+
+static void ocrdma_process_qpcat_error(struct ocrdma_dev *dev,
+ struct ocrdma_qp *qp)
+{
+ enum ib_qp_state new_ib_qps = IB_QPS_ERR;
+ enum ib_qp_state old_ib_qps;
+
+ if (qp == NULL)
+ BUG();
+ ocrdma_qp_state_machine(qp, new_ib_qps, &old_ib_qps);
+}
+
+static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
+ struct ocrdma_ae_mcqe *cqe)
+{
+ struct ocrdma_qp *qp = NULL;
+ struct ocrdma_cq *cq = NULL;
+ struct ib_event ib_evt;
+ int cq_event = 0;
+ int qp_event = 1;
+ int srq_event = 0;
+ int dev_event = 0;
+ int type = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_TYPE_MASK) >>
+ OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT;
+
+ if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID)
+ qp = dev->qp_tbl[cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK];
+ if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID)
+ cq = dev->cq_tbl[cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK];
+
+ ib_evt.device = &dev->ibdev;
+
+ switch (type) {
+ case OCRDMA_CQ_ERROR:
+ ib_evt.element.cq = &cq->ibcq;
+ ib_evt.event = IB_EVENT_CQ_ERR;
+ cq_event = 1;
+ qp_event = 0;
+ break;
+ case OCRDMA_CQ_OVERRUN_ERROR:
+ ib_evt.element.cq = &cq->ibcq;
+ ib_evt.event = IB_EVENT_CQ_ERR;
+ break;
+ case OCRDMA_CQ_QPCAT_ERROR:
+ ib_evt.element.qp = &qp->ibqp;
+ ib_evt.event = IB_EVENT_QP_FATAL;
+ ocrdma_process_qpcat_error(dev, qp);
+ break;
+ case OCRDMA_QP_ACCESS_ERROR:
+ ib_evt.element.qp = &qp->ibqp;
+ ib_evt.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ case OCRDMA_QP_COMM_EST_EVENT:
+ ib_evt.element.qp = &qp->ibqp;
+ ib_evt.event = IB_EVENT_COMM_EST;
+ break;
+ case OCRDMA_SQ_DRAINED_EVENT:
+ ib_evt.element.qp = &qp->ibqp;
+ ib_evt.event = IB_EVENT_SQ_DRAINED;
+ break;
+ case OCRDMA_DEVICE_FATAL_EVENT:
+ ib_evt.element.port_num = 1;
+ ib_evt.event = IB_EVENT_DEVICE_FATAL;
+ qp_event = 0;
+ dev_event = 1;
+ break;
+ case OCRDMA_SRQCAT_ERROR:
+ ib_evt.element.srq = &qp->srq->ibsrq;
+ ib_evt.event = IB_EVENT_SRQ_ERR;
+ srq_event = 1;
+ qp_event = 0;
+ break;
+ case OCRDMA_SRQ_LIMIT_EVENT:
+ ib_evt.element.srq = &qp->srq->ibsrq;
+ ib_evt.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ srq_event = 1;
+ qp_event = 0;
+ break;
+ case OCRDMA_QP_LAST_WQE_EVENT:
+ ib_evt.element.qp = &qp->ibqp;
+ ib_evt.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+ default:
+ cq_event = 0;
+ qp_event = 0;
+ srq_event = 0;
+ dev_event = 0;
+ ocrdma_err("%s() unknown type=0x%x\n", __func__, type);
+ break;
+ }
+
+ if (qp_event) {
+ if (qp->ibqp.event_handler)
+ qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);
+ } else if (cq_event) {
+ if (cq->ibcq.event_handler)
+ cq->ibcq.event_handler(&ib_evt, cq->ibcq.cq_context);
+ } else if (srq_event) {
+ if (qp->srq->ibsrq.event_handler)
+ qp->srq->ibsrq.event_handler(&ib_evt,
+ qp->srq->ibsrq.
+ srq_context);
+ } else if (dev_event)
+ ib_dispatch_event(&ib_evt);
+
+}
+
+static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
+{
+ /* async CQE processing */
+ struct ocrdma_ae_mcqe *cqe = ae_cqe;
+ u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>
+ OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;
+
+ if (evt_code == OCRDMA_ASYNC_EVE_CODE)
+ ocrdma_dispatch_ibevent(dev, cqe);
+ else
+ ocrdma_err("%s(%d) invalid evt code=0x%x\n",
+ __func__, dev->id, evt_code);
+}
+
+static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
+{
+ if (dev->mqe_ctx.tag == cqe->tag_lo && dev->mqe_ctx.cmd_done == false) {
+ dev->mqe_ctx.cqe_status = (cqe->status &
+ OCRDMA_MCQE_STATUS_MASK) >> OCRDMA_MCQE_STATUS_SHIFT;
+ dev->mqe_ctx.ext_status =
+ (cqe->status & OCRDMA_MCQE_ESTATUS_MASK)
+ >> OCRDMA_MCQE_ESTATUS_SHIFT;
+ dev->mqe_ctx.cmd_done = true;
+ wake_up(&dev->mqe_ctx.cmd_wait);
+ } else
+ ocrdma_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",
+ __func__, cqe->tag_lo, dev->mqe_ctx.tag);
+}
+
+static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
+{
+ u16 cqe_popped = 0;
+ struct ocrdma_mcqe *cqe;
+
+ while (1) {
+ cqe = ocrdma_get_mcqe(dev);
+ if (cqe == NULL)
+ break;
+ ocrdma_le32_to_cpu(cqe, sizeof(*cqe));
+ cqe_popped += 1;
+ if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_AE_MASK)
+ ocrdma_process_acqe(dev, cqe);
+ else if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_CMPL_MASK)
+ ocrdma_process_mcqe(dev, cqe);
+ else
+ ocrdma_err("%s() cqe->compl is not set.\n", __func__);
+ memset(cqe, 0, sizeof(struct ocrdma_mcqe));
+ ocrdma_mcq_inc_tail(dev);
+ }
+ ocrdma_ring_cq_db(dev, dev->mq.cq.id, true, false, cqe_popped);
+ return 0;
+}
+
+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq)
+{
+ unsigned long flags;
+ struct ocrdma_qp *qp;
+ bool buddy_cq_found = false;
+ /* Go through list of QPs in error state which are using this CQ
+ * and invoke its callback handler to trigger CQE processing for
+ * error/flushed CQE. It is rare to find more than few entries in
+ * this list as most consumers stops after getting error CQE.
+ * List is traversed only once when a matching buddy cq found for a QP.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ if (qp->srq)
+ continue;
+ /* if wq and rq share the same cq, than comp_handler
+ * is already invoked.
+ */
+ if (qp->sq_cq == qp->rq_cq)
+ continue;
+ /* if completion came on sq, rq's cq is buddy cq.
+ * if completion came on rq, sq's cq is buddy cq.
+ */
+ if (qp->sq_cq == cq)
+ cq = qp->rq_cq;
+ else
+ cq = qp->sq_cq;
+ buddy_cq_found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
+ if (buddy_cq_found == false)
+ return;
+ if (cq->ibcq.comp_handler) {
+ spin_lock_irqsave(&cq->comp_handler_lock, flags);
+ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
+ spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+ }
+}
+
+static void ocrdma_qp_cq_handler(struct ocrdma_dev *dev, u16 cq_idx)
+{
+ unsigned long flags;
+ struct ocrdma_cq *cq;
+
+ if (cq_idx >= OCRDMA_MAX_CQ)
+ BUG();
+
+ cq = dev->cq_tbl[cq_idx];
+ if (cq == NULL) {
+ ocrdma_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
+ return;
+ }
+ spin_lock_irqsave(&cq->cq_lock, flags);
+ cq->armed = false;
+ cq->solicited = false;
+ spin_unlock_irqrestore(&cq->cq_lock, flags);
+
+ ocrdma_ring_cq_db(dev, cq->id, false, false, 0);
+
+ if (cq->ibcq.comp_handler) {
+ spin_lock_irqsave(&cq->comp_handler_lock, flags);
+ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
+ spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+ }
+ ocrdma_qp_buddy_cq_handler(dev, cq);
+}
+
+static void ocrdma_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
+{
+ /* process the MQ-CQE. */
+ if (cq_id == dev->mq.cq.id)
+ ocrdma_mq_cq_handler(dev, cq_id);
+ else
+ ocrdma_qp_cq_handler(dev, cq_id);
+}
+
+static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
+{
+ struct ocrdma_eq *eq = handle;
+ struct ocrdma_dev *dev = eq->dev;
+ struct ocrdma_eqe eqe;
+ struct ocrdma_eqe *ptr;
+ u16 eqe_popped = 0;
+ u16 cq_id;
+ while (1) {
+ ptr = ocrdma_get_eqe(eq);
+ eqe = *ptr;
+ ocrdma_le32_to_cpu(&eqe, sizeof(eqe));
+ if ((eqe.id_valid & OCRDMA_EQE_VALID_MASK) == 0)
+ break;
+ eqe_popped += 1;
+ ptr->id_valid = 0;
+ /* check whether its CQE or not. */
+ if ((eqe.id_valid & OCRDMA_EQE_FOR_CQE_MASK) == 0) {
+ cq_id = eqe.id_valid >> OCRDMA_EQE_RESOURCE_ID_SHIFT;
+ ocrdma_cq_handler(dev, cq_id);
+ }
+ ocrdma_eq_inc_tail(eq);
+ }
+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, eqe_popped);
+ /* Ring EQ doorbell with num_popped to 0 to enable interrupts again. */
+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)
+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
+ return IRQ_HANDLED;
+}
+
+static void ocrdma_post_mqe(struct ocrdma_dev *dev, struct ocrdma_mqe *cmd)
+{
+ struct ocrdma_mqe *mqe;
+
+ dev->mqe_ctx.tag = dev->mq.sq.head;
+ dev->mqe_ctx.cmd_done = false;
+ mqe = ocrdma_get_mqe(dev);
+ cmd->hdr.tag_lo = dev->mq.sq.head;
+ ocrdma_copy_cpu_to_le32(mqe, cmd, sizeof(*mqe));
+ /* make sure descriptor is written before ringing doorbell */
+ wmb();
+ ocrdma_mq_inc_head(dev);
+ ocrdma_ring_mq_db(dev);
+}
+
+static int ocrdma_wait_mqe_cmpl(struct ocrdma_dev *dev)
+{
+ long status;
+ /* 30 sec timeout */
+ status = wait_event_timeout(dev->mqe_ctx.cmd_wait,
+ (dev->mqe_ctx.cmd_done != false),
+ msecs_to_jiffies(30000));
+ if (status)
+ return 0;
+ else
+ return -1;
+}
+
+/* issue a mailbox command on the MQ */
+static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)
+{
+ int status = 0;
+ u16 cqe_status, ext_status;
+ struct ocrdma_mqe *rsp;
+
+ mutex_lock(&dev->mqe_ctx.lock);
+ ocrdma_post_mqe(dev, mqe);
+ status = ocrdma_wait_mqe_cmpl(dev);
+ if (status)
+ goto mbx_err;
+ cqe_status = dev->mqe_ctx.cqe_status;
+ ext_status = dev->mqe_ctx.ext_status;
+ rsp = ocrdma_get_mqe_rsp(dev);
+ ocrdma_copy_le32_to_cpu(mqe, rsp, (sizeof(*mqe)));
+ if (cqe_status || ext_status) {
+ ocrdma_err
+ ("%s() opcode=0x%x, cqe_status=0x%x, ext_status=0x%x\n",
+ __func__,
+ (rsp->u.rsp.subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
+ OCRDMA_MBX_RSP_OPCODE_SHIFT, cqe_status, ext_status);
+ status = ocrdma_get_mbx_cqe_errno(cqe_status);
+ goto mbx_err;
+ }
+ if (mqe->u.rsp.status & OCRDMA_MBX_RSP_STATUS_MASK)
+ status = ocrdma_get_mbx_errno(mqe->u.rsp.status);
+mbx_err:
+ mutex_unlock(&dev->mqe_ctx.lock);
+ return status;
+}
+
+static void ocrdma_get_attr(struct ocrdma_dev *dev,
+ struct ocrdma_dev_attr *attr,
+ struct ocrdma_mbx_query_config *rsp)
+{
+ int max_q_mem;
+
+ attr->max_pd =
+ (rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;
+ attr->max_qp =
+ (rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
+ attr->max_send_sge = ((rsp->max_write_send_sge &
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT);
+ attr->max_recv_sge = (rsp->max_write_send_sge &
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT;
+ attr->max_ord_per_qp = (rsp->max_ird_ord_per_qp &
+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_SHIFT;
+ attr->max_ird_per_qp = (rsp->max_ird_ord_per_qp &
+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_SHIFT;
+ attr->cq_overflow_detect = (rsp->qp_srq_cq_ird_ord &
+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT;
+ attr->srq_supported = (rsp->qp_srq_cq_ird_ord &
+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_SHIFT;
+ attr->local_ca_ack_delay = (rsp->max_pd_ca_ack_delay &
+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_SHIFT;
+ attr->max_mr = rsp->max_mr;
+ attr->max_mr_size = ~0ull;
+ attr->max_fmr = 0;
+ attr->max_pages_per_frmr = rsp->max_pages_per_frmr;
+ attr->max_num_mr_pbl = rsp->max_num_mr_pbl;
+ attr->max_cqe = rsp->max_cq_cqes_per_cq &
+ OCRDMA_MBX_QUERY_CFG_MAX_CQES_PER_CQ_MASK;
+ attr->wqe_size = ((rsp->wqe_rqe_stride_max_dpp_cqs &
+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_OFFSET) *
+ OCRDMA_WQE_STRIDE;
+ attr->rqe_size = ((rsp->wqe_rqe_stride_max_dpp_cqs &
+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_OFFSET) *
+ OCRDMA_WQE_STRIDE;
+ attr->max_inline_data =
+ attr->wqe_size - (sizeof(struct ocrdma_hdr_wqe) +
+ sizeof(struct ocrdma_sge));
+ max_q_mem = OCRDMA_Q_PAGE_BASE_SIZE << (OCRDMA_MAX_Q_PAGE_SIZE_CNT - 1);
+ /* hw can queue one less then the configured size,
+ * so publish less by one to stack.
+ */
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ dev->attr.max_wqe = max_q_mem / dev->attr.wqe_size;
+ attr->ird = 1;
+ attr->ird_page_size = OCRDMA_MIN_Q_PAGE_SIZE;
+ attr->num_ird_pages = MAX_OCRDMA_IRD_PAGES;
+ } else
+ dev->attr.max_wqe = (max_q_mem / dev->attr.wqe_size) - 1;
+ dev->attr.max_rqe = (max_q_mem / dev->attr.rqe_size) - 1;
+}
+
+static int ocrdma_check_fw_config(struct ocrdma_dev *dev,
+ struct ocrdma_fw_conf_rsp *conf)
+{
+ u32 fn_mode;
+
+ fn_mode = conf->fn_mode & OCRDMA_FN_MODE_RDMA;
+ if (fn_mode != OCRDMA_FN_MODE_RDMA)
+ return -EINVAL;
+ dev->base_eqid = conf->base_eqid;
+ dev->max_eq = conf->max_eq;
+ dev->attr.max_cq = OCRDMA_MAX_CQ - 1;
+ return 0;
+}
+
+/* can be issued only during init time. */
+static int ocrdma_mbx_query_fw_ver(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ struct ocrdma_mqe *cmd;
+ struct ocrdma_fw_ver_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_GET_FW_VER, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)&cmd->u.cmd[0],
+ OCRDMA_CMD_GET_FW_VER,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_fw_ver_rsp *)cmd;
+ memset(&dev->attr.fw_ver[0], 0, sizeof(dev->attr.fw_ver));
+ memcpy(&dev->attr.fw_ver[0], &rsp->running_ver[0],
+ sizeof(rsp->running_ver));
+ ocrdma_le32_to_cpu(dev->attr.fw_ver, sizeof(rsp->running_ver));
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+/* can be issued only during init time. */
+static int ocrdma_mbx_query_fw_config(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ struct ocrdma_mqe *cmd;
+ struct ocrdma_fw_conf_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_GET_FW_CONFIG, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)&cmd->u.cmd[0],
+ OCRDMA_CMD_GET_FW_CONFIG,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_fw_conf_rsp *)cmd;
+ status = ocrdma_check_fw_config(dev, rsp);
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_mbx_query_dev(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ struct ocrdma_mbx_query_config *rsp;
+ struct ocrdma_mqe *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_CONFIG, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_mbx_query_config *)cmd;
+ ocrdma_get_attr(dev, &dev->attr, rsp);
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_alloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+{
+ int status = -ENOMEM;
+ struct ocrdma_alloc_pd *cmd;
+ struct ocrdma_alloc_pd_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ if (pd->dpp_enabled)
+ cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_rsp *)cmd;
+ pd->id = rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_PDID_MASK;
+ if (rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) {
+ pd->dpp_enabled = true;
+ pd->dpp_page = rsp->dpp_page_pdid >>
+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
+ } else {
+ pd->dpp_enabled = false;
+ pd->num_dpp_qp = 0;
+ }
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+{
+ int status = -ENOMEM;
+ struct ocrdma_dealloc_pd *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->id = pd->id;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
+ int *num_pages, int *page_size)
+{
+ int i;
+ int mem_size;
+
+ *num_entries = roundup_pow_of_two(*num_entries);
+ mem_size = *num_entries * entry_size;
+ /* find the possible lowest possible multiplier */
+ for (i = 0; i < OCRDMA_MAX_Q_PAGE_SIZE_CNT; i++) {
+ if (mem_size <= (OCRDMA_Q_PAGE_BASE_SIZE << i))
+ break;
+ }
+ if (i >= OCRDMA_MAX_Q_PAGE_SIZE_CNT)
+ return -EINVAL;
+ mem_size = roundup(mem_size,
+ ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES));
+ *num_pages =
+ mem_size / ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES);
+ *page_size = ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES);
+ *num_entries = mem_size / entry_size;
+ return 0;
+}
+
+static int ocrdma_mbx_create_ah_tbl(struct ocrdma_dev *dev)
+{
+ int i ;
+ int status = 0;
+ int max_ah;
+ struct ocrdma_create_ah_tbl *cmd;
+ struct ocrdma_create_ah_tbl_rsp *rsp;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ dma_addr_t pa;
+ struct ocrdma_pbe *pbes;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_AH_TBL, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ max_ah = OCRDMA_MAX_AH;
+ dev->av_tbl.size = sizeof(struct ocrdma_av) * max_ah;
+
+ /* number of PBEs in PBL */
+ cmd->ah_conf = (OCRDMA_AH_TBL_PAGES <<
+ OCRDMA_CREATE_AH_NUM_PAGES_SHIFT) &
+ OCRDMA_CREATE_AH_NUM_PAGES_MASK;
+
+ /* page size */
+ for (i = 0; i < OCRDMA_MAX_Q_PAGE_SIZE_CNT; i++) {
+ if (PAGE_SIZE == (OCRDMA_MIN_Q_PAGE_SIZE << i))
+ break;
+ }
+ cmd->ah_conf |= (i << OCRDMA_CREATE_AH_PAGE_SIZE_SHIFT) &
+ OCRDMA_CREATE_AH_PAGE_SIZE_MASK;
+
+ /* ah_entry size */
+ cmd->ah_conf |= (sizeof(struct ocrdma_av) <<
+ OCRDMA_CREATE_AH_ENTRY_SIZE_SHIFT) &
+ OCRDMA_CREATE_AH_ENTRY_SIZE_MASK;
+
+ dev->av_tbl.pbl.va = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+ &dev->av_tbl.pbl.pa,
+ GFP_KERNEL);
+ if (dev->av_tbl.pbl.va == NULL)
+ goto mem_err;
+
+ dev->av_tbl.va = dma_alloc_coherent(&pdev->dev, dev->av_tbl.size,
+ &pa, GFP_KERNEL);
+ if (dev->av_tbl.va == NULL)
+ goto mem_err_ah;
+ dev->av_tbl.pa = pa;
+ dev->av_tbl.num_ah = max_ah;
+ memset(dev->av_tbl.va, 0, dev->av_tbl.size);
+
+ pbes = (struct ocrdma_pbe *)dev->av_tbl.pbl.va;
+ for (i = 0; i < dev->av_tbl.size / OCRDMA_MIN_Q_PAGE_SIZE; i++) {
+ pbes[i].pa_lo = (u32) (pa & 0xffffffff);
+ pbes[i].pa_hi = (u32) upper_32_bits(pa);
+ pa += PAGE_SIZE;
+ }
+ cmd->tbl_addr[0].lo = (u32)(dev->av_tbl.pbl.pa & 0xFFFFFFFF);
+ cmd->tbl_addr[0].hi = (u32)upper_32_bits(dev->av_tbl.pbl.pa);
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_create_ah_tbl_rsp *)cmd;
+ dev->av_tbl.ahid = rsp->ahid & 0xFFFF;
+ kfree(cmd);
+ return 0;
+
+mbx_err:
+ dma_free_coherent(&pdev->dev, dev->av_tbl.size, dev->av_tbl.va,
+ dev->av_tbl.pa);
+ dev->av_tbl.va = NULL;
+mem_err_ah:
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->av_tbl.pbl.va,
+ dev->av_tbl.pbl.pa);
+ dev->av_tbl.pbl.va = NULL;
+ dev->av_tbl.size = 0;
+mem_err:
+ kfree(cmd);
+ return status;
+}
+
+static void ocrdma_mbx_delete_ah_tbl(struct ocrdma_dev *dev)
+{
+ struct ocrdma_delete_ah_tbl *cmd;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+
+ if (dev->av_tbl.va == NULL)
+ return;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_AH_TBL, sizeof(*cmd));
+ if (!cmd)
+ return;
+ cmd->ahid = dev->av_tbl.ahid;
+
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ dma_free_coherent(&pdev->dev, dev->av_tbl.size, dev->av_tbl.va,
+ dev->av_tbl.pa);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->av_tbl.pbl.va,
+ dev->av_tbl.pbl.pa);
+ kfree(cmd);
+}
+
+/* Multiple CQs uses the EQ. This routine returns least used
+ * EQ to associate with CQ. This will distributes the interrupt
+ * processing and CPU load to associated EQ, vector and so to that CPU.
+ */
+static u16 ocrdma_bind_eq(struct ocrdma_dev *dev)
+{
+ int i, selected_eq = 0, cq_cnt = 0;
+ u16 eq_id;
+
+ mutex_lock(&dev->dev_lock);
+ cq_cnt = dev->qp_eq_tbl[0].cq_cnt;
+ eq_id = dev->qp_eq_tbl[0].q.id;
+ /* find the EQ which is has the least number of
+ * CQs associated with it.
+ */
+ for (i = 0; i < dev->eq_cnt; i++) {
+ if (dev->qp_eq_tbl[i].cq_cnt < cq_cnt) {
+ cq_cnt = dev->qp_eq_tbl[i].cq_cnt;
+ eq_id = dev->qp_eq_tbl[i].q.id;
+ selected_eq = i;
+ }
+ }
+ dev->qp_eq_tbl[selected_eq].cq_cnt += 1;
+ mutex_unlock(&dev->dev_lock);
+ return eq_id;
+}
+
+static void ocrdma_unbind_eq(struct ocrdma_dev *dev, u16 eq_id)
+{
+ int i;
+
+ mutex_lock(&dev->dev_lock);
+ for (i = 0; i < dev->eq_cnt; i++) {
+ if (dev->qp_eq_tbl[i].q.id != eq_id)
+ continue;
+ dev->qp_eq_tbl[i].cq_cnt -= 1;
+ break;
+ }
+ mutex_unlock(&dev->dev_lock);
+}
+
+int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
+ int entries, int dpp_cq)
+{
+ int status = -ENOMEM; int max_hw_cqe;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ struct ocrdma_create_cq *cmd;
+ struct ocrdma_create_cq_rsp *rsp;
+ u32 hw_pages, cqe_size, page_size, cqe_count;
+
+ if (dpp_cq)
+ return -EINVAL;
+ if (entries > dev->attr.max_cqe) {
+ ocrdma_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",
+ __func__, dev->id, dev->attr.max_cqe, entries);
+ return -EINVAL;
+ }
+ if (dpp_cq && (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY))
+ return -EINVAL;
+
+ if (dpp_cq) {
+ cq->max_hw_cqe = 1;
+ max_hw_cqe = 1;
+ cqe_size = OCRDMA_DPP_CQE_SIZE;
+ hw_pages = 1;
+ } else {
+ cq->max_hw_cqe = dev->attr.max_cqe;
+ max_hw_cqe = dev->attr.max_cqe;
+ cqe_size = sizeof(struct ocrdma_cqe);
+ hw_pages = OCRDMA_CREATE_CQ_MAX_PAGES;
+ }
+
+ cq->len = roundup(max_hw_cqe * cqe_size, OCRDMA_MIN_Q_PAGE_SIZE);
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_CQ, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_CREATE_CQ,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+ cq->va = dma_alloc_coherent(&pdev->dev, cq->len, &cq->pa, GFP_KERNEL);
+ if (!cq->va) {
+ status = -ENOMEM;
+ goto mem_err;
+ }
+ memset(cq->va, 0, cq->len);
+ page_size = cq->len / hw_pages;
+ cmd->cmd.pgsz_pgcnt = (page_size / OCRDMA_MIN_Q_PAGE_SIZE) <<
+ OCRDMA_CREATE_CQ_PAGE_SIZE_SHIFT;
+ cmd->cmd.pgsz_pgcnt |= hw_pages;
+ cmd->cmd.ev_cnt_flags = OCRDMA_CREATE_CQ_DEF_FLAGS;
+
+ if (dev->eq_cnt < 0)
+ goto eq_err;
+ cq->eqn = ocrdma_bind_eq(dev);
+ cmd->cmd.req.rsvd_version = OCRDMA_CREATE_CQ_VER2;
+ cqe_count = cq->len / cqe_size;
+ if (cqe_count > 1024)
+ /* Set cnt to 3 to indicate more than 1024 cq entries */
+ cmd->cmd.ev_cnt_flags |= (0x3 << OCRDMA_CREATE_CQ_CNT_SHIFT);
+ else {
+ u8 count = 0;
+ switch (cqe_count) {
+ case 256:
+ count = 0;
+ break;
+ case 512:
+ count = 1;
+ break;
+ case 1024:
+ count = 2;
+ break;
+ default:
+ goto mbx_err;
+ }
+ cmd->cmd.ev_cnt_flags |= (count << OCRDMA_CREATE_CQ_CNT_SHIFT);
+ }
+ /* shared eq between all the consumer cqs. */
+ cmd->cmd.eqn = cq->eqn;
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (dpp_cq)
+ cmd->cmd.pgsz_pgcnt |= OCRDMA_CREATE_CQ_DPP <<
+ OCRDMA_CREATE_CQ_TYPE_SHIFT;
+ cq->phase_change = false;
+ cmd->cmd.cqe_count = (cq->len / cqe_size);
+ } else {
+ cmd->cmd.cqe_count = (cq->len / cqe_size) - 1;
+ cmd->cmd.ev_cnt_flags |= OCRDMA_CREATE_CQ_FLAGS_AUTO_VALID;
+ cq->phase_change = true;
+ }
+
+ ocrdma_build_q_pages(&cmd->cmd.pa[0], hw_pages, cq->pa, page_size);
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+
+ rsp = (struct ocrdma_create_cq_rsp *)cmd;
+ cq->id = (u16) (rsp->rsp.cq_id & OCRDMA_CREATE_CQ_RSP_CQ_ID_MASK);
+ kfree(cmd);
+ return 0;
+mbx_err:
+ ocrdma_unbind_eq(dev, cq->eqn);
+eq_err:
+ dma_free_coherent(&pdev->dev, cq->len, cq->va, cq->pa);
+mem_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)
+{
+ int status = -ENOMEM;
+ struct ocrdma_destroy_cq *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_CQ, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_DELETE_CQ,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ cmd->bypass_flush_qid |=
+ (cq->id << OCRDMA_DESTROY_CQ_QID_SHIFT) &
+ OCRDMA_DESTROY_CQ_QID_MASK;
+
+ ocrdma_unbind_eq(dev, cq->eqn);
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ dma_free_coherent(&dev->nic_info.pdev->dev, cq->len, cq->va, cq->pa);
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *dev, struct ocrdma_hw_mr *hwmr,
+ u32 pdid, int addr_check)
+{
+ int status = -ENOMEM;
+ struct ocrdma_alloc_lkey *cmd;
+ struct ocrdma_alloc_lkey_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_LKEY, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->pdid = pdid;
+ cmd->pbl_sz_flags |= addr_check;
+ cmd->pbl_sz_flags |= (hwmr->fr_mr << OCRDMA_ALLOC_LKEY_FMR_SHIFT);
+ cmd->pbl_sz_flags |=
+ (hwmr->remote_wr << OCRDMA_ALLOC_LKEY_REMOTE_WR_SHIFT);
+ cmd->pbl_sz_flags |=
+ (hwmr->remote_rd << OCRDMA_ALLOC_LKEY_REMOTE_RD_SHIFT);
+ cmd->pbl_sz_flags |=
+ (hwmr->local_wr << OCRDMA_ALLOC_LKEY_LOCAL_WR_SHIFT);
+ cmd->pbl_sz_flags |=
+ (hwmr->remote_atomic << OCRDMA_ALLOC_LKEY_REMOTE_ATOMIC_SHIFT);
+ cmd->pbl_sz_flags |=
+ (hwmr->num_pbls << OCRDMA_ALLOC_LKEY_PBL_SIZE_SHIFT);
+
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_lkey_rsp *)cmd;
+ hwmr->lkey = rsp->lrkey;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_dealloc_lkey(struct ocrdma_dev *dev, int fr_mr, u32 lkey)
+{
+ int status = -ENOMEM;
+ struct ocrdma_dealloc_lkey *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_LKEY, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->lkey = lkey;
+ cmd->rsvd_frmr = fr_mr ? 1 : 0;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_mbx_reg_mr(struct ocrdma_dev *dev, struct ocrdma_hw_mr *hwmr,
+ u32 pdid, u32 pbl_cnt, u32 pbe_size, u32 last)
+{
+ int status = -ENOMEM;
+ int i;
+ struct ocrdma_reg_nsmr *cmd;
+ struct ocrdma_reg_nsmr_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_REGISTER_NSMR, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->num_pbl_pdid =
+ pdid | (hwmr->num_pbls << OCRDMA_REG_NSMR_NUM_PBL_SHIFT);
+
+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_wr <<
+ OCRDMA_REG_NSMR_REMOTE_WR_SHIFT);
+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_rd <<
+ OCRDMA_REG_NSMR_REMOTE_RD_SHIFT);
+ cmd->flags_hpage_pbe_sz |= (hwmr->local_wr <<
+ OCRDMA_REG_NSMR_LOCAL_WR_SHIFT);
+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_atomic <<
+ OCRDMA_REG_NSMR_REMOTE_ATOMIC_SHIFT);
+ cmd->flags_hpage_pbe_sz |= (hwmr->mw_bind <<
+ OCRDMA_REG_NSMR_BIND_MEMWIN_SHIFT);
+ cmd->flags_hpage_pbe_sz |= (last << OCRDMA_REG_NSMR_LAST_SHIFT);
+
+ cmd->flags_hpage_pbe_sz |= (hwmr->pbe_size / OCRDMA_MIN_HPAGE_SIZE);
+ cmd->flags_hpage_pbe_sz |= (hwmr->pbl_size / OCRDMA_MIN_HPAGE_SIZE) <<
+ OCRDMA_REG_NSMR_HPAGE_SIZE_SHIFT;
+ cmd->totlen_low = hwmr->len;
+ cmd->totlen_high = upper_32_bits(hwmr->len);
+ cmd->fbo_low = (u32) (hwmr->fbo & 0xffffffff);
+ cmd->fbo_high = (u32) upper_32_bits(hwmr->fbo);
+ cmd->va_loaddr = (u32) hwmr->va;
+ cmd->va_hiaddr = (u32) upper_32_bits(hwmr->va);
+
+ for (i = 0; i < pbl_cnt; i++) {
+ cmd->pbl[i].lo = (u32) (hwmr->pbl_table[i].pa & 0xffffffff);
+ cmd->pbl[i].hi = upper_32_bits(hwmr->pbl_table[i].pa);
+ }
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_reg_nsmr_rsp *)cmd;
+ hwmr->lkey = rsp->lrkey;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_mbx_reg_mr_cont(struct ocrdma_dev *dev,
+ struct ocrdma_hw_mr *hwmr, u32 pbl_cnt,
+ u32 pbl_offset, u32 last)
+{
+ int status = -ENOMEM;
+ int i;
+ struct ocrdma_reg_nsmr_cont *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_REGISTER_NSMR_CONT, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->lrkey = hwmr->lkey;
+ cmd->num_pbl_offset = (pbl_cnt << OCRDMA_REG_NSMR_CONT_NUM_PBL_SHIFT) |
+ (pbl_offset & OCRDMA_REG_NSMR_CONT_PBL_SHIFT_MASK);
+ cmd->last = last << OCRDMA_REG_NSMR_CONT_LAST_SHIFT;
+
+ for (i = 0; i < pbl_cnt; i++) {
+ cmd->pbl[i].lo =
+ (u32) (hwmr->pbl_table[i + pbl_offset].pa & 0xffffffff);
+ cmd->pbl[i].hi =
+ upper_32_bits(hwmr->pbl_table[i + pbl_offset].pa);
+ }
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_reg_mr(struct ocrdma_dev *dev,
+ struct ocrdma_hw_mr *hwmr, u32 pdid, int acc)
+{
+ int status;
+ u32 last = 0;
+ u32 cur_pbl_cnt, pbl_offset;
+ u32 pending_pbl_cnt = hwmr->num_pbls;
+
+ pbl_offset = 0;
+ cur_pbl_cnt = min(pending_pbl_cnt, MAX_OCRDMA_NSMR_PBL);
+ if (cur_pbl_cnt == pending_pbl_cnt)
+ last = 1;
+
+ status = ocrdma_mbx_reg_mr(dev, hwmr, pdid,
+ cur_pbl_cnt, hwmr->pbe_size, last);
+ if (status) {
+ ocrdma_err("%s() status=%d\n", __func__, status);
+ return status;
+ }
+ /* if there is no more pbls to register then exit. */
+ if (last)
+ return 0;
+
+ while (!last) {
+ pbl_offset += cur_pbl_cnt;
+ pending_pbl_cnt -= cur_pbl_cnt;
+ cur_pbl_cnt = min(pending_pbl_cnt, MAX_OCRDMA_NSMR_PBL);
+ /* if we reach the end of the pbls, then need to set the last
+ * bit, indicating no more pbls to register for this memory key.
+ */
+ if (cur_pbl_cnt == pending_pbl_cnt)
+ last = 1;
+
+ status = ocrdma_mbx_reg_mr_cont(dev, hwmr, cur_pbl_cnt,
+ pbl_offset, last);
+ if (status)
+ break;
+ }
+ if (status)
+ ocrdma_err("%s() err. status=%d\n", __func__, status);
+
+ return status;
+}
+
+bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *cq, struct ocrdma_qp *qp)
+{
+ struct ocrdma_qp *tmp;
+ bool found = false;
+ list_for_each_entry(tmp, &cq->sq_head, sq_entry) {
+ if (qp == tmp) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *cq, struct ocrdma_qp *qp)
+{
+ struct ocrdma_qp *tmp;
+ bool found = false;
+ list_for_each_entry(tmp, &cq->rq_head, rq_entry) {
+ if (qp == tmp) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+void ocrdma_flush_qp(struct ocrdma_qp *qp)
+{
+ bool found;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->dev->flush_q_lock, flags);
+ found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
+ if (!found)
+ list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);
+ if (!qp->srq) {
+ found = ocrdma_is_qp_in_rq_flushlist(qp->rq_cq, qp);
+ if (!found)
+ list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);
+ }
+ spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);
+}
+
+int ocrdma_qp_state_machine(struct ocrdma_qp *qp, enum ib_qp_state new_ib_state,
+ enum ib_qp_state *old_ib_state)
+{
+ unsigned long flags;
+ int status = 0;
+ enum ocrdma_qp_state new_state;
+ new_state = get_ocrdma_qp_state(new_ib_state);
+
+ /* sync with wqe and rqe posting */
+ spin_lock_irqsave(&qp->q_lock, flags);
+
+ if (old_ib_state)
+ *old_ib_state = get_ibqp_state(qp->state);
+ if (new_state == qp->state) {
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ return 1;
+ }
+
+ switch (qp->state) {
+ case OCRDMA_QPS_RST:
+ switch (new_state) {
+ case OCRDMA_QPS_RST:
+ case OCRDMA_QPS_INIT:
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_INIT:
+ /* qps: INIT->XXX */
+ switch (new_state) {
+ case OCRDMA_QPS_INIT:
+ case OCRDMA_QPS_RTR:
+ break;
+ case OCRDMA_QPS_ERR:
+ ocrdma_flush_qp(qp);
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_RTR:
+ /* qps: RTS->XXX */
+ switch (new_state) {
+ case OCRDMA_QPS_RTS:
+ break;
+ case OCRDMA_QPS_ERR:
+ ocrdma_flush_qp(qp);
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_RTS:
+ /* qps: RTS->XXX */
+ switch (new_state) {
+ case OCRDMA_QPS_SQD:
+ case OCRDMA_QPS_SQE:
+ break;
+ case OCRDMA_QPS_ERR:
+ ocrdma_flush_qp(qp);
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_SQD:
+ /* qps: SQD->XXX */
+ switch (new_state) {
+ case OCRDMA_QPS_RTS:
+ case OCRDMA_QPS_SQE:
+ case OCRDMA_QPS_ERR:
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_SQE:
+ switch (new_state) {
+ case OCRDMA_QPS_RTS:
+ case OCRDMA_QPS_ERR:
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ case OCRDMA_QPS_ERR:
+ /* qps: ERR->XXX */
+ switch (new_state) {
+ case OCRDMA_QPS_RST:
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ };
+ if (!status)
+ qp->state = new_state;
+
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ return status;
+}
+
+static u32 ocrdma_set_create_qp_mbx_access_flags(struct ocrdma_qp *qp)
+{
+ u32 flags = 0;
+ if (qp->cap_flags & OCRDMA_QP_INB_RD)
+ flags |= OCRDMA_CREATE_QP_REQ_INB_RDEN_MASK;
+ if (qp->cap_flags & OCRDMA_QP_INB_WR)
+ flags |= OCRDMA_CREATE_QP_REQ_INB_WREN_MASK;
+ if (qp->cap_flags & OCRDMA_QP_MW_BIND)
+ flags |= OCRDMA_CREATE_QP_REQ_BIND_MEMWIN_MASK;
+ if (qp->cap_flags & OCRDMA_QP_LKEY0)
+ flags |= OCRDMA_CREATE_QP_REQ_ZERO_LKEYEN_MASK;
+ if (qp->cap_flags & OCRDMA_QP_FAST_REG)
+ flags |= OCRDMA_CREATE_QP_REQ_FMR_EN_MASK;
+ return flags;
+}
+
+static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
+ struct ib_qp_init_attr *attrs,
+ struct ocrdma_qp *qp)
+{
+ int status;
+ u32 len, hw_pages, hw_page_size;
+ dma_addr_t pa;
+ struct ocrdma_dev *dev = qp->dev;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ u32 max_wqe_allocated;
+ u32 max_sges = attrs->cap.max_send_sge;
+
+ max_wqe_allocated = attrs->cap.max_send_wr;
+ /* need to allocate one extra to for GEN1 family */
+ if (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY)
+ max_wqe_allocated += 1;
+
+ status = ocrdma_build_q_conf(&max_wqe_allocated,
+ dev->attr.wqe_size, &hw_pages, &hw_page_size);
+ if (status) {
+ ocrdma_err("%s() req. max_send_wr=0x%x\n", __func__,
+ max_wqe_allocated);
+ return -EINVAL;
+ }
+ qp->sq.max_cnt = max_wqe_allocated;
+ len = (hw_pages * hw_page_size);
+
+ qp->sq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);
+ if (!qp->sq.va)
+ return -EINVAL;
+ memset(qp->sq.va, 0, len);
+ qp->sq.len = len;
+ qp->sq.pa = pa;
+ qp->sq.entry_size = dev->attr.wqe_size;
+ ocrdma_build_q_pages(&cmd->wq_addr[0], hw_pages, pa, hw_page_size);
+
+ cmd->type_pgsz_pdn |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE)
+ << OCRDMA_CREATE_QP_REQ_SQ_PAGE_SIZE_SHIFT);
+ cmd->num_wq_rq_pages |= (hw_pages <<
+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_MASK;
+ cmd->max_sge_send_write |= (max_sges <<
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_MASK;
+ cmd->max_sge_send_write |= (max_sges <<
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_MASK;
+ cmd->max_wqe_rqe |= (ilog2(qp->sq.max_cnt) <<
+ OCRDMA_CREATE_QP_REQ_MAX_WQE_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_WQE_MASK;
+ cmd->wqe_rqe_size |= (dev->attr.wqe_size <<
+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_MASK;
+ return 0;
+}
+
+static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
+ struct ib_qp_init_attr *attrs,
+ struct ocrdma_qp *qp)
+{
+ int status;
+ u32 len, hw_pages, hw_page_size;
+ dma_addr_t pa = 0;
+ struct ocrdma_dev *dev = qp->dev;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;
+
+ status = ocrdma_build_q_conf(&max_rqe_allocated, dev->attr.rqe_size,
+ &hw_pages, &hw_page_size);
+ if (status) {
+ ocrdma_err("%s() req. max_recv_wr=0x%x\n", __func__,
+ attrs->cap.max_recv_wr + 1);
+ return status;
+ }
+ qp->rq.max_cnt = max_rqe_allocated;
+ len = (hw_pages * hw_page_size);
+
+ qp->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);
+ if (!qp->rq.va)
+ return status;
+ memset(qp->rq.va, 0, len);
+ qp->rq.pa = pa;
+ qp->rq.len = len;
+ qp->rq.entry_size = dev->attr.rqe_size;
+
+ ocrdma_build_q_pages(&cmd->rq_addr[0], hw_pages, pa, hw_page_size);
+ cmd->type_pgsz_pdn |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE) <<
+ OCRDMA_CREATE_QP_REQ_RQ_PAGE_SIZE_SHIFT);
+ cmd->num_wq_rq_pages |=
+ (hw_pages << OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_MASK;
+ cmd->max_sge_recv_flags |= (attrs->cap.max_recv_sge <<
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_MASK;
+ cmd->max_wqe_rqe |= (ilog2(qp->rq.max_cnt) <<
+ OCRDMA_CREATE_QP_REQ_MAX_RQE_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_RQE_MASK;
+ cmd->wqe_rqe_size |= (dev->attr.rqe_size <<
+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_MASK;
+ return 0;
+}
+
+static void ocrdma_set_create_qp_dpp_cmd(struct ocrdma_create_qp_req *cmd,
+ struct ocrdma_pd *pd,
+ struct ocrdma_qp *qp,
+ u8 enable_dpp_cq, u16 dpp_cq_id)
+{
+ pd->num_dpp_qp--;
+ qp->dpp_enabled = true;
+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_ENABLE_DPP_MASK;
+ if (!enable_dpp_cq)
+ return;
+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_ENABLE_DPP_MASK;
+ cmd->dpp_credits_cqid = dpp_cq_id;
+ cmd->dpp_credits_cqid |= OCRDMA_CREATE_QP_REQ_DPP_CREDIT_LIMIT <<
+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_SHIFT;
+}
+
+static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,
+ struct ocrdma_qp *qp)
+{
+ struct ocrdma_dev *dev = qp->dev;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ dma_addr_t pa = 0;
+ int ird_page_size = dev->attr.ird_page_size;
+ int ird_q_len = dev->attr.num_ird_pages * ird_page_size;
+
+ if (dev->attr.ird == 0)
+ return 0;
+
+ qp->ird_q_va = dma_alloc_coherent(&pdev->dev, ird_q_len,
+ &pa, GFP_KERNEL);
+ if (!qp->ird_q_va)
+ return -ENOMEM;
+ memset(qp->ird_q_va, 0, ird_q_len);
+ ocrdma_build_q_pages(&cmd->ird_addr[0], dev->attr.num_ird_pages,
+ pa, ird_page_size);
+ return 0;
+}
+
+static void ocrdma_get_create_qp_rsp(struct ocrdma_create_qp_rsp *rsp,
+ struct ocrdma_qp *qp,
+ struct ib_qp_init_attr *attrs,
+ u16 *dpp_offset, u16 *dpp_credit_lmt)
+{
+ u32 max_wqe_allocated, max_rqe_allocated;
+ qp->id = rsp->qp_id & OCRDMA_CREATE_QP_RSP_QP_ID_MASK;
+ qp->rq.dbid = rsp->sq_rq_id & OCRDMA_CREATE_QP_RSP_RQ_ID_MASK;
+ qp->sq.dbid = rsp->sq_rq_id >> OCRDMA_CREATE_QP_RSP_SQ_ID_SHIFT;
+ qp->max_ird = rsp->max_ord_ird & OCRDMA_CREATE_QP_RSP_MAX_IRD_MASK;
+ qp->max_ord = (rsp->max_ord_ird >> OCRDMA_CREATE_QP_RSP_MAX_ORD_SHIFT);
+ qp->dpp_enabled = false;
+ if (rsp->dpp_response & OCRDMA_CREATE_QP_RSP_DPP_ENABLED_MASK) {
+ qp->dpp_enabled = true;
+ *dpp_credit_lmt = (rsp->dpp_response &
+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_MASK) >>
+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_SHIFT;
+ *dpp_offset = (rsp->dpp_response &
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_MASK) >>
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_SHIFT;
+ }
+ max_wqe_allocated =
+ rsp->max_wqe_rqe >> OCRDMA_CREATE_QP_RSP_MAX_WQE_SHIFT;
+ max_wqe_allocated = 1 << max_wqe_allocated;
+ max_rqe_allocated = 1 << ((u16)rsp->max_wqe_rqe);
+
+ if (qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ qp->sq.free_delta = 0;
+ qp->rq.free_delta = 1;
+ } else
+ qp->sq.free_delta = 1;
+
+ qp->sq.max_cnt = max_wqe_allocated;
+ qp->sq.max_wqe_idx = max_wqe_allocated - 1;
+
+ if (!attrs->srq) {
+ qp->rq.max_cnt = max_rqe_allocated;
+ qp->rq.max_wqe_idx = max_rqe_allocated - 1;
+ qp->rq.free_delta = 1;
+ }
+}
+
+int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
+ u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,
+ u16 *dpp_credit_lmt)
+{
+ int status = -ENOMEM;
+ u32 flags = 0;
+ struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ struct ocrdma_cq *cq;
+ struct ocrdma_create_qp_req *cmd;
+ struct ocrdma_create_qp_rsp *rsp;
+ int qptype;
+
+ switch (attrs->qp_type) {
+ case IB_QPT_GSI:
+ qptype = OCRDMA_QPT_GSI;
+ break;
+ case IB_QPT_RC:
+ qptype = OCRDMA_QPT_RC;
+ break;
+ case IB_QPT_UD:
+ qptype = OCRDMA_QPT_UD;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_QP, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->type_pgsz_pdn |= (qptype << OCRDMA_CREATE_QP_REQ_QPT_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_QPT_MASK;
+ status = ocrdma_set_create_qp_sq_cmd(cmd, attrs, qp);
+ if (status)
+ goto sq_err;
+
+ if (attrs->srq) {
+ struct ocrdma_srq *srq = get_ocrdma_srq(attrs->srq);
+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_USE_SRQ_MASK;
+ cmd->rq_addr[0].lo = srq->id;
+ qp->srq = srq;
+ } else {
+ status = ocrdma_set_create_qp_rq_cmd(cmd, attrs, qp);
+ if (status)
+ goto rq_err;
+ }
+
+ status = ocrdma_set_create_qp_ird_cmd(cmd, qp);
+ if (status)
+ goto mbx_err;
+
+ cmd->type_pgsz_pdn |= (pd->id << OCRDMA_CREATE_QP_REQ_PD_ID_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_PD_ID_MASK;
+
+ flags = ocrdma_set_create_qp_mbx_access_flags(qp);
+
+ cmd->max_sge_recv_flags |= flags;
+ cmd->max_ord_ird |= (dev->attr.max_ord_per_qp <<
+ OCRDMA_CREATE_QP_REQ_MAX_ORD_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_ORD_MASK;
+ cmd->max_ord_ird |= (dev->attr.max_ird_per_qp <<
+ OCRDMA_CREATE_QP_REQ_MAX_IRD_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_MAX_IRD_MASK;
+ cq = get_ocrdma_cq(attrs->send_cq);
+ cmd->wq_rq_cqid |= (cq->id << OCRDMA_CREATE_QP_REQ_WQ_CQID_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_WQ_CQID_MASK;
+ qp->sq_cq = cq;
+ cq = get_ocrdma_cq(attrs->recv_cq);
+ cmd->wq_rq_cqid |= (cq->id << OCRDMA_CREATE_QP_REQ_RQ_CQID_SHIFT) &
+ OCRDMA_CREATE_QP_REQ_RQ_CQID_MASK;
+ qp->rq_cq = cq;
+
+ if (pd->dpp_enabled && attrs->cap.max_inline_data && pd->num_dpp_qp &&
+ (attrs->cap.max_inline_data <= dev->attr.max_inline_data))
+ ocrdma_set_create_qp_dpp_cmd(cmd, pd, qp, enable_dpp_cq,
+ dpp_cq_id);
+
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_create_qp_rsp *)cmd;
+ ocrdma_get_create_qp_rsp(rsp, qp, attrs, dpp_offset, dpp_credit_lmt);
+ qp->state = OCRDMA_QPS_RST;
+ kfree(cmd);
+ return 0;
+mbx_err:
+ if (qp->rq.va)
+ dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);
+rq_err:
+ ocrdma_err("%s(%d) rq_err\n", __func__, dev->id);
+ dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);
+sq_err:
+ ocrdma_err("%s(%d) sq_err\n", __func__, dev->id);
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_query_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
+ struct ocrdma_qp_params *param)
+{
+ int status = -ENOMEM;
+ struct ocrdma_query_qp *cmd;
+ struct ocrdma_query_qp_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_QP, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->qp_id = qp->id;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_query_qp_rsp *)cmd;
+ memcpy(param, &rsp->params, sizeof(struct ocrdma_qp_params));
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_resolve_dgid(struct ocrdma_dev *dev, union ib_gid *dgid,
+ u8 *mac_addr)
+{
+ struct in6_addr in6;
+
+ memcpy(&in6, dgid, sizeof in6);
+ if (rdma_is_multicast_addr(&in6))
+ rdma_get_mcast_mac(&in6, mac_addr);
+ else if (rdma_link_local_addr(&in6))
+ rdma_get_ll_mac(&in6, mac_addr);
+ else {
+ ocrdma_err("%s() fail to resolve mac_addr.\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void ocrdma_set_av_params(struct ocrdma_qp *qp,
+ struct ocrdma_modify_qp *cmd,
+ struct ib_qp_attr *attrs)
+{
+ struct ib_ah_attr *ah_attr = &attrs->ah_attr;
+ union ib_gid sgid;
+ u32 vlan_id;
+ u8 mac_addr[6];
+ if ((ah_attr->ah_flags & IB_AH_GRH) == 0)
+ return;
+ cmd->params.tclass_sq_psn |=
+ (ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);
+ cmd->params.rnt_rc_sl_fl |=
+ (ah_attr->grh.flow_label & OCRDMA_QP_PARAMS_FLOW_LABEL_MASK);
+ cmd->params.hop_lmt_rq_psn |=
+ (ah_attr->grh.hop_limit << OCRDMA_QP_PARAMS_HOP_LMT_SHIFT);
+ cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
+ memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
+ sizeof(cmd->params.dgid));
+ ocrdma_query_gid(&qp->dev->ibdev, 1,
+ ah_attr->grh.sgid_index, &sgid);
+ qp->sgid_idx = ah_attr->grh.sgid_index;
+ memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));
+ ocrdma_resolve_dgid(qp->dev, &ah_attr->grh.dgid, &mac_addr[0]);
+ cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |
+ (mac_addr[2] << 16) | (mac_addr[3] << 24);
+ /* convert them to LE format. */
+ ocrdma_cpu_to_le32(&cmd->params.dgid[0], sizeof(cmd->params.dgid));
+ ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
+ cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
+ vlan_id = rdma_get_vlan_id(&sgid);
+ if (vlan_id && (vlan_id < 0x1000)) {
+ cmd->params.vlan_dmac_b4_to_b5 |=
+ vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
+ cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
+ }
+}
+
+static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
+ struct ocrdma_modify_qp *cmd,
+ struct ib_qp_attr *attrs, int attr_mask,
+ enum ib_qp_state old_qps)
+{
+ int status = 0;
+ struct net_device *netdev = qp->dev->nic_info.netdev;
+ int eth_mtu = iboe_get_mtu(netdev->mtu);
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &
+ OCRDMA_QP_PARAMS_PKEY_INDEX_MASK);
+ cmd->flags |= OCRDMA_QP_PARA_PKEY_VALID;
+ }
+ if (attr_mask & IB_QP_QKEY) {
+ qp->qkey = attrs->qkey;
+ cmd->params.qkey = attrs->qkey;
+ cmd->flags |= OCRDMA_QP_PARA_QKEY_VALID;
+ }
+ if (attr_mask & IB_QP_AV)
+ ocrdma_set_av_params(qp, cmd, attrs);
+ else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {
+ /* set the default mac address for UD, GSI QPs */
+ cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |
+ (qp->dev->nic_info.mac_addr[1] << 8) |
+ (qp->dev->nic_info.mac_addr[2] << 16) |
+ (qp->dev->nic_info.mac_addr[3] << 24);
+ cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |
+ (qp->dev->nic_info.mac_addr[5] << 8);
+ }
+ if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&
+ attrs->en_sqd_async_notify) {
+ cmd->params.max_sge_recv_flags |=
+ OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC;
+ cmd->flags |= OCRDMA_QP_PARA_DST_QPN_VALID;
+ }
+ if (attr_mask & IB_QP_DEST_QPN) {
+ cmd->params.ack_to_rnr_rtc_dest_qpn |= (attrs->dest_qp_num &
+ OCRDMA_QP_PARAMS_DEST_QPN_MASK);
+ cmd->flags |= OCRDMA_QP_PARA_DST_QPN_VALID;
+ }
+ if (attr_mask & IB_QP_PATH_MTU) {
+ if (ib_mtu_enum_to_int(eth_mtu) <
+ ib_mtu_enum_to_int(attrs->path_mtu)) {
+ status = -EINVAL;
+ goto pmtu_err;
+ }
+ cmd->params.path_mtu_pkey_indx |=
+ (ib_mtu_enum_to_int(attrs->path_mtu) <<
+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT) &
+ OCRDMA_QP_PARAMS_PATH_MTU_MASK;
+ cmd->flags |= OCRDMA_QP_PARA_PMTU_VALID;
+ }
+ if (attr_mask & IB_QP_TIMEOUT) {
+ cmd->params.ack_to_rnr_rtc_dest_qpn |= attrs->timeout <<
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT;
+ cmd->flags |= OCRDMA_QP_PARA_ACK_TO_VALID;
+ }
+ if (attr_mask & IB_QP_RETRY_CNT) {
+ cmd->params.rnt_rc_sl_fl |= (attrs->retry_cnt <<
+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT) &
+ OCRDMA_QP_PARAMS_RETRY_CNT_MASK;
+ cmd->flags |= OCRDMA_QP_PARA_RETRY_CNT_VALID;
+ }
+ if (attr_mask & IB_QP_MIN_RNR_TIMER) {
+ cmd->params.rnt_rc_sl_fl |= (attrs->min_rnr_timer <<
+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_SHIFT) &
+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_MASK;
+ cmd->flags |= OCRDMA_QP_PARA_RNT_VALID;
+ }
+ if (attr_mask & IB_QP_RNR_RETRY) {
+ cmd->params.ack_to_rnr_rtc_dest_qpn |= (attrs->rnr_retry <<
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT)
+ & OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK;
+ cmd->flags |= OCRDMA_QP_PARA_RRC_VALID;
+ }
+ if (attr_mask & IB_QP_SQ_PSN) {
+ cmd->params.tclass_sq_psn |= (attrs->sq_psn & 0x00ffffff);
+ cmd->flags |= OCRDMA_QP_PARA_SQPSN_VALID;
+ }
+ if (attr_mask & IB_QP_RQ_PSN) {
+ cmd->params.hop_lmt_rq_psn |= (attrs->rq_psn & 0x00ffffff);
+ cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;
+ }
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {
+ status = -EINVAL;
+ goto pmtu_err;
+ }
+ qp->max_ord = attrs->max_rd_atomic;
+ cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;
+ }
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {
+ status = -EINVAL;
+ goto pmtu_err;
+ }
+ qp->max_ird = attrs->max_dest_rd_atomic;
+ cmd->flags |= OCRDMA_QP_PARA_MAX_IRD_VALID;
+ }
+ cmd->params.max_ord_ird = (qp->max_ord <<
+ OCRDMA_QP_PARAMS_MAX_ORD_SHIFT) |
+ (qp->max_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK);
+pmtu_err:
+ return status;
+}
+
+int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
+ struct ib_qp_attr *attrs, int attr_mask,
+ enum ib_qp_state old_qps)
+{
+ int status = -ENOMEM;
+ struct ocrdma_modify_qp *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_QP, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ cmd->params.id = qp->id;
+ cmd->flags = 0;
+ if (attr_mask & IB_QP_STATE) {
+ cmd->params.max_sge_recv_flags |=
+ (get_ocrdma_qp_state(attrs->qp_state) <<
+ OCRDMA_QP_PARAMS_STATE_SHIFT) &
+ OCRDMA_QP_PARAMS_STATE_MASK;
+ cmd->flags |= OCRDMA_QP_PARA_QPS_VALID;
+ } else
+ cmd->params.max_sge_recv_flags |=
+ (qp->state << OCRDMA_QP_PARAMS_STATE_SHIFT) &
+ OCRDMA_QP_PARAMS_STATE_MASK;
+ status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask, old_qps);
+ if (status)
+ goto mbx_err;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_destroy_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
+{
+ int status = -ENOMEM;
+ struct ocrdma_destroy_qp *cmd;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_QP, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->qp_id = qp->id;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+
+mbx_err:
+ kfree(cmd);
+ if (qp->sq.va)
+ dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);
+ if (!qp->srq && qp->rq.va)
+ dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);
+ if (qp->dpp_enabled)
+ qp->pd->num_dpp_qp++;
+ return status;
+}
+
+int ocrdma_mbx_create_srq(struct ocrdma_srq *srq,
+ struct ib_srq_init_attr *srq_attr,
+ struct ocrdma_pd *pd)
+{
+ int status = -ENOMEM;
+ int hw_pages, hw_page_size;
+ int len;
+ struct ocrdma_create_srq_rsp *rsp;
+ struct ocrdma_create_srq *cmd;
+ dma_addr_t pa;
+ struct ocrdma_dev *dev = srq->dev;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ u32 max_rqe_allocated;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ cmd->pgsz_pdid = pd->id & OCRDMA_CREATE_SRQ_PD_ID_MASK;
+ max_rqe_allocated = srq_attr->attr.max_wr + 1;
+ status = ocrdma_build_q_conf(&max_rqe_allocated,
+ dev->attr.rqe_size,
+ &hw_pages, &hw_page_size);
+ if (status) {
+ ocrdma_err("%s() req. max_wr=0x%x\n", __func__,
+ srq_attr->attr.max_wr);
+ status = -EINVAL;
+ goto ret;
+ }
+ len = hw_pages * hw_page_size;
+ srq->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);
+ if (!srq->rq.va) {
+ status = -ENOMEM;
+ goto ret;
+ }
+ ocrdma_build_q_pages(&cmd->rq_addr[0], hw_pages, pa, hw_page_size);
+
+ srq->rq.entry_size = dev->attr.rqe_size;
+ srq->rq.pa = pa;
+ srq->rq.len = len;
+ srq->rq.max_cnt = max_rqe_allocated;
+
+ cmd->max_sge_rqe = ilog2(max_rqe_allocated);
+ cmd->max_sge_rqe |= srq_attr->attr.max_sge <<
+ OCRDMA_CREATE_SRQ_MAX_SGE_RECV_SHIFT;
+
+ cmd->pgsz_pdid |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE)
+ << OCRDMA_CREATE_SRQ_PG_SZ_SHIFT);
+ cmd->pages_rqe_sz |= (dev->attr.rqe_size
+ << OCRDMA_CREATE_SRQ_RQE_SIZE_SHIFT)
+ & OCRDMA_CREATE_SRQ_RQE_SIZE_MASK;
+ cmd->pages_rqe_sz |= hw_pages << OCRDMA_CREATE_SRQ_NUM_RQ_PAGES_SHIFT;
+
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_create_srq_rsp *)cmd;
+ srq->id = rsp->id;
+ srq->rq.dbid = rsp->id;
+ max_rqe_allocated = ((rsp->max_sge_rqe_allocated &
+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_MASK) >>
+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_SHIFT);
+ max_rqe_allocated = (1 << max_rqe_allocated);
+ srq->rq.max_cnt = max_rqe_allocated;
+ srq->rq.max_wqe_idx = max_rqe_allocated - 1;
+ srq->rq.max_sges = (rsp->max_sge_rqe_allocated &
+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_MASK) >>
+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_SHIFT;
+ goto ret;
+mbx_err:
+ dma_free_coherent(&pdev->dev, srq->rq.len, srq->rq.va, pa);
+ret:
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_modify_srq(struct ocrdma_srq *srq, struct ib_srq_attr *srq_attr)
+{
+ int status = -ENOMEM;
+ struct ocrdma_modify_srq *cmd;
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->id = srq->id;
+ cmd->limit_max_rqe |= srq_attr->srq_limit <<
+ OCRDMA_MODIFY_SRQ_LIMIT_SHIFT;
+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_query_srq(struct ocrdma_srq *srq, struct ib_srq_attr *srq_attr)
+{
+ int status = -ENOMEM;
+ struct ocrdma_query_srq *cmd;
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->id = srq->rq.dbid;
+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);
+ if (status == 0) {
+ struct ocrdma_query_srq_rsp *rsp =
+ (struct ocrdma_query_srq_rsp *)cmd;
+ srq_attr->max_sge =
+ rsp->srq_lmt_max_sge &
+ OCRDMA_QUERY_SRQ_RSP_MAX_SGE_RECV_MASK;
+ srq_attr->max_wr =
+ rsp->max_rqe_pdid >> OCRDMA_QUERY_SRQ_RSP_MAX_RQE_SHIFT;
+ srq_attr->srq_limit = rsp->srq_lmt_max_sge >>
+ OCRDMA_QUERY_SRQ_RSP_SRQ_LIMIT_SHIFT;
+ }
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_mbx_destroy_srq(struct ocrdma_dev *dev, struct ocrdma_srq *srq)
+{
+ int status = -ENOMEM;
+ struct ocrdma_destroy_srq *cmd;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_SRQ, sizeof(*cmd));
+ if (!cmd)
+ return status;
+ cmd->id = srq->id;
+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);
+ if (srq->rq.va)
+ dma_free_coherent(&pdev->dev, srq->rq.len,
+ srq->rq.va, srq->rq.pa);
+ kfree(cmd);
+ return status;
+}
+
+int ocrdma_alloc_av(struct ocrdma_dev *dev, struct ocrdma_ah *ah)
+{
+ int i;
+ int status = -EINVAL;
+ struct ocrdma_av *av;
+ unsigned long flags;
+
+ av = dev->av_tbl.va;
+ spin_lock_irqsave(&dev->av_tbl.lock, flags);
+ for (i = 0; i < dev->av_tbl.num_ah; i++) {
+ if (av->valid == 0) {
+ av->valid = OCRDMA_AV_VALID;
+ ah->av = av;
+ ah->id = i;
+ status = 0;
+ break;
+ }
+ av++;
+ }
+ if (i == dev->av_tbl.num_ah)
+ status = -EAGAIN;
+ spin_unlock_irqrestore(&dev->av_tbl.lock, flags);
+ return status;
+}
+
+int ocrdma_free_av(struct ocrdma_dev *dev, struct ocrdma_ah *ah)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->av_tbl.lock, flags);
+ ah->av->valid = 0;
+ spin_unlock_irqrestore(&dev->av_tbl.lock, flags);
+ return 0;
+}
+
+static int ocrdma_create_mq_eq(struct ocrdma_dev *dev)
+{
+ int status;
+ int irq;
+ unsigned long flags = 0;
+ int num_eq = 0;
+
+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)
+ flags = IRQF_SHARED;
+ else {
+ num_eq = dev->nic_info.msix.num_vectors -
+ dev->nic_info.msix.start_vector;
+ /* minimum two vectors/eq are required for rdma to work.
+ * one for control path and one for data path.
+ */
+ if (num_eq < 2)
+ return -EBUSY;
+ }
+
+ status = ocrdma_create_eq(dev, &dev->meq, OCRDMA_EQ_LEN);
+ if (status)
+ return status;
+ sprintf(dev->meq.irq_name, "ocrdma_mq%d", dev->id);
+ irq = ocrdma_get_irq(dev, &dev->meq);
+ status = request_irq(irq, ocrdma_irq_handler, flags, dev->meq.irq_name,
+ &dev->meq);
+ if (status)
+ _ocrdma_destroy_eq(dev, &dev->meq);
+ return status;
+}
+
+static int ocrdma_create_qp_eqs(struct ocrdma_dev *dev)
+{
+ int num_eq, i, status = 0;
+ int irq;
+ unsigned long flags = 0;
+
+ num_eq = dev->nic_info.msix.num_vectors -
+ dev->nic_info.msix.start_vector;
+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX) {
+ num_eq = 1;
+ flags = IRQF_SHARED;
+ } else
+ num_eq = min_t(u32, num_eq, num_online_cpus());
+ dev->qp_eq_tbl = kzalloc(sizeof(struct ocrdma_eq) * num_eq, GFP_KERNEL);
+ if (!dev->qp_eq_tbl)
+ return -ENOMEM;
+
+ for (i = 0; i < num_eq; i++) {
+ status = ocrdma_create_eq(dev, &dev->qp_eq_tbl[i],
+ OCRDMA_EQ_LEN);
+ if (status) {
+ status = -EINVAL;
+ break;
+ }
+ sprintf(dev->qp_eq_tbl[i].irq_name, "ocrdma_qp%d-%d",
+ dev->id, i);
+ irq = ocrdma_get_irq(dev, &dev->qp_eq_tbl[i]);
+ status = request_irq(irq, ocrdma_irq_handler, flags,
+ dev->qp_eq_tbl[i].irq_name,
+ &dev->qp_eq_tbl[i]);
+ if (status) {
+ _ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]);
+ status = -EINVAL;
+ break;
+ }
+ dev->eq_cnt += 1;
+ }
+ /* one eq is sufficient for data path to work */
+ if (dev->eq_cnt >= 1)
+ return 0;
+ if (status)
+ ocrdma_destroy_qp_eqs(dev);
+ return status;
+}
+
+int ocrdma_init_hw(struct ocrdma_dev *dev)
+{
+ int status;
+ /* set up control path eq */
+ status = ocrdma_create_mq_eq(dev);
+ if (status)
+ return status;
+ /* set up data path eq */
+ status = ocrdma_create_qp_eqs(dev);
+ if (status)
+ goto qpeq_err;
+ status = ocrdma_create_mq(dev);
+ if (status)
+ goto mq_err;
+ status = ocrdma_mbx_query_fw_config(dev);
+ if (status)
+ goto conf_err;
+ status = ocrdma_mbx_query_dev(dev);
+ if (status)
+ goto conf_err;
+ status = ocrdma_mbx_query_fw_ver(dev);
+ if (status)
+ goto conf_err;
+ status = ocrdma_mbx_create_ah_tbl(dev);
+ if (status)
+ goto conf_err;
+ return 0;
+
+conf_err:
+ ocrdma_destroy_mq(dev);
+mq_err:
+ ocrdma_destroy_qp_eqs(dev);
+qpeq_err:
+ ocrdma_destroy_eq(dev, &dev->meq);
+ ocrdma_err("%s() status=%d\n", __func__, status);
+ return status;
+}
+
+void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
+{
+ ocrdma_mbx_delete_ah_tbl(dev);
+
+ /* cleanup the data path eqs */
+ ocrdma_destroy_qp_eqs(dev);
+
+ /* cleanup the control path */
+ ocrdma_destroy_mq(dev);
+ ocrdma_destroy_eq(dev, &dev->meq);
+}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
new file mode 100644
index 0000000..be5db77
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -0,0 +1,132 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) CNA Adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_HW_H__
+#define __OCRDMA_HW_H__
+
+#include "ocrdma_sli.h"
+
+static inline void ocrdma_cpu_to_le32(void *dst, u32 len)
+{
+#ifdef __BIG_ENDIAN
+ int i = 0;
+ u32 *src_ptr = dst;
+ u32 *dst_ptr = dst;
+ for (; i < (len / 4); i++)
+ *(dst_ptr + i) = cpu_to_le32p(src_ptr + i);
+#endif
+}
+
+static inline void ocrdma_le32_to_cpu(void *dst, u32 len)
+{
+#ifdef __BIG_ENDIAN
+ int i = 0;
+ u32 *src_ptr = dst;
+ u32 *dst_ptr = dst;
+ for (; i < (len / sizeof(u32)); i++)
+ *(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));
+#endif
+}
+
+static inline void ocrdma_copy_cpu_to_le32(void *dst, void *src, u32 len)
+{
+#ifdef __BIG_ENDIAN
+ int i = 0;
+ u32 *src_ptr = src;
+ u32 *dst_ptr = dst;
+ for (; i < (len / sizeof(u32)); i++)
+ *(dst_ptr + i) = cpu_to_le32p(src_ptr + i);
+#else
+ memcpy(dst, src, len);
+#endif
+}
+
+static inline void ocrdma_copy_le32_to_cpu(void *dst, void *src, u32 len)
+{
+#ifdef __BIG_ENDIAN
+ int i = 0;
+ u32 *src_ptr = src;
+ u32 *dst_ptr = dst;
+ for (; i < len / sizeof(u32); i++)
+ *(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));
+#else
+ memcpy(dst, src, len);
+#endif
+}
+
+int ocrdma_init_hw(struct ocrdma_dev *);
+void ocrdma_cleanup_hw(struct ocrdma_dev *);
+
+enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps);
+void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,
+ bool solicited, u16 cqe_popped);
+
+/* verbs specific mailbox commands */
+int ocrdma_query_config(struct ocrdma_dev *,
+ struct ocrdma_mbx_query_config *config);
+int ocrdma_resolve_dgid(struct ocrdma_dev *, union ib_gid *dgid, u8 *mac_addr);
+
+int ocrdma_mbx_alloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);
+int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);
+
+int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,
+ u32 pd_id, int addr_check);
+int ocrdma_mbx_dealloc_lkey(struct ocrdma_dev *, int fmr, u32 lkey);
+
+int ocrdma_reg_mr(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,
+ u32 pd_id, int acc);
+int ocrdma_mbx_create_cq(struct ocrdma_dev *, struct ocrdma_cq *,
+ int entries, int dpp_cq);
+int ocrdma_mbx_destroy_cq(struct ocrdma_dev *, struct ocrdma_cq *);
+
+int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs,
+ u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,
+ u16 *dpp_credit_lmt);
+int ocrdma_mbx_modify_qp(struct ocrdma_dev *, struct ocrdma_qp *,
+ struct ib_qp_attr *attrs, int attr_mask,
+ enum ib_qp_state old_qps);
+int ocrdma_mbx_query_qp(struct ocrdma_dev *, struct ocrdma_qp *,
+ struct ocrdma_qp_params *param);
+int ocrdma_mbx_destroy_qp(struct ocrdma_dev *, struct ocrdma_qp *);
+
+int ocrdma_mbx_create_srq(struct ocrdma_srq *,
+ struct ib_srq_init_attr *,
+ struct ocrdma_pd *);
+int ocrdma_mbx_modify_srq(struct ocrdma_srq *, struct ib_srq_attr *);
+int ocrdma_mbx_query_srq(struct ocrdma_srq *, struct ib_srq_attr *);
+int ocrdma_mbx_destroy_srq(struct ocrdma_dev *, struct ocrdma_srq *);
+
+int ocrdma_alloc_av(struct ocrdma_dev *, struct ocrdma_ah *);
+int ocrdma_free_av(struct ocrdma_dev *, struct ocrdma_ah *);
+
+int ocrdma_qp_state_machine(struct ocrdma_qp *, enum ib_qp_state new_state,
+ enum ib_qp_state *old_ib_state);
+bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
+bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
+void ocrdma_flush_qp(struct ocrdma_qp *);
+
+#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
new file mode 100644
index 0000000..a20d16e
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -0,0 +1,577 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/idr.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+
+#include <linux/netdevice.h>
+#include <net/addrconf.h>
+
+#include "ocrdma.h"
+#include "ocrdma_verbs.h"
+#include "ocrdma_ah.h"
+#include "be_roce.h"
+#include "ocrdma_hw.h"
+
+MODULE_VERSION(OCRDMA_ROCE_DEV_VERSION);
+MODULE_DESCRIPTION("Emulex RoCE HCA Driver");
+MODULE_AUTHOR("Emulex Corporation");
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(ocrdma_dev_list);
+static DEFINE_SPINLOCK(ocrdma_devlist_lock);
+static DEFINE_IDR(ocrdma_dev_id);
+
+static union ib_gid ocrdma_zero_sgid;
+
+static int ocrdma_get_instance(void)
+{
+ int instance = 0;
+
+ /* Assign an unused number */
+ if (!idr_pre_get(&ocrdma_dev_id, GFP_KERNEL))
+ return -1;
+ if (idr_get_new(&ocrdma_dev_id, NULL, &instance))
+ return -1;
+ return instance;
+}
+
+void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid)
+{
+ u8 mac_addr[6];
+
+ memcpy(&mac_addr[0], &dev->nic_info.mac_addr[0], ETH_ALEN);
+ guid[0] = mac_addr[0] ^ 2;
+ guid[1] = mac_addr[1];
+ guid[2] = mac_addr[2];
+ guid[3] = 0xff;
+ guid[4] = 0xfe;
+ guid[5] = mac_addr[3];
+ guid[6] = mac_addr[4];
+ guid[7] = mac_addr[5];
+}
+
+static void ocrdma_build_sgid_mac(union ib_gid *sgid, unsigned char *mac_addr,
+ bool is_vlan, u16 vlan_id)
+{
+ sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+ sgid->raw[8] = mac_addr[0] ^ 2;
+ sgid->raw[9] = mac_addr[1];
+ sgid->raw[10] = mac_addr[2];
+ if (is_vlan) {
+ sgid->raw[11] = vlan_id >> 8;
+ sgid->raw[12] = vlan_id & 0xff;
+ } else {
+ sgid->raw[11] = 0xff;
+ sgid->raw[12] = 0xfe;
+ }
+ sgid->raw[13] = mac_addr[3];
+ sgid->raw[14] = mac_addr[4];
+ sgid->raw[15] = mac_addr[5];
+}
+
+static void ocrdma_add_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
+ bool is_vlan, u16 vlan_id)
+{
+ int i;
+ bool found = false;
+ union ib_gid new_sgid;
+ int free_idx = OCRDMA_MAX_SGID;
+ unsigned long flags;
+
+ memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid));
+
+ ocrdma_build_sgid_mac(&new_sgid, mac_addr, is_vlan, vlan_id);
+
+ spin_lock_irqsave(&dev->sgid_lock, flags);
+ for (i = 0; i < OCRDMA_MAX_SGID; i++) {
+ if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid,
+ sizeof(union ib_gid))) {
+ /* found free entry */
+ if (!found) {
+ free_idx = i;
+ found = true;
+ break;
+ }
+ } else if (!memcmp(&dev->sgid_tbl[i], &new_sgid,
+ sizeof(union ib_gid))) {
+ /* entry already present, no addition is required. */
+ spin_unlock_irqrestore(&dev->sgid_lock, flags);
+ return;
+ }
+ }
+ /* if entry doesn't exist and if table has some space, add entry */
+ if (found)
+ memcpy(&dev->sgid_tbl[free_idx], &new_sgid,
+ sizeof(union ib_gid));
+ spin_unlock_irqrestore(&dev->sgid_lock, flags);
+}
+
+static bool ocrdma_del_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
+ bool is_vlan, u16 vlan_id)
+{
+ int found = false;
+ int i;
+ union ib_gid sgid;
+ unsigned long flags;
+
+ ocrdma_build_sgid_mac(&sgid, mac_addr, is_vlan, vlan_id);
+
+ spin_lock_irqsave(&dev->sgid_lock, flags);
+ /* first is default sgid, which cannot be deleted. */
+ for (i = 1; i < OCRDMA_MAX_SGID; i++) {
+ if (!memcmp(&dev->sgid_tbl[i], &sgid, sizeof(union ib_gid))) {
+ /* found matching entry */
+ memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid));
+ found = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->sgid_lock, flags);
+ return found;
+}
+
+static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
+{
+ /* GID Index 0 - Invariant manufacturer-assigned EUI-64 */
+ union ib_gid *sgid = &dev->sgid_tbl[0];
+
+ sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+ ocrdma_get_guid(dev, &sgid->raw[8]);
+}
+
+static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
+{
+ struct net_device *netdev, *tmp;
+ u16 vlan_id;
+ bool is_vlan;
+
+ netdev = dev->nic_info.netdev;
+
+ ocrdma_add_default_sgid(dev);
+
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, tmp) {
+ if (netdev == tmp || vlan_dev_real_dev(tmp) == netdev) {
+ if (!netif_running(tmp) || !netif_oper_up(tmp))
+ continue;
+ if (netdev != tmp) {
+ vlan_id = vlan_dev_vlan_id(tmp);
+ is_vlan = true;
+ } else {
+ is_vlan = false;
+ vlan_id = 0;
+ tmp = netdev;
+ }
+ ocrdma_add_sgid(dev, tmp->dev_addr, is_vlan, vlan_id);
+ }
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+static int ocrdma_inet6addr_event(struct notifier_block *notifier,
+ unsigned long event, void *ptr)
+{
+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+ struct net_device *event_netdev = ifa->idev->dev;
+ struct net_device *netdev = NULL;
+ struct ib_event gid_event;
+ struct ocrdma_dev *dev;
+ bool found = false;
+ bool is_vlan = false;
+ u16 vid = 0;
+
+ netdev = vlan_dev_real_dev(event_netdev);
+ if (netdev != event_netdev) {
+ is_vlan = true;
+ vid = vlan_dev_vlan_id(event_netdev);
+ }
+ rcu_read_lock();
+ list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
+ if (dev->nic_info.netdev == netdev) {
+ found = true;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!found)
+ return NOTIFY_DONE;
+ if (!rdma_link_local_addr((struct in6_addr *)&ifa->addr))
+ return NOTIFY_DONE;
+
+ mutex_lock(&dev->dev_lock);
+ switch (event) {
+ case NETDEV_UP:
+ ocrdma_add_sgid(dev, netdev->dev_addr, is_vlan, vid);
+ break;
+ case NETDEV_DOWN:
+ found = ocrdma_del_sgid(dev, netdev->dev_addr, is_vlan, vid);
+ if (found) {
+ /* found the matching entry, notify
+ * the consumers about it
+ */
+ gid_event.device = &dev->ibdev;
+ gid_event.element.port_num = 1;
+ gid_event.event = IB_EVENT_GID_CHANGE;
+ ib_dispatch_event(&gid_event);
+ }
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&dev->dev_lock);
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ocrdma_inet6addr_notifier = {
+ .notifier_call = ocrdma_inet6addr_event
+};
+
+#endif /* IPV6 */
+
+static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device,
+ u8 port_num)
+{
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+static int ocrdma_register_device(struct ocrdma_dev *dev)
+{
+ strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
+ ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid);
+ memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,
+ sizeof(OCRDMA_NODE_DESC));
+ dev->ibdev.owner = THIS_MODULE;
+ dev->ibdev.uverbs_cmd_mask =
+ OCRDMA_UVERBS(GET_CONTEXT) |
+ OCRDMA_UVERBS(QUERY_DEVICE) |
+ OCRDMA_UVERBS(QUERY_PORT) |
+ OCRDMA_UVERBS(ALLOC_PD) |
+ OCRDMA_UVERBS(DEALLOC_PD) |
+ OCRDMA_UVERBS(REG_MR) |
+ OCRDMA_UVERBS(DEREG_MR) |
+ OCRDMA_UVERBS(CREATE_COMP_CHANNEL) |
+ OCRDMA_UVERBS(CREATE_CQ) |
+ OCRDMA_UVERBS(RESIZE_CQ) |
+ OCRDMA_UVERBS(DESTROY_CQ) |
+ OCRDMA_UVERBS(REQ_NOTIFY_CQ) |
+ OCRDMA_UVERBS(CREATE_QP) |
+ OCRDMA_UVERBS(MODIFY_QP) |
+ OCRDMA_UVERBS(QUERY_QP) |
+ OCRDMA_UVERBS(DESTROY_QP) |
+ OCRDMA_UVERBS(POLL_CQ) |
+ OCRDMA_UVERBS(POST_SEND) |
+ OCRDMA_UVERBS(POST_RECV);
+
+ dev->ibdev.uverbs_cmd_mask |=
+ OCRDMA_UVERBS(CREATE_AH) |
+ OCRDMA_UVERBS(MODIFY_AH) |
+ OCRDMA_UVERBS(QUERY_AH) |
+ OCRDMA_UVERBS(DESTROY_AH);
+
+ dev->ibdev.node_type = RDMA_NODE_IB_CA;
+ dev->ibdev.phys_port_cnt = 1;
+ dev->ibdev.num_comp_vectors = 1;
+
+ /* mandatory verbs. */
+ dev->ibdev.query_device = ocrdma_query_device;
+ dev->ibdev.query_port = ocrdma_query_port;
+ dev->ibdev.modify_port = ocrdma_modify_port;
+ dev->ibdev.query_gid = ocrdma_query_gid;
+ dev->ibdev.get_link_layer = ocrdma_link_layer;
+ dev->ibdev.alloc_pd = ocrdma_alloc_pd;
+ dev->ibdev.dealloc_pd = ocrdma_dealloc_pd;
+
+ dev->ibdev.create_cq = ocrdma_create_cq;
+ dev->ibdev.destroy_cq = ocrdma_destroy_cq;
+ dev->ibdev.resize_cq = ocrdma_resize_cq;
+
+ dev->ibdev.create_qp = ocrdma_create_qp;
+ dev->ibdev.modify_qp = ocrdma_modify_qp;
+ dev->ibdev.query_qp = ocrdma_query_qp;
+ dev->ibdev.destroy_qp = ocrdma_destroy_qp;
+
+ dev->ibdev.query_pkey = ocrdma_query_pkey;
+ dev->ibdev.create_ah = ocrdma_create_ah;
+ dev->ibdev.destroy_ah = ocrdma_destroy_ah;
+ dev->ibdev.query_ah = ocrdma_query_ah;
+ dev->ibdev.modify_ah = ocrdma_modify_ah;
+
+ dev->ibdev.poll_cq = ocrdma_poll_cq;
+ dev->ibdev.post_send = ocrdma_post_send;
+ dev->ibdev.post_recv = ocrdma_post_recv;
+ dev->ibdev.req_notify_cq = ocrdma_arm_cq;
+
+ dev->ibdev.get_dma_mr = ocrdma_get_dma_mr;
+ dev->ibdev.dereg_mr = ocrdma_dereg_mr;
+ dev->ibdev.reg_user_mr = ocrdma_reg_user_mr;
+
+ /* mandatory to support user space verbs consumer. */
+ dev->ibdev.alloc_ucontext = ocrdma_alloc_ucontext;
+ dev->ibdev.dealloc_ucontext = ocrdma_dealloc_ucontext;
+ dev->ibdev.mmap = ocrdma_mmap;
+ dev->ibdev.dma_device = &dev->nic_info.pdev->dev;
+
+ dev->ibdev.process_mad = ocrdma_process_mad;
+
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ dev->ibdev.uverbs_cmd_mask |=
+ OCRDMA_UVERBS(CREATE_SRQ) |
+ OCRDMA_UVERBS(MODIFY_SRQ) |
+ OCRDMA_UVERBS(QUERY_SRQ) |
+ OCRDMA_UVERBS(DESTROY_SRQ) |
+ OCRDMA_UVERBS(POST_SRQ_RECV);
+
+ dev->ibdev.create_srq = ocrdma_create_srq;
+ dev->ibdev.modify_srq = ocrdma_modify_srq;
+ dev->ibdev.query_srq = ocrdma_query_srq;
+ dev->ibdev.destroy_srq = ocrdma_destroy_srq;
+ dev->ibdev.post_srq_recv = ocrdma_post_srq_recv;
+ }
+ return ib_register_device(&dev->ibdev, NULL);
+}
+
+static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
+{
+ mutex_init(&dev->dev_lock);
+ dev->sgid_tbl = kzalloc(sizeof(union ib_gid) *
+ OCRDMA_MAX_SGID, GFP_KERNEL);
+ if (!dev->sgid_tbl)
+ goto alloc_err;
+ spin_lock_init(&dev->sgid_lock);
+
+ dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) *
+ OCRDMA_MAX_CQ, GFP_KERNEL);
+ if (!dev->cq_tbl)
+ goto alloc_err;
+
+ if (dev->attr.max_qp) {
+ dev->qp_tbl = kzalloc(sizeof(struct ocrdma_qp *) *
+ OCRDMA_MAX_QP, GFP_KERNEL);
+ if (!dev->qp_tbl)
+ goto alloc_err;
+ }
+ spin_lock_init(&dev->av_tbl.lock);
+ spin_lock_init(&dev->flush_q_lock);
+ return 0;
+alloc_err:
+ ocrdma_err("%s(%d) error.\n", __func__, dev->id);
+ return -ENOMEM;
+}
+
+static void ocrdma_free_resources(struct ocrdma_dev *dev)
+{
+ kfree(dev->qp_tbl);
+ kfree(dev->cq_tbl);
+ kfree(dev->sgid_tbl);
+}
+
+static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
+{
+ int status = 0;
+ struct ocrdma_dev *dev;
+
+ dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
+ if (!dev) {
+ ocrdma_err("Unable to allocate ib device\n");
+ return NULL;
+ }
+ dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL);
+ if (!dev->mbx_cmd)
+ goto idr_err;
+
+ memcpy(&dev->nic_info, dev_info, sizeof(*dev_info));
+ dev->id = ocrdma_get_instance();
+ if (dev->id < 0)
+ goto idr_err;
+
+ status = ocrdma_init_hw(dev);
+ if (status)
+ goto init_err;
+
+ status = ocrdma_alloc_resources(dev);
+ if (status)
+ goto alloc_err;
+
+ status = ocrdma_build_sgid_tbl(dev);
+ if (status)
+ goto alloc_err;
+
+ status = ocrdma_register_device(dev);
+ if (status)
+ goto alloc_err;
+
+ spin_lock(&ocrdma_devlist_lock);
+ list_add_tail_rcu(&dev->entry, &ocrdma_dev_list);
+ spin_unlock(&ocrdma_devlist_lock);
+ return dev;
+
+alloc_err:
+ ocrdma_free_resources(dev);
+ ocrdma_cleanup_hw(dev);
+init_err:
+ idr_remove(&ocrdma_dev_id, dev->id);
+idr_err:
+ kfree(dev->mbx_cmd);
+ ib_dealloc_device(&dev->ibdev);
+ ocrdma_err("%s() leaving. ret=%d\n", __func__, status);
+ return NULL;
+}
+
+static void ocrdma_remove_free(struct rcu_head *rcu)
+{
+ struct ocrdma_dev *dev = container_of(rcu, struct ocrdma_dev, rcu);
+
+ ocrdma_free_resources(dev);
+ ocrdma_cleanup_hw(dev);
+
+ idr_remove(&ocrdma_dev_id, dev->id);
+ kfree(dev->mbx_cmd);
+ ib_dealloc_device(&dev->ibdev);
+}
+
+static void ocrdma_remove(struct ocrdma_dev *dev)
+{
+ /* first unregister with stack to stop all the active traffic
+ * of the registered clients.
+ */
+ ib_unregister_device(&dev->ibdev);
+
+ spin_lock(&ocrdma_devlist_lock);
+ list_del_rcu(&dev->entry);
+ spin_unlock(&ocrdma_devlist_lock);
+ call_rcu(&dev->rcu, ocrdma_remove_free);
+}
+
+static int ocrdma_open(struct ocrdma_dev *dev)
+{
+ struct ib_event port_event;
+
+ port_event.event = IB_EVENT_PORT_ACTIVE;
+ port_event.element.port_num = 1;
+ port_event.device = &dev->ibdev;
+ ib_dispatch_event(&port_event);
+ return 0;
+}
+
+static int ocrdma_close(struct ocrdma_dev *dev)
+{
+ int i;
+ struct ocrdma_qp *qp, **cur_qp;
+ struct ib_event err_event;
+ struct ib_qp_attr attrs;
+ int attr_mask = IB_QP_STATE;
+
+ attrs.qp_state = IB_QPS_ERR;
+ mutex_lock(&dev->dev_lock);
+ if (dev->qp_tbl) {
+ cur_qp = dev->qp_tbl;
+ for (i = 0; i < OCRDMA_MAX_QP; i++) {
+ qp = cur_qp[i];
+ if (qp) {
+ /* change the QP state to ERROR */
+ _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
+
+ err_event.event = IB_EVENT_QP_FATAL;
+ err_event.element.qp = &qp->ibqp;
+ err_event.device = &dev->ibdev;
+ ib_dispatch_event(&err_event);
+ }
+ }
+ }
+ mutex_unlock(&dev->dev_lock);
+
+ err_event.event = IB_EVENT_PORT_ERR;
+ err_event.element.port_num = 1;
+ err_event.device = &dev->ibdev;
+ ib_dispatch_event(&err_event);
+ return 0;
+}
+
+/* event handling via NIC driver ensures that all the NIC specific
+ * initialization done before RoCE driver notifies
+ * event to stack.
+ */
+static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
+{
+ switch (event) {
+ case BE_DEV_UP:
+ ocrdma_open(dev);
+ break;
+ case BE_DEV_DOWN:
+ ocrdma_close(dev);
+ break;
+ };
+}
+
+static struct ocrdma_driver ocrdma_drv = {
+ .name = "ocrdma_driver",
+ .add = ocrdma_add,
+ .remove = ocrdma_remove,
+ .state_change_handler = ocrdma_event_handler,
+};
+
+static void ocrdma_unregister_inet6addr_notifier(void)
+{
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier);
+#endif
+}
+
+static int __init ocrdma_init_module(void)
+{
+ int status;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier);
+ if (status)
+ return status;
+#endif
+
+ status = be_roce_register_driver(&ocrdma_drv);
+ if (status)
+ ocrdma_unregister_inet6addr_notifier();
+
+ return status;
+}
+
+static void __exit ocrdma_exit_module(void)
+{
+ be_roce_unregister_driver(&ocrdma_drv);
+ ocrdma_unregister_inet6addr_notifier();
+}
+
+module_init(ocrdma_init_module);
+module_exit(ocrdma_exit_module);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
new file mode 100644
index 0000000..7fd80cc
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -0,0 +1,1672 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_SLI_H__
+#define __OCRDMA_SLI_H__
+
+#define Bit(_b) (1 << (_b))
+
+#define OCRDMA_GEN1_FAMILY 0xB
+#define OCRDMA_GEN2_FAMILY 0x2
+
+#define OCRDMA_SUBSYS_ROCE 10
+enum {
+ OCRDMA_CMD_QUERY_CONFIG = 1,
+ OCRDMA_CMD_ALLOC_PD,
+ OCRDMA_CMD_DEALLOC_PD,
+
+ OCRDMA_CMD_CREATE_AH_TBL,
+ OCRDMA_CMD_DELETE_AH_TBL,
+
+ OCRDMA_CMD_CREATE_QP,
+ OCRDMA_CMD_QUERY_QP,
+ OCRDMA_CMD_MODIFY_QP,
+ OCRDMA_CMD_DELETE_QP,
+
+ OCRDMA_CMD_RSVD1,
+ OCRDMA_CMD_ALLOC_LKEY,
+ OCRDMA_CMD_DEALLOC_LKEY,
+ OCRDMA_CMD_REGISTER_NSMR,
+ OCRDMA_CMD_REREGISTER_NSMR,
+ OCRDMA_CMD_REGISTER_NSMR_CONT,
+ OCRDMA_CMD_QUERY_NSMR,
+ OCRDMA_CMD_ALLOC_MW,
+ OCRDMA_CMD_QUERY_MW,
+
+ OCRDMA_CMD_CREATE_SRQ,
+ OCRDMA_CMD_QUERY_SRQ,
+ OCRDMA_CMD_MODIFY_SRQ,
+ OCRDMA_CMD_DELETE_SRQ,
+
+ OCRDMA_CMD_ATTACH_MCAST,
+ OCRDMA_CMD_DETACH_MCAST,
+
+ OCRDMA_CMD_MAX
+};
+
+#define OCRDMA_SUBSYS_COMMON 1
+enum {
+ OCRDMA_CMD_CREATE_CQ = 12,
+ OCRDMA_CMD_CREATE_EQ = 13,
+ OCRDMA_CMD_CREATE_MQ = 21,
+ OCRDMA_CMD_GET_FW_VER = 35,
+ OCRDMA_CMD_DELETE_MQ = 53,
+ OCRDMA_CMD_DELETE_CQ = 54,
+ OCRDMA_CMD_DELETE_EQ = 55,
+ OCRDMA_CMD_GET_FW_CONFIG = 58,
+ OCRDMA_CMD_CREATE_MQ_EXT = 90
+};
+
+enum {
+ QTYPE_EQ = 1,
+ QTYPE_CQ = 2,
+ QTYPE_MCCQ = 3
+};
+
+#define OCRDMA_MAX_SGID (8)
+
+#define OCRDMA_MAX_QP 2048
+#define OCRDMA_MAX_CQ 2048
+
+enum {
+ OCRDMA_DB_RQ_OFFSET = 0xE0,
+ OCRDMA_DB_GEN2_RQ1_OFFSET = 0x100,
+ OCRDMA_DB_GEN2_RQ2_OFFSET = 0xC0,
+ OCRDMA_DB_SQ_OFFSET = 0x60,
+ OCRDMA_DB_GEN2_SQ_OFFSET = 0x1C0,
+ OCRDMA_DB_SRQ_OFFSET = OCRDMA_DB_RQ_OFFSET,
+ OCRDMA_DB_GEN2_SRQ_OFFSET = OCRDMA_DB_GEN2_RQ1_OFFSET,
+ OCRDMA_DB_CQ_OFFSET = 0x120,
+ OCRDMA_DB_EQ_OFFSET = OCRDMA_DB_CQ_OFFSET,
+ OCRDMA_DB_MQ_OFFSET = 0x140
+};
+
+#define OCRDMA_DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define OCRDMA_DB_CQ_RING_ID_EXT_MASK 0x0C00 /* bits 10-11 of qid at 12-11 */
+/* qid #2 msbits at 12-11 */
+#define OCRDMA_DB_CQ_RING_ID_EXT_MASK_SHIFT 0x1
+#define OCRDMA_DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define OCRDMA_DB_CQ_REARM_SHIFT (29) /* bit 29 */
+/* solicited bit */
+#define OCRDMA_DB_CQ_SOLICIT_SHIFT (31) /* bit 31 */
+
+#define OCRDMA_EQ_ID_MASK 0x1FF /* bits 0 - 8 */
+#define OCRDMA_EQ_ID_EXT_MASK 0x3e00 /* bits 9-13 */
+#define OCRDMA_EQ_ID_EXT_MASK_SHIFT (2) /* qid bits 9-13 at 11-15 */
+
+/* Clear the interrupt for this eq */
+#define OCRDMA_EQ_CLR_SHIFT (9) /* bit 9 */
+/* Must be 1 */
+#define OCRDMA_EQ_TYPE_SHIFT (10) /* bit 10 */
+/* Number of event entries processed */
+#define OCRDMA_NUM_EQE_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define OCRDMA_REARM_SHIFT (29) /* bit 29 */
+
+#define OCRDMA_MQ_ID_MASK 0x7FF /* bits 0 - 10 */
+/* Number of entries posted */
+#define OCRDMA_MQ_NUM_MQE_SHIFT (16) /* bits 16 - 29 */
+
+#define OCRDMA_MIN_HPAGE_SIZE (4096)
+
+#define OCRDMA_MIN_Q_PAGE_SIZE (4096)
+#define OCRDMA_MAX_Q_PAGES (8)
+
+/*
+# 0: 4K Bytes
+# 1: 8K Bytes
+# 2: 16K Bytes
+# 3: 32K Bytes
+# 4: 64K Bytes
+*/
+#define OCRDMA_MAX_Q_PAGE_SIZE_CNT (5)
+#define OCRDMA_Q_PAGE_BASE_SIZE (OCRDMA_MIN_Q_PAGE_SIZE * OCRDMA_MAX_Q_PAGES)
+
+#define MAX_OCRDMA_QP_PAGES (8)
+#define OCRDMA_MAX_WQE_MEM_SIZE (MAX_OCRDMA_QP_PAGES * OCRDMA_MIN_HQ_PAGE_SIZE)
+
+#define OCRDMA_CREATE_CQ_MAX_PAGES (4)
+#define OCRDMA_DPP_CQE_SIZE (4)
+
+#define OCRDMA_GEN2_MAX_CQE 1024
+#define OCRDMA_GEN2_CQ_PAGE_SIZE 4096
+#define OCRDMA_GEN2_WQE_SIZE 256
+#define OCRDMA_MAX_CQE 4095
+#define OCRDMA_CQ_PAGE_SIZE 16384
+#define OCRDMA_WQE_SIZE 128
+#define OCRDMA_WQE_STRIDE 8
+#define OCRDMA_WQE_ALIGN_BYTES 16
+
+#define MAX_OCRDMA_SRQ_PAGES MAX_OCRDMA_QP_PAGES
+
+enum {
+ OCRDMA_MCH_OPCODE_SHIFT = 0,
+ OCRDMA_MCH_OPCODE_MASK = 0xFF,
+ OCRDMA_MCH_SUBSYS_SHIFT = 8,
+ OCRDMA_MCH_SUBSYS_MASK = 0xFF00
+};
+
+/* mailbox cmd header */
+struct ocrdma_mbx_hdr {
+ u32 subsys_op;
+ u32 timeout; /* in seconds */
+ u32 cmd_len;
+ u32 rsvd_version;
+} __packed;
+
+enum {
+ OCRDMA_MBX_RSP_OPCODE_SHIFT = 0,
+ OCRDMA_MBX_RSP_OPCODE_MASK = 0xFF,
+ OCRDMA_MBX_RSP_SUBSYS_SHIFT = 8,
+ OCRDMA_MBX_RSP_SUBSYS_MASK = 0xFF << OCRDMA_MBX_RSP_SUBSYS_SHIFT,
+
+ OCRDMA_MBX_RSP_STATUS_SHIFT = 0,
+ OCRDMA_MBX_RSP_STATUS_MASK = 0xFF,
+ OCRDMA_MBX_RSP_ASTATUS_SHIFT = 8,
+ OCRDMA_MBX_RSP_ASTATUS_MASK = 0xFF << OCRDMA_MBX_RSP_ASTATUS_SHIFT
+};
+
+/* mailbox cmd response */
+struct ocrdma_mbx_rsp {
+ u32 subsys_op;
+ u32 status;
+ u32 rsp_len;
+ u32 add_rsp_len;
+} __packed;
+
+enum {
+ OCRDMA_MQE_EMBEDDED = 1,
+ OCRDMA_MQE_NONEMBEDDED = 0
+};
+
+struct ocrdma_mqe_sge {
+ u32 pa_lo;
+ u32 pa_hi;
+ u32 len;
+} __packed;
+
+enum {
+ OCRDMA_MQE_HDR_EMB_SHIFT = 0,
+ OCRDMA_MQE_HDR_EMB_MASK = Bit(0),
+ OCRDMA_MQE_HDR_SGE_CNT_SHIFT = 3,
+ OCRDMA_MQE_HDR_SGE_CNT_MASK = 0x1F << OCRDMA_MQE_HDR_SGE_CNT_SHIFT,
+ OCRDMA_MQE_HDR_SPECIAL_SHIFT = 24,
+ OCRDMA_MQE_HDR_SPECIAL_MASK = 0xFF << OCRDMA_MQE_HDR_SPECIAL_SHIFT
+};
+
+struct ocrdma_mqe_hdr {
+ u32 spcl_sge_cnt_emb;
+ u32 pyld_len;
+ u32 tag_lo;
+ u32 tag_hi;
+ u32 rsvd3;
+} __packed;
+
+struct ocrdma_mqe_emb_cmd {
+ struct ocrdma_mbx_hdr mch;
+ u8 pyld[220];
+} __packed;
+
+struct ocrdma_mqe {
+ struct ocrdma_mqe_hdr hdr;
+ union {
+ struct ocrdma_mqe_emb_cmd emb_req;
+ struct {
+ struct ocrdma_mqe_sge sge[19];
+ } nonemb_req;
+ u8 cmd[236];
+ struct ocrdma_mbx_rsp rsp;
+ } u;
+} __packed;
+
+#define OCRDMA_EQ_LEN 4096
+#define OCRDMA_MQ_CQ_LEN 256
+#define OCRDMA_MQ_LEN 128
+
+#define PAGE_SHIFT_4K 12
+#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
+
+/* Returns number of pages spanned by the data starting at the given addr */
+#define PAGES_4K_SPANNED(_address, size) \
+ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
+ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
+
+struct ocrdma_delete_q_req {
+ struct ocrdma_mbx_hdr req;
+ u32 id;
+} __packed;
+
+struct ocrdma_pa {
+ u32 lo;
+ u32 hi;
+} __packed;
+
+#define MAX_OCRDMA_EQ_PAGES (8)
+struct ocrdma_create_eq_req {
+ struct ocrdma_mbx_hdr req;
+ u32 num_pages;
+ u32 valid;
+ u32 cnt;
+ u32 delay;
+ u32 rsvd;
+ struct ocrdma_pa pa[MAX_OCRDMA_EQ_PAGES];
+} __packed;
+
+enum {
+ OCRDMA_CREATE_EQ_VALID = Bit(29),
+ OCRDMA_CREATE_EQ_CNT_SHIFT = 26,
+ OCRDMA_CREATE_CQ_DELAY_SHIFT = 13,
+};
+
+struct ocrdma_create_eq_rsp {
+ struct ocrdma_mbx_rsp rsp;
+ u32 vector_eqid;
+};
+
+#define OCRDMA_EQ_MINOR_OTHER (0x1)
+
+enum {
+ OCRDMA_MCQE_STATUS_SHIFT = 0,
+ OCRDMA_MCQE_STATUS_MASK = 0xFFFF,
+ OCRDMA_MCQE_ESTATUS_SHIFT = 16,
+ OCRDMA_MCQE_ESTATUS_MASK = 0xFFFF << OCRDMA_MCQE_ESTATUS_SHIFT,
+ OCRDMA_MCQE_CONS_SHIFT = 27,
+ OCRDMA_MCQE_CONS_MASK = Bit(27),
+ OCRDMA_MCQE_CMPL_SHIFT = 28,
+ OCRDMA_MCQE_CMPL_MASK = Bit(28),
+ OCRDMA_MCQE_AE_SHIFT = 30,
+ OCRDMA_MCQE_AE_MASK = Bit(30),
+ OCRDMA_MCQE_VALID_SHIFT = 31,
+ OCRDMA_MCQE_VALID_MASK = Bit(31)
+};
+
+struct ocrdma_mcqe {
+ u32 status;
+ u32 tag_lo;
+ u32 tag_hi;
+ u32 valid_ae_cmpl_cons;
+} __packed;
+
+enum {
+ OCRDMA_AE_MCQE_QPVALID = Bit(31),
+ OCRDMA_AE_MCQE_QPID_MASK = 0xFFFF,
+
+ OCRDMA_AE_MCQE_CQVALID = Bit(31),
+ OCRDMA_AE_MCQE_CQID_MASK = 0xFFFF,
+ OCRDMA_AE_MCQE_VALID = Bit(31),
+ OCRDMA_AE_MCQE_AE = Bit(30),
+ OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT = 16,
+ OCRDMA_AE_MCQE_EVENT_TYPE_MASK =
+ 0xFF << OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT,
+ OCRDMA_AE_MCQE_EVENT_CODE_SHIFT = 8,
+ OCRDMA_AE_MCQE_EVENT_CODE_MASK =
+ 0xFF << OCRDMA_AE_MCQE_EVENT_CODE_SHIFT
+};
+struct ocrdma_ae_mcqe {
+ u32 qpvalid_qpid;
+ u32 cqvalid_cqid;
+ u32 evt_tag;
+ u32 valid_ae_event;
+} __packed;
+
+enum {
+ OCRDMA_AE_MPA_MCQE_REQ_ID_SHIFT = 16,
+ OCRDMA_AE_MPA_MCQE_REQ_ID_MASK = 0xFFFF <<
+ OCRDMA_AE_MPA_MCQE_REQ_ID_SHIFT,
+
+ OCRDMA_AE_MPA_MCQE_EVENT_CODE_SHIFT = 8,
+ OCRDMA_AE_MPA_MCQE_EVENT_CODE_MASK = 0xFF <<
+ OCRDMA_AE_MPA_MCQE_EVENT_CODE_SHIFT,
+ OCRDMA_AE_MPA_MCQE_EVENT_TYPE_SHIFT = 16,
+ OCRDMA_AE_MPA_MCQE_EVENT_TYPE_MASK = 0xFF <<
+ OCRDMA_AE_MPA_MCQE_EVENT_TYPE_SHIFT,
+ OCRDMA_AE_MPA_MCQE_EVENT_AE_SHIFT = 30,
+ OCRDMA_AE_MPA_MCQE_EVENT_AE_MASK = Bit(30),
+ OCRDMA_AE_MPA_MCQE_EVENT_VALID_SHIFT = 31,
+ OCRDMA_AE_MPA_MCQE_EVENT_VALID_MASK = Bit(31)
+};
+
+struct ocrdma_ae_mpa_mcqe {
+ u32 req_id;
+ u32 w1;
+ u32 w2;
+ u32 valid_ae_event;
+} __packed;
+
+enum {
+ OCRDMA_AE_QP_MCQE_NEW_QP_STATE_SHIFT = 0,
+ OCRDMA_AE_QP_MCQE_NEW_QP_STATE_MASK = 0xFFFF,
+ OCRDMA_AE_QP_MCQE_QP_ID_SHIFT = 16,
+ OCRDMA_AE_QP_MCQE_QP_ID_MASK = 0xFFFF <<
+ OCRDMA_AE_QP_MCQE_QP_ID_SHIFT,
+
+ OCRDMA_AE_QP_MCQE_EVENT_CODE_SHIFT = 8,
+ OCRDMA_AE_QP_MCQE_EVENT_CODE_MASK = 0xFF <<
+ OCRDMA_AE_QP_MCQE_EVENT_CODE_SHIFT,
+ OCRDMA_AE_QP_MCQE_EVENT_TYPE_SHIFT = 16,
+ OCRDMA_AE_QP_MCQE_EVENT_TYPE_MASK = 0xFF <<
+ OCRDMA_AE_QP_MCQE_EVENT_TYPE_SHIFT,
+ OCRDMA_AE_QP_MCQE_EVENT_AE_SHIFT = 30,
+ OCRDMA_AE_QP_MCQE_EVENT_AE_MASK = Bit(30),
+ OCRDMA_AE_QP_MCQE_EVENT_VALID_SHIFT = 31,
+ OCRDMA_AE_QP_MCQE_EVENT_VALID_MASK = Bit(31)
+};
+
+struct ocrdma_ae_qp_mcqe {
+ u32 qp_id_state;
+ u32 w1;
+ u32 w2;
+ u32 valid_ae_event;
+} __packed;
+
+#define OCRDMA_ASYNC_EVE_CODE 0x14
+
+enum OCRDMA_ASYNC_EVENT_TYPE {
+ OCRDMA_CQ_ERROR = 0x00,
+ OCRDMA_CQ_OVERRUN_ERROR = 0x01,
+ OCRDMA_CQ_QPCAT_ERROR = 0x02,
+ OCRDMA_QP_ACCESS_ERROR = 0x03,
+ OCRDMA_QP_COMM_EST_EVENT = 0x04,
+ OCRDMA_SQ_DRAINED_EVENT = 0x05,
+ OCRDMA_DEVICE_FATAL_EVENT = 0x08,
+ OCRDMA_SRQCAT_ERROR = 0x0E,
+ OCRDMA_SRQ_LIMIT_EVENT = 0x0F,
+ OCRDMA_QP_LAST_WQE_EVENT = 0x10
+};
+
+/* mailbox command request and responses */
+enum {
+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT = 2,
+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_MASK = Bit(2),
+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_SHIFT = 3,
+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_MASK = Bit(3),
+ OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT = 8,
+ OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK = 0xFFFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT,
+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_SHIFT = 8,
+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_MASK = 0xFF <<
+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_SHIFT,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK = 0xFFFF,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_SHIFT = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_MASK = 0xFFFF,
+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_SHIFT = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_SHIFT,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_OFFSET = 24,
+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_MASK = 0xFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_MASK = 0xFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CQES_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CQES_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CQES_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_RPIR_QPS_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_RPIR_QPS_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_RPIR_QPS_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CREDITS_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CREDITS_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_CREDITS_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_QPS_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_QPS_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_QPS_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_WQES_PER_WQ_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_WQES_PER_WQ_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_WQES_PER_WQ_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_RQES_PER_RQ_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_RQES_PER_RQ_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_WQES_PER_WQ_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_CQ_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_CQ_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_CQ_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_CQES_PER_CQ_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_CQES_PER_CQ_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_CQES_PER_CQ_OFFSET,
+
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_RQE_OFFSET = 16,
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_RQE_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_RQE_OFFSET,
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_SGE_OFFSET = 0,
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_SGE_MASK = 0xFFFF <<
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_SGE_OFFSET,
+};
+
+struct ocrdma_mbx_query_config {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 qp_srq_cq_ird_ord;
+ u32 max_pd_ca_ack_delay;
+ u32 max_write_send_sge;
+ u32 max_ird_ord_per_qp;
+ u32 max_shared_ird_ord;
+ u32 max_mr;
+ u64 max_mr_size;
+ u32 max_num_mr_pbl;
+ u32 max_mw;
+ u32 max_fmr;
+ u32 max_pages_per_frmr;
+ u32 max_mcast_group;
+ u32 max_mcast_qp_attach;
+ u32 max_total_mcast_qp_attach;
+ u32 wqe_rqe_stride_max_dpp_cqs;
+ u32 max_srq_rpir_qps;
+ u32 max_dpp_pds_credits;
+ u32 max_dpp_credits_pds_per_pd;
+ u32 max_wqes_rqes_per_q;
+ u32 max_cq_cqes_per_cq;
+ u32 max_srq_rqe_sge;
+} __packed;
+
+struct ocrdma_fw_ver_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u8 running_ver[32];
+} __packed;
+
+struct ocrdma_fw_conf_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 config_num;
+ u32 asic_revision;
+ u32 phy_port;
+ u32 fn_mode;
+ struct {
+ u32 mode;
+ u32 nic_wqid_base;
+ u32 nic_wq_tot;
+ u32 prot_wqid_base;
+ u32 prot_wq_tot;
+ u32 prot_rqid_base;
+ u32 prot_rqid_tot;
+ u32 rsvd[6];
+ } ulp[2];
+ u32 fn_capabilities;
+ u32 rsvd1;
+ u32 rsvd2;
+ u32 base_eqid;
+ u32 max_eq;
+
+} __packed;
+
+enum {
+ OCRDMA_FN_MODE_RDMA = 0x4
+};
+
+enum {
+ OCRDMA_CREATE_CQ_VER2 = 2,
+
+ OCRDMA_CREATE_CQ_PAGE_CNT_MASK = 0xFFFF,
+ OCRDMA_CREATE_CQ_PAGE_SIZE_SHIFT = 16,
+ OCRDMA_CREATE_CQ_PAGE_SIZE_MASK = 0xFF,
+
+ OCRDMA_CREATE_CQ_COALESCWM_SHIFT = 12,
+ OCRDMA_CREATE_CQ_COALESCWM_MASK = Bit(13) | Bit(12),
+ OCRDMA_CREATE_CQ_FLAGS_NODELAY = Bit(14),
+ OCRDMA_CREATE_CQ_FLAGS_AUTO_VALID = Bit(15),
+
+ OCRDMA_CREATE_CQ_EQ_ID_MASK = 0xFFFF,
+ OCRDMA_CREATE_CQ_CQE_COUNT_MASK = 0xFFFF
+};
+
+enum {
+ OCRDMA_CREATE_CQ_VER0 = 0,
+ OCRDMA_CREATE_CQ_DPP = 1,
+ OCRDMA_CREATE_CQ_TYPE_SHIFT = 24,
+ OCRDMA_CREATE_CQ_EQID_SHIFT = 22,
+
+ OCRDMA_CREATE_CQ_CNT_SHIFT = 27,
+ OCRDMA_CREATE_CQ_FLAGS_VALID = Bit(29),
+ OCRDMA_CREATE_CQ_FLAGS_EVENTABLE = Bit(31),
+ OCRDMA_CREATE_CQ_DEF_FLAGS = OCRDMA_CREATE_CQ_FLAGS_VALID |
+ OCRDMA_CREATE_CQ_FLAGS_EVENTABLE |
+ OCRDMA_CREATE_CQ_FLAGS_NODELAY
+};
+
+struct ocrdma_create_cq_cmd {
+ struct ocrdma_mbx_hdr req;
+ u32 pgsz_pgcnt;
+ u32 ev_cnt_flags;
+ u32 eqn;
+ u32 cqe_count;
+ u32 rsvd6;
+ struct ocrdma_pa pa[OCRDMA_CREATE_CQ_MAX_PAGES];
+};
+
+struct ocrdma_create_cq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_create_cq_cmd cmd;
+} __packed;
+
+enum {
+ OCRDMA_CREATE_CQ_RSP_CQ_ID_MASK = 0xFFFF
+};
+
+struct ocrdma_create_cq_cmd_rsp {
+ struct ocrdma_mbx_rsp rsp;
+ u32 cq_id;
+} __packed;
+
+struct ocrdma_create_cq_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_create_cq_cmd_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_CREATE_MQ_V0_CQ_ID_SHIFT = 22,
+ OCRDMA_CREATE_MQ_CQ_ID_SHIFT = 16,
+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT = 16,
+ OCRDMA_CREATE_MQ_VALID = Bit(31),
+ OCRDMA_CREATE_MQ_ASYNC_CQ_VALID = Bit(0)
+};
+
+struct ocrdma_create_mq_v0 {
+ u32 pages;
+ u32 cqid_ringsize;
+ u32 valid;
+ u32 async_cqid_valid;
+ u32 rsvd;
+ struct ocrdma_pa pa[8];
+} __packed;
+
+struct ocrdma_create_mq_v1 {
+ u32 cqid_pages;
+ u32 async_event_bitmap;
+ u32 async_cqid_ringsize;
+ u32 valid;
+ u32 async_cqid_valid;
+ u32 rsvd;
+ struct ocrdma_pa pa[8];
+} __packed;
+
+struct ocrdma_create_mq_req {
+ struct ocrdma_mbx_hdr req;
+ union {
+ struct ocrdma_create_mq_v0 v0;
+ struct ocrdma_create_mq_v1 v1;
+ };
+} __packed;
+
+struct ocrdma_create_mq_rsp {
+ struct ocrdma_mbx_rsp rsp;
+ u32 id;
+} __packed;
+
+enum {
+ OCRDMA_DESTROY_CQ_QID_SHIFT = 0,
+ OCRDMA_DESTROY_CQ_QID_MASK = 0xFFFF,
+ OCRDMA_DESTROY_CQ_QID_BYPASS_FLUSH_SHIFT = 16,
+ OCRDMA_DESTROY_CQ_QID_BYPASS_FLUSH_MASK = 0xFFFF <<
+ OCRDMA_DESTROY_CQ_QID_BYPASS_FLUSH_SHIFT
+};
+
+struct ocrdma_destroy_cq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 bypass_flush_qid;
+} __packed;
+
+struct ocrdma_destroy_cq_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_QPT_GSI = 1,
+ OCRDMA_QPT_RC = 2,
+ OCRDMA_QPT_UD = 4,
+};
+
+enum {
+ OCRDMA_CREATE_QP_REQ_PD_ID_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_PD_ID_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_SQ_PAGE_SIZE_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_RQ_PAGE_SIZE_SHIFT = 19,
+ OCRDMA_CREATE_QP_REQ_QPT_SHIFT = 29,
+ OCRDMA_CREATE_QP_REQ_QPT_MASK = Bit(31) | Bit(30) | Bit(29),
+
+ OCRDMA_CREATE_QP_REQ_MAX_RQE_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_MAX_RQE_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_MAX_WQE_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_MAX_WQE_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_MAX_WQE_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_FMR_EN_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_FMR_EN_MASK = Bit(0),
+ OCRDMA_CREATE_QP_REQ_ZERO_LKEYEN_SHIFT = 1,
+ OCRDMA_CREATE_QP_REQ_ZERO_LKEYEN_MASK = Bit(1),
+ OCRDMA_CREATE_QP_REQ_BIND_MEMWIN_SHIFT = 2,
+ OCRDMA_CREATE_QP_REQ_BIND_MEMWIN_MASK = Bit(2),
+ OCRDMA_CREATE_QP_REQ_INB_WREN_SHIFT = 3,
+ OCRDMA_CREATE_QP_REQ_INB_WREN_MASK = Bit(3),
+ OCRDMA_CREATE_QP_REQ_INB_RDEN_SHIFT = 4,
+ OCRDMA_CREATE_QP_REQ_INB_RDEN_MASK = Bit(4),
+ OCRDMA_CREATE_QP_REQ_USE_SRQ_SHIFT = 5,
+ OCRDMA_CREATE_QP_REQ_USE_SRQ_MASK = Bit(5),
+ OCRDMA_CREATE_QP_REQ_ENABLE_RPIR_SHIFT = 6,
+ OCRDMA_CREATE_QP_REQ_ENABLE_RPIR_MASK = Bit(6),
+ OCRDMA_CREATE_QP_REQ_ENABLE_DPP_SHIFT = 7,
+ OCRDMA_CREATE_QP_REQ_ENABLE_DPP_MASK = Bit(7),
+ OCRDMA_CREATE_QP_REQ_ENABLE_DPP_CQ_SHIFT = 8,
+ OCRDMA_CREATE_QP_REQ_ENABLE_DPP_CQ_MASK = Bit(8),
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_MAX_IRD_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_MAX_IRD_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_MAX_ORD_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_MAX_ORD_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_MAX_ORD_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_RQ_CQID_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_RQ_CQID_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_WQ_CQID_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_WQ_CQID_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_WQ_CQID_SHIFT,
+
+ OCRDMA_CREATE_QP_REQ_DPP_CQPID_SHIFT = 0,
+ OCRDMA_CREATE_QP_REQ_DPP_CQPID_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_SHIFT = 16,
+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_SHIFT
+};
+
+enum {
+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_LIMIT = 16,
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_SHIFT = 1
+};
+
+#define MAX_OCRDMA_IRD_PAGES 4
+
+enum ocrdma_qp_flags {
+ OCRDMA_QP_MW_BIND = 1,
+ OCRDMA_QP_LKEY0 = (1 << 1),
+ OCRDMA_QP_FAST_REG = (1 << 2),
+ OCRDMA_QP_INB_RD = (1 << 6),
+ OCRDMA_QP_INB_WR = (1 << 7),
+};
+
+enum ocrdma_qp_state {
+ OCRDMA_QPS_RST = 0,
+ OCRDMA_QPS_INIT = 1,
+ OCRDMA_QPS_RTR = 2,
+ OCRDMA_QPS_RTS = 3,
+ OCRDMA_QPS_SQE = 4,
+ OCRDMA_QPS_SQ_DRAINING = 5,
+ OCRDMA_QPS_ERR = 6,
+ OCRDMA_QPS_SQD = 7
+};
+
+struct ocrdma_create_qp_req {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 type_pgsz_pdn;
+ u32 max_wqe_rqe;
+ u32 max_sge_send_write;
+ u32 max_sge_recv_flags;
+ u32 max_ord_ird;
+ u32 num_wq_rq_pages;
+ u32 wqe_rqe_size;
+ u32 wq_rq_cqid;
+ struct ocrdma_pa wq_addr[MAX_OCRDMA_QP_PAGES];
+ struct ocrdma_pa rq_addr[MAX_OCRDMA_QP_PAGES];
+ u32 dpp_credits_cqid;
+ u32 rpir_lkey;
+ struct ocrdma_pa ird_addr[MAX_OCRDMA_IRD_PAGES];
+} __packed;
+
+enum {
+ OCRDMA_CREATE_QP_RSP_QP_ID_SHIFT = 0,
+ OCRDMA_CREATE_QP_RSP_QP_ID_MASK = 0xFFFF,
+
+ OCRDMA_CREATE_QP_RSP_MAX_RQE_SHIFT = 0,
+ OCRDMA_CREATE_QP_RSP_MAX_RQE_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_RSP_MAX_WQE_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_MAX_WQE_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_MAX_WQE_SHIFT,
+
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_WRITE_SHIFT = 0,
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_WRITE_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_SEND_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_SEND_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_SEND_SHIFT,
+
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_RECV_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_RECV_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_MAX_SGE_RECV_SHIFT,
+
+ OCRDMA_CREATE_QP_RSP_MAX_IRD_SHIFT = 0,
+ OCRDMA_CREATE_QP_RSP_MAX_IRD_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_RSP_MAX_ORD_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_MAX_ORD_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_MAX_ORD_SHIFT,
+
+ OCRDMA_CREATE_QP_RSP_RQ_ID_SHIFT = 0,
+ OCRDMA_CREATE_QP_RSP_RQ_ID_MASK = 0xFFFF,
+ OCRDMA_CREATE_QP_RSP_SQ_ID_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_SQ_ID_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_SQ_ID_SHIFT,
+
+ OCRDMA_CREATE_QP_RSP_DPP_ENABLED_MASK = Bit(0),
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_SHIFT = 1,
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_MASK = 0x7FFF <<
+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_SHIFT,
+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_SHIFT = 16,
+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_MASK = 0xFFFF <<
+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_SHIFT,
+};
+
+struct ocrdma_create_qp_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 qp_id;
+ u32 max_wqe_rqe;
+ u32 max_sge_send_write;
+ u32 max_sge_recv;
+ u32 max_ord_ird;
+ u32 sq_rq_id;
+ u32 dpp_response;
+} __packed;
+
+struct ocrdma_destroy_qp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 qp_id;
+} __packed;
+
+struct ocrdma_destroy_qp_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_MODIFY_QP_ID_SHIFT = 0,
+ OCRDMA_MODIFY_QP_ID_MASK = 0xFFFF,
+
+ OCRDMA_QP_PARA_QPS_VALID = Bit(0),
+ OCRDMA_QP_PARA_SQD_ASYNC_VALID = Bit(1),
+ OCRDMA_QP_PARA_PKEY_VALID = Bit(2),
+ OCRDMA_QP_PARA_QKEY_VALID = Bit(3),
+ OCRDMA_QP_PARA_PMTU_VALID = Bit(4),
+ OCRDMA_QP_PARA_ACK_TO_VALID = Bit(5),
+ OCRDMA_QP_PARA_RETRY_CNT_VALID = Bit(6),
+ OCRDMA_QP_PARA_RRC_VALID = Bit(7),
+ OCRDMA_QP_PARA_RQPSN_VALID = Bit(8),
+ OCRDMA_QP_PARA_MAX_IRD_VALID = Bit(9),
+ OCRDMA_QP_PARA_MAX_ORD_VALID = Bit(10),
+ OCRDMA_QP_PARA_RNT_VALID = Bit(11),
+ OCRDMA_QP_PARA_SQPSN_VALID = Bit(12),
+ OCRDMA_QP_PARA_DST_QPN_VALID = Bit(13),
+ OCRDMA_QP_PARA_MAX_WQE_VALID = Bit(14),
+ OCRDMA_QP_PARA_MAX_RQE_VALID = Bit(15),
+ OCRDMA_QP_PARA_SGE_SEND_VALID = Bit(16),
+ OCRDMA_QP_PARA_SGE_RECV_VALID = Bit(17),
+ OCRDMA_QP_PARA_SGE_WR_VALID = Bit(18),
+ OCRDMA_QP_PARA_INB_RDEN_VALID = Bit(19),
+ OCRDMA_QP_PARA_INB_WREN_VALID = Bit(20),
+ OCRDMA_QP_PARA_FLOW_LBL_VALID = Bit(21),
+ OCRDMA_QP_PARA_BIND_EN_VALID = Bit(22),
+ OCRDMA_QP_PARA_ZLKEY_EN_VALID = Bit(23),
+ OCRDMA_QP_PARA_FMR_EN_VALID = Bit(24),
+ OCRDMA_QP_PARA_INBAT_EN_VALID = Bit(25),
+ OCRDMA_QP_PARA_VLAN_EN_VALID = Bit(26),
+
+ OCRDMA_MODIFY_QP_FLAGS_RD = Bit(0),
+ OCRDMA_MODIFY_QP_FLAGS_WR = Bit(1),
+ OCRDMA_MODIFY_QP_FLAGS_SEND = Bit(2),
+ OCRDMA_MODIFY_QP_FLAGS_ATOMIC = Bit(3)
+};
+
+enum {
+ OCRDMA_QP_PARAMS_SRQ_ID_SHIFT = 0,
+ OCRDMA_QP_PARAMS_SRQ_ID_MASK = 0xFFFF,
+
+ OCRDMA_QP_PARAMS_MAX_RQE_SHIFT = 0,
+ OCRDMA_QP_PARAMS_MAX_RQE_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_MAX_WQE_SHIFT = 16,
+ OCRDMA_QP_PARAMS_MAX_WQE_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_MAX_WQE_SHIFT,
+
+ OCRDMA_QP_PARAMS_MAX_SGE_WRITE_SHIFT = 0,
+ OCRDMA_QP_PARAMS_MAX_SGE_WRITE_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_MAX_SGE_SEND_SHIFT = 16,
+ OCRDMA_QP_PARAMS_MAX_SGE_SEND_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_MAX_SGE_SEND_SHIFT,
+
+ OCRDMA_QP_PARAMS_FLAGS_FMR_EN = Bit(0),
+ OCRDMA_QP_PARAMS_FLAGS_LKEY_0_EN = Bit(1),
+ OCRDMA_QP_PARAMS_FLAGS_BIND_MW_EN = Bit(2),
+ OCRDMA_QP_PARAMS_FLAGS_INBWR_EN = Bit(3),
+ OCRDMA_QP_PARAMS_FLAGS_INBRD_EN = Bit(4),
+ OCRDMA_QP_PARAMS_STATE_SHIFT = 5,
+ OCRDMA_QP_PARAMS_STATE_MASK = Bit(5) | Bit(6) | Bit(7),
+ OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC = Bit(8),
+ OCRDMA_QP_PARAMS_FLAGS_INB_ATEN = Bit(9),
+ OCRDMA_QP_PARAMS_MAX_SGE_RECV_SHIFT = 16,
+ OCRDMA_QP_PARAMS_MAX_SGE_RECV_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_MAX_SGE_RECV_SHIFT,
+
+ OCRDMA_QP_PARAMS_MAX_IRD_SHIFT = 0,
+ OCRDMA_QP_PARAMS_MAX_IRD_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_MAX_ORD_SHIFT = 16,
+ OCRDMA_QP_PARAMS_MAX_ORD_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_MAX_ORD_SHIFT,
+
+ OCRDMA_QP_PARAMS_RQ_CQID_SHIFT = 0,
+ OCRDMA_QP_PARAMS_RQ_CQID_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_WQ_CQID_SHIFT = 16,
+ OCRDMA_QP_PARAMS_WQ_CQID_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_WQ_CQID_SHIFT,
+
+ OCRDMA_QP_PARAMS_RQ_PSN_SHIFT = 0,
+ OCRDMA_QP_PARAMS_RQ_PSN_MASK = 0xFFFFFF,
+ OCRDMA_QP_PARAMS_HOP_LMT_SHIFT = 24,
+ OCRDMA_QP_PARAMS_HOP_LMT_MASK = 0xFF <<
+ OCRDMA_QP_PARAMS_HOP_LMT_SHIFT,
+
+ OCRDMA_QP_PARAMS_SQ_PSN_SHIFT = 0,
+ OCRDMA_QP_PARAMS_SQ_PSN_MASK = 0xFFFFFF,
+ OCRDMA_QP_PARAMS_TCLASS_SHIFT = 24,
+ OCRDMA_QP_PARAMS_TCLASS_MASK = 0xFF <<
+ OCRDMA_QP_PARAMS_TCLASS_SHIFT,
+
+ OCRDMA_QP_PARAMS_DEST_QPN_SHIFT = 0,
+ OCRDMA_QP_PARAMS_DEST_QPN_MASK = 0xFFFFFF,
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT = 24,
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK = 0x7 <<
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT,
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT = 27,
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_MASK = 0x1F <<
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT,
+
+ OCRDMA_QP_PARAMS_PKEY_IDNEX_SHIFT = 0,
+ OCRDMA_QP_PARAMS_PKEY_INDEX_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT = 18,
+ OCRDMA_QP_PARAMS_PATH_MTU_MASK = 0x3FFF <<
+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT,
+
+ OCRDMA_QP_PARAMS_FLOW_LABEL_SHIFT = 0,
+ OCRDMA_QP_PARAMS_FLOW_LABEL_MASK = 0xFFFFF,
+ OCRDMA_QP_PARAMS_SL_SHIFT = 20,
+ OCRDMA_QP_PARAMS_SL_MASK = 0xF <<
+ OCRDMA_QP_PARAMS_SL_SHIFT,
+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT = 24,
+ OCRDMA_QP_PARAMS_RETRY_CNT_MASK = 0x7 <<
+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT,
+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_SHIFT = 27,
+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_MASK = 0x1F <<
+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_SHIFT,
+
+ OCRDMA_QP_PARAMS_DMAC_B4_TO_B5_SHIFT = 0,
+ OCRDMA_QP_PARAMS_DMAC_B4_TO_B5_MASK = 0xFFFF,
+ OCRDMA_QP_PARAMS_VLAN_SHIFT = 16,
+ OCRDMA_QP_PARAMS_VLAN_MASK = 0xFFFF <<
+ OCRDMA_QP_PARAMS_VLAN_SHIFT
+};
+
+struct ocrdma_qp_params {
+ u32 id;
+ u32 max_wqe_rqe;
+ u32 max_sge_send_write;
+ u32 max_sge_recv_flags;
+ u32 max_ord_ird;
+ u32 wq_rq_cqid;
+ u32 hop_lmt_rq_psn;
+ u32 tclass_sq_psn;
+ u32 ack_to_rnr_rtc_dest_qpn;
+ u32 path_mtu_pkey_indx;
+ u32 rnt_rc_sl_fl;
+ u8 sgid[16];
+ u8 dgid[16];
+ u32 dmac_b0_to_b3;
+ u32 vlan_dmac_b4_to_b5;
+ u32 qkey;
+} __packed;
+
+
+struct ocrdma_modify_qp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ struct ocrdma_qp_params params;
+ u32 flags;
+ u32 rdma_flags;
+ u32 num_outstanding_atomic_rd;
+} __packed;
+
+enum {
+ OCRDMA_MODIFY_QP_RSP_MAX_RQE_SHIFT = 0,
+ OCRDMA_MODIFY_QP_RSP_MAX_RQE_MASK = 0xFFFF,
+ OCRDMA_MODIFY_QP_RSP_MAX_WQE_SHIFT = 16,
+ OCRDMA_MODIFY_QP_RSP_MAX_WQE_MASK = 0xFFFF <<
+ OCRDMA_MODIFY_QP_RSP_MAX_WQE_SHIFT,
+
+ OCRDMA_MODIFY_QP_RSP_MAX_IRD_SHIFT = 0,
+ OCRDMA_MODIFY_QP_RSP_MAX_IRD_MASK = 0xFFFF,
+ OCRDMA_MODIFY_QP_RSP_MAX_ORD_SHIFT = 16,
+ OCRDMA_MODIFY_QP_RSP_MAX_ORD_MASK = 0xFFFF <<
+ OCRDMA_MODIFY_QP_RSP_MAX_ORD_SHIFT
+};
+struct ocrdma_modify_qp_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 max_wqe_rqe;
+ u32 max_ord_ird;
+} __packed;
+
+struct ocrdma_query_qp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+#define OCRDMA_QUERY_UP_QP_ID_SHIFT 0
+#define OCRDMA_QUERY_UP_QP_ID_MASK 0xFFFFFF
+ u32 qp_id;
+} __packed;
+
+struct ocrdma_query_qp_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ struct ocrdma_qp_params params;
+} __packed;
+
+enum {
+ OCRDMA_CREATE_SRQ_PD_ID_SHIFT = 0,
+ OCRDMA_CREATE_SRQ_PD_ID_MASK = 0xFFFF,
+ OCRDMA_CREATE_SRQ_PG_SZ_SHIFT = 16,
+ OCRDMA_CREATE_SRQ_PG_SZ_MASK = 0x3 <<
+ OCRDMA_CREATE_SRQ_PG_SZ_SHIFT,
+
+ OCRDMA_CREATE_SRQ_MAX_RQE_SHIFT = 0,
+ OCRDMA_CREATE_SRQ_MAX_SGE_RECV_SHIFT = 16,
+ OCRDMA_CREATE_SRQ_MAX_SGE_RECV_MASK = 0xFFFF <<
+ OCRDMA_CREATE_SRQ_MAX_SGE_RECV_SHIFT,
+
+ OCRDMA_CREATE_SRQ_RQE_SIZE_SHIFT = 0,
+ OCRDMA_CREATE_SRQ_RQE_SIZE_MASK = 0xFFFF,
+ OCRDMA_CREATE_SRQ_NUM_RQ_PAGES_SHIFT = 16,
+ OCRDMA_CREATE_SRQ_NUM_RQ_PAGES_MASK = 0xFFFF <<
+ OCRDMA_CREATE_SRQ_NUM_RQ_PAGES_SHIFT
+};
+
+struct ocrdma_create_srq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 pgsz_pdid;
+ u32 max_sge_rqe;
+ u32 pages_rqe_sz;
+ struct ocrdma_pa rq_addr[MAX_OCRDMA_SRQ_PAGES];
+} __packed;
+
+enum {
+ OCRDMA_CREATE_SRQ_RSP_SRQ_ID_SHIFT = 0,
+ OCRDMA_CREATE_SRQ_RSP_SRQ_ID_MASK = 0xFFFFFF,
+
+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_SHIFT = 0,
+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_MASK = 0xFFFF,
+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_SHIFT = 16,
+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_MASK = 0xFFFF <<
+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_SHIFT
+};
+
+struct ocrdma_create_srq_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 id;
+ u32 max_sge_rqe_allocated;
+} __packed;
+
+enum {
+ OCRDMA_MODIFY_SRQ_ID_SHIFT = 0,
+ OCRDMA_MODIFY_SRQ_ID_MASK = 0xFFFFFF,
+
+ OCRDMA_MODIFY_SRQ_MAX_RQE_SHIFT = 0,
+ OCRDMA_MODIFY_SRQ_MAX_RQE_MASK = 0xFFFF,
+ OCRDMA_MODIFY_SRQ_LIMIT_SHIFT = 16,
+ OCRDMA_MODIFY_SRQ__LIMIT_MASK = 0xFFFF <<
+ OCRDMA_MODIFY_SRQ_LIMIT_SHIFT
+};
+
+struct ocrdma_modify_srq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rep;
+
+ u32 id;
+ u32 limit_max_rqe;
+} __packed;
+
+enum {
+ OCRDMA_QUERY_SRQ_ID_SHIFT = 0,
+ OCRDMA_QUERY_SRQ_ID_MASK = 0xFFFFFF
+};
+
+struct ocrdma_query_srq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp req;
+
+ u32 id;
+} __packed;
+
+enum {
+ OCRDMA_QUERY_SRQ_RSP_PD_ID_SHIFT = 0,
+ OCRDMA_QUERY_SRQ_RSP_PD_ID_MASK = 0xFFFF,
+ OCRDMA_QUERY_SRQ_RSP_MAX_RQE_SHIFT = 16,
+ OCRDMA_QUERY_SRQ_RSP_MAX_RQE_MASK = 0xFFFF <<
+ OCRDMA_QUERY_SRQ_RSP_MAX_RQE_SHIFT,
+
+ OCRDMA_QUERY_SRQ_RSP_MAX_SGE_RECV_SHIFT = 0,
+ OCRDMA_QUERY_SRQ_RSP_MAX_SGE_RECV_MASK = 0xFFFF,
+ OCRDMA_QUERY_SRQ_RSP_SRQ_LIMIT_SHIFT = 16,
+ OCRDMA_QUERY_SRQ_RSP_SRQ_LIMIT_MASK = 0xFFFF <<
+ OCRDMA_QUERY_SRQ_RSP_SRQ_LIMIT_SHIFT
+};
+
+struct ocrdma_query_srq_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp req;
+
+ u32 max_rqe_pdid;
+ u32 srq_lmt_max_sge;
+} __packed;
+
+enum {
+ OCRDMA_DESTROY_SRQ_ID_SHIFT = 0,
+ OCRDMA_DESTROY_SRQ_ID_MASK = 0xFFFFFF
+};
+
+struct ocrdma_destroy_srq {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp req;
+
+ u32 id;
+} __packed;
+
+enum {
+ OCRDMA_ALLOC_PD_ENABLE_DPP = BIT(16),
+ OCRDMA_PD_MAX_DPP_ENABLED_QP = 8,
+ OCRDMA_DPP_PAGE_SIZE = 4096
+};
+
+struct ocrdma_alloc_pd {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 enable_dpp_rsvd;
+} __packed;
+
+enum {
+ OCRDMA_ALLOC_PD_RSP_DPP = Bit(16),
+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT = 20,
+ OCRDMA_ALLOC_PD_RSP_PDID_MASK = 0xFFFF,
+};
+
+struct ocrdma_alloc_pd_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 dpp_page_pdid;
+} __packed;
+
+struct ocrdma_dealloc_pd {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 id;
+} __packed;
+
+struct ocrdma_dealloc_pd_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_ADDR_CHECK_ENABLE = 1,
+ OCRDMA_ADDR_CHECK_DISABLE = 0
+};
+
+enum {
+ OCRDMA_ALLOC_LKEY_PD_ID_SHIFT = 0,
+ OCRDMA_ALLOC_LKEY_PD_ID_MASK = 0xFFFF,
+
+ OCRDMA_ALLOC_LKEY_ADDR_CHECK_SHIFT = 0,
+ OCRDMA_ALLOC_LKEY_ADDR_CHECK_MASK = Bit(0),
+ OCRDMA_ALLOC_LKEY_FMR_SHIFT = 1,
+ OCRDMA_ALLOC_LKEY_FMR_MASK = Bit(1),
+ OCRDMA_ALLOC_LKEY_REMOTE_INV_SHIFT = 2,
+ OCRDMA_ALLOC_LKEY_REMOTE_INV_MASK = Bit(2),
+ OCRDMA_ALLOC_LKEY_REMOTE_WR_SHIFT = 3,
+ OCRDMA_ALLOC_LKEY_REMOTE_WR_MASK = Bit(3),
+ OCRDMA_ALLOC_LKEY_REMOTE_RD_SHIFT = 4,
+ OCRDMA_ALLOC_LKEY_REMOTE_RD_MASK = Bit(4),
+ OCRDMA_ALLOC_LKEY_LOCAL_WR_SHIFT = 5,
+ OCRDMA_ALLOC_LKEY_LOCAL_WR_MASK = Bit(5),
+ OCRDMA_ALLOC_LKEY_REMOTE_ATOMIC_MASK = Bit(6),
+ OCRDMA_ALLOC_LKEY_REMOTE_ATOMIC_SHIFT = 6,
+ OCRDMA_ALLOC_LKEY_PBL_SIZE_SHIFT = 16,
+ OCRDMA_ALLOC_LKEY_PBL_SIZE_MASK = 0xFFFF <<
+ OCRDMA_ALLOC_LKEY_PBL_SIZE_SHIFT
+};
+
+struct ocrdma_alloc_lkey {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 pdid;
+ u32 pbl_sz_flags;
+} __packed;
+
+struct ocrdma_alloc_lkey_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 lrkey;
+ u32 num_pbl_rsvd;
+} __packed;
+
+struct ocrdma_dealloc_lkey {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 lkey;
+ u32 rsvd_frmr;
+} __packed;
+
+struct ocrdma_dealloc_lkey_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+#define MAX_OCRDMA_NSMR_PBL (u32)22
+#define MAX_OCRDMA_PBL_SIZE 65536
+#define MAX_OCRDMA_PBL_PER_LKEY 32767
+
+enum {
+ OCRDMA_REG_NSMR_LRKEY_INDEX_SHIFT = 0,
+ OCRDMA_REG_NSMR_LRKEY_INDEX_MASK = 0xFFFFFF,
+ OCRDMA_REG_NSMR_LRKEY_SHIFT = 24,
+ OCRDMA_REG_NSMR_LRKEY_MASK = 0xFF <<
+ OCRDMA_REG_NSMR_LRKEY_SHIFT,
+
+ OCRDMA_REG_NSMR_PD_ID_SHIFT = 0,
+ OCRDMA_REG_NSMR_PD_ID_MASK = 0xFFFF,
+ OCRDMA_REG_NSMR_NUM_PBL_SHIFT = 16,
+ OCRDMA_REG_NSMR_NUM_PBL_MASK = 0xFFFF <<
+ OCRDMA_REG_NSMR_NUM_PBL_SHIFT,
+
+ OCRDMA_REG_NSMR_PBE_SIZE_SHIFT = 0,
+ OCRDMA_REG_NSMR_PBE_SIZE_MASK = 0xFFFF,
+ OCRDMA_REG_NSMR_HPAGE_SIZE_SHIFT = 16,
+ OCRDMA_REG_NSMR_HPAGE_SIZE_MASK = 0xFF <<
+ OCRDMA_REG_NSMR_HPAGE_SIZE_SHIFT,
+ OCRDMA_REG_NSMR_BIND_MEMWIN_SHIFT = 24,
+ OCRDMA_REG_NSMR_BIND_MEMWIN_MASK = Bit(24),
+ OCRDMA_REG_NSMR_ZB_SHIFT = 25,
+ OCRDMA_REG_NSMR_ZB_SHIFT_MASK = Bit(25),
+ OCRDMA_REG_NSMR_REMOTE_INV_SHIFT = 26,
+ OCRDMA_REG_NSMR_REMOTE_INV_MASK = Bit(26),
+ OCRDMA_REG_NSMR_REMOTE_WR_SHIFT = 27,
+ OCRDMA_REG_NSMR_REMOTE_WR_MASK = Bit(27),
+ OCRDMA_REG_NSMR_REMOTE_RD_SHIFT = 28,
+ OCRDMA_REG_NSMR_REMOTE_RD_MASK = Bit(28),
+ OCRDMA_REG_NSMR_LOCAL_WR_SHIFT = 29,
+ OCRDMA_REG_NSMR_LOCAL_WR_MASK = Bit(29),
+ OCRDMA_REG_NSMR_REMOTE_ATOMIC_SHIFT = 30,
+ OCRDMA_REG_NSMR_REMOTE_ATOMIC_MASK = Bit(30),
+ OCRDMA_REG_NSMR_LAST_SHIFT = 31,
+ OCRDMA_REG_NSMR_LAST_MASK = Bit(31)
+};
+
+struct ocrdma_reg_nsmr {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr cmd;
+
+ u32 lrkey_key_index;
+ u32 num_pbl_pdid;
+ u32 flags_hpage_pbe_sz;
+ u32 totlen_low;
+ u32 totlen_high;
+ u32 fbo_low;
+ u32 fbo_high;
+ u32 va_loaddr;
+ u32 va_hiaddr;
+ struct ocrdma_pa pbl[MAX_OCRDMA_NSMR_PBL];
+} __packed;
+
+enum {
+ OCRDMA_REG_NSMR_CONT_PBL_SHIFT = 0,
+ OCRDMA_REG_NSMR_CONT_PBL_SHIFT_MASK = 0xFFFF,
+ OCRDMA_REG_NSMR_CONT_NUM_PBL_SHIFT = 16,
+ OCRDMA_REG_NSMR_CONT_NUM_PBL_MASK = 0xFFFF <<
+ OCRDMA_REG_NSMR_CONT_NUM_PBL_SHIFT,
+
+ OCRDMA_REG_NSMR_CONT_LAST_SHIFT = 31,
+ OCRDMA_REG_NSMR_CONT_LAST_MASK = Bit(31)
+};
+
+struct ocrdma_reg_nsmr_cont {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr cmd;
+
+ u32 lrkey;
+ u32 num_pbl_offset;
+ u32 last;
+
+ struct ocrdma_pa pbl[MAX_OCRDMA_NSMR_PBL];
+} __packed;
+
+struct ocrdma_pbe {
+ u32 pa_hi;
+ u32 pa_lo;
+} __packed;
+
+enum {
+ OCRDMA_REG_NSMR_RSP_NUM_PBL_SHIFT = 16,
+ OCRDMA_REG_NSMR_RSP_NUM_PBL_MASK = 0xFFFF0000
+};
+struct ocrdma_reg_nsmr_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 lrkey;
+ u32 num_pbl;
+} __packed;
+
+enum {
+ OCRDMA_REG_NSMR_CONT_RSP_LRKEY_INDEX_SHIFT = 0,
+ OCRDMA_REG_NSMR_CONT_RSP_LRKEY_INDEX_MASK = 0xFFFFFF,
+ OCRDMA_REG_NSMR_CONT_RSP_LRKEY_SHIFT = 24,
+ OCRDMA_REG_NSMR_CONT_RSP_LRKEY_MASK = 0xFF <<
+ OCRDMA_REG_NSMR_CONT_RSP_LRKEY_SHIFT,
+
+ OCRDMA_REG_NSMR_CONT_RSP_NUM_PBL_SHIFT = 16,
+ OCRDMA_REG_NSMR_CONT_RSP_NUM_PBL_MASK = 0xFFFF <<
+ OCRDMA_REG_NSMR_CONT_RSP_NUM_PBL_SHIFT
+};
+
+struct ocrdma_reg_nsmr_cont_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 lrkey_key_index;
+ u32 num_pbl;
+} __packed;
+
+enum {
+ OCRDMA_ALLOC_MW_PD_ID_SHIFT = 0,
+ OCRDMA_ALLOC_MW_PD_ID_MASK = 0xFFFF
+};
+
+struct ocrdma_alloc_mw {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 pdid;
+} __packed;
+
+enum {
+ OCRDMA_ALLOC_MW_RSP_LRKEY_INDEX_SHIFT = 0,
+ OCRDMA_ALLOC_MW_RSP_LRKEY_INDEX_MASK = 0xFFFFFF
+};
+
+struct ocrdma_alloc_mw_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u32 lrkey_index;
+} __packed;
+
+struct ocrdma_attach_mcast {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 qp_id;
+ u8 mgid[16];
+ u32 mac_b0_to_b3;
+ u32 vlan_mac_b4_to_b5;
+} __packed;
+
+struct ocrdma_attach_mcast_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+struct ocrdma_detach_mcast {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 qp_id;
+ u8 mgid[16];
+ u32 mac_b0_to_b3;
+ u32 vlan_mac_b4_to_b5;
+} __packed;
+
+struct ocrdma_detach_mcast_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_CREATE_AH_NUM_PAGES_SHIFT = 19,
+ OCRDMA_CREATE_AH_NUM_PAGES_MASK = 0xF <<
+ OCRDMA_CREATE_AH_NUM_PAGES_SHIFT,
+
+ OCRDMA_CREATE_AH_PAGE_SIZE_SHIFT = 16,
+ OCRDMA_CREATE_AH_PAGE_SIZE_MASK = 0x7 <<
+ OCRDMA_CREATE_AH_PAGE_SIZE_SHIFT,
+
+ OCRDMA_CREATE_AH_ENTRY_SIZE_SHIFT = 23,
+ OCRDMA_CREATE_AH_ENTRY_SIZE_MASK = 0x1FF <<
+ OCRDMA_CREATE_AH_ENTRY_SIZE_SHIFT,
+};
+
+#define OCRDMA_AH_TBL_PAGES 8
+
+struct ocrdma_create_ah_tbl {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+
+ u32 ah_conf;
+ struct ocrdma_pa tbl_addr[8];
+} __packed;
+
+struct ocrdma_create_ah_tbl_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 ahid;
+} __packed;
+
+struct ocrdma_delete_ah_tbl {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 ahid;
+} __packed;
+
+struct ocrdma_delete_ah_tbl_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+} __packed;
+
+enum {
+ OCRDMA_EQE_VALID_SHIFT = 0,
+ OCRDMA_EQE_VALID_MASK = Bit(0),
+ OCRDMA_EQE_FOR_CQE_MASK = 0xFFFE,
+ OCRDMA_EQE_RESOURCE_ID_SHIFT = 16,
+ OCRDMA_EQE_RESOURCE_ID_MASK = 0xFFFF <<
+ OCRDMA_EQE_RESOURCE_ID_SHIFT,
+};
+
+struct ocrdma_eqe {
+ u32 id_valid;
+} __packed;
+
+enum OCRDMA_CQE_STATUS {
+ OCRDMA_CQE_SUCCESS = 0,
+ OCRDMA_CQE_LOC_LEN_ERR,
+ OCRDMA_CQE_LOC_QP_OP_ERR,
+ OCRDMA_CQE_LOC_EEC_OP_ERR,
+ OCRDMA_CQE_LOC_PROT_ERR,
+ OCRDMA_CQE_WR_FLUSH_ERR,
+ OCRDMA_CQE_MW_BIND_ERR,
+ OCRDMA_CQE_BAD_RESP_ERR,
+ OCRDMA_CQE_LOC_ACCESS_ERR,
+ OCRDMA_CQE_REM_INV_REQ_ERR,
+ OCRDMA_CQE_REM_ACCESS_ERR,
+ OCRDMA_CQE_REM_OP_ERR,
+ OCRDMA_CQE_RETRY_EXC_ERR,
+ OCRDMA_CQE_RNR_RETRY_EXC_ERR,
+ OCRDMA_CQE_LOC_RDD_VIOL_ERR,
+ OCRDMA_CQE_REM_INV_RD_REQ_ERR,
+ OCRDMA_CQE_REM_ABORT_ERR,
+ OCRDMA_CQE_INV_EECN_ERR,
+ OCRDMA_CQE_INV_EEC_STATE_ERR,
+ OCRDMA_CQE_FATAL_ERR,
+ OCRDMA_CQE_RESP_TIMEOUT_ERR,
+ OCRDMA_CQE_GENERAL_ERR
+};
+
+enum {
+ /* w0 */
+ OCRDMA_CQE_WQEIDX_SHIFT = 0,
+ OCRDMA_CQE_WQEIDX_MASK = 0xFFFF,
+
+ /* w1 */
+ OCRDMA_CQE_UD_XFER_LEN_SHIFT = 16,
+ OCRDMA_CQE_PKEY_SHIFT = 0,
+ OCRDMA_CQE_PKEY_MASK = 0xFFFF,
+
+ /* w2 */
+ OCRDMA_CQE_QPN_SHIFT = 0,
+ OCRDMA_CQE_QPN_MASK = 0x0000FFFF,
+
+ OCRDMA_CQE_BUFTAG_SHIFT = 16,
+ OCRDMA_CQE_BUFTAG_MASK = 0xFFFF << OCRDMA_CQE_BUFTAG_SHIFT,
+
+ /* w3 */
+ OCRDMA_CQE_UD_STATUS_SHIFT = 24,
+ OCRDMA_CQE_UD_STATUS_MASK = 0x7 << OCRDMA_CQE_UD_STATUS_SHIFT,
+ OCRDMA_CQE_STATUS_SHIFT = 16,
+ OCRDMA_CQE_STATUS_MASK = 0xFF << OCRDMA_CQE_STATUS_SHIFT,
+ OCRDMA_CQE_VALID = Bit(31),
+ OCRDMA_CQE_INVALIDATE = Bit(30),
+ OCRDMA_CQE_QTYPE = Bit(29),
+ OCRDMA_CQE_IMM = Bit(28),
+ OCRDMA_CQE_WRITE_IMM = Bit(27),
+ OCRDMA_CQE_QTYPE_SQ = 0,
+ OCRDMA_CQE_QTYPE_RQ = 1,
+ OCRDMA_CQE_SRCQP_MASK = 0xFFFFFF
+};
+
+struct ocrdma_cqe {
+ union {
+ /* w0 to w2 */
+ struct {
+ u32 wqeidx;
+ u32 bytes_xfered;
+ u32 qpn;
+ } wq;
+ struct {
+ u32 lkey_immdt;
+ u32 rxlen;
+ u32 buftag_qpn;
+ } rq;
+ struct {
+ u32 lkey_immdt;
+ u32 rxlen_pkey;
+ u32 buftag_qpn;
+ } ud;
+ struct {
+ u32 word_0;
+ u32 word_1;
+ u32 qpn;
+ } cmn;
+ };
+ u32 flags_status_srcqpn; /* w3 */
+} __packed;
+
+#define is_cqe_valid(cq, cqe) \
+ (((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_VALID)\
+ == cq->phase) ? 1 : 0)
+#define is_cqe_for_sq(cqe) \
+ ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 0 : 1)
+#define is_cqe_for_rq(cqe) \
+ ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 1 : 0)
+#define is_cqe_invalidated(cqe) \
+ ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_INVALIDATE) ? \
+ 1 : 0)
+#define is_cqe_imm(cqe) \
+ ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_IMM) ? 1 : 0)
+#define is_cqe_wr_imm(cqe) \
+ ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_WRITE_IMM) ? 1 : 0)
+
+struct ocrdma_sge {
+ u32 addr_hi;
+ u32 addr_lo;
+ u32 lrkey;
+ u32 len;
+} __packed;
+
+enum {
+ OCRDMA_FLAG_SIG = 0x1,
+ OCRDMA_FLAG_INV = 0x2,
+ OCRDMA_FLAG_FENCE_L = 0x4,
+ OCRDMA_FLAG_FENCE_R = 0x8,
+ OCRDMA_FLAG_SOLICIT = 0x10,
+ OCRDMA_FLAG_IMM = 0x20,
+
+ /* Stag flags */
+ OCRDMA_LKEY_FLAG_LOCAL_WR = 0x1,
+ OCRDMA_LKEY_FLAG_REMOTE_RD = 0x2,
+ OCRDMA_LKEY_FLAG_REMOTE_WR = 0x4,
+ OCRDMA_LKEY_FLAG_VATO = 0x8,
+};
+
+enum OCRDMA_WQE_OPCODE {
+ OCRDMA_WRITE = 0x06,
+ OCRDMA_READ = 0x0C,
+ OCRDMA_RESV0 = 0x02,
+ OCRDMA_SEND = 0x00,
+ OCRDMA_CMP_SWP = 0x14,
+ OCRDMA_BIND_MW = 0x10,
+ OCRDMA_RESV1 = 0x0A,
+ OCRDMA_LKEY_INV = 0x15,
+ OCRDMA_FETCH_ADD = 0x13,
+ OCRDMA_POST_RQ = 0x12
+};
+
+enum {
+ OCRDMA_TYPE_INLINE = 0x0,
+ OCRDMA_TYPE_LKEY = 0x1,
+};
+
+enum {
+ OCRDMA_WQE_OPCODE_SHIFT = 0,
+ OCRDMA_WQE_OPCODE_MASK = 0x0000001F,
+ OCRDMA_WQE_FLAGS_SHIFT = 5,
+ OCRDMA_WQE_TYPE_SHIFT = 16,
+ OCRDMA_WQE_TYPE_MASK = 0x00030000,
+ OCRDMA_WQE_SIZE_SHIFT = 18,
+ OCRDMA_WQE_SIZE_MASK = 0xFF,
+ OCRDMA_WQE_NXT_WQE_SIZE_SHIFT = 25,
+
+ OCRDMA_WQE_LKEY_FLAGS_SHIFT = 0,
+ OCRDMA_WQE_LKEY_FLAGS_MASK = 0xF
+};
+
+/* header WQE for all the SQ and RQ operations */
+struct ocrdma_hdr_wqe {
+ u32 cw;
+ union {
+ u32 rsvd_tag;
+ u32 rsvd_lkey_flags;
+ };
+ union {
+ u32 immdt;
+ u32 lkey;
+ };
+ u32 total_len;
+} __packed;
+
+struct ocrdma_ewqe_ud_hdr {
+ u32 rsvd_dest_qpn;
+ u32 qkey;
+ u32 rsvd_ahid;
+ u32 rsvd;
+} __packed;
+
+struct ocrdma_eth_basic {
+ u8 dmac[6];
+ u8 smac[6];
+ __be16 eth_type;
+} __packed;
+
+struct ocrdma_eth_vlan {
+ u8 dmac[6];
+ u8 smac[6];
+ __be16 eth_type;
+ __be16 vlan_tag;
+#define OCRDMA_ROCE_ETH_TYPE 0x8915
+ __be16 roce_eth_type;
+} __packed;
+
+struct ocrdma_grh {
+ __be32 tclass_flow;
+ __be32 pdid_hoplimit;
+ u8 sgid[16];
+ u8 dgid[16];
+ u16 rsvd;
+} __packed;
+
+#define OCRDMA_AV_VALID Bit(0)
+#define OCRDMA_AV_VLAN_VALID Bit(1)
+
+struct ocrdma_av {
+ struct ocrdma_eth_vlan eth_hdr;
+ struct ocrdma_grh grh;
+ u32 valid;
+} __packed;
+
+#endif /* __OCRDMA_SLI_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
new file mode 100644
index 0000000..e9f74d1
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -0,0 +1,2537 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#include <linux/dma-mapping.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/iw_cm.h>
+#include <rdma/ib_umem.h>
+#include <rdma/ib_addr.h>
+
+#include "ocrdma.h"
+#include "ocrdma_hw.h"
+#include "ocrdma_verbs.h"
+#include "ocrdma_abi.h"
+
+int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ if (index > 1)
+ return -EINVAL;
+
+ *pkey = 0xffff;
+ return 0;
+}
+
+int ocrdma_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *sgid)
+{
+ struct ocrdma_dev *dev;
+
+ dev = get_ocrdma_dev(ibdev);
+ memset(sgid, 0, sizeof(*sgid));
+ if (index > OCRDMA_MAX_SGID)
+ return -EINVAL;
+
+ memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));
+
+ return 0;
+}
+
+int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr)
+{
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
+
+ memset(attr, 0, sizeof *attr);
+ memcpy(&attr->fw_ver, &dev->attr.fw_ver[0],
+ min(sizeof(dev->attr.fw_ver), sizeof(attr->fw_ver)));
+ ocrdma_get_guid(dev, (u8 *)&attr->sys_image_guid);
+ attr->max_mr_size = ~0ull;
+ attr->page_size_cap = 0xffff000;
+ attr->vendor_id = dev->nic_info.pdev->vendor;
+ attr->vendor_part_id = dev->nic_info.pdev->device;
+ attr->hw_ver = 0;
+ attr->max_qp = dev->attr.max_qp;
+ attr->max_ah = dev->attr.max_qp;
+ attr->max_qp_wr = dev->attr.max_wqe;
+
+ attr->device_cap_flags = IB_DEVICE_CURR_QP_STATE_MOD |
+ IB_DEVICE_RC_RNR_NAK_GEN |
+ IB_DEVICE_SHUTDOWN_PORT |
+ IB_DEVICE_SYS_IMAGE_GUID |
+ IB_DEVICE_LOCAL_DMA_LKEY;
+ attr->max_sge = dev->attr.max_send_sge;
+ attr->max_sge_rd = dev->attr.max_send_sge;
+ attr->max_cq = dev->attr.max_cq;
+ attr->max_cqe = dev->attr.max_cqe;
+ attr->max_mr = dev->attr.max_mr;
+ attr->max_mw = 0;
+ attr->max_pd = dev->attr.max_pd;
+ attr->atomic_cap = 0;
+ attr->max_fmr = 0;
+ attr->max_map_per_fmr = 0;
+ attr->max_qp_rd_atom =
+ min(dev->attr.max_ord_per_qp, dev->attr.max_ird_per_qp);
+ attr->max_qp_init_rd_atom = dev->attr.max_ord_per_qp;
+ attr->max_srq = (dev->attr.max_qp - 1);
+ attr->max_srq_sge = attr->max_sge;
+ attr->max_srq_wr = dev->attr.max_rqe;
+ attr->local_ca_ack_delay = dev->attr.local_ca_ack_delay;
+ attr->max_fast_reg_page_list_len = 0;
+ attr->max_pkeys = 1;
+ return 0;
+}
+
+int ocrdma_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ enum ib_port_state port_state;
+ struct ocrdma_dev *dev;
+ struct net_device *netdev;
+
+ dev = get_ocrdma_dev(ibdev);
+ if (port > 1) {
+ ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
+ dev->id, port);
+ return -EINVAL;
+ }
+ netdev = dev->nic_info.netdev;
+ if (netif_running(netdev) && netif_oper_up(netdev)) {
+ port_state = IB_PORT_ACTIVE;
+ props->phys_state = 5;
+ } else {
+ port_state = IB_PORT_DOWN;
+ props->phys_state = 3;
+ }
+ props->max_mtu = IB_MTU_4096;
+ props->active_mtu = iboe_get_mtu(netdev->mtu);
+ props->lid = 0;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ props->state = port_state;
+ props->port_cap_flags =
+ IB_PORT_CM_SUP |
+ IB_PORT_REINIT_SUP |
+ IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP;
+ props->gid_tbl_len = OCRDMA_MAX_SGID;
+ props->pkey_tbl_len = 1;
+ props->bad_pkey_cntr = 0;
+ props->qkey_viol_cntr = 0;
+ props->active_width = IB_WIDTH_1X;
+ props->active_speed = 4;
+ props->max_msg_sz = 0x80000000;
+ props->max_vl_num = 4;
+ return 0;
+}
+
+int ocrdma_modify_port(struct ib_device *ibdev, u8 port, int mask,
+ struct ib_port_modify *props)
+{
+ struct ocrdma_dev *dev;
+
+ dev = get_ocrdma_dev(ibdev);
+ if (port > 1) {
+ ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
+ dev->id, port);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ocrdma_add_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
+ unsigned long len)
+{
+ struct ocrdma_mm *mm;
+
+ mm = kzalloc(sizeof(*mm), GFP_KERNEL);
+ if (mm == NULL)
+ return -ENOMEM;
+ mm->key.phy_addr = phy_addr;
+ mm->key.len = len;
+ INIT_LIST_HEAD(&mm->entry);
+
+ mutex_lock(&uctx->mm_list_lock);
+ list_add_tail(&mm->entry, &uctx->mm_head);
+ mutex_unlock(&uctx->mm_list_lock);
+ return 0;
+}
+
+static void ocrdma_del_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
+ unsigned long len)
+{
+ struct ocrdma_mm *mm, *tmp;
+
+ mutex_lock(&uctx->mm_list_lock);
+ list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {
+ if (len != mm->key.len || phy_addr != mm->key.phy_addr)
+ continue;
+
+ list_del(&mm->entry);
+ kfree(mm);
+ break;
+ }
+ mutex_unlock(&uctx->mm_list_lock);
+}
+
+static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
+ unsigned long len)
+{
+ bool found = false;
+ struct ocrdma_mm *mm;
+
+ mutex_lock(&uctx->mm_list_lock);
+ list_for_each_entry(mm, &uctx->mm_head, entry) {
+ if (len != mm->key.len || phy_addr != mm->key.phy_addr)
+ continue;
+
+ found = true;
+ break;
+ }
+ mutex_unlock(&uctx->mm_list_lock);
+ return found;
+}
+
+struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ int status;
+ struct ocrdma_ucontext *ctx;
+ struct ocrdma_alloc_ucontext_resp resp;
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ u32 map_len = roundup(sizeof(u32) * 2048, PAGE_SIZE);
+
+ if (!udata)
+ return ERR_PTR(-EFAULT);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+ ctx->dev = dev;
+ INIT_LIST_HEAD(&ctx->mm_head);
+ mutex_init(&ctx->mm_list_lock);
+
+ ctx->ah_tbl.va = dma_alloc_coherent(&pdev->dev, map_len,
+ &ctx->ah_tbl.pa, GFP_KERNEL);
+ if (!ctx->ah_tbl.va) {
+ kfree(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
+ memset(ctx->ah_tbl.va, 0, map_len);
+ ctx->ah_tbl.len = map_len;
+
+ resp.ah_tbl_len = ctx->ah_tbl.len;
+ resp.ah_tbl_page = ctx->ah_tbl.pa;
+
+ status = ocrdma_add_mmap(ctx, resp.ah_tbl_page, resp.ah_tbl_len);
+ if (status)
+ goto map_err;
+ resp.dev_id = dev->id;
+ resp.max_inline_data = dev->attr.max_inline_data;
+ resp.wqe_size = dev->attr.wqe_size;
+ resp.rqe_size = dev->attr.rqe_size;
+ resp.dpp_wqe_size = dev->attr.wqe_size;
+ resp.rsvd = 0;
+
+ memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));
+ status = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ if (status)
+ goto cpy_err;
+ return &ctx->ibucontext;
+
+cpy_err:
+ ocrdma_del_mmap(ctx, ctx->ah_tbl.pa, ctx->ah_tbl.len);
+map_err:
+ dma_free_coherent(&pdev->dev, ctx->ah_tbl.len, ctx->ah_tbl.va,
+ ctx->ah_tbl.pa);
+ kfree(ctx);
+ return ERR_PTR(status);
+}
+
+int ocrdma_dealloc_ucontext(struct ib_ucontext *ibctx)
+{
+ struct ocrdma_mm *mm, *tmp;
+ struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ibctx);
+ struct pci_dev *pdev = uctx->dev->nic_info.pdev;
+
+ ocrdma_del_mmap(uctx, uctx->ah_tbl.pa, uctx->ah_tbl.len);
+ dma_free_coherent(&pdev->dev, uctx->ah_tbl.len, uctx->ah_tbl.va,
+ uctx->ah_tbl.pa);
+
+ list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {
+ list_del(&mm->entry);
+ kfree(mm);
+ }
+ kfree(uctx);
+ return 0;
+}
+
+int ocrdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ struct ocrdma_ucontext *ucontext = get_ocrdma_ucontext(context);
+ struct ocrdma_dev *dev = ucontext->dev;
+ unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT;
+ u64 unmapped_db = (u64) dev->nic_info.unmapped_db;
+ unsigned long len = (vma->vm_end - vma->vm_start);
+ int status = 0;
+ bool found;
+
+ if (vma->vm_start & (PAGE_SIZE - 1))
+ return -EINVAL;
+ found = ocrdma_search_mmap(ucontext, vma->vm_pgoff << PAGE_SHIFT, len);
+ if (!found)
+ return -EINVAL;
+
+ if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db +
+ dev->nic_info.db_total_size)) &&
+ (len <= dev->nic_info.db_page_size)) {
+ /* doorbell mapping */
+ status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ len, vma->vm_page_prot);
+ } else if (dev->nic_info.dpp_unmapped_len &&
+ (vm_page >= (u64) dev->nic_info.dpp_unmapped_addr) &&
+ (vm_page <= (u64) (dev->nic_info.dpp_unmapped_addr +
+ dev->nic_info.dpp_unmapped_len)) &&
+ (len <= dev->nic_info.dpp_unmapped_len)) {
+ /* dpp area mapping */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ len, vma->vm_page_prot);
+ } else {
+ /* queue memory mapping */
+ status = remap_pfn_range(vma, vma->vm_start,
+ vma->vm_pgoff, len, vma->vm_page_prot);
+ }
+ return status;
+}
+
+static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,
+ struct ib_ucontext *ib_ctx,
+ struct ib_udata *udata)
+{
+ int status;
+ u64 db_page_addr;
+ u64 dpp_page_addr = 0;
+ u32 db_page_size;
+ struct ocrdma_alloc_pd_uresp rsp;
+ struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);
+
+ rsp.id = pd->id;
+ rsp.dpp_enabled = pd->dpp_enabled;
+ db_page_addr = pd->dev->nic_info.unmapped_db +
+ (pd->id * pd->dev->nic_info.db_page_size);
+ db_page_size = pd->dev->nic_info.db_page_size;
+
+ status = ocrdma_add_mmap(uctx, db_page_addr, db_page_size);
+ if (status)
+ return status;
+
+ if (pd->dpp_enabled) {
+ dpp_page_addr = pd->dev->nic_info.dpp_unmapped_addr +
+ (pd->id * OCRDMA_DPP_PAGE_SIZE);
+ status = ocrdma_add_mmap(uctx, dpp_page_addr,
+ OCRDMA_DPP_PAGE_SIZE);
+ if (status)
+ goto dpp_map_err;
+ rsp.dpp_page_addr_hi = upper_32_bits(dpp_page_addr);
+ rsp.dpp_page_addr_lo = dpp_page_addr;
+ }
+
+ status = ib_copy_to_udata(udata, &rsp, sizeof(rsp));
+ if (status)
+ goto ucopy_err;
+
+ pd->uctx = uctx;
+ return 0;
+
+ucopy_err:
+ if (pd->dpp_enabled)
+ ocrdma_del_mmap(pd->uctx, dpp_page_addr, OCRDMA_DPP_PAGE_SIZE);
+dpp_map_err:
+ ocrdma_del_mmap(pd->uctx, db_page_addr, db_page_size);
+ return status;
+}
+
+struct ib_pd *ocrdma_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
+ struct ocrdma_pd *pd;
+ int status;
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+ pd->dev = dev;
+ if (udata && context) {
+ pd->dpp_enabled = (dev->nic_info.dev_family ==
+ OCRDMA_GEN2_FAMILY) ? true : false;
+ pd->num_dpp_qp =
+ pd->dpp_enabled ? OCRDMA_PD_MAX_DPP_ENABLED_QP : 0;
+ }
+ status = ocrdma_mbx_alloc_pd(dev, pd);
+ if (status) {
+ kfree(pd);
+ return ERR_PTR(status);
+ }
+ atomic_set(&pd->use_cnt, 0);
+
+ if (udata && context) {
+ status = ocrdma_copy_pd_uresp(pd, context, udata);
+ if (status)
+ goto err;
+ }
+ return &pd->ibpd;
+
+err:
+ ocrdma_dealloc_pd(&pd->ibpd);
+ return ERR_PTR(status);
+}
+
+int ocrdma_dealloc_pd(struct ib_pd *ibpd)
+{
+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+ struct ocrdma_dev *dev = pd->dev;
+ int status;
+ u64 usr_db;
+
+ if (atomic_read(&pd->use_cnt)) {
+ ocrdma_err("%s(%d) pd=0x%x is in use.\n",
+ __func__, dev->id, pd->id);
+ status = -EFAULT;
+ goto dealloc_err;
+ }
+ status = ocrdma_mbx_dealloc_pd(dev, pd);
+ if (pd->uctx) {
+ u64 dpp_db = dev->nic_info.dpp_unmapped_addr +
+ (pd->id * OCRDMA_DPP_PAGE_SIZE);
+ if (pd->dpp_enabled)
+ ocrdma_del_mmap(pd->uctx, dpp_db, OCRDMA_DPP_PAGE_SIZE);
+ usr_db = dev->nic_info.unmapped_db +
+ (pd->id * dev->nic_info.db_page_size);
+ ocrdma_del_mmap(pd->uctx, usr_db, dev->nic_info.db_page_size);
+ }
+ kfree(pd);
+dealloc_err:
+ return status;
+}
+
+static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,
+ int acc, u32 num_pbls,
+ u32 addr_check)
+{
+ int status;
+ struct ocrdma_mr *mr;
+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+ struct ocrdma_dev *dev = pd->dev;
+
+ if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) {
+ ocrdma_err("%s(%d) leaving err, invalid access rights\n",
+ __func__, dev->id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+ mr->hwmr.dev = dev;
+ mr->hwmr.fr_mr = 0;
+ mr->hwmr.local_rd = 1;
+ mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0;
+ mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0;
+ mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0;
+ mr->hwmr.mw_bind = (acc & IB_ACCESS_MW_BIND) ? 1 : 0;
+ mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0;
+ mr->hwmr.num_pbls = num_pbls;
+
+ status = ocrdma_mbx_alloc_lkey(dev, &mr->hwmr, pd->id, addr_check);
+ if (status) {
+ kfree(mr);
+ return ERR_PTR(-ENOMEM);
+ }
+ mr->pd = pd;
+ atomic_inc(&pd->use_cnt);
+ mr->ibmr.lkey = mr->hwmr.lkey;
+ if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
+ mr->ibmr.rkey = mr->hwmr.lkey;
+ return mr;
+}
+
+struct ib_mr *ocrdma_get_dma_mr(struct ib_pd *ibpd, int acc)
+{
+ struct ocrdma_mr *mr;
+
+ mr = ocrdma_alloc_lkey(ibpd, acc, 0, OCRDMA_ADDR_CHECK_DISABLE);
+ if (IS_ERR(mr))
+ return ERR_CAST(mr);
+
+ return &mr->ibmr;
+}
+
+static void ocrdma_free_mr_pbl_tbl(struct ocrdma_dev *dev,
+ struct ocrdma_hw_mr *mr)
+{
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ int i = 0;
+
+ if (mr->pbl_table) {
+ for (i = 0; i < mr->num_pbls; i++) {
+ if (!mr->pbl_table[i].va)
+ continue;
+ dma_free_coherent(&pdev->dev, mr->pbl_size,
+ mr->pbl_table[i].va,
+ mr->pbl_table[i].pa);
+ }
+ kfree(mr->pbl_table);
+ mr->pbl_table = NULL;
+ }
+}
+
+static int ocrdma_get_pbl_info(struct ocrdma_mr *mr, u32 num_pbes)
+{
+ u32 num_pbls = 0;
+ u32 idx = 0;
+ int status = 0;
+ u32 pbl_size;
+
+ do {
+ pbl_size = OCRDMA_MIN_HPAGE_SIZE * (1 << idx);
+ if (pbl_size > MAX_OCRDMA_PBL_SIZE) {
+ status = -EFAULT;
+ break;
+ }
+ num_pbls = roundup(num_pbes, (pbl_size / sizeof(u64)));
+ num_pbls = num_pbls / (pbl_size / sizeof(u64));
+ idx++;
+ } while (num_pbls >= mr->hwmr.dev->attr.max_num_mr_pbl);
+
+ mr->hwmr.num_pbes = num_pbes;
+ mr->hwmr.num_pbls = num_pbls;
+ mr->hwmr.pbl_size = pbl_size;
+ return status;
+}
+
+static int ocrdma_build_pbl_tbl(struct ocrdma_dev *dev, struct ocrdma_hw_mr *mr)
+{
+ int status = 0;
+ int i;
+ u32 dma_len = mr->pbl_size;
+ struct pci_dev *pdev = dev->nic_info.pdev;
+ void *va;
+ dma_addr_t pa;
+
+ mr->pbl_table = kzalloc(sizeof(struct ocrdma_pbl) *
+ mr->num_pbls, GFP_KERNEL);
+
+ if (!mr->pbl_table)
+ return -ENOMEM;
+
+ for (i = 0; i < mr->num_pbls; i++) {
+ va = dma_alloc_coherent(&pdev->dev, dma_len, &pa, GFP_KERNEL);
+ if (!va) {
+ ocrdma_free_mr_pbl_tbl(dev, mr);
+ status = -ENOMEM;
+ break;
+ }
+ memset(va, 0, dma_len);
+ mr->pbl_table[i].va = va;
+ mr->pbl_table[i].pa = pa;
+ }
+ return status;
+}
+
+static void build_user_pbes(struct ocrdma_dev *dev, struct ocrdma_mr *mr,
+ u32 num_pbes)
+{
+ struct ocrdma_pbe *pbe;
+ struct ib_umem_chunk *chunk;
+ struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table;
+ struct ib_umem *umem = mr->umem;
+ int i, shift, pg_cnt, pages, pbe_cnt, total_num_pbes = 0;
+
+ if (!mr->hwmr.num_pbes)
+ return;
+
+ pbe = (struct ocrdma_pbe *)pbl_tbl->va;
+ pbe_cnt = 0;
+
+ shift = ilog2(umem->page_size);
+
+ list_for_each_entry(chunk, &umem->chunk_list, list) {
+ /* get all the dma regions from the chunk. */
+ for (i = 0; i < chunk->nmap; i++) {
+ pages = sg_dma_len(&chunk->page_list[i]) >> shift;
+ for (pg_cnt = 0; pg_cnt < pages; pg_cnt++) {
+ /* store the page address in pbe */
+ pbe->pa_lo =
+ cpu_to_le32(sg_dma_address
+ (&chunk->page_list[i]) +
+ (umem->page_size * pg_cnt));
+ pbe->pa_hi =
+ cpu_to_le32(upper_32_bits
+ ((sg_dma_address
+ (&chunk->page_list[i]) +
+ umem->page_size * pg_cnt)));
+ pbe_cnt += 1;
+ total_num_pbes += 1;
+ pbe++;
+
+ /* if done building pbes, issue the mbx cmd. */
+ if (total_num_pbes == num_pbes)
+ return;
+
+ /* if the given pbl is full storing the pbes,
+ * move to next pbl.
+ */
+ if (pbe_cnt ==
+ (mr->hwmr.pbl_size / sizeof(u64))) {
+ pbl_tbl++;
+ pbe = (struct ocrdma_pbe *)pbl_tbl->va;
+ pbe_cnt = 0;
+ }
+ }
+ }
+ }
+}
+
+struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len,
+ u64 usr_addr, int acc, struct ib_udata *udata)
+{
+ int status = -ENOMEM;
+ struct ocrdma_dev *dev;
+ struct ocrdma_mr *mr;
+ struct ocrdma_pd *pd;
+ u32 num_pbes;
+
+ pd = get_ocrdma_pd(ibpd);
+ dev = pd->dev;
+
+ if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE))
+ return ERR_PTR(-EINVAL);
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(status);
+ mr->hwmr.dev = dev;
+ mr->umem = ib_umem_get(ibpd->uobject->context, start, len, acc, 0);
+ if (IS_ERR(mr->umem)) {
+ status = -EFAULT;
+ goto umem_err;
+ }
+ num_pbes = ib_umem_page_count(mr->umem);
+ status = ocrdma_get_pbl_info(mr, num_pbes);
+ if (status)
+ goto umem_err;
+
+ mr->hwmr.pbe_size = mr->umem->page_size;
+ mr->hwmr.fbo = mr->umem->offset;
+ mr->hwmr.va = usr_addr;
+ mr->hwmr.len = len;
+ mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0;
+ mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0;
+ mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0;
+ mr->hwmr.local_rd = 1;
+ mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0;
+ status = ocrdma_build_pbl_tbl(dev, &mr->hwmr);
+ if (status)
+ goto umem_err;
+ build_user_pbes(dev, mr, num_pbes);
+ status = ocrdma_reg_mr(dev, &mr->hwmr, pd->id, acc);
+ if (status)
+ goto mbx_err;
+ mr->pd = pd;
+ atomic_inc(&pd->use_cnt);
+ mr->ibmr.lkey = mr->hwmr.lkey;
+ if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
+ mr->ibmr.rkey = mr->hwmr.lkey;
+
+ return &mr->ibmr;
+
+mbx_err:
+ ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
+umem_err:
+ kfree(mr);
+ return ERR_PTR(status);
+}
+
+int ocrdma_dereg_mr(struct ib_mr *ib_mr)
+{
+ struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);
+ struct ocrdma_dev *dev = mr->hwmr.dev;
+ int status;
+
+ status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
+
+ if (mr->hwmr.fr_mr == 0)
+ ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
+
+ atomic_dec(&mr->pd->use_cnt);
+ /* it could be user registered memory. */
+ if (mr->umem)
+ ib_umem_release(mr->umem);
+ kfree(mr);
+ return status;
+}
+
+static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
+ struct ib_ucontext *ib_ctx)
+{
+ int status;
+ struct ocrdma_ucontext *uctx;
+ struct ocrdma_create_cq_uresp uresp;
+
+ uresp.cq_id = cq->id;
+ uresp.page_size = cq->len;
+ uresp.num_pages = 1;
+ uresp.max_hw_cqe = cq->max_hw_cqe;
+ uresp.page_addr[0] = cq->pa;
+ uresp.db_page_addr = cq->dev->nic_info.unmapped_db;
+ uresp.db_page_size = cq->dev->nic_info.db_page_size;
+ uresp.phase_change = cq->phase_change ? 1 : 0;
+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (status) {
+ ocrdma_err("%s(%d) copy error cqid=0x%x.\n",
+ __func__, cq->dev->id, cq->id);
+ goto err;
+ }
+ uctx = get_ocrdma_ucontext(ib_ctx);
+ status = ocrdma_add_mmap(uctx, uresp.db_page_addr, uresp.db_page_size);
+ if (status)
+ goto err;
+ status = ocrdma_add_mmap(uctx, uresp.page_addr[0], uresp.page_size);
+ if (status) {
+ ocrdma_del_mmap(uctx, uresp.db_page_addr, uresp.db_page_size);
+ goto err;
+ }
+ cq->ucontext = uctx;
+err:
+ return status;
+}
+
+struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
+ struct ib_ucontext *ib_ctx,
+ struct ib_udata *udata)
+{
+ struct ocrdma_cq *cq;
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
+ int status;
+ struct ocrdma_create_cq_ureq ureq;
+
+ if (udata) {
+ if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))
+ return ERR_PTR(-EFAULT);
+ } else
+ ureq.dpp_cq = 0;
+ cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+ if (!cq)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&cq->cq_lock);
+ spin_lock_init(&cq->comp_handler_lock);
+ atomic_set(&cq->use_cnt, 0);
+ INIT_LIST_HEAD(&cq->sq_head);
+ INIT_LIST_HEAD(&cq->rq_head);
+ cq->dev = dev;
+
+ status = ocrdma_mbx_create_cq(dev, cq, entries, ureq.dpp_cq);
+ if (status) {
+ kfree(cq);
+ return ERR_PTR(status);
+ }
+ if (ib_ctx) {
+ status = ocrdma_copy_cq_uresp(cq, udata, ib_ctx);
+ if (status)
+ goto ctx_err;
+ }
+ cq->phase = OCRDMA_CQE_VALID;
+ cq->arm_needed = true;
+ dev->cq_tbl[cq->id] = cq;
+
+ return &cq->ibcq;
+
+ctx_err:
+ ocrdma_mbx_destroy_cq(dev, cq);
+ kfree(cq);
+ return ERR_PTR(status);
+}
+
+int ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt,
+ struct ib_udata *udata)
+{
+ int status = 0;
+ struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
+
+ if (new_cnt < 1 || new_cnt > cq->max_hw_cqe) {
+ status = -EINVAL;
+ return status;
+ }
+ ibcq->cqe = new_cnt;
+ return status;
+}
+
+int ocrdma_destroy_cq(struct ib_cq *ibcq)
+{
+ int status;
+ struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
+ struct ocrdma_dev *dev = cq->dev;
+
+ if (atomic_read(&cq->use_cnt))
+ return -EINVAL;
+
+ status = ocrdma_mbx_destroy_cq(dev, cq);
+
+ if (cq->ucontext) {
+ ocrdma_del_mmap(cq->ucontext, (u64) cq->pa, cq->len);
+ ocrdma_del_mmap(cq->ucontext, dev->nic_info.unmapped_db,
+ dev->nic_info.db_page_size);
+ }
+ dev->cq_tbl[cq->id] = NULL;
+
+ kfree(cq);
+ return status;
+}
+
+static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
+{
+ int status = -EINVAL;
+
+ if (qp->id < OCRDMA_MAX_QP && dev->qp_tbl[qp->id] == NULL) {
+ dev->qp_tbl[qp->id] = qp;
+ status = 0;
+ }
+ return status;
+}
+
+static void ocrdma_del_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
+{
+ dev->qp_tbl[qp->id] = NULL;
+}
+
+static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,
+ struct ib_qp_init_attr *attrs)
+{
+ if (attrs->qp_type != IB_QPT_GSI &&
+ attrs->qp_type != IB_QPT_RC &&
+ attrs->qp_type != IB_QPT_UD) {
+ ocrdma_err("%s(%d) unsupported qp type=0x%x requested\n",
+ __func__, dev->id, attrs->qp_type);
+ return -EINVAL;
+ }
+ if (attrs->cap.max_send_wr > dev->attr.max_wqe) {
+ ocrdma_err("%s(%d) unsupported send_wr=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_send_wr);
+ ocrdma_err("%s(%d) supported send_wr=0x%x\n",
+ __func__, dev->id, dev->attr.max_wqe);
+ return -EINVAL;
+ }
+ if (!attrs->srq && (attrs->cap.max_recv_wr > dev->attr.max_rqe)) {
+ ocrdma_err("%s(%d) unsupported recv_wr=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_recv_wr);
+ ocrdma_err("%s(%d) supported recv_wr=0x%x\n",
+ __func__, dev->id, dev->attr.max_rqe);
+ return -EINVAL;
+ }
+ if (attrs->cap.max_inline_data > dev->attr.max_inline_data) {
+ ocrdma_err("%s(%d) unsupported inline data size=0x%x"
+ " requested\n", __func__, dev->id,
+ attrs->cap.max_inline_data);
+ ocrdma_err("%s(%d) supported inline data size=0x%x\n",
+ __func__, dev->id, dev->attr.max_inline_data);
+ return -EINVAL;
+ }
+ if (attrs->cap.max_send_sge > dev->attr.max_send_sge) {
+ ocrdma_err("%s(%d) unsupported send_sge=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_send_sge);
+ ocrdma_err("%s(%d) supported send_sge=0x%x\n",
+ __func__, dev->id, dev->attr.max_send_sge);
+ return -EINVAL;
+ }
+ if (attrs->cap.max_recv_sge > dev->attr.max_recv_sge) {
+ ocrdma_err("%s(%d) unsupported recv_sge=0x%x requested\n",
+ __func__, dev->id, attrs->cap.max_recv_sge);
+ ocrdma_err("%s(%d) supported recv_sge=0x%x\n",
+ __func__, dev->id, dev->attr.max_recv_sge);
+ return -EINVAL;
+ }
+ /* unprivileged user space cannot create special QP */
+ if (ibpd->uobject && attrs->qp_type == IB_QPT_GSI) {
+ ocrdma_err
+ ("%s(%d) Userspace can't create special QPs of type=0x%x\n",
+ __func__, dev->id, attrs->qp_type);
+ return -EINVAL;
+ }
+ /* allow creating only one GSI type of QP */
+ if (attrs->qp_type == IB_QPT_GSI && dev->gsi_qp_created) {
+ ocrdma_err("%s(%d) GSI special QPs already created.\n",
+ __func__, dev->id);
+ return -EINVAL;
+ }
+ /* verify consumer QPs are not trying to use GSI QP's CQ */
+ if ((attrs->qp_type != IB_QPT_GSI) && (dev->gsi_qp_created)) {
+ if ((dev->gsi_sqcq == get_ocrdma_cq(attrs->send_cq)) ||
+ (dev->gsi_sqcq == get_ocrdma_cq(attrs->send_cq))) {
+ ocrdma_err("%s(%d) Consumer QP cannot use GSI CQs.\n",
+ __func__, dev->id);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
+ struct ib_udata *udata, int dpp_offset,
+ int dpp_credit_lmt, int srq)
+{
+ int status = 0;
+ u64 usr_db;
+ struct ocrdma_create_qp_uresp uresp;
+ struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+
+ memset(&uresp, 0, sizeof(uresp));
+ usr_db = dev->nic_info.unmapped_db +
+ (pd->id * dev->nic_info.db_page_size);
+ uresp.qp_id = qp->id;
+ uresp.sq_dbid = qp->sq.dbid;
+ uresp.num_sq_pages = 1;
+ uresp.sq_page_size = qp->sq.len;
+ uresp.sq_page_addr[0] = qp->sq.pa;
+ uresp.num_wqe_allocated = qp->sq.max_cnt;
+ if (!srq) {
+ uresp.rq_dbid = qp->rq.dbid;
+ uresp.num_rq_pages = 1;
+ uresp.rq_page_size = qp->rq.len;
+ uresp.rq_page_addr[0] = qp->rq.pa;
+ uresp.num_rqe_allocated = qp->rq.max_cnt;
+ }
+ uresp.db_page_addr = usr_db;
+ uresp.db_page_size = dev->nic_info.db_page_size;
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ uresp.db_sq_offset = OCRDMA_DB_GEN2_SQ_OFFSET;
+ uresp.db_rq_offset = ((qp->id & 0xFFFF) < 128) ?
+ OCRDMA_DB_GEN2_RQ1_OFFSET : OCRDMA_DB_GEN2_RQ2_OFFSET;
+ uresp.db_shift = (qp->id < 128) ? 24 : 16;
+ } else {
+ uresp.db_sq_offset = OCRDMA_DB_SQ_OFFSET;
+ uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET;
+ uresp.db_shift = 16;
+ }
+ uresp.free_wqe_delta = qp->sq.free_delta;
+ uresp.free_rqe_delta = qp->rq.free_delta;
+
+ if (qp->dpp_enabled) {
+ uresp.dpp_credit = dpp_credit_lmt;
+ uresp.dpp_offset = dpp_offset;
+ }
+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (status) {
+ ocrdma_err("%s(%d) user copy error.\n", __func__, dev->id);
+ goto err;
+ }
+ status = ocrdma_add_mmap(pd->uctx, uresp.sq_page_addr[0],
+ uresp.sq_page_size);
+ if (status)
+ goto err;
+
+ if (!srq) {
+ status = ocrdma_add_mmap(pd->uctx, uresp.rq_page_addr[0],
+ uresp.rq_page_size);
+ if (status)
+ goto rq_map_err;
+ }
+ return status;
+rq_map_err:
+ ocrdma_del_mmap(pd->uctx, uresp.sq_page_addr[0], uresp.sq_page_size);
+err:
+ return status;
+}
+
+static void ocrdma_set_qp_db(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
+ struct ocrdma_pd *pd)
+{
+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ qp->sq_db = dev->nic_info.db +
+ (pd->id * dev->nic_info.db_page_size) +
+ OCRDMA_DB_GEN2_SQ_OFFSET;
+ qp->rq_db = dev->nic_info.db +
+ (pd->id * dev->nic_info.db_page_size) +
+ ((qp->id < 128) ?
+ OCRDMA_DB_GEN2_RQ1_OFFSET : OCRDMA_DB_GEN2_RQ2_OFFSET);
+ } else {
+ qp->sq_db = dev->nic_info.db +
+ (pd->id * dev->nic_info.db_page_size) +
+ OCRDMA_DB_SQ_OFFSET;
+ qp->rq_db = dev->nic_info.db +
+ (pd->id * dev->nic_info.db_page_size) +
+ OCRDMA_DB_RQ_OFFSET;
+ }
+}
+
+static int ocrdma_alloc_wr_id_tbl(struct ocrdma_qp *qp)
+{
+ qp->wqe_wr_id_tbl =
+ kzalloc(sizeof(*(qp->wqe_wr_id_tbl)) * qp->sq.max_cnt,
+ GFP_KERNEL);
+ if (qp->wqe_wr_id_tbl == NULL)
+ return -ENOMEM;
+ qp->rqe_wr_id_tbl =
+ kzalloc(sizeof(u64) * qp->rq.max_cnt, GFP_KERNEL);
+ if (qp->rqe_wr_id_tbl == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp,
+ struct ocrdma_pd *pd,
+ struct ib_qp_init_attr *attrs)
+{
+ qp->pd = pd;
+ spin_lock_init(&qp->q_lock);
+ INIT_LIST_HEAD(&qp->sq_entry);
+ INIT_LIST_HEAD(&qp->rq_entry);
+
+ qp->qp_type = attrs->qp_type;
+ qp->cap_flags = OCRDMA_QP_INB_RD | OCRDMA_QP_INB_WR;
+ qp->max_inline_data = attrs->cap.max_inline_data;
+ qp->sq.max_sges = attrs->cap.max_send_sge;
+ qp->rq.max_sges = attrs->cap.max_recv_sge;
+ qp->state = OCRDMA_QPS_RST;
+}
+
+static void ocrdma_set_qp_use_cnt(struct ocrdma_qp *qp, struct ocrdma_pd *pd)
+{
+ atomic_inc(&pd->use_cnt);
+ atomic_inc(&qp->sq_cq->use_cnt);
+ atomic_inc(&qp->rq_cq->use_cnt);
+ if (qp->srq)
+ atomic_inc(&qp->srq->use_cnt);
+ qp->ibqp.qp_num = qp->id;
+}
+
+static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev,
+ struct ib_qp_init_attr *attrs)
+{
+ if (attrs->qp_type == IB_QPT_GSI) {
+ dev->gsi_qp_created = 1;
+ dev->gsi_sqcq = get_ocrdma_cq(attrs->send_cq);
+ dev->gsi_rqcq = get_ocrdma_cq(attrs->recv_cq);
+ }
+}
+
+struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *attrs,
+ struct ib_udata *udata)
+{
+ int status;
+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+ struct ocrdma_qp *qp;
+ struct ocrdma_dev *dev = pd->dev;
+ struct ocrdma_create_qp_ureq ureq;
+ u16 dpp_credit_lmt, dpp_offset;
+
+ status = ocrdma_check_qp_params(ibpd, dev, attrs);
+ if (status)
+ goto gen_err;
+
+ memset(&ureq, 0, sizeof(ureq));
+ if (udata) {
+ if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))
+ return ERR_PTR(-EFAULT);
+ }
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ if (!qp) {
+ status = -ENOMEM;
+ goto gen_err;
+ }
+ qp->dev = dev;
+ ocrdma_set_qp_init_params(qp, pd, attrs);
+
+ mutex_lock(&dev->dev_lock);
+ status = ocrdma_mbx_create_qp(qp, attrs, ureq.enable_dpp_cq,
+ ureq.dpp_cq_id,
+ &dpp_offset, &dpp_credit_lmt);
+ if (status)
+ goto mbx_err;
+
+ /* user space QP's wr_id table are managed in library */
+ if (udata == NULL) {
+ qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |
+ OCRDMA_QP_FAST_REG);
+ status = ocrdma_alloc_wr_id_tbl(qp);
+ if (status)
+ goto map_err;
+ }
+
+ status = ocrdma_add_qpn_map(dev, qp);
+ if (status)
+ goto map_err;
+ ocrdma_set_qp_db(dev, qp, pd);
+ if (udata) {
+ status = ocrdma_copy_qp_uresp(qp, udata, dpp_offset,
+ dpp_credit_lmt,
+ (attrs->srq != NULL));
+ if (status)
+ goto cpy_err;
+ }
+ ocrdma_store_gsi_qp_cq(dev, attrs);
+ ocrdma_set_qp_use_cnt(qp, pd);
+ mutex_unlock(&dev->dev_lock);
+ return &qp->ibqp;
+
+cpy_err:
+ ocrdma_del_qpn_map(dev, qp);
+map_err:
+ ocrdma_mbx_destroy_qp(dev, qp);
+mbx_err:
+ mutex_unlock(&dev->dev_lock);
+ kfree(qp->wqe_wr_id_tbl);
+ kfree(qp->rqe_wr_id_tbl);
+ kfree(qp);
+ ocrdma_err("%s(%d) error=%d\n", __func__, dev->id, status);
+gen_err:
+ return ERR_PTR(status);
+}
+
+int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask)
+{
+ int status = 0;
+ struct ocrdma_qp *qp;
+ struct ocrdma_dev *dev;
+ enum ib_qp_state old_qps;
+
+ qp = get_ocrdma_qp(ibqp);
+ dev = qp->dev;
+ if (attr_mask & IB_QP_STATE)
+ status = ocrdma_qp_state_machine(qp, attr->qp_state, &old_qps);
+ /* if new and previous states are same hw doesn't need to
+ * know about it.
+ */
+ if (status < 0)
+ return status;
+ status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask, old_qps);
+ return status;
+}
+
+int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ unsigned long flags;
+ int status = -EINVAL;
+ struct ocrdma_qp *qp;
+ struct ocrdma_dev *dev;
+ enum ib_qp_state old_qps, new_qps;
+
+ qp = get_ocrdma_qp(ibqp);
+ dev = qp->dev;
+
+ /* syncronize with multiple context trying to change, retrive qps */
+ mutex_lock(&dev->dev_lock);
+ /* syncronize with wqe, rqe posting and cqe processing contexts */
+ spin_lock_irqsave(&qp->q_lock, flags);
+ old_qps = get_ibqp_state(qp->state);
+ if (attr_mask & IB_QP_STATE)
+ new_qps = attr->qp_state;
+ else
+ new_qps = old_qps;
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+
+ if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) {
+ ocrdma_err("%s(%d) invalid attribute mask=0x%x specified for "
+ "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
+ __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
+ old_qps, new_qps);
+ goto param_err;
+ }
+
+ status = _ocrdma_modify_qp(ibqp, attr, attr_mask);
+ if (status > 0)
+ status = 0;
+param_err:
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
+static enum ib_mtu ocrdma_mtu_int_to_enum(u16 mtu)
+{
+ switch (mtu) {
+ case 256:
+ return IB_MTU_256;
+ case 512:
+ return IB_MTU_512;
+ case 1024:
+ return IB_MTU_1024;
+ case 2048:
+ return IB_MTU_2048;
+ case 4096:
+ return IB_MTU_4096;
+ default:
+ return IB_MTU_1024;
+ }
+}
+
+static int ocrdma_to_ib_qp_acc_flags(int qp_cap_flags)
+{
+ int ib_qp_acc_flags = 0;
+
+ if (qp_cap_flags & OCRDMA_QP_INB_WR)
+ ib_qp_acc_flags |= IB_ACCESS_REMOTE_WRITE;
+ if (qp_cap_flags & OCRDMA_QP_INB_RD)
+ ib_qp_acc_flags |= IB_ACCESS_LOCAL_WRITE;
+ return ib_qp_acc_flags;
+}
+
+int ocrdma_query_qp(struct ib_qp *ibqp,
+ struct ib_qp_attr *qp_attr,
+ int attr_mask, struct ib_qp_init_attr *qp_init_attr)
+{
+ int status;
+ u32 qp_state;
+ struct ocrdma_qp_params params;
+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
+ struct ocrdma_dev *dev = qp->dev;
+
+ memset(&params, 0, sizeof(params));
+ mutex_lock(&dev->dev_lock);
+ status = ocrdma_mbx_query_qp(dev, qp, &params);
+ mutex_unlock(&dev->dev_lock);
+ if (status)
+ goto mbx_err;
+ qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);
+ qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);
+ qp_attr->path_mtu =
+ ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &
+ OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>
+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT;
+ qp_attr->path_mig_state = IB_MIG_MIGRATED;
+ qp_attr->rq_psn = params.hop_lmt_rq_psn & OCRDMA_QP_PARAMS_RQ_PSN_MASK;
+ qp_attr->sq_psn = params.tclass_sq_psn & OCRDMA_QP_PARAMS_SQ_PSN_MASK;
+ qp_attr->dest_qp_num =
+ params.ack_to_rnr_rtc_dest_qpn & OCRDMA_QP_PARAMS_DEST_QPN_MASK;
+
+ qp_attr->qp_access_flags = ocrdma_to_ib_qp_acc_flags(qp->cap_flags);
+ qp_attr->cap.max_send_wr = qp->sq.max_cnt - 1;
+ qp_attr->cap.max_recv_wr = qp->rq.max_cnt - 1;
+ qp_attr->cap.max_send_sge = qp->sq.max_sges;
+ qp_attr->cap.max_recv_sge = qp->rq.max_sges;
+ qp_attr->cap.max_inline_data = dev->attr.max_inline_data;
+ qp_init_attr->cap = qp_attr->cap;
+ memcpy(&qp_attr->ah_attr.grh.dgid, &params.dgid[0],
+ sizeof(params.dgid));
+ qp_attr->ah_attr.grh.flow_label = params.rnt_rc_sl_fl &
+ OCRDMA_QP_PARAMS_FLOW_LABEL_MASK;
+ qp_attr->ah_attr.grh.sgid_index = qp->sgid_idx;
+ qp_attr->ah_attr.grh.hop_limit = (params.hop_lmt_rq_psn &
+ OCRDMA_QP_PARAMS_HOP_LMT_MASK) >>
+ OCRDMA_QP_PARAMS_HOP_LMT_SHIFT;
+ qp_attr->ah_attr.grh.traffic_class = (params.tclass_sq_psn &
+ OCRDMA_QP_PARAMS_SQ_PSN_MASK) >>
+ OCRDMA_QP_PARAMS_TCLASS_SHIFT;
+
+ qp_attr->ah_attr.ah_flags = IB_AH_GRH;
+ qp_attr->ah_attr.port_num = 1;
+ qp_attr->ah_attr.sl = (params.rnt_rc_sl_fl &
+ OCRDMA_QP_PARAMS_SL_MASK) >>
+ OCRDMA_QP_PARAMS_SL_SHIFT;
+ qp_attr->timeout = (params.ack_to_rnr_rtc_dest_qpn &
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_MASK) >>
+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT;
+ qp_attr->rnr_retry = (params.ack_to_rnr_rtc_dest_qpn &
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK) >>
+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT;
+ qp_attr->retry_cnt =
+ (params.rnt_rc_sl_fl & OCRDMA_QP_PARAMS_RETRY_CNT_MASK) >>
+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT;
+ qp_attr->min_rnr_timer = 0;
+ qp_attr->pkey_index = 0;
+ qp_attr->port_num = 1;
+ qp_attr->ah_attr.src_path_bits = 0;
+ qp_attr->ah_attr.static_rate = 0;
+ qp_attr->alt_pkey_index = 0;
+ qp_attr->alt_port_num = 0;
+ qp_attr->alt_timeout = 0;
+ memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));
+ qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>
+ OCRDMA_QP_PARAMS_STATE_SHIFT;
+ qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;
+ qp_attr->max_dest_rd_atomic =
+ params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;
+ qp_attr->max_rd_atomic =
+ params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;
+ qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &
+ OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;
+mbx_err:
+ return status;
+}
+
+static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, int idx)
+{
+ int i = idx / 32;
+ unsigned int mask = (1 << (idx % 32));
+
+ if (srq->idx_bit_fields[i] & mask)
+ srq->idx_bit_fields[i] &= ~mask;
+ else
+ srq->idx_bit_fields[i] |= mask;
+}
+
+static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q)
+{
+ int free_cnt;
+ if (q->head >= q->tail)
+ free_cnt = (q->max_cnt - q->head) + q->tail;
+ else
+ free_cnt = q->tail - q->head;
+ if (q->free_delta)
+ free_cnt -= q->free_delta;
+ return free_cnt;
+}
+
+static int is_hw_sq_empty(struct ocrdma_qp *qp)
+{
+ return (qp->sq.tail == qp->sq.head &&
+ ocrdma_hwq_free_cnt(&qp->sq) ? 1 : 0);
+}
+
+static int is_hw_rq_empty(struct ocrdma_qp *qp)
+{
+ return (qp->rq.tail == qp->rq.head) ? 1 : 0;
+}
+
+static void *ocrdma_hwq_head(struct ocrdma_qp_hwq_info *q)
+{
+ return q->va + (q->head * q->entry_size);
+}
+
+static void *ocrdma_hwq_head_from_idx(struct ocrdma_qp_hwq_info *q,
+ u32 idx)
+{
+ return q->va + (idx * q->entry_size);
+}
+
+static void ocrdma_hwq_inc_head(struct ocrdma_qp_hwq_info *q)
+{
+ q->head = (q->head + 1) & q->max_wqe_idx;
+}
+
+static void ocrdma_hwq_inc_tail(struct ocrdma_qp_hwq_info *q)
+{
+ q->tail = (q->tail + 1) & q->max_wqe_idx;
+}
+
+/* discard the cqe for a given QP */
+static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq)
+{
+ unsigned long cq_flags;
+ unsigned long flags;
+ int discard_cnt = 0;
+ u32 cur_getp, stop_getp;
+ struct ocrdma_cqe *cqe;
+ u32 qpn = 0;
+
+ spin_lock_irqsave(&cq->cq_lock, cq_flags);
+
+ /* traverse through the CQEs in the hw CQ,
+ * find the matching CQE for a given qp,
+ * mark the matching one discarded by clearing qpn.
+ * ring the doorbell in the poll_cq() as
+ * we don't complete out of order cqe.
+ */
+
+ cur_getp = cq->getp;
+ /* find upto when do we reap the cq. */
+ stop_getp = cur_getp;
+ do {
+ if (is_hw_sq_empty(qp) && (!qp->srq && is_hw_rq_empty(qp)))
+ break;
+
+ cqe = cq->va + cur_getp;
+ /* if (a) done reaping whole hw cq, or
+ * (b) qp_xq becomes empty.
+ * then exit
+ */
+ qpn = cqe->cmn.qpn & OCRDMA_CQE_QPN_MASK;
+ /* if previously discarded cqe found, skip that too. */
+ /* check for matching qp */
+ if (qpn == 0 || qpn != qp->id)
+ goto skip_cqe;
+
+ /* mark cqe discarded so that it is not picked up later
+ * in the poll_cq().
+ */
+ discard_cnt += 1;
+ cqe->cmn.qpn = 0;
+ if (is_cqe_for_sq(cqe))
+ ocrdma_hwq_inc_tail(&qp->sq);
+ else {
+ if (qp->srq) {
+ spin_lock_irqsave(&qp->srq->q_lock, flags);
+ ocrdma_hwq_inc_tail(&qp->srq->rq);
+ ocrdma_srq_toggle_bit(qp->srq, cur_getp);
+ spin_unlock_irqrestore(&qp->srq->q_lock, flags);
+
+ } else
+ ocrdma_hwq_inc_tail(&qp->rq);
+ }
+skip_cqe:
+ cur_getp = (cur_getp + 1) % cq->max_hw_cqe;
+ } while (cur_getp != stop_getp);
+ spin_unlock_irqrestore(&cq->cq_lock, cq_flags);
+}
+
+static void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
+{
+ int found = false;
+ unsigned long flags;
+ struct ocrdma_dev *dev = qp->dev;
+ /* sync with any active CQ poll */
+
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
+ if (found)
+ list_del(&qp->sq_entry);
+ if (!qp->srq) {
+ found = ocrdma_is_qp_in_rq_flushlist(qp->rq_cq, qp);
+ if (found)
+ list_del(&qp->rq_entry);
+ }
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
+}
+
+int ocrdma_destroy_qp(struct ib_qp *ibqp)
+{
+ int status;
+ struct ocrdma_pd *pd;
+ struct ocrdma_qp *qp;
+ struct ocrdma_dev *dev;
+ struct ib_qp_attr attrs;
+ int attr_mask = IB_QP_STATE;
+ unsigned long flags;
+
+ qp = get_ocrdma_qp(ibqp);
+ dev = qp->dev;
+
+ attrs.qp_state = IB_QPS_ERR;
+ pd = qp->pd;
+
+ /* change the QP state to ERROR */
+ _ocrdma_modify_qp(ibqp, &attrs, attr_mask);
+
+ /* ensure that CQEs for newly created QP (whose id may be same with
+ * one which just getting destroyed are same), dont get
+ * discarded until the old CQEs are discarded.
+ */
+ mutex_lock(&dev->dev_lock);
+ status = ocrdma_mbx_destroy_qp(dev, qp);
+
+ /*
+ * acquire CQ lock while destroy is in progress, in order to
+ * protect against proessing in-flight CQEs for this QP.
+ */
+ spin_lock_irqsave(&qp->sq_cq->cq_lock, flags);
+ if (qp->rq_cq && (qp->rq_cq != qp->sq_cq))
+ spin_lock(&qp->rq_cq->cq_lock);
+
+ ocrdma_del_qpn_map(dev, qp);
+
+ if (qp->rq_cq && (qp->rq_cq != qp->sq_cq))
+ spin_unlock(&qp->rq_cq->cq_lock);
+ spin_unlock_irqrestore(&qp->sq_cq->cq_lock, flags);
+
+ if (!pd->uctx) {
+ ocrdma_discard_cqes(qp, qp->sq_cq);
+ ocrdma_discard_cqes(qp, qp->rq_cq);
+ }
+ mutex_unlock(&dev->dev_lock);
+
+ if (pd->uctx) {
+ ocrdma_del_mmap(pd->uctx, (u64) qp->sq.pa, qp->sq.len);
+ if (!qp->srq)
+ ocrdma_del_mmap(pd->uctx, (u64) qp->rq.pa, qp->rq.len);
+ }
+
+ ocrdma_del_flush_qp(qp);
+
+ atomic_dec(&qp->pd->use_cnt);
+ atomic_dec(&qp->sq_cq->use_cnt);
+ atomic_dec(&qp->rq_cq->use_cnt);
+ if (qp->srq)
+ atomic_dec(&qp->srq->use_cnt);
+ kfree(qp->wqe_wr_id_tbl);
+ kfree(qp->rqe_wr_id_tbl);
+ kfree(qp);
+ return status;
+}
+
+static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)
+{
+ int status;
+ struct ocrdma_create_srq_uresp uresp;
+
+ uresp.rq_dbid = srq->rq.dbid;
+ uresp.num_rq_pages = 1;
+ uresp.rq_page_addr[0] = srq->rq.pa;
+ uresp.rq_page_size = srq->rq.len;
+ uresp.db_page_addr = srq->dev->nic_info.unmapped_db +
+ (srq->pd->id * srq->dev->nic_info.db_page_size);
+ uresp.db_page_size = srq->dev->nic_info.db_page_size;
+ uresp.num_rqe_allocated = srq->rq.max_cnt;
+ uresp.free_rqe_delta = 1;
+ if (srq->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ1_OFFSET;
+ uresp.db_shift = 24;
+ } else {
+ uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET;
+ uresp.db_shift = 16;
+ }
+
+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (status)
+ return status;
+ status = ocrdma_add_mmap(srq->pd->uctx, uresp.rq_page_addr[0],
+ uresp.rq_page_size);
+ if (status)
+ return status;
+ return status;
+}
+
+struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ int status = -ENOMEM;
+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+ struct ocrdma_dev *dev = pd->dev;
+ struct ocrdma_srq *srq;
+
+ if (init_attr->attr.max_sge > dev->attr.max_recv_sge)
+ return ERR_PTR(-EINVAL);
+ if (init_attr->attr.max_wr > dev->attr.max_rqe)
+ return ERR_PTR(-EINVAL);
+
+ srq = kzalloc(sizeof(*srq), GFP_KERNEL);
+ if (!srq)
+ return ERR_PTR(status);
+
+ spin_lock_init(&srq->q_lock);
+ srq->dev = dev;
+ srq->pd = pd;
+ srq->db = dev->nic_info.db + (pd->id * dev->nic_info.db_page_size);
+ status = ocrdma_mbx_create_srq(srq, init_attr, pd);
+ if (status)
+ goto err;
+
+ if (udata == NULL) {
+ srq->rqe_wr_id_tbl = kzalloc(sizeof(u64) * srq->rq.max_cnt,
+ GFP_KERNEL);
+ if (srq->rqe_wr_id_tbl == NULL)
+ goto arm_err;
+
+ srq->bit_fields_len = (srq->rq.max_cnt / 32) +
+ (srq->rq.max_cnt % 32 ? 1 : 0);
+ srq->idx_bit_fields =
+ kmalloc(srq->bit_fields_len * sizeof(u32), GFP_KERNEL);
+ if (srq->idx_bit_fields == NULL)
+ goto arm_err;
+ memset(srq->idx_bit_fields, 0xff,
+ srq->bit_fields_len * sizeof(u32));
+ }
+
+ if (init_attr->attr.srq_limit) {
+ status = ocrdma_mbx_modify_srq(srq, &init_attr->attr);
+ if (status)
+ goto arm_err;
+ }
+
+ atomic_set(&srq->use_cnt, 0);
+ if (udata) {
+ status = ocrdma_copy_srq_uresp(srq, udata);
+ if (status)
+ goto arm_err;
+ }
+
+ atomic_inc(&pd->use_cnt);
+ return &srq->ibsrq;
+
+arm_err:
+ ocrdma_mbx_destroy_srq(dev, srq);
+err:
+ kfree(srq->rqe_wr_id_tbl);
+ kfree(srq->idx_bit_fields);
+ kfree(srq);
+ return ERR_PTR(status);
+}
+
+int ocrdma_modify_srq(struct ib_srq *ibsrq,
+ struct ib_srq_attr *srq_attr,
+ enum ib_srq_attr_mask srq_attr_mask,
+ struct ib_udata *udata)
+{
+ int status = 0;
+ struct ocrdma_srq *srq;
+
+ srq = get_ocrdma_srq(ibsrq);
+ if (srq_attr_mask & IB_SRQ_MAX_WR)
+ status = -EINVAL;
+ else
+ status = ocrdma_mbx_modify_srq(srq, srq_attr);
+ return status;
+}
+
+int ocrdma_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ int status;
+ struct ocrdma_srq *srq;
+
+ srq = get_ocrdma_srq(ibsrq);
+ status = ocrdma_mbx_query_srq(srq, srq_attr);
+ return status;
+}
+
+int ocrdma_destroy_srq(struct ib_srq *ibsrq)
+{
+ int status;
+ struct ocrdma_srq *srq;
+ struct ocrdma_dev *dev;
+
+ srq = get_ocrdma_srq(ibsrq);
+ dev = srq->dev;
+ if (atomic_read(&srq->use_cnt)) {
+ ocrdma_err("%s(%d) err, srq=0x%x in use\n",
+ __func__, dev->id, srq->id);
+ return -EAGAIN;
+ }
+
+ status = ocrdma_mbx_destroy_srq(dev, srq);
+
+ if (srq->pd->uctx)
+ ocrdma_del_mmap(srq->pd->uctx, (u64) srq->rq.pa, srq->rq.len);
+
+ atomic_dec(&srq->pd->use_cnt);
+ kfree(srq->idx_bit_fields);
+ kfree(srq->rqe_wr_id_tbl);
+ kfree(srq);
+ return status;
+}
+
+/* unprivileged verbs and their support functions. */
+static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,
+ struct ocrdma_hdr_wqe *hdr,
+ struct ib_send_wr *wr)
+{
+ struct ocrdma_ewqe_ud_hdr *ud_hdr =
+ (struct ocrdma_ewqe_ud_hdr *)(hdr + 1);
+ struct ocrdma_ah *ah = get_ocrdma_ah(wr->wr.ud.ah);
+
+ ud_hdr->rsvd_dest_qpn = wr->wr.ud.remote_qpn;
+ if (qp->qp_type == IB_QPT_GSI)
+ ud_hdr->qkey = qp->qkey;
+ else
+ ud_hdr->qkey = wr->wr.ud.remote_qkey;
+ ud_hdr->rsvd_ahid = ah->id;
+}
+
+static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,
+ struct ocrdma_sge *sge, int num_sge,
+ struct ib_sge *sg_list)
+{
+ int i;
+
+ for (i = 0; i < num_sge; i++) {
+ sge[i].lrkey = sg_list[i].lkey;
+ sge[i].addr_lo = sg_list[i].addr;
+ sge[i].addr_hi = upper_32_bits(sg_list[i].addr);
+ sge[i].len = sg_list[i].length;
+ hdr->total_len += sg_list[i].length;
+ }
+ if (num_sge == 0)
+ memset(sge, 0, sizeof(*sge));
+}
+
+static int ocrdma_build_inline_sges(struct ocrdma_qp *qp,
+ struct ocrdma_hdr_wqe *hdr,
+ struct ocrdma_sge *sge,
+ struct ib_send_wr *wr, u32 wqe_size)
+{
+ if (wr->send_flags & IB_SEND_INLINE) {
+ if (wr->sg_list[0].length > qp->max_inline_data) {
+ ocrdma_err("%s() supported_len=0x%x,"
+ " unspported len req=0x%x\n", __func__,
+ qp->max_inline_data, wr->sg_list[0].length);
+ return -EINVAL;
+ }
+ memcpy(sge,
+ (void *)(unsigned long)wr->sg_list[0].addr,
+ wr->sg_list[0].length);
+ hdr->total_len = wr->sg_list[0].length;
+ wqe_size += roundup(hdr->total_len, OCRDMA_WQE_ALIGN_BYTES);
+ hdr->cw |= (OCRDMA_TYPE_INLINE << OCRDMA_WQE_TYPE_SHIFT);
+ } else {
+ ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list);
+ if (wr->num_sge)
+ wqe_size += (wr->num_sge * sizeof(struct ocrdma_sge));
+ else
+ wqe_size += sizeof(struct ocrdma_sge);
+ hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);
+ }
+ hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT);
+ return 0;
+}
+
+static int ocrdma_build_send(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
+ struct ib_send_wr *wr)
+{
+ int status;
+ struct ocrdma_sge *sge;
+ u32 wqe_size = sizeof(*hdr);
+
+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) {
+ ocrdma_build_ud_hdr(qp, hdr, wr);
+ sge = (struct ocrdma_sge *)(hdr + 2);
+ wqe_size += sizeof(struct ocrdma_ewqe_ud_hdr);
+ } else
+ sge = (struct ocrdma_sge *)(hdr + 1);
+
+ status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size);
+ return status;
+}
+
+static int ocrdma_build_write(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
+ struct ib_send_wr *wr)
+{
+ int status;
+ struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1);
+ struct ocrdma_sge *sge = ext_rw + 1;
+ u32 wqe_size = sizeof(*hdr) + sizeof(*ext_rw);
+
+ status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size);
+ if (status)
+ return status;
+ ext_rw->addr_lo = wr->wr.rdma.remote_addr;
+ ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);
+ ext_rw->lrkey = wr->wr.rdma.rkey;
+ ext_rw->len = hdr->total_len;
+ return 0;
+}
+
+static void ocrdma_build_read(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
+ struct ib_send_wr *wr)
+{
+ struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1);
+ struct ocrdma_sge *sge = ext_rw + 1;
+ u32 wqe_size = ((wr->num_sge + 1) * sizeof(struct ocrdma_sge)) +
+ sizeof(struct ocrdma_hdr_wqe);
+
+ ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list);
+ hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT);
+ hdr->cw |= (OCRDMA_READ << OCRDMA_WQE_OPCODE_SHIFT);
+ hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);
+
+ ext_rw->addr_lo = wr->wr.rdma.remote_addr;
+ ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);
+ ext_rw->lrkey = wr->wr.rdma.rkey;
+ ext_rw->len = hdr->total_len;
+}
+
+static void ocrdma_ring_sq_db(struct ocrdma_qp *qp)
+{
+ u32 val = qp->sq.dbid | (1 << 16);
+
+ iowrite32(val, qp->sq_db);
+}
+
+int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ int status = 0;
+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
+ struct ocrdma_hdr_wqe *hdr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->q_lock, flags);
+ if (qp->state != OCRDMA_QPS_RTS && qp->state != OCRDMA_QPS_SQD) {
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ return -EINVAL;
+ }
+
+ while (wr) {
+ if (ocrdma_hwq_free_cnt(&qp->sq) == 0 ||
+ wr->num_sge > qp->sq.max_sges) {
+ status = -ENOMEM;
+ break;
+ }
+ hdr = ocrdma_hwq_head(&qp->sq);
+ hdr->cw = 0;
+ if (wr->send_flags & IB_SEND_SIGNALED)
+ hdr->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT);
+ if (wr->send_flags & IB_SEND_FENCE)
+ hdr->cw |=
+ (OCRDMA_FLAG_FENCE_L << OCRDMA_WQE_FLAGS_SHIFT);
+ if (wr->send_flags & IB_SEND_SOLICITED)
+ hdr->cw |=
+ (OCRDMA_FLAG_SOLICIT << OCRDMA_WQE_FLAGS_SHIFT);
+ hdr->total_len = 0;
+ switch (wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);
+ hdr->immdt = ntohl(wr->ex.imm_data);
+ case IB_WR_SEND:
+ hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT);
+ ocrdma_build_send(qp, hdr, wr);
+ break;
+ case IB_WR_SEND_WITH_INV:
+ hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
+ hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT);
+ hdr->lkey = wr->ex.invalidate_rkey;
+ status = ocrdma_build_send(qp, hdr, wr);
+ break;
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);
+ hdr->immdt = ntohl(wr->ex.imm_data);
+ case IB_WR_RDMA_WRITE:
+ hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
+ status = ocrdma_build_write(qp, hdr, wr);
+ break;
+ case IB_WR_RDMA_READ_WITH_INV:
+ hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
+ case IB_WR_RDMA_READ:
+ ocrdma_build_read(qp, hdr, wr);
+ break;
+ case IB_WR_LOCAL_INV:
+ hdr->cw |=
+ (OCRDMA_LKEY_INV << OCRDMA_WQE_OPCODE_SHIFT);
+ hdr->cw |= (sizeof(struct ocrdma_hdr_wqe) /
+ OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT;
+ hdr->lkey = wr->ex.invalidate_rkey;
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ }
+ if (status) {
+ *bad_wr = wr;
+ break;
+ }
+ if (wr->send_flags & IB_SEND_SIGNALED)
+ qp->wqe_wr_id_tbl[qp->sq.head].signaled = 1;
+ else
+ qp->wqe_wr_id_tbl[qp->sq.head].signaled = 0;
+ qp->wqe_wr_id_tbl[qp->sq.head].wrid = wr->wr_id;
+ ocrdma_cpu_to_le32(hdr, ((hdr->cw >> OCRDMA_WQE_SIZE_SHIFT) &
+ OCRDMA_WQE_SIZE_MASK) * OCRDMA_WQE_STRIDE);
+ /* make sure wqe is written before adapter can access it */
+ wmb();
+ /* inform hw to start processing it */
+ ocrdma_ring_sq_db(qp);
+
+ /* update pointer, counter for next wr */
+ ocrdma_hwq_inc_head(&qp->sq);
+ wr = wr->next;
+ }
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ return status;
+}
+
+static void ocrdma_ring_rq_db(struct ocrdma_qp *qp)
+{
+ u32 val = qp->rq.dbid | (1 << OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp));
+
+ iowrite32(val, qp->rq_db);
+}
+
+static void ocrdma_build_rqe(struct ocrdma_hdr_wqe *rqe, struct ib_recv_wr *wr,
+ u16 tag)
+{
+ u32 wqe_size = 0;
+ struct ocrdma_sge *sge;
+ if (wr->num_sge)
+ wqe_size = (wr->num_sge * sizeof(*sge)) + sizeof(*rqe);
+ else
+ wqe_size = sizeof(*sge) + sizeof(*rqe);
+
+ rqe->cw = ((wqe_size / OCRDMA_WQE_STRIDE) <<
+ OCRDMA_WQE_SIZE_SHIFT);
+ rqe->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT);
+ rqe->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);
+ rqe->total_len = 0;
+ rqe->rsvd_tag = tag;
+ sge = (struct ocrdma_sge *)(rqe + 1);
+ ocrdma_build_sges(rqe, sge, wr->num_sge, wr->sg_list);
+ ocrdma_cpu_to_le32(rqe, wqe_size);
+}
+
+int ocrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ int status = 0;
+ unsigned long flags;
+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
+ struct ocrdma_hdr_wqe *rqe;
+
+ spin_lock_irqsave(&qp->q_lock, flags);
+ if (qp->state == OCRDMA_QPS_RST || qp->state == OCRDMA_QPS_ERR) {
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+ while (wr) {
+ if (ocrdma_hwq_free_cnt(&qp->rq) == 0 ||
+ wr->num_sge > qp->rq.max_sges) {
+ *bad_wr = wr;
+ status = -ENOMEM;
+ break;
+ }
+ rqe = ocrdma_hwq_head(&qp->rq);
+ ocrdma_build_rqe(rqe, wr, 0);
+
+ qp->rqe_wr_id_tbl[qp->rq.head] = wr->wr_id;
+ /* make sure rqe is written before adapter can access it */
+ wmb();
+
+ /* inform hw to start processing it */
+ ocrdma_ring_rq_db(qp);
+
+ /* update pointer, counter for next wr */
+ ocrdma_hwq_inc_head(&qp->rq);
+ wr = wr->next;
+ }
+ spin_unlock_irqrestore(&qp->q_lock, flags);
+ return status;
+}
+
+/* cqe for srq's rqe can potentially arrive out of order.
+ * index gives the entry in the shadow table where to store
+ * the wr_id. tag/index is returned in cqe to reference back
+ * for a given rqe.
+ */
+static int ocrdma_srq_get_idx(struct ocrdma_srq *srq)
+{
+ int row = 0;
+ int indx = 0;
+
+ for (row = 0; row < srq->bit_fields_len; row++) {
+ if (srq->idx_bit_fields[row]) {
+ indx = ffs(srq->idx_bit_fields[row]);
+ indx = (row * 32) + (indx - 1);
+ if (indx >= srq->rq.max_cnt)
+ BUG();
+ ocrdma_srq_toggle_bit(srq, indx);
+ break;
+ }
+ }
+
+ if (row == srq->bit_fields_len)
+ BUG();
+ return indx;
+}
+
+static void ocrdma_ring_srq_db(struct ocrdma_srq *srq)
+{
+ u32 val = srq->rq.dbid | (1 << 16);
+
+ iowrite32(val, srq->db + OCRDMA_DB_GEN2_SRQ_OFFSET);
+}
+
+int ocrdma_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ int status = 0;
+ unsigned long flags;
+ struct ocrdma_srq *srq;
+ struct ocrdma_hdr_wqe *rqe;
+ u16 tag;
+
+ srq = get_ocrdma_srq(ibsrq);
+
+ spin_lock_irqsave(&srq->q_lock, flags);
+ while (wr) {
+ if (ocrdma_hwq_free_cnt(&srq->rq) == 0 ||
+ wr->num_sge > srq->rq.max_sges) {
+ status = -ENOMEM;
+ *bad_wr = wr;
+ break;
+ }
+ tag = ocrdma_srq_get_idx(srq);
+ rqe = ocrdma_hwq_head(&srq->rq);
+ ocrdma_build_rqe(rqe, wr, tag);
+
+ srq->rqe_wr_id_tbl[tag] = wr->wr_id;
+ /* make sure rqe is written before adapter can perform DMA */
+ wmb();
+ /* inform hw to start processing it */
+ ocrdma_ring_srq_db(srq);
+ /* update pointer, counter for next wr */
+ ocrdma_hwq_inc_head(&srq->rq);
+ wr = wr->next;
+ }
+ spin_unlock_irqrestore(&srq->q_lock, flags);
+ return status;
+}
+
+static enum ib_wc_status ocrdma_to_ibwc_err(u16 status)
+{
+ enum ib_wc_status ibwc_status = IB_WC_GENERAL_ERR;
+
+ switch (status) {
+ case OCRDMA_CQE_GENERAL_ERR:
+ ibwc_status = IB_WC_GENERAL_ERR;
+ break;
+ case OCRDMA_CQE_LOC_LEN_ERR:
+ ibwc_status = IB_WC_LOC_LEN_ERR;
+ break;
+ case OCRDMA_CQE_LOC_QP_OP_ERR:
+ ibwc_status = IB_WC_LOC_QP_OP_ERR;
+ break;
+ case OCRDMA_CQE_LOC_EEC_OP_ERR:
+ ibwc_status = IB_WC_LOC_EEC_OP_ERR;
+ break;
+ case OCRDMA_CQE_LOC_PROT_ERR:
+ ibwc_status = IB_WC_LOC_PROT_ERR;
+ break;
+ case OCRDMA_CQE_WR_FLUSH_ERR:
+ ibwc_status = IB_WC_WR_FLUSH_ERR;
+ break;
+ case OCRDMA_CQE_MW_BIND_ERR:
+ ibwc_status = IB_WC_MW_BIND_ERR;
+ break;
+ case OCRDMA_CQE_BAD_RESP_ERR:
+ ibwc_status = IB_WC_BAD_RESP_ERR;
+ break;
+ case OCRDMA_CQE_LOC_ACCESS_ERR:
+ ibwc_status = IB_WC_LOC_ACCESS_ERR;
+ break;
+ case OCRDMA_CQE_REM_INV_REQ_ERR:
+ ibwc_status = IB_WC_REM_INV_REQ_ERR;
+ break;
+ case OCRDMA_CQE_REM_ACCESS_ERR:
+ ibwc_status = IB_WC_REM_ACCESS_ERR;
+ break;
+ case OCRDMA_CQE_REM_OP_ERR:
+ ibwc_status = IB_WC_REM_OP_ERR;
+ break;
+ case OCRDMA_CQE_RETRY_EXC_ERR:
+ ibwc_status = IB_WC_RETRY_EXC_ERR;
+ break;
+ case OCRDMA_CQE_RNR_RETRY_EXC_ERR:
+ ibwc_status = IB_WC_RNR_RETRY_EXC_ERR;
+ break;
+ case OCRDMA_CQE_LOC_RDD_VIOL_ERR:
+ ibwc_status = IB_WC_LOC_RDD_VIOL_ERR;
+ break;
+ case OCRDMA_CQE_REM_INV_RD_REQ_ERR:
+ ibwc_status = IB_WC_REM_INV_RD_REQ_ERR;
+ break;
+ case OCRDMA_CQE_REM_ABORT_ERR:
+ ibwc_status = IB_WC_REM_ABORT_ERR;
+ break;
+ case OCRDMA_CQE_INV_EECN_ERR:
+ ibwc_status = IB_WC_INV_EECN_ERR;
+ break;
+ case OCRDMA_CQE_INV_EEC_STATE_ERR:
+ ibwc_status = IB_WC_INV_EEC_STATE_ERR;
+ break;
+ case OCRDMA_CQE_FATAL_ERR:
+ ibwc_status = IB_WC_FATAL_ERR;
+ break;
+ case OCRDMA_CQE_RESP_TIMEOUT_ERR:
+ ibwc_status = IB_WC_RESP_TIMEOUT_ERR;
+ break;
+ default:
+ ibwc_status = IB_WC_GENERAL_ERR;
+ break;
+ };
+ return ibwc_status;
+}
+
+static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
+ u32 wqe_idx)
+{
+ struct ocrdma_hdr_wqe *hdr;
+ struct ocrdma_sge *rw;
+ int opcode;
+
+ hdr = ocrdma_hwq_head_from_idx(&qp->sq, wqe_idx);
+
+ ibwc->wr_id = qp->wqe_wr_id_tbl[wqe_idx].wrid;
+ /* Undo the hdr->cw swap */
+ opcode = le32_to_cpu(hdr->cw) & OCRDMA_WQE_OPCODE_MASK;
+ switch (opcode) {
+ case OCRDMA_WRITE:
+ ibwc->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case OCRDMA_READ:
+ rw = (struct ocrdma_sge *)(hdr + 1);
+ ibwc->opcode = IB_WC_RDMA_READ;
+ ibwc->byte_len = rw->len;
+ break;
+ case OCRDMA_SEND:
+ ibwc->opcode = IB_WC_SEND;
+ break;
+ case OCRDMA_LKEY_INV:
+ ibwc->opcode = IB_WC_LOCAL_INV;
+ break;
+ default:
+ ibwc->status = IB_WC_GENERAL_ERR;
+ ocrdma_err("%s() invalid opcode received = 0x%x\n",
+ __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
+ break;
+ };
+}
+
+static void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp,
+ struct ocrdma_cqe *cqe)
+{
+ if (is_cqe_for_sq(cqe)) {
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) &
+ ~OCRDMA_CQE_STATUS_MASK);
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) |
+ (OCRDMA_CQE_WR_FLUSH_ERR <<
+ OCRDMA_CQE_STATUS_SHIFT));
+ } else {
+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) {
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) &
+ ~OCRDMA_CQE_UD_STATUS_MASK);
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) |
+ (OCRDMA_CQE_WR_FLUSH_ERR <<
+ OCRDMA_CQE_UD_STATUS_SHIFT));
+ } else {
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) &
+ ~OCRDMA_CQE_STATUS_MASK);
+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(
+ cqe->flags_status_srcqpn) |
+ (OCRDMA_CQE_WR_FLUSH_ERR <<
+ OCRDMA_CQE_STATUS_SHIFT));
+ }
+ }
+}
+
+static bool ocrdma_update_err_cqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,
+ struct ocrdma_qp *qp, int status)
+{
+ bool expand = false;
+
+ ibwc->byte_len = 0;
+ ibwc->qp = &qp->ibqp;
+ ibwc->status = ocrdma_to_ibwc_err(status);
+
+ ocrdma_flush_qp(qp);
+ ocrdma_qp_state_machine(qp, IB_QPS_ERR, NULL);
+
+ /* if wqe/rqe pending for which cqe needs to be returned,
+ * trigger inflating it.
+ */
+ if (!is_hw_rq_empty(qp) || !is_hw_sq_empty(qp)) {
+ expand = true;
+ ocrdma_set_cqe_status_flushed(qp, cqe);
+ }
+ return expand;
+}
+
+static int ocrdma_update_err_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,
+ struct ocrdma_qp *qp, int status)
+{
+ ibwc->opcode = IB_WC_RECV;
+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];
+ ocrdma_hwq_inc_tail(&qp->rq);
+
+ return ocrdma_update_err_cqe(ibwc, cqe, qp, status);
+}
+
+static int ocrdma_update_err_scqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,
+ struct ocrdma_qp *qp, int status)
+{
+ ocrdma_update_wc(qp, ibwc, qp->sq.tail);
+ ocrdma_hwq_inc_tail(&qp->sq);
+
+ return ocrdma_update_err_cqe(ibwc, cqe, qp, status);
+}
+
+
+static bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp,
+ struct ocrdma_cqe *cqe, struct ib_wc *ibwc,
+ bool *polled, bool *stop)
+{
+ bool expand;
+ int status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+
+ /* when hw sq is empty, but rq is not empty, so we continue
+ * to keep the cqe in order to get the cq event again.
+ */
+ if (is_hw_sq_empty(qp) && !is_hw_rq_empty(qp)) {
+ /* when cq for rq and sq is same, it is safe to return
+ * flush cqe for RQEs.
+ */
+ if (!qp->srq && (qp->sq_cq == qp->rq_cq)) {
+ *polled = true;
+ status = OCRDMA_CQE_WR_FLUSH_ERR;
+ expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status);
+ } else {
+ /* stop processing further cqe as this cqe is used for
+ * triggering cq event on buddy cq of RQ.
+ * When QP is destroyed, this cqe will be removed
+ * from the cq's hardware q.
+ */
+ *polled = false;
+ *stop = true;
+ expand = false;
+ }
+ } else {
+ *polled = true;
+ expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status);
+ }
+ return expand;
+}
+
+static bool ocrdma_poll_success_scqe(struct ocrdma_qp *qp,
+ struct ocrdma_cqe *cqe,
+ struct ib_wc *ibwc, bool *polled)
+{
+ bool expand = false;
+ int tail = qp->sq.tail;
+ u32 wqe_idx;
+
+ if (!qp->wqe_wr_id_tbl[tail].signaled) {
+ expand = true; /* CQE cannot be consumed yet */
+ *polled = false; /* WC cannot be consumed yet */
+ } else {
+ ibwc->status = IB_WC_SUCCESS;
+ ibwc->wc_flags = 0;
+ ibwc->qp = &qp->ibqp;
+ ocrdma_update_wc(qp, ibwc, tail);
+ *polled = true;
+ wqe_idx = le32_to_cpu(cqe->wq.wqeidx) & OCRDMA_CQE_WQEIDX_MASK;
+ if (tail != wqe_idx)
+ expand = true; /* Coalesced CQE can't be consumed yet */
+ }
+ ocrdma_hwq_inc_tail(&qp->sq);
+ return expand;
+}
+
+static bool ocrdma_poll_scqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
+ struct ib_wc *ibwc, bool *polled, bool *stop)
+{
+ int status;
+ bool expand;
+
+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+
+ if (status == OCRDMA_CQE_SUCCESS)
+ expand = ocrdma_poll_success_scqe(qp, cqe, ibwc, polled);
+ else
+ expand = ocrdma_poll_err_scqe(qp, cqe, ibwc, polled, stop);
+ return expand;
+}
+
+static int ocrdma_update_ud_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe)
+{
+ int status;
+
+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_UD_STATUS_MASK) >> OCRDMA_CQE_UD_STATUS_SHIFT;
+ ibwc->src_qp = le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_SRCQP_MASK;
+ ibwc->pkey_index = le32_to_cpu(cqe->ud.rxlen_pkey) &
+ OCRDMA_CQE_PKEY_MASK;
+ ibwc->wc_flags = IB_WC_GRH;
+ ibwc->byte_len = (le32_to_cpu(cqe->ud.rxlen_pkey) >>
+ OCRDMA_CQE_UD_XFER_LEN_SHIFT);
+ return status;
+}
+
+static void ocrdma_update_free_srq_cqe(struct ib_wc *ibwc,
+ struct ocrdma_cqe *cqe,
+ struct ocrdma_qp *qp)
+{
+ unsigned long flags;
+ struct ocrdma_srq *srq;
+ u32 wqe_idx;
+
+ srq = get_ocrdma_srq(qp->ibqp.srq);
+ wqe_idx = le32_to_cpu(cqe->rq.buftag_qpn) >> OCRDMA_CQE_BUFTAG_SHIFT;
+ ibwc->wr_id = srq->rqe_wr_id_tbl[wqe_idx];
+ spin_lock_irqsave(&srq->q_lock, flags);
+ ocrdma_srq_toggle_bit(srq, wqe_idx);
+ spin_unlock_irqrestore(&srq->q_lock, flags);
+ ocrdma_hwq_inc_tail(&srq->rq);
+}
+
+static bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
+ struct ib_wc *ibwc, bool *polled, bool *stop,
+ int status)
+{
+ bool expand;
+
+ /* when hw_rq is empty, but wq is not empty, so continue
+ * to keep the cqe to get the cq event again.
+ */
+ if (is_hw_rq_empty(qp) && !is_hw_sq_empty(qp)) {
+ if (!qp->srq && (qp->sq_cq == qp->rq_cq)) {
+ *polled = true;
+ status = OCRDMA_CQE_WR_FLUSH_ERR;
+ expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status);
+ } else {
+ *polled = false;
+ *stop = true;
+ expand = false;
+ }
+ } else
+ expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status);
+ return expand;
+}
+
+static void ocrdma_poll_success_rcqe(struct ocrdma_qp *qp,
+ struct ocrdma_cqe *cqe, struct ib_wc *ibwc)
+{
+ ibwc->opcode = IB_WC_RECV;
+ ibwc->qp = &qp->ibqp;
+ ibwc->status = IB_WC_SUCCESS;
+
+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI)
+ ocrdma_update_ud_rcqe(ibwc, cqe);
+ else
+ ibwc->byte_len = le32_to_cpu(cqe->rq.rxlen);
+
+ if (is_cqe_imm(cqe)) {
+ ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt));
+ ibwc->wc_flags |= IB_WC_WITH_IMM;
+ } else if (is_cqe_wr_imm(cqe)) {
+ ibwc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt));
+ ibwc->wc_flags |= IB_WC_WITH_IMM;
+ } else if (is_cqe_invalidated(cqe)) {
+ ibwc->ex.invalidate_rkey = le32_to_cpu(cqe->rq.lkey_immdt);
+ ibwc->wc_flags |= IB_WC_WITH_INVALIDATE;
+ }
+ if (qp->ibqp.srq)
+ ocrdma_update_free_srq_cqe(ibwc, cqe, qp);
+ else {
+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];
+ ocrdma_hwq_inc_tail(&qp->rq);
+ }
+}
+
+static bool ocrdma_poll_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
+ struct ib_wc *ibwc, bool *polled, bool *stop)
+{
+ int status;
+ bool expand = false;
+
+ ibwc->wc_flags = 0;
+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI)
+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_UD_STATUS_MASK) >>
+ OCRDMA_CQE_UD_STATUS_SHIFT;
+ else
+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+
+ if (status == OCRDMA_CQE_SUCCESS) {
+ *polled = true;
+ ocrdma_poll_success_rcqe(qp, cqe, ibwc);
+ } else {
+ expand = ocrdma_poll_err_rcqe(qp, cqe, ibwc, polled, stop,
+ status);
+ }
+ return expand;
+}
+
+static void ocrdma_change_cq_phase(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe,
+ u16 cur_getp)
+{
+ if (cq->phase_change) {
+ if (cur_getp == 0)
+ cq->phase = (~cq->phase & OCRDMA_CQE_VALID);
+ } else
+ /* clear valid bit */
+ cqe->flags_status_srcqpn = 0;
+}
+
+static int ocrdma_poll_hwcq(struct ocrdma_cq *cq, int num_entries,
+ struct ib_wc *ibwc)
+{
+ u16 qpn = 0;
+ int i = 0;
+ bool expand = false;
+ int polled_hw_cqes = 0;
+ struct ocrdma_qp *qp = NULL;
+ struct ocrdma_dev *dev = cq->dev;
+ struct ocrdma_cqe *cqe;
+ u16 cur_getp; bool polled = false; bool stop = false;
+
+ cur_getp = cq->getp;
+ while (num_entries) {
+ cqe = cq->va + cur_getp;
+ /* check whether valid cqe or not */
+ if (!is_cqe_valid(cq, cqe))
+ break;
+ qpn = (le32_to_cpu(cqe->cmn.qpn) & OCRDMA_CQE_QPN_MASK);
+ /* ignore discarded cqe */
+ if (qpn == 0)
+ goto skip_cqe;
+ qp = dev->qp_tbl[qpn];
+ BUG_ON(qp == NULL);
+
+ if (is_cqe_for_sq(cqe)) {
+ expand = ocrdma_poll_scqe(qp, cqe, ibwc, &polled,
+ &stop);
+ } else {
+ expand = ocrdma_poll_rcqe(qp, cqe, ibwc, &polled,
+ &stop);
+ }
+ if (expand)
+ goto expand_cqe;
+ if (stop)
+ goto stop_cqe;
+ /* clear qpn to avoid duplicate processing by discard_cqe() */
+ cqe->cmn.qpn = 0;
+skip_cqe:
+ polled_hw_cqes += 1;
+ cur_getp = (cur_getp + 1) % cq->max_hw_cqe;
+ ocrdma_change_cq_phase(cq, cqe, cur_getp);
+expand_cqe:
+ if (polled) {
+ num_entries -= 1;
+ i += 1;
+ ibwc = ibwc + 1;
+ polled = false;
+ }
+ }
+stop_cqe:
+ cq->getp = cur_getp;
+ if (polled_hw_cqes || expand || stop) {
+ ocrdma_ring_cq_db(dev, cq->id, cq->armed, cq->solicited,
+ polled_hw_cqes);
+ }
+ return i;
+}
+
+/* insert error cqe if the QP's SQ or RQ's CQ matches the CQ under poll. */
+static int ocrdma_add_err_cqe(struct ocrdma_cq *cq, int num_entries,
+ struct ocrdma_qp *qp, struct ib_wc *ibwc)
+{
+ int err_cqes = 0;
+
+ while (num_entries) {
+ if (is_hw_sq_empty(qp) && is_hw_rq_empty(qp))
+ break;
+ if (!is_hw_sq_empty(qp) && qp->sq_cq == cq) {
+ ocrdma_update_wc(qp, ibwc, qp->sq.tail);
+ ocrdma_hwq_inc_tail(&qp->sq);
+ } else if (!is_hw_rq_empty(qp) && qp->rq_cq == cq) {
+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];
+ ocrdma_hwq_inc_tail(&qp->rq);
+ } else
+ return err_cqes;
+ ibwc->byte_len = 0;
+ ibwc->status = IB_WC_WR_FLUSH_ERR;
+ ibwc = ibwc + 1;
+ err_cqes += 1;
+ num_entries -= 1;
+ }
+ return err_cqes;
+}
+
+int ocrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ int cqes_to_poll = num_entries;
+ struct ocrdma_cq *cq = NULL;
+ unsigned long flags;
+ struct ocrdma_dev *dev;
+ int num_os_cqe = 0, err_cqes = 0;
+ struct ocrdma_qp *qp;
+
+ cq = get_ocrdma_cq(ibcq);
+ dev = cq->dev;
+
+ /* poll cqes from adapter CQ */
+ spin_lock_irqsave(&cq->cq_lock, flags);
+ num_os_cqe = ocrdma_poll_hwcq(cq, cqes_to_poll, wc);
+ spin_unlock_irqrestore(&cq->cq_lock, flags);
+ cqes_to_poll -= num_os_cqe;
+
+ if (cqes_to_poll) {
+ wc = wc + num_os_cqe;
+ /* adapter returns single error cqe when qp moves to
+ * error state. So insert error cqes with wc_status as
+ * FLUSHED for pending WQEs and RQEs of QP's SQ and RQ
+ * respectively which uses this CQ.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ if (cqes_to_poll == 0)
+ break;
+ err_cqes = ocrdma_add_err_cqe(cq, cqes_to_poll, qp, wc);
+ cqes_to_poll -= err_cqes;
+ num_os_cqe += err_cqes;
+ wc = wc + err_cqes;
+ }
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
+ }
+ return num_os_cqe;
+}
+
+int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)
+{
+ struct ocrdma_cq *cq;
+ unsigned long flags;
+ struct ocrdma_dev *dev;
+ u16 cq_id;
+ u16 cur_getp;
+ struct ocrdma_cqe *cqe;
+
+ cq = get_ocrdma_cq(ibcq);
+ cq_id = cq->id;
+ dev = cq->dev;
+
+ spin_lock_irqsave(&cq->cq_lock, flags);
+ if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED)
+ cq->armed = true;
+ if (cq_flags & IB_CQ_SOLICITED)
+ cq->solicited = true;
+
+ cur_getp = cq->getp;
+ cqe = cq->va + cur_getp;
+
+ /* check whether any valid cqe exist or not, if not then safe to
+ * arm. If cqe is not yet consumed, then let it get consumed and then
+ * we arm it to avoid false interrupts.
+ */
+ if (!is_cqe_valid(cq, cqe) || cq->arm_needed) {
+ cq->arm_needed = false;
+ ocrdma_ring_cq_db(dev, cq_id, cq->armed, cq->solicited, 0);
+ }
+ spin_unlock_irqrestore(&cq->cq_lock, flags);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
new file mode 100644
index 0000000..e648343
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
@@ -0,0 +1,94 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_VERBS_H__
+#define __OCRDMA_VERBS_H__
+
+#include <linux/version.h>
+int ocrdma_post_send(struct ib_qp *, struct ib_send_wr *,
+ struct ib_send_wr **bad_wr);
+int ocrdma_post_recv(struct ib_qp *, struct ib_recv_wr *,
+ struct ib_recv_wr **bad_wr);
+
+int ocrdma_poll_cq(struct ib_cq *, int num_entries, struct ib_wc *wc);
+int ocrdma_arm_cq(struct ib_cq *, enum ib_cq_notify_flags flags);
+
+int ocrdma_query_device(struct ib_device *, struct ib_device_attr *props);
+int ocrdma_query_port(struct ib_device *, u8 port, struct ib_port_attr *props);
+int ocrdma_modify_port(struct ib_device *, u8 port, int mask,
+ struct ib_port_modify *props);
+
+void ocrdma_get_guid(struct ocrdma_dev *, u8 *guid);
+int ocrdma_query_gid(struct ib_device *, u8 port,
+ int index, union ib_gid *gid);
+int ocrdma_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey);
+
+struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *,
+ struct ib_udata *);
+int ocrdma_dealloc_ucontext(struct ib_ucontext *);
+
+int ocrdma_mmap(struct ib_ucontext *, struct vm_area_struct *vma);
+
+struct ib_pd *ocrdma_alloc_pd(struct ib_device *,
+ struct ib_ucontext *, struct ib_udata *);
+int ocrdma_dealloc_pd(struct ib_pd *pd);
+
+struct ib_cq *ocrdma_create_cq(struct ib_device *, int entries, int vector,
+ struct ib_ucontext *, struct ib_udata *);
+int ocrdma_resize_cq(struct ib_cq *, int cqe, struct ib_udata *);
+int ocrdma_destroy_cq(struct ib_cq *);
+
+struct ib_qp *ocrdma_create_qp(struct ib_pd *,
+ struct ib_qp_init_attr *attrs,
+ struct ib_udata *);
+int _ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,
+ int attr_mask);
+int ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+int ocrdma_query_qp(struct ib_qp *,
+ struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *);
+int ocrdma_destroy_qp(struct ib_qp *);
+
+struct ib_srq *ocrdma_create_srq(struct ib_pd *, struct ib_srq_init_attr *,
+ struct ib_udata *);
+int ocrdma_modify_srq(struct ib_srq *, struct ib_srq_attr *,
+ enum ib_srq_attr_mask, struct ib_udata *);
+int ocrdma_query_srq(struct ib_srq *, struct ib_srq_attr *);
+int ocrdma_destroy_srq(struct ib_srq *);
+int ocrdma_post_srq_recv(struct ib_srq *, struct ib_recv_wr *,
+ struct ib_recv_wr **bad_recv_wr);
+
+int ocrdma_dereg_mr(struct ib_mr *);
+struct ib_mr *ocrdma_get_dma_mr(struct ib_pd *, int acc);
+struct ib_mr *ocrdma_reg_kernel_mr(struct ib_pd *,
+ struct ib_phys_buf *buffer_list,
+ int num_phys_buf, int acc, u64 *iova_start);
+struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *, u64 start, u64 length,
+ u64 virt, int acc, struct ib_udata *);
+
+#endif /* __OCRDMA_VERBS_H__ */
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 6b811e3..7e62f41 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -530,8 +530,6 @@ struct qib_pportdata {
/* qib_lflags driver is waiting for */
u32 state_wanted;
spinlock_t lflags_lock;
- /* number of (port-specific) interrupts for this port -- saturates... */
- u32 int_counter;
/* ref count for each pkey */
atomic_t pkeyrefs[4];
@@ -543,24 +541,26 @@ struct qib_pportdata {
u64 *statusp;
/* SendDMA related entries */
- spinlock_t sdma_lock;
- struct qib_sdma_state sdma_state;
- unsigned long sdma_buf_jiffies;
+
+ /* read mostly */
struct qib_sdma_desc *sdma_descq;
+ struct qib_sdma_state sdma_state;
+ dma_addr_t sdma_descq_phys;
+ volatile __le64 *sdma_head_dma; /* DMA'ed by chip */
+ dma_addr_t sdma_head_phys;
+ u16 sdma_descq_cnt;
+
+ /* read/write using lock */
+ spinlock_t sdma_lock ____cacheline_aligned_in_smp;
+ struct list_head sdma_activelist;
u64 sdma_descq_added;
u64 sdma_descq_removed;
- u16 sdma_descq_cnt;
u16 sdma_descq_tail;
u16 sdma_descq_head;
- u16 sdma_next_intr;
- u16 sdma_reset_wait;
u8 sdma_generation;
- struct tasklet_struct sdma_sw_clean_up_task;
- struct list_head sdma_activelist;
- dma_addr_t sdma_descq_phys;
- volatile __le64 *sdma_head_dma; /* DMA'ed by chip */
- dma_addr_t sdma_head_phys;
+ struct tasklet_struct sdma_sw_clean_up_task
+ ____cacheline_aligned_in_smp;
wait_queue_head_t state_wait; /* for state_wanted */
@@ -873,7 +873,14 @@ struct qib_devdata {
* pio_writing.
*/
spinlock_t pioavail_lock;
-
+ /*
+ * index of last buffer to optimize search for next
+ */
+ u32 last_pio;
+ /*
+ * min kernel pio buffer to optimize search
+ */
+ u32 min_kernel_pio;
/*
* Shadow copies of registers; size indicates read access size.
* Most of them are readonly, but some are write-only register,
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 6fc9365..8895cfe 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -38,6 +38,7 @@
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include <linux/prefetch.h>
#include "qib.h"
@@ -481,8 +482,10 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
etail = qib_hdrget_index(rhf_addr);
updegr = 1;
if (tlen > sizeof(*hdr) ||
- etype >= RCVHQ_RCV_TYPE_NON_KD)
+ etype >= RCVHQ_RCV_TYPE_NON_KD) {
ebuf = qib_get_egrbuf(rcd, etail);
+ prefetch_range(ebuf, tlen - sizeof(*hdr));
+ }
}
if (!eflags) {
u16 lrh_len = be16_to_cpu(hdr->lrh[2]) << 2;
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index d0c64d5..4d352b9 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -3132,6 +3132,7 @@ static void get_6120_chip_params(struct qib_devdata *dd)
val = qib_read_kreg64(dd, kr_sendpiobufcnt);
dd->piobcnt2k = val & ~0U;
dd->piobcnt4k = val >> 32;
+ dd->last_pio = dd->piobcnt4k + dd->piobcnt2k - 1;
/* these may be adjusted in init_chip_wc_pat() */
dd->pio2kbase = (u32 __iomem *)
(((char __iomem *)dd->kregbase) + dd->pio2k_bufbase);
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 3c722f7..86a0ba7 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -4157,6 +4157,7 @@ static int qib_init_7220_variables(struct qib_devdata *dd)
dd->cspec->sdmabufcnt;
dd->lastctxt_piobuf = dd->cspec->lastbuf_for_pio - sbufs;
dd->cspec->lastbuf_for_pio--; /* range is <= , not < */
+ dd->last_pio = dd->cspec->lastbuf_for_pio;
dd->pbufsctxt = dd->lastctxt_piobuf /
(dd->cfgctxts - dd->first_user_ctxt);
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 060b960..c881e74 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -6379,6 +6379,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
dd->cspec->sdmabufcnt;
dd->lastctxt_piobuf = dd->cspec->lastbuf_for_pio - sbufs;
dd->cspec->lastbuf_for_pio--; /* range is <= , not < */
+ dd->last_pio = dd->cspec->lastbuf_for_pio;
dd->pbufsctxt = (dd->cfgctxts > dd->first_user_ctxt) ?
dd->lastctxt_piobuf / (dd->cfgctxts - dd->first_user_ctxt) : 0;
@@ -7708,7 +7709,7 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd)
ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
msleep(20);
/* Set Frequency Loop Bandwidth */
- ibsd_wr_allchans(ppd, 2, (7 << 5), BMASK(8, 5));
+ ibsd_wr_allchans(ppd, 2, (15 << 5), BMASK(8, 5));
/* Enable Frequency Loop */
ibsd_wr_allchans(ppd, 2, (1 << 4), BMASK(4, 4));
/* Set Timing Loop Bandwidth */
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index cf0cd30..dc14e10 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -102,6 +102,8 @@ void qib_set_ctxtcnt(struct qib_devdata *dd)
dd->cfgctxts = qib_cfgctxts;
else
dd->cfgctxts = dd->ctxtcnt;
+ dd->freectxts = (dd->first_user_ctxt > dd->cfgctxts) ? 0 :
+ dd->cfgctxts - dd->first_user_ctxt;
}
/*
@@ -402,7 +404,6 @@ static void enable_chip(struct qib_devdata *dd)
if (rcd)
dd->f_rcvctrl(rcd->ppd, rcvmask, i);
}
- dd->freectxts = dd->cfgctxts - dd->first_user_ctxt;
}
static void verify_interrupt(unsigned long opaque)
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index c4ff788..4339021 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -396,6 +396,7 @@ static int get_linkdowndefaultstate(struct qib_pportdata *ppd)
static int check_mkey(struct qib_ibport *ibp, struct ib_smp *smp, int mad_flags)
{
+ int valid_mkey = 0;
int ret = 0;
/* Is the mkey in the process of expiring? */
@@ -406,23 +407,36 @@ static int check_mkey(struct qib_ibport *ibp, struct ib_smp *smp, int mad_flags)
ibp->mkeyprot = 0;
}
- /* M_Key checking depends on Portinfo:M_Key_protect_bits */
- if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && ibp->mkey != 0 &&
- ibp->mkey != smp->mkey &&
- (smp->method == IB_MGMT_METHOD_SET ||
- smp->method == IB_MGMT_METHOD_TRAP_REPRESS ||
- (smp->method == IB_MGMT_METHOD_GET && ibp->mkeyprot >= 2))) {
- if (ibp->mkey_violations != 0xFFFF)
- ++ibp->mkey_violations;
- if (!ibp->mkey_lease_timeout && ibp->mkey_lease_period)
- ibp->mkey_lease_timeout = jiffies +
- ibp->mkey_lease_period * HZ;
- /* Generate a trap notice. */
- qib_bad_mkey(ibp, smp);
- ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
- } else if (ibp->mkey_lease_timeout)
+ if ((mad_flags & IB_MAD_IGNORE_MKEY) || ibp->mkey == 0 ||
+ ibp->mkey == smp->mkey)
+ valid_mkey = 1;
+
+ /* Unset lease timeout on any valid Get/Set/TrapRepress */
+ if (valid_mkey && ibp->mkey_lease_timeout &&
+ (smp->method == IB_MGMT_METHOD_GET ||
+ smp->method == IB_MGMT_METHOD_SET ||
+ smp->method == IB_MGMT_METHOD_TRAP_REPRESS))
ibp->mkey_lease_timeout = 0;
+ if (!valid_mkey) {
+ switch (smp->method) {
+ case IB_MGMT_METHOD_GET:
+ /* Bad mkey not a violation below level 2 */
+ if (ibp->mkeyprot < 2)
+ break;
+ case IB_MGMT_METHOD_SET:
+ case IB_MGMT_METHOD_TRAP_REPRESS:
+ if (ibp->mkey_violations != 0xFFFF)
+ ++ibp->mkey_violations;
+ if (!ibp->mkey_lease_timeout && ibp->mkey_lease_period)
+ ibp->mkey_lease_timeout = jiffies +
+ ibp->mkey_lease_period * HZ;
+ /* Generate a trap notice. */
+ qib_bad_mkey(ibp, smp);
+ ret = 1;
+ }
+ }
+
return ret;
}
@@ -450,6 +464,7 @@ static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
ibp = to_iport(ibdev, port_num);
ret = check_mkey(ibp, smp, 0);
if (ret)
+ ret = IB_MAD_RESULT_FAILURE;
goto bail;
}
}
@@ -631,7 +646,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
struct qib_devdata *dd;
struct qib_pportdata *ppd;
struct qib_ibport *ibp;
- char clientrereg = 0;
+ u8 clientrereg = (pip->clientrereg_resv_subnetto & 0x80);
unsigned long flags;
u16 lid, smlid;
u8 lwe;
@@ -781,12 +796,6 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
ibp->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
- if (pip->clientrereg_resv_subnetto & 0x80) {
- clientrereg = 1;
- event.event = IB_EVENT_CLIENT_REREGISTER;
- ib_dispatch_event(&event);
- }
-
/*
* Do the port state change now that the other link parameters
* have been set.
@@ -844,10 +853,15 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
smp->status |= IB_SMP_INVALID_FIELD;
}
+ if (clientrereg) {
+ event.event = IB_EVENT_CLIENT_REREGISTER;
+ ib_dispatch_event(&event);
+ }
+
ret = subn_get_portinfo(smp, ibdev, port);
- if (clientrereg)
- pip->clientrereg_resv_subnetto |= 0x80;
+ /* restore re-reg bit per o14-12.2.1 */
+ pip->clientrereg_resv_subnetto |= clientrereg;
goto get_only;
@@ -1835,6 +1849,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
port_num && port_num <= ibdev->phys_port_cnt &&
port != port_num)
(void) check_mkey(to_iport(ibdev, port_num), smp, 0);
+ ret = IB_MAD_RESULT_FAILURE;
goto bail;
}
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 7e7e16f..1ce56b5 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -1038,6 +1038,11 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
goto bail_swq;
}
RCU_INIT_POINTER(qp->next, NULL);
+ qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), GFP_KERNEL);
+ if (!qp->s_hdr) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_qp;
+ }
qp->timeout_jiffies =
usecs_to_jiffies((4096UL * (1UL << qp->timeout)) /
1000UL);
@@ -1159,6 +1164,7 @@ bail_ip:
vfree(qp->r_rq.wq);
free_qpn(&dev->qpn_table, qp->ibqp.qp_num);
bail_qp:
+ kfree(qp->s_hdr);
kfree(qp);
bail_swq:
vfree(swq);
@@ -1214,6 +1220,7 @@ int qib_destroy_qp(struct ib_qp *ibqp)
else
vfree(qp->r_rq.wq);
vfree(qp->s_wq);
+ kfree(qp->s_hdr);
kfree(qp);
return 0;
}
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 765b4cb..b641416 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -244,9 +244,9 @@ int qib_make_rc_req(struct qib_qp *qp)
int ret = 0;
int delta;
- ohdr = &qp->s_hdr.u.oth;
+ ohdr = &qp->s_hdr->u.oth;
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
+ ohdr = &qp->s_hdr->u.l.oth;
/*
* The lock is needed to synchronize between the sending tasklet,
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index b4b37e4..c0ee7e0 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -688,17 +688,17 @@ void qib_make_ruc_header(struct qib_qp *qp, struct qib_other_headers *ohdr,
nwords = (qp->s_cur_size + extra_bytes) >> 2;
lrh0 = QIB_LRH_BTH;
if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,
+ qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr->u.l.grh,
&qp->remote_ah_attr.grh,
qp->s_hdrwords, nwords);
lrh0 = QIB_LRH_GRH;
}
lrh0 |= ibp->sl_to_vl[qp->remote_ah_attr.sl] << 12 |
qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid |
+ qp->s_hdr->lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr->lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ qp->s_hdr->lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr->lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid |
qp->remote_ah_attr.src_path_bits);
bth0 |= qib_get_pkey(ibp, qp->s_pkey_index);
bth0 |= extra_bytes << 20;
@@ -758,7 +758,7 @@ void qib_do_send(struct work_struct *work)
* If the packet cannot be sent now, return and
* the send tasklet will be woken up later.
*/
- if (qib_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
+ if (qib_verbs_send(qp, qp->s_hdr, qp->s_hdrwords,
qp->s_cur_sge, qp->s_cur_size))
break;
/* Record that s_hdr is empty. */
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index dae5160..dd9cd49 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -503,8 +503,11 @@ static ssize_t show_nctxts(struct device *device,
struct qib_devdata *dd = dd_from_dev(dev);
/* Return the number of user ports (contexts) available. */
- return scnprintf(buf, PAGE_SIZE, "%u\n", dd->cfgctxts -
- dd->first_user_ctxt);
+ /* The calculation below deals with a special case where
+ * cfgctxts is set to 1 on a single-port board. */
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ (dd->first_user_ctxt > dd->cfgctxts) ? 0 :
+ (dd->cfgctxts - dd->first_user_ctxt));
}
static ssize_t show_nfreectxts(struct device *device,
diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c
index 1bf626c..31d3561 100644
--- a/drivers/infiniband/hw/qib/qib_tx.c
+++ b/drivers/infiniband/hw/qib/qib_tx.c
@@ -295,6 +295,7 @@ u32 __iomem *qib_getsendbuf_range(struct qib_devdata *dd, u32 *pbufnum,
nbufs = last - first + 1; /* number in range to check */
if (dd->upd_pio_shadow) {
+update_shadow:
/*
* Minor optimization. If we had no buffers on last call,
* start out by doing the update; continue and do scan even
@@ -304,37 +305,39 @@ u32 __iomem *qib_getsendbuf_range(struct qib_devdata *dd, u32 *pbufnum,
updated++;
}
i = first;
-rescan:
/*
* While test_and_set_bit() is atomic, we do that and then the
* change_bit(), and the pair is not. See if this is the cause
* of the remaining armlaunch errors.
*/
spin_lock_irqsave(&dd->pioavail_lock, flags);
+ if (dd->last_pio >= first && dd->last_pio <= last)
+ i = dd->last_pio + 1;
+ if (!first)
+ /* adjust to min possible */
+ nbufs = last - dd->min_kernel_pio + 1;
for (j = 0; j < nbufs; j++, i++) {
if (i > last)
- i = first;
+ i = !first ? dd->min_kernel_pio : first;
if (__test_and_set_bit((2 * i) + 1, shadow))
continue;
/* flip generation bit */
__change_bit(2 * i, shadow);
/* remember that the buffer can be written to now */
__set_bit(i, dd->pio_writing);
+ if (!first && first != last) /* first == last on VL15, avoid */
+ dd->last_pio = i;
break;
}
spin_unlock_irqrestore(&dd->pioavail_lock, flags);
if (j == nbufs) {
- if (!updated) {
+ if (!updated)
/*
* First time through; shadow exhausted, but may be
* buffers available, try an update and then rescan.
*/
- update_send_bufs(dd);
- updated++;
- i = first;
- goto rescan;
- }
+ goto update_shadow;
no_send_bufs(dd);
buf = NULL;
} else {
@@ -422,14 +425,20 @@ void qib_chg_pioavailkernel(struct qib_devdata *dd, unsigned start,
__clear_bit(QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT
+ start, dd->pioavailshadow);
__set_bit(start, dd->pioavailkernel);
+ if ((start >> 1) < dd->min_kernel_pio)
+ dd->min_kernel_pio = start >> 1;
} else {
__set_bit(start + QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT,
dd->pioavailshadow);
__clear_bit(start, dd->pioavailkernel);
+ if ((start >> 1) > dd->min_kernel_pio)
+ dd->min_kernel_pio = start >> 1;
}
start += 2;
}
+ if (dd->min_kernel_pio > 0 && dd->last_pio < dd->min_kernel_pio - 1)
+ dd->last_pio = dd->min_kernel_pio - 1;
spin_unlock_irqrestore(&dd->pioavail_lock, flags);
dd->f_txchk_change(dd, ostart, len, avail, rcd);
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
index 7ce2ac2..ce7387f 100644
--- a/drivers/infiniband/hw/qib/qib_uc.c
+++ b/drivers/infiniband/hw/qib/qib_uc.c
@@ -72,9 +72,9 @@ int qib_make_uc_req(struct qib_qp *qp)
goto done;
}
- ohdr = &qp->s_hdr.u.oth;
+ ohdr = &qp->s_hdr->u.oth;
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
+ ohdr = &qp->s_hdr->u.l.oth;
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index 828609f..a468bf2 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -321,11 +321,11 @@ int qib_make_ud_req(struct qib_qp *qp)
if (ah_attr->ah_flags & IB_AH_GRH) {
/* Header size in 32-bit words. */
- qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,
+ qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr->u.l.grh,
&ah_attr->grh,
qp->s_hdrwords, nwords);
lrh0 = QIB_LRH_GRH;
- ohdr = &qp->s_hdr.u.l.oth;
+ ohdr = &qp->s_hdr->u.l.oth;
/*
* Don't worry about sending to locally attached multicast
* QPs. It is unspecified by the spec. what happens.
@@ -333,7 +333,7 @@ int qib_make_ud_req(struct qib_qp *qp)
} else {
/* Header size in 32-bit words. */
lrh0 = QIB_LRH_BTH;
- ohdr = &qp->s_hdr.u.oth;
+ ohdr = &qp->s_hdr->u.oth;
}
if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
qp->s_hdrwords++;
@@ -346,15 +346,15 @@ int qib_make_ud_req(struct qib_qp *qp)
lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
else
lrh0 |= ibp->sl_to_vl[ah_attr->sl] << 12;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr->lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr->lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
+ qp->s_hdr->lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
lid = ppd->lid;
if (lid) {
lid |= ah_attr->src_path_bits & ((1 << ppd->lmc) - 1);
- qp->s_hdr.lrh[3] = cpu_to_be16(lid);
+ qp->s_hdr->lrh[3] = cpu_to_be16(lid);
} else
- qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
+ qp->s_hdr->lrh[3] = IB_LID_PERMISSIVE;
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= IB_BTH_SOLICITED;
bth0 |= extra_bytes << 20;
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index 0c19ef0..4876060 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -367,9 +367,10 @@ struct qib_rwq {
struct qib_rq {
struct qib_rwq *wq;
- spinlock_t lock; /* protect changes in this struct */
u32 size; /* size of RWQE array */
u8 max_sge;
+ spinlock_t lock /* protect changes in this struct */
+ ____cacheline_aligned_in_smp;
};
struct qib_srq {
@@ -412,31 +413,75 @@ struct qib_ack_entry {
*/
struct qib_qp {
struct ib_qp ibqp;
- struct qib_qp *next; /* link list for QPN hash table */
- struct qib_qp *timer_next; /* link list for qib_ib_timer() */
- struct list_head iowait; /* link for wait PIO buf */
- struct list_head rspwait; /* link for waititing to respond */
+ /* read mostly fields above and below */
struct ib_ah_attr remote_ah_attr;
struct ib_ah_attr alt_ah_attr;
- struct qib_ib_header s_hdr; /* next packet header to send */
- atomic_t refcount;
- wait_queue_head_t wait;
- wait_queue_head_t wait_dma;
- struct timer_list s_timer;
- struct work_struct s_work;
+ struct qib_qp *next; /* link list for QPN hash table */
+ struct qib_swqe *s_wq; /* send work queue */
struct qib_mmap_info *ip;
+ struct qib_ib_header *s_hdr; /* next packet header to send */
+ unsigned long timeout_jiffies; /* computed from timeout */
+
+ enum ib_mtu path_mtu;
+ u32 remote_qpn;
+ u32 pmtu; /* decoded from path_mtu */
+ u32 qkey; /* QKEY for this QP (for UD or RD) */
+ u32 s_size; /* send work queue size */
+ u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */
+
+ u8 state; /* QP state */
+ u8 qp_access_flags;
+ u8 alt_timeout; /* Alternate path timeout for this QP */
+ u8 timeout; /* Timeout for this QP */
+ u8 s_srate;
+ u8 s_mig_state;
+ u8 port_num;
+ u8 s_pkey_index; /* PKEY index to use */
+ u8 s_alt_pkey_index; /* Alternate path PKEY index to use */
+ u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */
+ u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */
+ u8 s_retry_cnt; /* number of times to retry */
+ u8 s_rnr_retry_cnt;
+ u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
+ u8 s_max_sge; /* size of s_wq->sg_list */
+ u8 s_draining;
+
+ /* start of read/write fields */
+
+ atomic_t refcount ____cacheline_aligned_in_smp;
+ wait_queue_head_t wait;
+
+
+ struct qib_ack_entry s_ack_queue[QIB_MAX_RDMA_ATOMIC + 1]
+ ____cacheline_aligned_in_smp;
+ struct qib_sge_state s_rdma_read_sge;
+
+ spinlock_t r_lock ____cacheline_aligned_in_smp; /* used for APM */
+ unsigned long r_aflags;
+ u64 r_wr_id; /* ID for current receive WQE */
+ u32 r_ack_psn; /* PSN for next ACK or atomic ACK */
+ u32 r_len; /* total length of r_sge */
+ u32 r_rcv_len; /* receive data len processed */
+ u32 r_psn; /* expected rcv packet sequence number */
+ u32 r_msn; /* message sequence number */
+
+ u8 r_state; /* opcode of last packet received */
+ u8 r_flags;
+ u8 r_head_ack_queue; /* index into s_ack_queue[] */
+
+ struct list_head rspwait; /* link for waititing to respond */
+
+ struct qib_sge_state r_sge; /* current receive data */
+ struct qib_rq r_rq; /* receive work queue */
+
+ spinlock_t s_lock ____cacheline_aligned_in_smp;
struct qib_sge_state *s_cur_sge;
+ u32 s_flags;
struct qib_verbs_txreq *s_tx;
- struct qib_mregion *s_rdma_mr;
+ struct qib_swqe *s_wqe;
struct qib_sge_state s_sge; /* current send request data */
- struct qib_ack_entry s_ack_queue[QIB_MAX_RDMA_ATOMIC + 1];
- struct qib_sge_state s_ack_rdma_sge;
- struct qib_sge_state s_rdma_read_sge;
- struct qib_sge_state r_sge; /* current receive data */
- spinlock_t r_lock; /* used for APM */
- spinlock_t s_lock;
+ struct qib_mregion *s_rdma_mr;
atomic_t s_dma_busy;
- u32 s_flags;
u32 s_cur_size; /* size of send packet in bytes */
u32 s_len; /* total length of s_sge */
u32 s_rdma_read_len; /* total length of s_rdma_read_sge */
@@ -447,60 +492,34 @@ struct qib_qp {
u32 s_psn; /* current packet sequence number */
u32 s_ack_rdma_psn; /* PSN for sending RDMA read responses */
u32 s_ack_psn; /* PSN for acking sends and RDMA writes */
- u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */
- u32 r_ack_psn; /* PSN for next ACK or atomic ACK */
- u64 r_wr_id; /* ID for current receive WQE */
- unsigned long r_aflags;
- u32 r_len; /* total length of r_sge */
- u32 r_rcv_len; /* receive data len processed */
- u32 r_psn; /* expected rcv packet sequence number */
- u32 r_msn; /* message sequence number */
+ u32 s_head; /* new entries added here */
+ u32 s_tail; /* next entry to process */
+ u32 s_cur; /* current work queue entry */
+ u32 s_acked; /* last un-ACK'ed entry */
+ u32 s_last; /* last completed entry */
+ u32 s_ssn; /* SSN of tail entry */
+ u32 s_lsn; /* limit sequence number (credit) */
u16 s_hdrwords; /* size of s_hdr in 32 bit words */
u16 s_rdma_ack_cnt;
- u8 state; /* QP state */
u8 s_state; /* opcode of last packet sent */
u8 s_ack_state; /* opcode of packet to ACK */
u8 s_nak_state; /* non-zero if NAK is pending */
- u8 r_state; /* opcode of last packet received */
u8 r_nak_state; /* non-zero if NAK is pending */
- u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
- u8 r_flags;
- u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */
- u8 r_head_ack_queue; /* index into s_ack_queue[] */
- u8 qp_access_flags;
- u8 s_max_sge; /* size of s_wq->sg_list */
- u8 s_retry_cnt; /* number of times to retry */
- u8 s_rnr_retry_cnt;
u8 s_retry; /* requester retry counter */
u8 s_rnr_retry; /* requester RNR retry counter */
- u8 s_pkey_index; /* PKEY index to use */
- u8 s_alt_pkey_index; /* Alternate path PKEY index to use */
- u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */
u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */
u8 s_tail_ack_queue; /* index into s_ack_queue[] */
- u8 s_srate;
- u8 s_draining;
- u8 s_mig_state;
- u8 timeout; /* Timeout for this QP */
- u8 alt_timeout; /* Alternate path timeout for this QP */
- u8 port_num;
- enum ib_mtu path_mtu;
- u32 pmtu; /* decoded from path_mtu */
- u32 remote_qpn;
- u32 qkey; /* QKEY for this QP (for UD or RD) */
- u32 s_size; /* send work queue size */
- u32 s_head; /* new entries added here */
- u32 s_tail; /* next entry to process */
- u32 s_cur; /* current work queue entry */
- u32 s_acked; /* last un-ACK'ed entry */
- u32 s_last; /* last completed entry */
- u32 s_ssn; /* SSN of tail entry */
- u32 s_lsn; /* limit sequence number (credit) */
- unsigned long timeout_jiffies; /* computed from timeout */
- struct qib_swqe *s_wq; /* send work queue */
- struct qib_swqe *s_wqe;
- struct qib_rq r_rq; /* receive work queue */
- struct qib_sge r_sg_list[0]; /* verified SGEs */
+
+ struct qib_sge_state s_ack_rdma_sge;
+ struct timer_list s_timer;
+ struct list_head iowait; /* link for wait PIO buf */
+
+ struct work_struct s_work;
+
+ wait_queue_head_t wait_dma;
+
+ struct qib_sge r_sg_list[0] /* verified SGEs */
+ ____cacheline_aligned_in_smp;
};
/*
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index db43b31..0ab8c9c 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -573,10 +573,9 @@ iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr,
non_blocking);
- if (err) {
- iscsi_destroy_endpoint(ep);
+ if (err)
return ERR_PTR(err);
- }
+
return ep;
}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 14224ba..2dddabd 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -613,8 +613,9 @@ id_failure:
ib_conn->cma_id = NULL;
addr_failure:
ib_conn->state = ISER_CONN_DOWN;
+ iser_conn_put(ib_conn, 1); /* deref ib conn's cma id */
connect_failure:
- iser_conn_release(ib_conn, 1);
+ iser_conn_put(ib_conn, 1); /* deref ib conn deallocate */
return err;
}
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index daf21b8..5f6b7f6 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1099,9 +1099,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
dir = cmd->data_direction;
BUG_ON(dir == DMA_NONE);
- transport_do_task_sg_chain(cmd);
- ioctx->sg = sg = sg_orig = cmd->t_tasks_sg_chained;
- ioctx->sg_cnt = sg_cnt = cmd->t_tasks_sg_chained_no;
+ ioctx->sg = sg = sg_orig = cmd->t_data_sg;
+ ioctx->sg_cnt = sg_cnt = cmd->t_data_nents;
count = ib_dma_map_sg(ch->sport->sdev->device, sg, sg_cnt,
opposite_dma_dir(dir));
@@ -1769,7 +1768,7 @@ static int srpt_handle_cmd(struct srpt_rdma_ch *ch,
kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
goto send_sense;
}
- ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb);
+ ret = target_setup_cmd_from_cdb(cmd, srp_cmd->cdb);
if (ret < 0) {
kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) {
@@ -4004,9 +4003,6 @@ static int __init srpt_init_module(void)
srpt_target->tf_ops = srpt_template;
- /* Enable SG chaining */
- srpt_target->tf_ops.task_sg_chaining = true;
-
/*
* Set up default attribute lists.
*/
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 405febd..daeeb4c 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -317,7 +317,8 @@ int iforce_init_device(struct iforce *iforce)
break;
if (i == 20) { /* 5 seconds */
- err("Timeout waiting for response from device.");
+ dev_err(&input_dev->dev,
+ "Timeout waiting for response from device.\n");
error = -ENODEV;
goto fail;
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index a17b500..08f98f2 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -257,7 +257,8 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
status = usb_submit_urb(iforce->ctrl, GFP_ATOMIC);
if (status) {
- err("usb_submit_urb failed %d", status);
+ dev_err(&iforce->intf->dev,
+ "usb_submit_urb failed %d\n", status);
return -1;
}
@@ -265,12 +266,14 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce->ctrl->status != -EINPROGRESS, HZ);
if (iforce->ctrl->status) {
- dbg("iforce->ctrl->status = %d", iforce->ctrl->status);
+ dev_dbg(&iforce->intf->dev,
+ "iforce->ctrl->status = %d\n",
+ iforce->ctrl->status);
usb_unlink_urb(iforce->ctrl);
return -1;
}
#else
- dbg("iforce_get_id_packet: iforce->bus = USB!");
+ printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
#endif
}
break;
@@ -289,12 +292,15 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
return -1;
}
#else
- err("iforce_get_id_packet: iforce->bus = SERIO!");
+ dev_err(&iforce->dev->dev,
+ "iforce_get_id_packet: iforce->bus = SERIO!\n");
#endif
break;
default:
- err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
+ dev_err(&iforce->dev->dev,
+ "iforce_get_id_packet: iforce->bus = %d\n",
+ iforce->bus);
break;
}
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 6c96631..d96aa27 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);
- dev_warn(&iforce->dev->dev, "usb_submit_urb failed %d\n", n);
+ dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -76,6 +76,7 @@ void iforce_usb_xmit(struct iforce *iforce)
static void iforce_usb_irq(struct urb *urb)
{
struct iforce *iforce = urb->context;
+ struct device *dev = &iforce->intf->dev;
int status;
switch (urb->status) {
@@ -86,11 +87,12 @@ static void iforce_usb_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - urb has status of: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb has status of: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -100,8 +102,8 @@ static void iforce_usb_irq(struct urb *urb)
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, status);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, status);
}
static void iforce_usb_out(struct urb *urb)
@@ -110,7 +112,8 @@ static void iforce_usb_out(struct urb *urb)
if (urb->status) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dbg("urb->status %d, exiting", urb->status);
+ dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+ urb->status);
return;
}
@@ -155,6 +158,7 @@ static int iforce_usb_probe(struct usb_interface *intf,
iforce->bus = IFORCE_USB;
iforce->usbdev = dev;
+ iforce->intf = intf;
iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
iforce->cr.wIndex = 0;
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 9f494b7..b1d7d9b 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -115,6 +115,7 @@ struct iforce {
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_USB
struct usb_device *usbdev; /* USB transfer */
+ struct usb_interface *intf;
struct urb *irq, *out, *ctrl;
struct usb_ctrlrequest cr;
#endif
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fd7a0d5..ee16fb6 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -252,6 +252,7 @@ MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad {
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
int pad_present;
@@ -457,6 +458,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
static void xpad_irq_in(struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
int retval, status;
status = urb->status;
@@ -469,11 +471,11 @@ static void xpad_irq_in(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status);
goto exit;
}
@@ -492,12 +494,15 @@ static void xpad_irq_in(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(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static void xpad_bulk_out(struct urb *urb)
{
+ struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
+
switch (urb->status) {
case 0:
/* success */
@@ -506,16 +511,20 @@ static void xpad_bulk_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
break;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
}
}
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out(struct urb *urb)
{
+ struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
int retval, status;
status = urb->status;
@@ -529,19 +538,21 @@ static void xpad_irq_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -654,7 +665,8 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
default:
- dbg("%s - rumble command sent to unsupported xpad type: %d",
+ dev_dbg(&xpad->dev->dev,
+ "%s - rumble command sent to unsupported xpad type: %d\n",
__func__, xpad->xtype);
return -1;
}
@@ -844,6 +856,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
}
xpad->udev = udev;
+ xpad->intf = intf;
xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype;
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index ab86051..082684e 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -327,7 +327,9 @@ static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
}
/*
@@ -339,7 +341,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
const int status = urb->status;
int error;
- dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
+ dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
dev->irq_data->byte[0],
dev->irq_data->byte[1],
dev->irq_data->byte[2],
@@ -349,7 +351,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
if (status) {
if (status == -ESHUTDOWN)
return;
- err("%s: urb status %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
}
/* Special keys */
@@ -396,7 +398,8 @@ static void cm109_urb_irq_callback(struct urb *urb)
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d",
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_ctl) failed %d\n",
__func__, error);
}
@@ -409,14 +412,14 @@ static void cm109_urb_ctl_callback(struct urb *urb)
const int status = urb->status;
int error;
- dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
dev->ctl_data->byte[0],
dev->ctl_data->byte[1],
dev->ctl_data->byte[2],
dev->ctl_data->byte[3]);
if (status)
- err("%s: urb status %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
spin_lock(&dev->ctl_submit_lock);
@@ -433,7 +436,8 @@ static void cm109_urb_ctl_callback(struct urb *urb)
dev->irq_urb_pending = 1;
error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_irq) failed %d",
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_irq) failed %d\n",
__func__, error);
}
}
@@ -476,7 +480,8 @@ static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
dev->ctl_data,
USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
if (error < 0 && error != -EINTR)
- err("%s: usb_control_msg() failed %d", __func__, error);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg() failed %d\n",
+ __func__, error);
}
static void cm109_stop_traffic(struct cm109_dev *dev)
@@ -518,8 +523,8 @@ static int cm109_input_open(struct input_dev *idev)
error = usb_autopm_get_interface(dev->intf);
if (error < 0) {
- err("%s - cannot autoresume, result %d",
- __func__, error);
+ dev_err(&idev->dev, "%s - cannot autoresume, result %d\n",
+ __func__, error);
return error;
}
@@ -537,7 +542,8 @@ static int cm109_input_open(struct input_dev *idev)
error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
else
dev->open = 1;
@@ -573,7 +579,7 @@ static int cm109_input_ev(struct input_dev *idev, unsigned int type,
{
struct cm109_dev *dev = input_get_drvdata(idev);
- dev_dbg(&dev->udev->dev,
+ dev_dbg(&dev->intf->dev,
"input_ev: type=%u code=%u value=%d\n", type, code, value);
if (type != EV_SND)
@@ -710,7 +716,8 @@ static int cm109_usb_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (ret != USB_PKT_LEN)
- err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+ dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
+ ret, USB_PKT_LEN);
/* initialise irq urb */
usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index d99151a..290fa5f 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -157,7 +157,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
* though so it's not too big a deal
*/
if (dev->data.pos >= dev->data.len) {
- dev_dbg(&dev->udev->dev,
+ dev_dbg(&dev->interface->dev,
"%s - Error ran out of data. pos: %d, len: %d\n",
__func__, dev->data.pos, dev->data.len);
return -1;
@@ -267,7 +267,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Unknown sequence found in system data.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Unknown sequence found in system data.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -286,7 +288,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Unknown sequence found in button data.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Unknown sequence found in button data.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -302,7 +306,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Error in message, invalid toggle.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Error in message, invalid toggle.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -312,10 +318,11 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 5;
remote->data.bits_left -= 5;
} else {
- err("Bad message received, no stop bit found.\n");
+ dev_err(&remote->interface->dev,
+ "Bad message received, no stop bit found.\n");
}
- dev_dbg(&remote->udev->dev,
+ dev_dbg(&remote->interface->dev,
"%s found valid message: system: %d, button: %d, toggle: %d\n",
__func__, message.system, message.button, message.toggle);
@@ -397,7 +404,9 @@ static void keyspan_irq_recv(struct urb *urb)
resubmit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result: %d", __func__, retval);
+ dev_err(&dev->interface->dev,
+ "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
static int keyspan_open(struct input_dev *dev)
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index 538f704..49c0c3e 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -65,6 +65,7 @@ struct powermate_device {
struct urb *irq, *config;
struct usb_ctrlrequest *configcr;
struct usb_device *udev;
+ struct usb_interface *intf;
struct input_dev *input;
spinlock_t lock;
int static_brightness;
@@ -85,6 +86,7 @@ static void powermate_config_complete(struct urb *urb);
static void powermate_irq(struct urb *urb)
{
struct powermate_device *pm = urb->context;
+ struct device *dev = &pm->intf->dev;
int retval;
switch (urb->status) {
@@ -95,10 +97,12 @@ static void powermate_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -110,8 +114,8 @@ static void powermate_irq(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(dev, "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
@@ -330,6 +334,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
goto fail3;
pm->udev = udev;
+ pm->intf = intf;
pm->input = input_dev;
usb_make_path(udev, pm->phys, sizeof(pm->phys));
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index f4776e7..285a5bd 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -101,6 +101,7 @@ static const struct lcd_segment_map {
struct yealink_dev {
struct input_dev *idev; /* input device */
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
/* irq input channel */
struct yld_ctl_packet *irq_data;
@@ -428,7 +429,8 @@ static void urb_irq_callback(struct urb *urb)
int ret, status = urb->status;
if (status)
- err("%s - urb status %d", __func__, status);
+ dev_err(&yld->intf->dev, "%s - urb status %d\n",
+ __func__, status);
switch (yld->irq_data->cmd) {
case CMD_KEYPRESS:
@@ -437,13 +439,15 @@ static void urb_irq_callback(struct urb *urb)
break;
case CMD_SCANCODE:
- dbg("get scancode %x", yld->irq_data->data[0]);
+ dev_dbg(&yld->intf->dev, "get scancode %x\n",
+ yld->irq_data->data[0]);
report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
break;
default:
- err("unexpected response %x", yld->irq_data->cmd);
+ dev_err(&yld->intf->dev, "unexpected response %x\n",
+ yld->irq_data->cmd);
}
yealink_do_idle_tasks(yld);
@@ -451,7 +455,9 @@ static void urb_irq_callback(struct urb *urb)
if (!yld->shutdown) {
ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
if (ret && ret != -EPERM)
- err("%s - usb_submit_urb failed %d", __func__, ret);
+ dev_err(&yld->intf->dev,
+ "%s - usb_submit_urb failed %d\n",
+ __func__, ret);
}
}
@@ -461,7 +467,8 @@ static void urb_ctl_callback(struct urb *urb)
int ret = 0, status = urb->status;
if (status)
- err("%s - urb status %d", __func__, status);
+ dev_err(&yld->intf->dev, "%s - urb status %d\n",
+ __func__, status);
switch (yld->ctl_data->cmd) {
case CMD_KEYPRESS:
@@ -479,7 +486,8 @@ static void urb_ctl_callback(struct urb *urb)
}
if (ret && ret != -EPERM)
- err("%s - usb_submit_urb failed %d", __func__, ret);
+ dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
+ __func__, ret);
}
/*******************************************************************************
@@ -511,7 +519,7 @@ static int input_open(struct input_dev *dev)
struct yealink_dev *yld = input_get_drvdata(dev);
int i, ret;
- dbg("%s", __func__);
+ dev_dbg(&yld->intf->dev, "%s\n", __func__);
/* force updates to device */
for (i = 0; i<sizeof(yld->master); i++)
@@ -526,8 +534,9 @@ static int input_open(struct input_dev *dev)
yld->ctl_data->size = 10;
yld->ctl_data->sum = 0x100-CMD_INIT-10;
if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
- dbg("%s - usb_submit_urb failed with result %d",
- __func__, ret);
+ dev_dbg(&yld->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, ret);
return ret;
}
return 0;
@@ -876,6 +885,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENOMEM;
yld->udev = udev;
+ yld->intf = intf;
yld->idev = input_dev = input_allocate_device();
if (!input_dev)
@@ -909,7 +919,8 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (ret != USB_PKT_LEN)
- err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+ dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
+ ret, USB_PKT_LEN);
/* initialise irq urb */
usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 0acbc7d..e42f1fa 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -195,6 +195,7 @@ enum atp_status_bits {
struct atp {
char phys[64];
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
struct urb *urb; /* usb request block */
u8 *data; /* transferred data */
struct input_dev *input; /* input dev */
@@ -253,8 +254,9 @@ MODULE_PARM_DESC(debug, "Activate debugging output");
* packets (Report ID 2). This code changes device mode, so it
* sends raw sensor reports (Report ID 5).
*/
-static int atp_geyser_init(struct usb_device *udev)
+static int atp_geyser_init(struct atp *dev)
{
+ struct usb_device *udev = dev->udev;
char *data;
int size;
int i;
@@ -262,7 +264,7 @@ static int atp_geyser_init(struct usb_device *udev)
data = kmalloc(8, GFP_KERNEL);
if (!data) {
- err("Out of memory");
+ dev_err(&dev->intf->dev, "Out of memory\n");
return -ENOMEM;
}
@@ -277,7 +279,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to read mode from device.");
+ dev_err(&dev->intf->dev, "Failed to read mode from device.\n");
ret = -EIO;
goto out_free;
}
@@ -296,7 +298,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to request geyser raw mode");
+ dev_err(&dev->intf->dev, "Failed to request geyser raw mode\n");
ret = -EIO;
goto out_free;
}
@@ -313,16 +315,16 @@ out_free:
static void atp_reinit(struct work_struct *work)
{
struct atp *dev = container_of(work, struct atp, work);
- struct usb_device *udev = dev->udev;
int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n");
- atp_geyser_init(udev);
+ atp_geyser_init(dev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_reinit: usb_submit_urb failed with error %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_reinit: usb_submit_urb failed with error %d\n",
+ retval);
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
@@ -400,6 +402,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
static int atp_status_check(struct urb *urb)
{
struct atp *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
switch (urb->status) {
case 0:
@@ -407,8 +410,8 @@ static int atp_status_check(struct urb *urb)
break;
case -EOVERFLOW:
if (!dev->overflow_warned) {
- printk(KERN_WARNING "appletouch: OVERFLOW with data "
- "length %d, actual length is %d\n",
+ dev_warn(&intf->dev,
+ "appletouch: OVERFLOW with data length %d, actual length is %d\n",
dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true;
}
@@ -416,13 +419,15 @@ static int atp_status_check(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("atp_complete: urb shutting down with status: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: urb shutting down with status: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR_FATAL;
default:
- dbg("atp_complete: nonzero urb status received: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: nonzero urb status received: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR;
}
@@ -445,7 +450,8 @@ static void atp_detect_size(struct atp *dev)
for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
if (dev->xy_cur[i]) {
- printk(KERN_INFO "appletouch: 17\" model detected.\n");
+ dev_info(&dev->intf->dev,
+ "appletouch: 17\" model detected.\n");
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
@@ -588,8 +594,9 @@ static void atp_complete_geyser_1_2(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
@@ -722,8 +729,9 @@ static void atp_complete_geyser_3_4(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
static int atp_open(struct input_dev *input)
@@ -748,14 +756,12 @@ static void atp_close(struct input_dev *input)
static int atp_handle_geyser(struct atp *dev)
{
- struct usb_device *udev = dev->udev;
-
if (dev->info != &fountain_info) {
/* switch to raw sensor mode */
- if (atp_geyser_init(udev))
+ if (atp_geyser_init(dev))
return -EIO;
- printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+ dev_info(&dev->intf->dev, "Geyser mode initialized.\n");
}
return 0;
@@ -785,7 +791,7 @@ static int atp_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;
}
@@ -793,11 +799,12 @@ static int atp_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("Out of memory");
+ dev_err(&iface->dev, "Out of memory\n");
goto err_free_devs;
}
dev->udev = udev;
+ dev->intf = iface;
dev->input = input_dev;
dev->info = info;
dev->overflow_warned = false;
@@ -886,7 +893,7 @@ static void atp_disconnect(struct usb_interface *iface)
usb_free_urb(dev->urb);
kfree(dev);
}
- printk(KERN_INFO "input: appletouch disconnected\n");
+ dev_info(&iface->dev, "input: appletouch disconnected\n");
}
static int atp_recover(struct atp *dev)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index f9e2758..2cf681d 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -584,7 +584,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
int retval = 0, size;
if (!data) {
- err("bcm5974: out of memory");
+ dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;
goto out;
}
@@ -597,7 +597,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not read from device");
+ dev_err(&dev->intf->dev, "could not read from device\n");
retval = -EIO;
goto out;
}
@@ -615,7 +615,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not write to device");
+ dev_err(&dev->intf->dev, "could not write to device\n");
retval = -EIO;
goto out;
}
@@ -631,6 +631,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -640,10 +641,11 @@ static void bcm5974_irq_button(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: button urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: button urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb status: %d\n", urb->status);
goto exit;
}
@@ -654,12 +656,13 @@ static void bcm5974_irq_button(struct urb *urb)
exit:
error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: button urb failed: %d", error);
+ dev_err(&intf->dev, "button urb failed: %d\n", error);
}
static void bcm5974_irq_trackpad(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -669,10 +672,11 @@ static void bcm5974_irq_trackpad(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: trackpad urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status);
goto exit;
}
@@ -687,7 +691,7 @@ static void bcm5974_irq_trackpad(struct urb *urb)
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: trackpad urb failed: %d", error);
+ dev_err(&intf->dev, "trackpad urb failed: %d\n", error);
}
/*
@@ -833,7 +837,7 @@ static int bcm5974_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("bcm5974: out of memory");
+ dev_err(&iface->dev, "out of memory\n");
goto err_free_devs;
}
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index f8b0b1d..e062ec8 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -51,6 +51,7 @@ struct usb_acecad {
char name[128];
char phys[64];
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct input_dev *input;
struct urb *irq;
@@ -63,6 +64,7 @@ static void usb_acecad_irq(struct urb *urb)
struct usb_acecad *acecad = urb->context;
unsigned char *data = acecad->data;
struct input_dev *dev = acecad->input;
+ struct usb_interface *intf = acecad->intf;
int prox, status;
switch (urb->status) {
@@ -73,10 +75,12 @@ static void usb_acecad_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto resubmit;
}
@@ -105,8 +109,10 @@ static void usb_acecad_irq(struct urb *urb)
resubmit:
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
- err("can't resubmit intr, %s-%s/input0, status %d",
- acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+ dev_err(&intf->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ acecad->usbdev->bus->bus_name,
+ acecad->usbdev->devpath, status);
}
static int usb_acecad_open(struct input_dev *dev)
@@ -168,6 +174,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
}
acecad->usbdev = dev;
+ acecad->intf = intf;
acecad->input = input_dev;
if (dev->manufacturer)
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 205d16a..755a39e 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -309,6 +309,7 @@ struct aiptek_settings {
struct aiptek {
struct input_dev *inputdev; /* input device struct */
struct usb_device *usbdev; /* usb device struct */
+ struct usb_interface *intf; /* usb interface struct */
struct urb *urb; /* urb for incoming reports */
dma_addr_t data_dma; /* our dma stuffage */
struct aiptek_features features; /* tablet's array of features */
@@ -435,6 +436,7 @@ static void aiptek_irq(struct urb *urb)
struct aiptek *aiptek = urb->context;
unsigned char *data = aiptek->data;
struct input_dev *inputdev = aiptek->inputdev;
+ struct usb_interface *intf = aiptek->intf;
int jitterable = 0;
int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
@@ -447,13 +449,13 @@ static void aiptek_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -785,7 +787,7 @@ static void aiptek_irq(struct urb *urb)
1 | AIPTEK_REPORT_TOOL_UNKNOWN);
input_sync(inputdev);
} else {
- dbg("Unknown report %d", data[0]);
+ dev_dbg(&intf->dev, "Unknown report %d\n", data[0]);
}
/* Jitter may occur when the user presses a button on the stlyus
@@ -811,8 +813,9 @@ static void aiptek_irq(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval != 0) {
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
}
@@ -912,8 +915,9 @@ aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
if ((ret =
aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
- dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
- command, data);
+ dev_dbg(&aiptek->intf->dev,
+ "aiptek_program: failed, tried to send: 0x%02x 0x%02x\n",
+ command, data);
}
kfree(buf);
return ret < 0 ? ret : 0;
@@ -947,8 +951,9 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
if ((ret =
aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
- dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
- buf[0], buf[1], buf[2]);
+ dev_dbg(&aiptek->intf->dev,
+ "aiptek_query failed: returned 0x%02x 0x%02x 0x%02x\n",
+ buf[0], buf[1], buf[2]);
ret = -EIO;
} else {
ret = get_unaligned_le16(buf + 1);
@@ -1726,6 +1731,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
aiptek->inputdev = inputdev;
aiptek->usbdev = usbdev;
+ aiptek->intf = intf;
aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
aiptek->inDelay = 0;
aiptek->endDelay = 0;
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 89a2978..29e01ab 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -2,8 +2,6 @@
GTCO digitizer USB driver
-Use the err() and dbg() macros from usb.h for system logging
-
TO CHECK: Is pressure done right on report 5?
Copyright (C) 2006 GTCO CalComp
@@ -108,6 +106,7 @@ struct gtco {
struct input_dev *inputdevice; /* input device struct pointer */
struct usb_device *usbdev; /* the usb device for this device */
+ struct usb_interface *intf; /* the usb interface for this device */
struct urb *urbinfo; /* urb for incoming reports */
dma_addr_t buf_dma; /* dma addr of the data buffer*/
unsigned char * buffer; /* databuffer for reports */
@@ -202,6 +201,7 @@ struct hid_descriptor
static void parse_hid_report_descriptor(struct gtco *device, char * report,
int length)
{
+ struct device *ddev = &device->intf->dev;
int x, i = 0;
/* Tag primitive vars */
@@ -228,7 +228,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
char indentstr[10] = "";
- dbg("======>>>>>>PARSE<<<<<<======");
+ dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
/* Walk this report and pull out the info we need */
while (i < length) {
@@ -277,11 +277,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
else if (data == 3)
strcpy(globtype, "Var|Const");
- dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
- globalval[TAG_GLOB_REPORT_ID], inputnum,
- globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
- globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
- globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
+ dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n",
+ globalval[TAG_GLOB_REPORT_ID], inputnum,
+ globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+ globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
/*
@@ -292,7 +292,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
*/
switch (inputnum) {
case 0: /* X coord */
- dbg("GER: X Usage: 0x%x", usage);
+ dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage);
if (device->max_X == 0) {
device->max_X = globalval[TAG_GLOB_LOG_MAX];
device->min_X = globalval[TAG_GLOB_LOG_MIN];
@@ -300,7 +300,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
break;
case 1: /* Y coord */
- dbg("GER: Y Usage: 0x%x", usage);
+ dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage);
if (device->max_Y == 0) {
device->max_Y = globalval[TAG_GLOB_LOG_MAX];
device->min_Y = globalval[TAG_GLOB_LOG_MIN];
@@ -350,10 +350,10 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
maintype = 'S';
if (data == 0) {
- dbg("======>>>>>> Physical");
+ dev_dbg(ddev, "======>>>>>> Physical\n");
strcpy(globtype, "Physical");
} else
- dbg("======>>>>>>");
+ dev_dbg(ddev, "======>>>>>>\n");
/* Indent the debug output */
indent++;
@@ -368,7 +368,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
break;
case TAG_MAIN_COL_END:
- dbg("<<<<<<======");
+ dev_dbg(ddev, "<<<<<<======\n");
maintype = 'E';
indent--;
for (x = 0; x < indent; x++)
@@ -384,18 +384,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
switch (size) {
case 1:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data);
break;
case 2:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data16);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data16);
break;
case 4:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data32);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data32);
break;
}
break;
@@ -465,26 +465,26 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
if (tag < TAG_GLOB_MAX) {
switch (size) {
case 1:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data);
globalval[tag] = data;
break;
case 2:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data16);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data16);
globalval[tag] = data16;
break;
case 4:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data32);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data32);
globalval[tag] = data32;
break;
}
} else {
- dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
- indentstr, tag, size);
+ dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n",
+ indentstr, tag, size);
}
break;
@@ -511,18 +511,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
switch (size) {
case 1:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data);
break;
case 2:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data16);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data16);
break;
case 4:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data32);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data32);
break;
}
@@ -714,8 +714,9 @@ static void gtco_urb_callback(struct urb *urbinfo)
* the rest as 0
*/
val = device->buffer[5] & MASK_BUTTON;
- dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
- val, val);
+ dev_dbg(&device->intf->dev,
+ "======>>>>>>REPORT 1: val 0x%X(%d)\n",
+ val, val);
/*
* We don't apply any meaning to the button
@@ -808,7 +809,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
resubmit:
rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
if (rc != 0)
- err("usb_submit_urb failed rc=0x%x", rc);
+ dev_err(&device->intf->dev,
+ "usb_submit_urb failed rc=0x%x\n", rc);
}
/*
@@ -838,7 +840,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gtco || !input_dev) {
- err("No more memory");
+ dev_err(&usbinterface->dev, "No more memory\n");
error = -ENOMEM;
goto err_free_devs;
}
@@ -848,12 +850,13 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* Save interface information */
gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+ gtco->intf = usbinterface;
/* Allocate some data for incoming reports */
gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE,
GFP_KERNEL, &gtco->buf_dma);
if (!gtco->buffer) {
- err("No more memory for us buffers");
+ dev_err(&usbinterface->dev, "No more memory for us buffers\n");
error = -ENOMEM;
goto err_free_devs;
}
@@ -861,7 +864,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* Allocate URB for reports */
gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
if (!gtco->urbinfo) {
- err("Failed to allocate URB");
+ dev_err(&usbinterface->dev, "Failed to allocate URB\n");
error = -ENOMEM;
goto err_free_buf;
}
@@ -873,14 +876,14 @@ static int gtco_probe(struct usb_interface *usbinterface,
endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
/* Some debug */
- dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
- dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
- dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
- dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
+ dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
+ dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType);
if (usb_endpoint_xfer_int(endpoint))
- dbg("endpoint: we have interrupt endpoint\n");
+ dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n");
- dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
+ dev_dbg(&usbinterface->dev, "endpoint extra len:%d\n", usbinterface->altsetting[0].extralen);
/*
* Find the HID descriptor so we can find out the size of the
@@ -888,17 +891,19 @@ static int gtco_probe(struct usb_interface *usbinterface,
*/
if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
HID_DEVICE_TYPE, &hid_desc) != 0){
- err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+ dev_err(&usbinterface->dev,
+ "Can't retrieve exta USB descriptor to get hid report descriptor length\n");
error = -EIO;
goto err_free_urb;
}
- dbg("Extra descriptor success: type:%d len:%d",
- hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
+ dev_dbg(&usbinterface->dev,
+ "Extra descriptor success: type:%d len:%d\n",
+ hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL);
if (!report) {
- err("No more memory for report");
+ dev_err(&usbinterface->dev, "No more memory for report\n");
error = -ENOMEM;
goto err_free_urb;
}
@@ -915,7 +920,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
le16_to_cpu(hid_desc->wDescriptorLength),
5000); /* 5 secs */
- dbg("usb_control_msg result: %d", result);
+ dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result);
if (result == le16_to_cpu(hid_desc->wDescriptorLength)) {
parse_hid_report_descriptor(gtco, report, result);
break;
@@ -926,8 +931,9 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* If we didn't get the report, fail */
if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
- err("Failed to get HID Report Descriptor of size: %d",
- hid_desc->wDescriptorLength);
+ dev_err(&usbinterface->dev,
+ "Failed to get HID Report Descriptor of size: %d\n",
+ hid_desc->wDescriptorLength);
error = -EIO;
goto err_free_urb;
}
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 85a5b40..3fba74b 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -33,6 +33,7 @@ struct kbtab {
dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct urb *irq;
char phys[32];
};
@@ -53,10 +54,14 @@ static void kbtab_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(&kbtab->intf->dev,
+ "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(&kbtab->intf->dev,
+ "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -80,8 +85,9 @@ static void kbtab_irq(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(&kbtab->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static struct usb_device_id kbtab_ids[] = {
@@ -131,6 +137,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
goto fail2;
kbtab->usbdev = dev;
+ kbtab->intf = intf;
kbtab->dev = input_dev;
usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 0d26921..79a0509 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -99,6 +99,7 @@ static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
static void wacom_sys_irq(struct urb *urb)
{
struct wacom *wacom = urb->context;
+ struct device *dev = &wacom->intf->dev;
int retval;
switch (urb->status) {
@@ -109,10 +110,12 @@ static void wacom_sys_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -122,8 +125,8 @@ static void wacom_sys_irq(struct urb *urb)
usb_mark_last_busy(wacom->usbdev);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static int wacom_open(struct input_dev *dev)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index cecd35c..b327790 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -76,7 +76,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
int prox, pressure;
if (data[0] != WACOM_REPORT_PENABLED) {
- dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+ dev_dbg(&input->dev,
+ "wacom_pl_irq: received unknown report #%d\n", data[0]);
return 0;
}
@@ -175,7 +176,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
int prox = data[1] & 0x20, pressure;
- dbg("wacom_dtu_irq: received report #%d", data[0]);
+ dev_dbg(&input->dev, "wacom_dtu_irq: received report #%d\n", data[0]);
if (prox) {
/* Going into proximity select tool */
@@ -211,7 +212,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
int retval = 0;
if (data[0] != WACOM_REPORT_PENABLED) {
- dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+ dev_dbg(&input->dev,
+ "wacom_graphire_irq: received unknown report #%d\n",
+ data[0]);
goto exit;
}
@@ -484,7 +487,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
&& data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
- dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+ dev_dbg(&input->dev,
+ "wacom_intuos_irq: received unknown report #%d\n",
+ data[0]);
return 0;
}
@@ -830,7 +835,8 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
{
char *data = wacom->data;
- dbg("wacom_tpc_irq: received report #%d", data[0]);
+ dev_dbg(&wacom->input->dev, "wacom_tpc_irq: received report #%d\n",
+ data[0]);
switch (len) {
case WACOM_PKGLEN_TPC1FG:
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 2a21419..75838d7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -489,10 +489,10 @@ config TOUCHSCREEN_TI_TSCADC
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Say Y here if you have a 4-wire touchscreen connected to the
- ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+ ADC Controller on your Atmel SoC.
If unsure, say N.
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 22cd96f..e32709e 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -269,8 +269,9 @@ static int e2i_init(struct usbtouch_usb *usbtouch)
0x01, 0x02, 0x0000, 0x0081,
NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - E2I_RESET - bytes|err: %d\n",
+ __func__, ret);
return ret;
}
@@ -425,8 +426,9 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
MTOUCHUSB_RESET,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d\n",
+ __func__, ret);
if (ret < 0)
return ret;
msleep(150);
@@ -436,8 +438,9 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d\n",
+ __func__, ret);
if (ret >= 0)
break;
if (ret != -EPIPE)
@@ -737,27 +740,29 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
+ struct usb_interface *intf = dev->interface;
+
switch (pkt[0]) {
case 0x3A: /* command response */
- dbg("%s: Command response %d", __func__, pkt[1]);
+ dev_dbg(&intf->dev, "%s: Command response %d\n", __func__, pkt[1]);
break;
case 0xC0: /* down */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 1;
- dbg("%s: down %d,%d", __func__, dev->x, dev->y);
+ dev_dbg(&intf->dev, "%s: down %d,%d\n", __func__, dev->x, dev->y);
return 1;
case 0x80: /* up */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 0;
- dbg("%s: up %d,%d", __func__, dev->x, dev->y);
+ dev_dbg(&intf->dev, "%s: up %d,%d\n", __func__, dev->x, dev->y);
return 1;
default:
- dbg("%s: Unknown return %d", __func__, pkt[0]);
+ dev_dbg(&intf->dev, "%s: Unknown return %d\n", __func__, pkt[0]);
break;
}
@@ -812,7 +817,8 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch)
priv->ack = usb_alloc_urb(0, GFP_KERNEL);
if (!priv->ack) {
- dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_alloc_urb failed: usbtouch->ack\n", __func__);
goto err_ack_buf;
}
@@ -1349,6 +1355,7 @@ out_flush_buf:
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
+ struct device *dev = &usbtouch->interface->dev;
int retval;
switch (urb->status) {
@@ -1357,20 +1364,21 @@ static void usbtouch_irq(struct urb *urb)
break;
case -ETIME:
/* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __func__);
+ dev_dbg(dev,
+ "%s - urb timed out - was the device unplugged?\n",
+ __func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EPIPE:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -1380,8 +1388,8 @@ exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result: %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
static int usbtouch_open(struct input_dev *input)
@@ -1456,8 +1464,9 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
if (usbtouch->type->init) {
err = usbtouch->type->init(usbtouch);
if (err) {
- dbg("%s - type->init() failed, err: %d",
- __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->init() failed, err: %d\n",
+ __func__, err);
return err;
}
}
@@ -1532,7 +1541,8 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!usbtouch->irq) {
- dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
+ dev_dbg(&intf->dev,
+ "%s - usb_alloc_urb failed: usbtouch->irq\n", __func__);
goto out_free_buffers;
}
@@ -1594,7 +1604,9 @@ static int usbtouch_probe(struct usb_interface *intf,
if (type->alloc) {
err = type->alloc(usbtouch);
if (err) {
- dbg("%s - type->alloc() failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->alloc() failed, err: %d\n",
+ __func__, err);
goto out_free_urb;
}
}
@@ -1603,14 +1615,18 @@ static int usbtouch_probe(struct usb_interface *intf,
if (type->init) {
err = type->init(usbtouch);
if (err) {
- dbg("%s - type->init() failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->init() failed, err: %d\n",
+ __func__, err);
goto out_do_exit;
}
}
err = input_register_device(usbtouch->input);
if (err) {
- dbg("%s - input_register_device failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - input_register_device failed, err: %d\n",
+ __func__, err);
goto out_do_exit;
}
@@ -1622,8 +1638,9 @@ static int usbtouch_probe(struct usb_interface *intf,
err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
if (err) {
usb_autopm_put_interface(intf);
- err("%s - usb_submit_urb failed with result: %d",
- __func__, err);
+ dev_err(&intf->dev,
+ "%s - usb_submit_urb failed with result: %d\n",
+ __func__, err);
goto out_unregister_input;
}
}
@@ -1650,12 +1667,12 @@ static void usbtouch_disconnect(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- dbg("%s - called", __func__);
-
if (!usbtouch)
return;
- dbg("%s - usbtouch is initialized, cleaning up", __func__);
+ dev_dbg(&intf->dev,
+ "%s - usbtouch is initialized, cleaning up\n", __func__);
+
usb_set_intfdata(intf, NULL);
/* this will stop IO via close */
input_unregister_device(usbtouch->input);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3bd9fff..c698437 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -43,7 +43,7 @@ config AMD_IOMMU
With this option you can enable support for AMD IOMMU hardware in
your system. An IOMMU is a hardware component which provides
remapping of DMA memory accesses from devices. With an AMD IOMMU you
- can isolate the the DMA memory of different devices and protect the
+ can isolate the DMA memory of different devices and protect the
system from misbehaving device drivers or hardware.
You can find out if your system has an AMD IOMMU if you look into
@@ -67,7 +67,7 @@ config AMD_IOMMU_V2
---help---
This option enables support for the AMD IOMMUv2 features of the IOMMU
hardware. Select this option if you want to use devices that support
- the the PCI PRI and PASID interface.
+ the PCI PRI and PASID interface.
# Intel IOMMU support
config DMAR_TABLE
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 7ad7a3b..3e5e82a 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
-obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
+obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 35c1e17..3a74e44 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -36,6 +36,7 @@
#include <linux/tboot.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>
#define PREFIX "DMAR: "
@@ -555,7 +556,7 @@ int __init detect_intel_iommu(void)
dmar = (struct acpi_table_dmar *) dmar_tbl;
- if (ret && intr_remapping_enabled && cpu_has_x2apic &&
+ if (ret && irq_remapping_enabled && cpu_has_x2apic &&
dmar->flags & 0x1)
printk(KERN_INFO
"Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
@@ -1041,7 +1042,7 @@ static const char *dma_remap_fault_reasons[] =
"non-zero reserved fields in PTE",
};
-static const char *intr_remap_fault_reasons[] =
+static const char *irq_remap_fault_reasons[] =
{
"Detected reserved fields in the decoded interrupt-remapped request",
"Interrupt index exceeded the interrupt-remapping table size",
@@ -1056,10 +1057,10 @@ static const char *intr_remap_fault_reasons[] =
const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
{
- if (fault_reason >= 0x20 && (fault_reason <= 0x20 +
- ARRAY_SIZE(intr_remap_fault_reasons))) {
+ if (fault_reason >= 0x20 && (fault_reason - 0x20 <
+ ARRAY_SIZE(irq_remap_fault_reasons))) {
*fault_type = INTR_REMAP;
- return intr_remap_fault_reasons[fault_reason - 0x20];
+ return irq_remap_fault_reasons[fault_reason - 0x20];
} else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
*fault_type = DMA_REMAP;
return dma_remap_fault_reasons[fault_reason];
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f93d5ac..bf2fbaa 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -42,6 +42,7 @@
#include <linux/dmi.h>
#include <linux/pci-ats.h>
#include <linux/memblock.h>
+#include <asm/irq_remapping.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
@@ -4082,7 +4083,7 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
if (cap == IOMMU_CAP_CACHE_COHERENCY)
return dmar_domain->iommu_snooping;
if (cap == IOMMU_CAP_INTR_REMAP)
- return intr_remapping_enabled;
+ return irq_remapping_enabled;
return 0;
}
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 6777ca0..6d34706 100644
--- a/drivers/iommu/intr_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -10,49 +10,33 @@
#include <asm/smp.h>
#include <asm/cpu.h>
#include <linux/intel-iommu.h>
-#include "intr_remapping.h"
#include <acpi/acpi.h>
+#include <asm/irq_remapping.h>
#include <asm/pci-direct.h>
+#include <asm/msidef.h>
-static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
-static struct hpet_scope ir_hpet[MAX_HPET_TBS];
-static int ir_ioapic_num, ir_hpet_num;
-int intr_remapping_enabled;
-
-static int disable_intremap;
-static int disable_sourceid_checking;
-static int no_x2apic_optout;
+#include "irq_remapping.h"
-static __init int setup_nointremap(char *str)
-{
- disable_intremap = 1;
- return 0;
-}
-early_param("nointremap", setup_nointremap);
+struct ioapic_scope {
+ struct intel_iommu *iommu;
+ unsigned int id;
+ unsigned int bus; /* PCI bus number */
+ unsigned int devfn; /* PCI devfn number */
+};
-static __init int setup_intremap(char *str)
-{
- if (!str)
- return -EINVAL;
+struct hpet_scope {
+ struct intel_iommu *iommu;
+ u8 id;
+ unsigned int bus;
+ unsigned int devfn;
+};
- while (*str) {
- if (!strncmp(str, "on", 2))
- disable_intremap = 0;
- else if (!strncmp(str, "off", 3))
- disable_intremap = 1;
- else if (!strncmp(str, "nosid", 5))
- disable_sourceid_checking = 1;
- else if (!strncmp(str, "no_x2apic_optout", 16))
- no_x2apic_optout = 1;
-
- str += strcspn(str, ",");
- while (*str == ',')
- str++;
- }
+#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
+#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
- return 0;
-}
-early_param("intremap", setup_intremap);
+static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
+static struct hpet_scope ir_hpet[MAX_HPET_TBS];
+static int ir_ioapic_num, ir_hpet_num;
static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
@@ -80,7 +64,7 @@ int get_irte(int irq, struct irte *entry)
return 0;
}
-int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
+static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{
struct ir_table *table = iommu->ir_table;
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
@@ -152,7 +136,7 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
return qi_submit_sync(&desc, iommu);
}
-int map_irq_to_irte_handle(int irq, u16 *sub_handle)
+static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
{
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
@@ -168,7 +152,7 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle)
return index;
}
-int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
+static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
{
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
@@ -188,7 +172,7 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
return 0;
}
-int modify_irte(int irq, struct irte *irte_modified)
+static int modify_irte(int irq, struct irte *irte_modified)
{
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
struct intel_iommu *iommu;
@@ -216,7 +200,7 @@ int modify_irte(int irq, struct irte *irte_modified)
return rc;
}
-struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
+static struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
{
int i;
@@ -226,7 +210,7 @@ struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
return NULL;
}
-struct intel_iommu *map_ioapic_to_ir(int apic)
+static struct intel_iommu *map_ioapic_to_ir(int apic)
{
int i;
@@ -236,7 +220,7 @@ struct intel_iommu *map_ioapic_to_ir(int apic)
return NULL;
}
-struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
+static struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
{
struct dmar_drhd_unit *drhd;
@@ -270,7 +254,7 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
}
-int free_irte(int irq)
+static int free_irte(int irq)
{
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
unsigned long flags;
@@ -328,7 +312,7 @@ static void set_irte_sid(struct irte *irte, unsigned int svt,
irte->sid = sid;
}
-int set_ioapic_sid(struct irte *irte, int apic)
+static int set_ioapic_sid(struct irte *irte, int apic)
{
int i;
u16 sid = 0;
@@ -353,7 +337,7 @@ int set_ioapic_sid(struct irte *irte, int apic)
return 0;
}
-int set_hpet_sid(struct irte *irte, u8 id)
+static int set_hpet_sid(struct irte *irte, u8 id)
{
int i;
u16 sid = 0;
@@ -383,7 +367,7 @@ int set_hpet_sid(struct irte *irte, u8 id)
return 0;
}
-int set_msi_sid(struct irte *irte, struct pci_dev *dev)
+static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
struct pci_dev *bridge;
@@ -410,7 +394,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev)
return 0;
}
-static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
+static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode)
{
u64 addr;
u32 sts;
@@ -450,7 +434,7 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
}
-static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
+static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
{
struct ir_table *ir_table;
struct page *pages;
@@ -473,14 +457,14 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
ir_table->base = page_address(pages);
- iommu_set_intr_remapping(iommu, mode);
+ iommu_set_irq_remapping(iommu, mode);
return 0;
}
/*
* Disable Interrupt Remapping.
*/
-static void iommu_disable_intr_remapping(struct intel_iommu *iommu)
+static void iommu_disable_irq_remapping(struct intel_iommu *iommu)
{
unsigned long flags;
u32 sts;
@@ -519,11 +503,11 @@ static int __init dmar_x2apic_optout(void)
return dmar->flags & DMAR_X2APIC_OPT_OUT;
}
-int __init intr_remapping_supported(void)
+static int __init intel_irq_remapping_supported(void)
{
struct dmar_drhd_unit *drhd;
- if (disable_intremap)
+ if (disable_irq_remap)
return 0;
if (!dmar_ir_support())
@@ -539,7 +523,7 @@ int __init intr_remapping_supported(void)
return 1;
}
-int __init enable_intr_remapping(void)
+static int __init intel_enable_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
int setup = 0;
@@ -577,7 +561,7 @@ int __init enable_intr_remapping(void)
* Disable intr remapping and queued invalidation, if already
* enabled prior to OS handover.
*/
- iommu_disable_intr_remapping(iommu);
+ iommu_disable_irq_remapping(iommu);
dmar_disable_qi(iommu);
}
@@ -623,7 +607,7 @@ int __init enable_intr_remapping(void)
if (!ecap_ir_support(iommu->ecap))
continue;
- if (setup_intr_remapping(iommu, eim))
+ if (intel_setup_irq_remapping(iommu, eim))
goto error;
setup = 1;
@@ -632,7 +616,7 @@ int __init enable_intr_remapping(void)
if (!setup)
goto error;
- intr_remapping_enabled = 1;
+ irq_remapping_enabled = 1;
pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
@@ -775,14 +759,14 @@ int __init parse_ioapics_under_ir(void)
int __init ir_dev_scope_init(void)
{
- if (!intr_remapping_enabled)
+ if (!irq_remapping_enabled)
return 0;
return dmar_dev_scope_init();
}
rootfs_initcall(ir_dev_scope_init);
-void disable_intr_remapping(void)
+static void disable_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
@@ -794,11 +778,11 @@ void disable_intr_remapping(void)
if (!ecap_ir_support(iommu->ecap))
continue;
- iommu_disable_intr_remapping(iommu);
+ iommu_disable_irq_remapping(iommu);
}
}
-int reenable_intr_remapping(int eim)
+static int reenable_irq_remapping(int eim)
{
struct dmar_drhd_unit *drhd;
int setup = 0;
@@ -816,7 +800,7 @@ int reenable_intr_remapping(int eim)
continue;
/* Set up interrupt remapping for iommu.*/
- iommu_set_intr_remapping(iommu, eim);
+ iommu_set_irq_remapping(iommu, eim);
setup = 1;
}
@@ -832,3 +816,254 @@ error:
return -1;
}
+static void prepare_irte(struct irte *irte, int vector,
+ unsigned int dest)
+{
+ memset(irte, 0, sizeof(*irte));
+
+ irte->present = 1;
+ irte->dst_mode = apic->irq_dest_mode;
+ /*
+ * Trigger mode in the IRTE will always be edge, and for IO-APIC, the
+ * actual level or edge trigger will be setup in the IO-APIC
+ * RTE. This will help simplify level triggered irq migration.
+ * For more details, see the comments (in io_apic.c) explainig IO-APIC
+ * irq migration in the presence of interrupt-remapping.
+ */
+ irte->trigger_mode = 0;
+ irte->dlvry_mode = apic->irq_delivery_mode;
+ irte->vector = vector;
+ irte->dest_id = IRTE_DEST(dest);
+ irte->redir_hint = 1;
+}
+
+static int intel_setup_ioapic_entry(int irq,
+ struct IO_APIC_route_entry *route_entry,
+ unsigned int destination, int vector,
+ struct io_apic_irq_attr *attr)
+{
+ int ioapic_id = mpc_ioapic_id(attr->ioapic);
+ struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id);
+ struct IR_IO_APIC_route_entry *entry;
+ struct irte irte;
+ int index;
+
+ if (!iommu) {
+ pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
+ return -ENODEV;
+ }
+
+ entry = (struct IR_IO_APIC_route_entry *)route_entry;
+
+ index = alloc_irte(iommu, irq, 1);
+ if (index < 0) {
+ pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id);
+ return -ENOMEM;
+ }
+
+ prepare_irte(&irte, vector, destination);
+
+ /* Set source-id of interrupt request */
+ set_ioapic_sid(&irte, ioapic_id);
+
+ modify_irte(irq, &irte);
+
+ apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
+ "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
+ "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
+ "Avail:%X Vector:%02X Dest:%08X "
+ "SID:%04X SQ:%X SVT:%X)\n",
+ attr->ioapic, irte.present, irte.fpd, irte.dst_mode,
+ irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
+ irte.avail, irte.vector, irte.dest_id,
+ irte.sid, irte.sq, irte.svt);
+
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index2 = (index >> 15) & 0x1;
+ entry->zero = 0;
+ entry->format = 1;
+ entry->index = (index & 0x7fff);
+ /*
+ * IO-APIC RTE will be configured with virtual vector.
+ * irq handler will do the explicit EOI to the io-apic.
+ */
+ entry->vector = attr->ioapic_pin;
+ entry->mask = 0; /* enable IRQ */
+ entry->trigger = attr->trigger;
+ entry->polarity = attr->polarity;
+
+ /* Mask level triggered irqs.
+ * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
+ */
+ if (attr->trigger)
+ entry->mask = 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Migrate the IO-APIC irq in the presence of intr-remapping.
+ *
+ * For both level and edge triggered, irq migration is a simple atomic
+ * update(of vector and cpu destination) of IRTE and flush the hardware cache.
+ *
+ * For level triggered, we eliminate the io-apic RTE modification (with the
+ * updated vector information), by using a virtual vector (io-apic pin number).
+ * Real vector that is used for interrupting cpu will be coming from
+ * the interrupt-remapping table entry.
+ *
+ * As the migration is a simple atomic update of IRTE, the same mechanism
+ * is used to migrate MSI irq's in the presence of interrupt-remapping.
+ */
+static int
+intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
+{
+ struct irq_cfg *cfg = data->chip_data;
+ unsigned int dest, irq = data->irq;
+ struct irte irte;
+
+ if (!cpumask_intersects(mask, cpu_online_mask))
+ return -EINVAL;
+
+ if (get_irte(irq, &irte))
+ return -EBUSY;
+
+ if (assign_irq_vector(irq, cfg, mask))
+ return -EBUSY;
+
+ dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
+
+ irte.vector = cfg->vector;
+ irte.dest_id = IRTE_DEST(dest);
+
+ /*
+ * Atomically updates the IRTE with the new destination, vector
+ * and flushes the interrupt entry cache.
+ */
+ modify_irte(irq, &irte);
+
+ /*
+ * After this point, all the interrupts will start arriving
+ * at the new destination. So, time to cleanup the previous
+ * vector allocation.
+ */
+ if (cfg->move_in_progress)
+ send_cleanup_vector(cfg);
+
+ cpumask_copy(data->affinity, mask);
+ return 0;
+}
+#endif
+
+static void intel_compose_msi_msg(struct pci_dev *pdev,
+ unsigned int irq, unsigned int dest,
+ struct msi_msg *msg, u8 hpet_id)
+{
+ struct irq_cfg *cfg;
+ struct irte irte;
+ u16 sub_handle = 0;
+ int ir_index;
+
+ cfg = irq_get_chip_data(irq);
+
+ ir_index = map_irq_to_irte_handle(irq, &sub_handle);
+ BUG_ON(ir_index == -1);
+
+ prepare_irte(&irte, cfg->vector, dest);
+
+ /* Set source-id of interrupt request */
+ if (pdev)
+ set_msi_sid(&irte, pdev);
+ else
+ set_hpet_sid(&irte, hpet_id);
+
+ modify_irte(irq, &irte);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->data = sub_handle;
+ msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
+ MSI_ADDR_IR_SHV |
+ MSI_ADDR_IR_INDEX1(ir_index) |
+ MSI_ADDR_IR_INDEX2(ir_index);
+}
+
+/*
+ * Map the PCI dev to the corresponding remapping hardware unit
+ * and allocate 'nvec' consecutive interrupt-remapping table entries
+ * in it.
+ */
+static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec)
+{
+ struct intel_iommu *iommu;
+ int index;
+
+ iommu = map_dev_to_ir(dev);
+ if (!iommu) {
+ printk(KERN_ERR
+ "Unable to map PCI %s to iommu\n", pci_name(dev));
+ return -ENOENT;
+ }
+
+ index = alloc_irte(iommu, irq, nvec);
+ if (index < 0) {
+ printk(KERN_ERR
+ "Unable to allocate %d IRTE for PCI %s\n", nvec,
+ pci_name(dev));
+ return -ENOSPC;
+ }
+ return index;
+}
+
+static int intel_msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
+ int index, int sub_handle)
+{
+ struct intel_iommu *iommu;
+
+ iommu = map_dev_to_ir(pdev);
+ if (!iommu)
+ return -ENOENT;
+ /*
+ * setup the mapping between the irq and the IRTE
+ * base index, the sub_handle pointing to the
+ * appropriate interrupt remap table entry.
+ */
+ set_irte_irq(irq, iommu, index, sub_handle);
+
+ return 0;
+}
+
+static int intel_setup_hpet_msi(unsigned int irq, unsigned int id)
+{
+ struct intel_iommu *iommu = map_hpet_to_ir(id);
+ int index;
+
+ if (!iommu)
+ return -1;
+
+ index = alloc_irte(iommu, irq, 1);
+ if (index < 0)
+ return -1;
+
+ return 0;
+}
+
+struct irq_remap_ops intel_irq_remap_ops = {
+ .supported = intel_irq_remapping_supported,
+ .prepare = dmar_table_init,
+ .enable = intel_enable_irq_remapping,
+ .disable = disable_irq_remapping,
+ .reenable = reenable_irq_remapping,
+ .enable_faulting = enable_drhd_fault_handling,
+ .setup_ioapic_entry = intel_setup_ioapic_entry,
+#ifdef CONFIG_SMP
+ .set_affinity = intel_ioapic_set_affinity,
+#endif
+ .free_irq = free_irte,
+ .compose_msi_msg = intel_compose_msi_msg,
+ .msi_alloc_irq = intel_msi_alloc_irq,
+ .msi_setup_irq = intel_msi_setup_irq,
+ .setup_hpet_msi = intel_setup_hpet_msi,
+};
diff --git a/drivers/iommu/intr_remapping.h b/drivers/iommu/intr_remapping.h
deleted file mode 100644
index 5662fec..0000000
--- a/drivers/iommu/intr_remapping.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#include <linux/intel-iommu.h>
-
-struct ioapic_scope {
- struct intel_iommu *iommu;
- unsigned int id;
- unsigned int bus; /* PCI bus number */
- unsigned int devfn; /* PCI devfn number */
-};
-
-struct hpet_scope {
- struct intel_iommu *iommu;
- u8 id;
- unsigned int bus;
- unsigned int devfn;
-};
-
-#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
new file mode 100644
index 0000000..40cda8e
--- /dev/null
+++ b/drivers/iommu/irq_remapping.c
@@ -0,0 +1,166 @@
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include "irq_remapping.h"
+
+int irq_remapping_enabled;
+
+int disable_irq_remap;
+int disable_sourceid_checking;
+int no_x2apic_optout;
+
+static struct irq_remap_ops *remap_ops;
+
+static __init int setup_nointremap(char *str)
+{
+ disable_irq_remap = 1;
+ return 0;
+}
+early_param("nointremap", setup_nointremap);
+
+static __init int setup_irqremap(char *str)
+{
+ if (!str)
+ return -EINVAL;
+
+ while (*str) {
+ if (!strncmp(str, "on", 2))
+ disable_irq_remap = 0;
+ else if (!strncmp(str, "off", 3))
+ disable_irq_remap = 1;
+ else if (!strncmp(str, "nosid", 5))
+ disable_sourceid_checking = 1;
+ else if (!strncmp(str, "no_x2apic_optout", 16))
+ no_x2apic_optout = 1;
+
+ str += strcspn(str, ",");
+ while (*str == ',')
+ str++;
+ }
+
+ return 0;
+}
+early_param("intremap", setup_irqremap);
+
+void __init setup_irq_remapping_ops(void)
+{
+ remap_ops = &intel_irq_remap_ops;
+}
+
+int irq_remapping_supported(void)
+{
+ if (disable_irq_remap)
+ return 0;
+
+ if (!remap_ops || !remap_ops->supported)
+ return 0;
+
+ return remap_ops->supported();
+}
+
+int __init irq_remapping_prepare(void)
+{
+ if (!remap_ops || !remap_ops->prepare)
+ return -ENODEV;
+
+ return remap_ops->prepare();
+}
+
+int __init irq_remapping_enable(void)
+{
+ if (!remap_ops || !remap_ops->enable)
+ return -ENODEV;
+
+ return remap_ops->enable();
+}
+
+void irq_remapping_disable(void)
+{
+ if (!remap_ops || !remap_ops->disable)
+ return;
+
+ remap_ops->disable();
+}
+
+int irq_remapping_reenable(int mode)
+{
+ if (!remap_ops || !remap_ops->reenable)
+ return 0;
+
+ return remap_ops->reenable(mode);
+}
+
+int __init irq_remap_enable_fault_handling(void)
+{
+ if (!remap_ops || !remap_ops->enable_faulting)
+ return -ENODEV;
+
+ return remap_ops->enable_faulting();
+}
+
+int setup_ioapic_remapped_entry(int irq,
+ struct IO_APIC_route_entry *entry,
+ unsigned int destination, int vector,
+ struct io_apic_irq_attr *attr)
+{
+ if (!remap_ops || !remap_ops->setup_ioapic_entry)
+ return -ENODEV;
+
+ return remap_ops->setup_ioapic_entry(irq, entry, destination,
+ vector, attr);
+}
+
+#ifdef CONFIG_SMP
+int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
+{
+ if (!remap_ops || !remap_ops->set_affinity)
+ return 0;
+
+ return remap_ops->set_affinity(data, mask, force);
+}
+#endif
+
+void free_remapped_irq(int irq)
+{
+ if (!remap_ops || !remap_ops->free_irq)
+ return;
+
+ remap_ops->free_irq(irq);
+}
+
+void compose_remapped_msi_msg(struct pci_dev *pdev,
+ unsigned int irq, unsigned int dest,
+ struct msi_msg *msg, u8 hpet_id)
+{
+ if (!remap_ops || !remap_ops->compose_msi_msg)
+ return;
+
+ remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+}
+
+int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+{
+ if (!remap_ops || !remap_ops->msi_alloc_irq)
+ return -ENODEV;
+
+ return remap_ops->msi_alloc_irq(pdev, irq, nvec);
+}
+
+int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+ int index, int sub_handle)
+{
+ if (!remap_ops || !remap_ops->msi_setup_irq)
+ return -ENODEV;
+
+ return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
+}
+
+int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
+{
+ if (!remap_ops || !remap_ops->setup_hpet_msi)
+ return -ENODEV;
+
+ return remap_ops->setup_hpet_msi(irq, id);
+}
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
new file mode 100644
index 0000000..be9d729
--- /dev/null
+++ b/drivers/iommu/irq_remapping.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This header file contains stuff that is shared between different interrupt
+ * remapping drivers but with no need to be visible outside of the IOMMU layer.
+ */
+
+#ifndef __IRQ_REMAPPING_H
+#define __IRQ_REMAPPING_H
+
+#ifdef CONFIG_IRQ_REMAP
+
+struct IO_APIC_route_entry;
+struct io_apic_irq_attr;
+struct irq_data;
+struct cpumask;
+struct pci_dev;
+struct msi_msg;
+
+extern int disable_irq_remap;
+extern int disable_sourceid_checking;
+extern int no_x2apic_optout;
+
+struct irq_remap_ops {
+ /* Check whether Interrupt Remapping is supported */
+ int (*supported)(void);
+
+ /* Initializes hardware and makes it ready for remapping interrupts */
+ int (*prepare)(void);
+
+ /* Enables the remapping hardware */
+ int (*enable)(void);
+
+ /* Disables the remapping hardware */
+ void (*disable)(void);
+
+ /* Reenables the remapping hardware */
+ int (*reenable)(int);
+
+ /* Enable fault handling */
+ int (*enable_faulting)(void);
+
+ /* IO-APIC setup routine */
+ int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *,
+ unsigned int, int,
+ struct io_apic_irq_attr *);
+
+#ifdef CONFIG_SMP
+ /* Set the CPU affinity of a remapped interrupt */
+ int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
+ bool force);
+#endif
+
+ /* Free an IRQ */
+ int (*free_irq)(int);
+
+ /* Create MSI msg to use for interrupt remapping */
+ void (*compose_msi_msg)(struct pci_dev *,
+ unsigned int, unsigned int,
+ struct msi_msg *, u8);
+
+ /* Allocate remapping resources for MSI */
+ int (*msi_alloc_irq)(struct pci_dev *, int, int);
+
+ /* Setup the remapped MSI irq */
+ int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int);
+
+ /* Setup interrupt remapping for an HPET MSI */
+ int (*setup_hpet_msi)(unsigned int, unsigned int);
+};
+
+extern struct irq_remap_ops intel_irq_remap_ops;
+
+#endif /* CONFIG_IRQ_REMAP */
+
+#endif /* __IRQ_REMAPPING_H */
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 3b9278b..5275887 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -148,6 +148,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_post_reset,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_post_reset,
+ .disable_hub_initiated_lpm = 1,
};
/* get message text for usb_submit_urb return code
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index bb12d80..d0a41cb 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -124,6 +124,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_resume,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_resume,
+ .disable_hub_initiated_lpm = 1,
};
struct usb_cardstate {
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 83206e4..c65c344 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -2126,6 +2126,7 @@ static struct usb_driver hfcsusb_drv = {
.id_table = hfcsusb_idtab,
.probe = hfcsusb_probe,
.disconnect = hfcsusb_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(hfcsusb_drv);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 62c65bd..84f9c810 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1568,6 +1568,7 @@ static struct usb_driver hfc_drv = {
.id_table = hfcusb_idtab,
.probe = hfc_usb_probe,
.disconnect = hfc_usb_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
static void __exit
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 100296e..54ef9e4 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -182,6 +182,7 @@ static struct usb_driver st5481_usb_driver = {
.probe = probe_st5481,
.disconnect = disconnect_st5481,
.id_table = st5481_ids,
+ .disable_hub_initiated_lpm = 1,
};
static int __init st5481_usb_init(void)
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index d9f5524..8c610fa 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
static char *isdn_revision = "$Revision: 1.1.2.3 $";
extern char *isdn_net_revision;
-extern char *isdn_tty_revision;
#ifdef CONFIG_ISDN_PPP
extern char *isdn_ppp_revision;
#else
@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
- init_waitqueue_head(&dev->mdm.info[i].open_wait);
- init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
strcpy(tmprev, isdn_revision);
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_tty_revision);
- printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_net_revision);
printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_ppp_revision);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 3831abd..7bc5067 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1,5 +1,4 @@
-/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
+/*
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
@@ -12,6 +11,7 @@
#undef ISDN_TTY_STAT_DEBUG
#include <linux/isdn.h>
+#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -48,9 +48,6 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
-
-
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
@@ -68,49 +65,54 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
struct tty_struct *tty;
char last;
- if (info->online) {
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- len = skb->len
+ if (!info->online)
+ return 0;
+
+ tty = info->port.tty;
+ if (!tty)
+ return 0;
+
+ if (!(info->mcr & UART_MCR_RTS))
+ return 0;
+
+ len = skb->len
#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif
- ;
+ ;
+
+ c = tty_buffer_request_room(tty, len);
+ if (c < len)
+ return 0;
- c = tty_buffer_request_room(tty, len);
- if (c >= len) {
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
- int l = skb->len;
- unsigned char *dp = skb->data;
- while (--l) {
- if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- tty_insert_flip_char(tty, *dp++, 0);
- }
- if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- last = *dp;
- } else {
-#endif
- if (len > 1)
- tty_insert_flip_string(tty, skb->data, len - 1);
- last = skb->data[len - 1];
#ifdef CONFIG_ISDN_AUDIO
- }
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ int l = skb->len;
+ unsigned char *dp = skb->data;
+ while (--l) {
+ if (*dp == DLE)
+ tty_insert_flip_char(tty, DLE, 0);
+ tty_insert_flip_char(tty, *dp++, 0);
+ }
+ if (*dp == DLE)
+ tty_insert_flip_char(tty, DLE, 0);
+ last = *dp;
+ } else {
#endif
- if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(tty, last, 0xFF);
- else
- tty_insert_flip_char(tty, last, TTY_NORMAL);
- tty_flip_buffer_push(tty);
- kfree_skb(skb);
- return 1;
- }
- }
- }
+ if (len > 1)
+ tty_insert_flip_string(tty, skb->data, len - 1);
+ last = skb->data[len - 1];
+#ifdef CONFIG_ISDN_AUDIO
}
- return 0;
+#endif
+ if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
+ tty_insert_flip_char(tty, last, 0xFF);
+ else
+ tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_flip_buffer_push(tty);
+ kfree_skb(skb);
+
+ return 1;
}
/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
@@ -128,35 +130,39 @@ isdn_tty_readmodem(void)
modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if ((midx = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[midx];
- if (info->online) {
- r = 0;
+ midx = dev->m_idx[i];
+ if (midx < 0)
+ continue;
+
+ info = &dev->mdm.info[midx];
+ if (!info->online)
+ continue;
+
+ r = 0;
#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
- if (r)
- tty_flip_buffer_push(tty);
- } else
- r = 1;
- } else
- r = 1;
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
- }
- }
+ isdn_audio_eval_dtmf(info);
+ if ((info->vonline & 1) && (info->emu.vpar[1]))
+ isdn_audio_eval_silence(info);
+#endif
+ tty = info->port.tty;
+ if (tty) {
+ if (info->mcr & UART_MCR_RTS) {
+ /* CISCO AsyncPPP Hack */
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
+ else
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
+ if (r)
+ tty_flip_buffer_push(tty);
+ } else
+ r = 1;
+ } else
+ r = 1;
+ if (r) {
+ info->rcvsched = 0;
+ resched = 1;
+ } else
+ info->rcvsched = 1;
}
if (!resched)
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
@@ -294,7 +300,7 @@ isdn_tty_tint(modem_info *info)
len = skb->len;
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
info->isdn_channel, 1, skb)) == len) {
- struct tty_struct *tty = info->tty;
+ struct tty_struct *tty = info->port.tty;
info->send_outstanding++;
info->msr &= ~UART_MSR_CTS;
info->lsr &= ~UART_LSR_TEMT;
@@ -327,7 +333,7 @@ isdn_tty_countDLE(unsigned char *buf, int len)
static int
isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
{
- unsigned char *p = &info->xmit_buf[info->xmit_count];
+ unsigned char *p = &info->port.xmit_buf[info->xmit_count];
int count = 0;
while (len > 0) {
@@ -471,7 +477,7 @@ isdn_tty_senddown(modem_info *info)
return;
}
skb_reserve(skb, skb_res);
- memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+ memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);
info->xmit_count = 0;
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 2) {
@@ -699,7 +705,7 @@ isdn_tty_modem_hup(modem_info *info, int local)
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
#endif
info->rcvsched = 0;
- isdn_tty_flush_buffer(info->tty);
+ isdn_tty_flush_buffer(info->port.tty);
if (info->online) {
info->last_lhup = local;
info->online = 0;
@@ -997,20 +1003,21 @@ isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
static void
isdn_tty_change_speed(modem_info *info)
{
+ struct tty_port *port = &info->port;
uint cflag,
cval,
quot;
int i;
- if (!info->tty || !info->tty->termios)
+ if (!port->tty || !port->tty->termios)
return;
- cflag = info->tty->termios->c_cflag;
+ cflag = port->tty->termios->c_cflag;
quot = i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
if (i < 1 || i > 2)
- info->tty->termios->c_cflag &= ~CBAUDEX;
+ port->tty->termios->c_cflag &= ~CBAUDEX;
else
i += 15;
}
@@ -1040,20 +1047,20 @@ isdn_tty_change_speed(modem_info *info)
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
- info->flags |= ISDN_ASYNC_CTS_FLOW;
+ port->flags |= ASYNC_CTS_FLOW;
} else
- info->flags &= ~ISDN_ASYNC_CTS_FLOW;
+ port->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
- info->flags &= ~ISDN_ASYNC_CHECK_CD;
+ port->flags &= ~ASYNC_CHECK_CD;
else {
- info->flags |= ISDN_ASYNC_CHECK_CD;
+ port->flags |= ASYNC_CHECK_CD;
}
}
static int
isdn_tty_startup(modem_info *info)
{
- if (info->flags & ISDN_ASYNC_INITIALIZED)
+ if (info->port.flags & ASYNC_INITIALIZED)
return 0;
isdn_lock_drivers();
#ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1063,14 +1070,14 @@ isdn_tty_startup(modem_info *info)
* Now, initialize the UART
*/
info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->port.tty)
+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
/*
* and set the speed of the serial port
*/
isdn_tty_change_speed(info);
- info->flags |= ISDN_ASYNC_INITIALIZED;
+ info->port.flags |= ASYNC_INITIALIZED;
info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
info->send_outstanding = 0;
return 0;
@@ -1083,14 +1090,14 @@ isdn_tty_startup(modem_info *info)
static void
isdn_tty_shutdown(modem_info *info)
{
- if (!(info->flags & ISDN_ASYNC_INITIALIZED))
+ if (!(info->port.flags & ASYNC_INITIALIZED))
return;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
#endif
isdn_unlock_drivers();
info->msr &= ~UART_MSR_RI;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
@@ -1100,10 +1107,10 @@ isdn_tty_shutdown(modem_info *info)
isdn_tty_modem_hup(info, 1);
}
}
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->port.tty)
+ set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->flags &= ~ISDN_ASYNC_INITIALIZED;
+ info->port.flags &= ~ASYNC_INITIALIZED;
}
/* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1146,7 +1153,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
&(m->pluscount),
&(m->lastplus));
- memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+ memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline) {
int cc = isdn_tty_handleDLEdown(info, m, c);
@@ -1478,107 +1485,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* isdn_tty_open() and friends
* ------------------------------------------------------------
*/
-static int
-isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info)
-{
- DECLARE_WAITQUEUE(wait, NULL);
- int do_clocal = 0;
- int retval;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ISDN_ASYNC_CLOSING)) {
- if (info->flags & ISDN_ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef MODEM_DO_RESTART
- if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
- return -EBUSY;
- info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
- return 0;
- }
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
- if (info->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * isdn_tty_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- if (!(tty_hung_up_p(filp)))
- info->count--;
- info->blocked_open++;
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ISDN_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
- if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
- !(info->flags & ISDN_ASYNC_CLOSING) &&
- (do_clocal || (info->msr & UART_MSR_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
- return 0;
-}
/*
* This routine is called whenever a serial port is opened. It
@@ -1589,23 +1495,22 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
+ struct tty_port *port;
modem_info *info;
int retval;
info = &dev->mdm.info[tty->index];
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
return -ENODEV;
- if (!try_module_get(info->owner)) {
- printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
- return -ENODEV;
- }
+ port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
- info->count);
+ port->count);
#endif
- info->count++;
+ port->count++;
tty->driver_data = info;
- info->tty = tty;
+ port->tty = tty;
+ tty->port = port;
/*
* Start up serial port
*/
@@ -1614,15 +1519,13 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open return after startup\n");
#endif
- module_put(info->owner);
return retval;
}
- retval = isdn_tty_block_til_ready(tty, filp, info);
+ retval = tty_port_block_til_ready(port, tty, filp);
if (retval) {
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
#endif
- module_put(info->owner);
return retval;
}
#ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1639,6 +1542,7 @@ static void
isdn_tty_close(struct tty_struct *tty, struct file *filp)
{
modem_info *info = (modem_info *) tty->driver_data;
+ struct tty_port *port = &info->port;
ulong timeout;
if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
@@ -1649,7 +1553,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#endif
return;
}
- if ((tty->count == 1) && (info->count != 1)) {
+ if ((tty->count == 1) && (port->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1658,30 +1562,21 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
* serial port won't be shutdown.
*/
printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
+ "info->count is %d\n", port->count);
+ port->count = 1;
}
- if (--info->count < 0) {
+ if (--port->count < 0) {
printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
- info->line, info->count);
- info->count = 0;
+ info->line, port->count);
+ port->count = 0;
}
- if (info->count) {
+ if (port->count) {
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
#endif
- module_put(info->owner);
return;
}
- info->flags |= ISDN_ASYNC_CLOSING;
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
+ port->flags |= ASYNC_CLOSING;
tty->closing = 1;
/*
@@ -1690,7 +1585,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
* interrupt driver to stop checking the data ready bit in the
* line status register.
*/
- if (info->flags & ISDN_ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED) {
tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
@@ -1708,16 +1603,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
isdn_tty_shutdown(info);
isdn_tty_flush_buffer(tty);
tty_ldisc_flush(tty);
- info->tty = NULL;
+ port->tty = NULL;
info->ncarrier = 0;
- tty->closing = 0;
- module_put(info->owner);
- if (info->blocked_open) {
- msleep_interruptible(500);
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+
+ tty_port_close_end(port, tty);
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
#endif
@@ -1730,14 +1619,15 @@ static void
isdn_tty_hangup(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
+ struct tty_port *port = &info->port;
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
return;
isdn_tty_shutdown(info);
- info->count = 0;
- info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
- info->tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ port->count = 0;
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
+ port->tty = NULL;
+ wake_up_interruptible(&port->open_wait);
}
/* This routine initializes all emulator-data.
@@ -1864,6 +1754,16 @@ static const struct tty_operations modem_ops = {
.tiocmset = isdn_tty_tiocmset,
};
+static int isdn_tty_carrier_raised(struct tty_port *port)
+{
+ modem_info *info = container_of(port, modem_info, port);
+ return info->msr & UART_MSR_DCD;
+}
+
+static const struct tty_port_operations isdn_tty_port_ops = {
+ .carrier_raised = isdn_tty_carrier_raised,
+};
+
int
isdn_tty_modem_init(void)
{
@@ -1899,9 +1799,8 @@ isdn_tty_modem_init(void)
goto err_unregister;
}
#endif
-#ifdef MODULE
- info->owner = THIS_MODULE;
-#endif
+ tty_port_init(&info->port);
+ info->port.ops = &isdn_tty_port_ops;
spin_lock_init(&info->readlock);
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
@@ -1913,12 +1812,7 @@ isdn_tty_modem_init(void)
isdn_tty_modem_reset_regs(info, 1);
info->magic = ISDN_ASYNC_MAGIC;
info->line = i;
- info->tty = NULL;
info->x_char = 0;
- info->count = 0;
- info->blocked_open = 0;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
info->isdn_driver = -1;
info->isdn_channel = -1;
info->drv_index = -1;
@@ -1930,13 +1824,15 @@ isdn_tty_modem_init(void)
#ifdef CONFIG_ISDN_AUDIO
skb_queue_head_init(&info->dtmf_queue);
#endif
- if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
+ info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
+ GFP_KERNEL);
+ if (!info->port.xmit_buf) {
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
retval = -ENOMEM;
goto err_unregister;
}
/* Make room for T.70 header */
- info->xmit_buf += 4;
+ info->port.xmit_buf += 4;
}
return 0;
err_unregister:
@@ -1945,7 +1841,7 @@ err_unregister:
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
- kfree(info->xmit_buf - 4);
+ kfree(info->port.xmit_buf - 4);
}
tty_unregister_driver(m->tty_modem);
err:
@@ -1966,7 +1862,7 @@ isdn_tty_exit(void)
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
- kfree(info->xmit_buf - 4);
+ kfree(info->port.xmit_buf - 4);
}
tty_unregister_driver(dev->mdm.tty_modem);
put_tty_driver(dev->mdm.tty_modem);
@@ -2068,7 +1964,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
- if (info->count == 0)
+ if (info->port.count == 0)
continue;
if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
(info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
@@ -2076,12 +1972,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
- info->flags, info->isdn_driver, info->isdn_channel,
- dev->usage[idx]);
+ info->port.flags, info->isdn_driver,
+ info->isdn_channel, dev->usage[idx]);
#endif
if (
#ifndef FIX_FILE_TRANSFER
- (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+ (info->port.flags & ASYNC_NORMAL_ACTIVE) &&
#endif
(info->isdn_driver == -1) &&
(info->isdn_channel == -1) &&
@@ -2120,8 +2016,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
return (wret == 2) ? 3 : 0;
}
-#define TTY_IS_ACTIVE(info) \
- (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+#define TTY_IS_ACTIVE(info) (info->port.flags & ASYNC_NORMAL_ACTIVE)
int
isdn_tty_stat_callback(int i, isdn_ctrl *c)
@@ -2212,9 +2107,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
* for incoming call of this device when
* DCD follow the state of incoming carrier
*/
- if (info->blocked_open &&
+ if (info->port.blocked_open &&
(info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
- wake_up_interruptible(&info->open_wait);
+ wake_up_interruptible(&info->port.open_wait);
}
/* Schedule CONNECT-Message to any tty
@@ -2222,7 +2117,8 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
* set DCD-bit of its modem-status.
*/
if (TTY_IS_ACTIVE(info) ||
- (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
+ (info->port.blocked_open &&
+ (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
info->msr |= UART_MSR_DCD;
info->emu.charge = 0;
if (info->dialing & 0xf)
@@ -2339,8 +2235,8 @@ isdn_tty_at_cout(char *msg, modem_info *info)
l = strlen(msg);
spin_lock_irqsave(&info->readlock, flags);
- tty = info->tty;
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
+ tty = info->port.tty;
+ if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
spin_unlock_irqrestore(&info->readlock, flags);
return;
}
@@ -2490,15 +2386,15 @@ isdn_tty_modem_result(int code, modem_info *info)
case RESULT_NO_CARRIER:
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- (info->flags & ISDN_ASYNC_CLOSING),
- (!info->tty));
+ (info->port.flags & ASYNC_CLOSING),
+ (!info->port.tty));
#endif
m->mdmreg[REG_RINGCNT] = 0;
del_timer(&info->nc_timer);
info->ncarrier = 0;
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+ if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
return;
- }
+
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 1) {
#ifdef ISDN_DEBUG_MODEM_VOICE
@@ -2629,14 +2525,11 @@ isdn_tty_modem_result(int code, modem_info *info)
}
}
if (code == RESULT_NO_CARRIER) {
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+ if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
return;
- }
- if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
- (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
- tty_hangup(info->tty);
- }
+
+ if (info->port.flags & ASYNC_CHECK_CD)
+ tty_hangup(info->port.tty);
}
}
@@ -3803,19 +3696,19 @@ isdn_tty_modem_escape(void)
int midx;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(dev->usage[i]))
- if ((midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
+ if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
+ modem_info *info = &dev->mdm.info[midx];
+ if (info->online) {
+ ton = 1;
+ if ((info->emu.pluscount == 3) &&
+ time_after(jiffies,
+ info->emu.lastplus + PLUSWAIT2)) {
+ info->emu.pluscount = 0;
+ info->online = 0;
+ isdn_tty_modem_result(RESULT_OK, info);
}
}
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
}
@@ -3873,15 +3766,14 @@ isdn_tty_carrier_timeout(void)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
- if (info->dialing) {
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- }
- else
- ton = 1;
- }
+ if (!info->dialing)
+ continue;
+ if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+ info->dialing = 0;
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+ isdn_tty_modem_hup(info, 1);
+ } else
+ ton = 1;
}
isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
}
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index fa51af1..a555da6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -204,11 +204,14 @@ config THERM_ADT746X
better fan behaviour by default, and some manual control.
config THERM_PM72
- tristate "Support for thermal management on PowerMac G5"
+ tristate "Support for thermal management on PowerMac G5 (AGP)"
depends on I2C && I2C_POWERMAC && PPC_PMAC64
+ default n
help
This driver provides thermostat and fan control for the desktop
- G5 machines.
+ G5 machines.
+
+ This is deprecated, use windfarm instead.
config WINDFARM
tristate "New PowerMac thermal control infrastructure"
@@ -221,6 +224,22 @@ config WINDFARM_PM81
help
This driver provides thermal control for the iMacG5
+config WINDFARM_PM72
+ tristate "Support for thermal management on PowerMac G5 (AGP)"
+ depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the PowerMac G5
+ "AGP" variants (PowerMac 7,2 and 7,3)
+
+config WINDFARM_RM31
+ tristate "Support for thermal management on Xserve G5"
+ depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the Xserve G5
+ (RackMac3,1)
+
config WINDFARM_PM91
tristate "Support for thermal management on PowerMac9,1"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6652a6e..6753b65 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -29,6 +29,20 @@ obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM72) += windfarm_fcu_controls.o \
+ windfarm_ad7417_sensor.o \
+ windfarm_lm75_sensor.o \
+ windfarm_max6690_sensor.o \
+ windfarm_pid.o \
+ windfarm_cpufreq_clamp.o \
+ windfarm_pm72.o
+obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \
+ windfarm_ad7417_sensor.o \
+ windfarm_lm75_sensor.o \
+ windfarm_lm87_sensor.o \
+ windfarm_pid.o \
+ windfarm_cpufreq_clamp.o \
+ windfarm_rm31.o
obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
windfarm_smu_sensors.o \
windfarm_lm75_sensor.o windfarm_pid.o \
diff --git a/drivers/macintosh/ams/ams-i2c.c b/drivers/macintosh/ams/ams-i2c.c
index abeecd2..978eda8 100644
--- a/drivers/macintosh/ams/ams-i2c.c
+++ b/drivers/macintosh/ams/ams-i2c.c
@@ -65,7 +65,7 @@ static int ams_i2c_probe(struct i2c_client *client,
static int ams_i2c_remove(struct i2c_client *client);
static const struct i2c_device_id ams_id[] = {
- { "ams", 0 },
+ { "MAC,accelerometer_1", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index fc71723c..f433521 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -47,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */
static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */
-static const char *sensor_location[3];
+static const char *sensor_location[3] = { "?", "?", "?" };
static int limit_adjust;
static int fan_speed = -1;
@@ -79,18 +79,16 @@ struct thermostat {
int last_speed[2];
int last_var[2];
int pwm_inv[2];
+ struct task_struct *thread;
+ struct platform_device *pdev;
+ enum {
+ ADT7460,
+ ADT7467
+ } type;
};
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct platform_device * of_dev;
-static struct thermostat* thermostat;
-static struct task_struct *thread_therm = NULL;
-
static void write_both_fan_speed(struct thermostat *th, int speed);
static void write_fan_speed(struct thermostat *th, int speed, int fan);
-static void thermostat_create_files(void);
-static void thermostat_remove_files(void);
static int
write_reg(struct thermostat* th, int reg, u8 data)
@@ -126,66 +124,6 @@ read_reg(struct thermostat* th, int reg)
return data;
}
-static struct i2c_driver thermostat_driver;
-
-static int
-attach_thermostat(struct i2c_adapter *adapter)
-{
- unsigned long bus_no;
- struct i2c_board_info info;
- struct i2c_client *client;
-
- if (strncmp(adapter->name, "uni-n", 5))
- return -ENODEV;
- bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
- if (bus_no != therm_bus)
- return -ENODEV;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
- info.addr = therm_address;
- client = i2c_new_device(adapter, &info);
- if (!client)
- return -ENODEV;
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &thermostat_driver.clients);
- return 0;
-}
-
-static int
-remove_thermostat(struct i2c_client *client)
-{
- struct thermostat *th = i2c_get_clientdata(client);
- int i;
-
- thermostat_remove_files();
-
- if (thread_therm != NULL) {
- kthread_stop(thread_therm);
- }
-
- printk(KERN_INFO "adt746x: Putting max temperatures back from "
- "%d, %d, %d to %d, %d, %d\n",
- th->limits[0], th->limits[1], th->limits[2],
- th->initial_limits[0], th->initial_limits[1],
- th->initial_limits[2]);
-
- for (i = 0; i < 3; i++)
- write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
- write_both_fan_speed(th, -1);
-
- thermostat = NULL;
-
- kfree(th);
-
- return 0;
-}
-
static int read_fan_speed(struct thermostat *th, u8 addr)
{
u8 tmp[2];
@@ -203,7 +141,7 @@ static int read_fan_speed(struct thermostat *th, u8 addr)
static void write_both_fan_speed(struct thermostat *th, int speed)
{
write_fan_speed(th, speed, 0);
- if (therm_type == ADT7460)
+ if (th->type == ADT7460)
write_fan_speed(th, speed, 1);
}
@@ -216,7 +154,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
else if (speed < -1)
speed = 0;
- if (therm_type == ADT7467 && fan == 1)
+ if (th->type == ADT7467 && fan == 1)
return;
if (th->last_speed[fan] != speed) {
@@ -239,7 +177,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
write_reg(th, FAN_SPD_SET[fan], speed);
} else {
/* back to automatic */
- if(therm_type == ADT7460) {
+ if(th->type == ADT7460) {
manual = read_reg(th,
MANUAL_MODE[fan]) & (~MANUAL_MASK);
manual &= ~INVERT_MASK;
@@ -293,7 +231,7 @@ static void update_fans_speed (struct thermostat *th)
/* we don't care about local sensor, so we start at sensor 1 */
for (i = 1; i < 3; i++) {
int started = 0;
- int fan_number = (therm_type == ADT7460 && i == 2);
+ int fan_number = (th->type == ADT7460 && i == 2);
int var = th->temps[i] - th->limits[i];
if (var > -1) {
@@ -370,116 +308,22 @@ static int monitor_task(void *arg)
static void set_limit(struct thermostat *th, int i)
{
- /* Set sensor1 limit higher to avoid powerdowns */
- th->limits[i] = default_limits_chip[i] + limit_adjust;
- write_reg(th, LIMIT_REG[i], th->limits[i]);
+ /* Set sensor1 limit higher to avoid powerdowns */
+ th->limits[i] = default_limits_chip[i] + limit_adjust;
+ write_reg(th, LIMIT_REG[i], th->limits[i]);
- /* set our limits to normal */
- th->limits[i] = default_limits_local[i] + limit_adjust;
+ /* set our limits to normal */
+ th->limits[i] = default_limits_local[i] + limit_adjust;
}
-static int probe_thermostat(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct thermostat* th;
- int rc;
- int i;
-
- if (thermostat)
- return 0;
-
- th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
- if (!th)
- return -ENOMEM;
-
- i2c_set_clientdata(client, th);
- th->clt = client;
-
- rc = read_reg(th, CONFIG_REG);
- if (rc < 0) {
- dev_err(&client->dev, "Thermostat failed to read config!\n");
- kfree(th);
- return -ENODEV;
- }
-
- /* force manual control to start the fan quieter */
- if (fan_speed == -1)
- fan_speed = 64;
-
- if(therm_type == ADT7460) {
- printk(KERN_INFO "adt746x: ADT7460 initializing\n");
- /* The 7460 needs to be started explicitly */
- write_reg(th, CONFIG_REG, 1);
- } else
- printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
- for (i = 0; i < 3; i++) {
- th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
- set_limit(th, i);
- }
-
- printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
- " to %d, %d, %d\n",
- th->initial_limits[0], th->initial_limits[1],
- th->initial_limits[2], th->limits[0], th->limits[1],
- th->limits[2]);
-
- thermostat = th;
-
- /* record invert bit status because fw can corrupt it after suspend */
- th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
- th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
-
- /* be sure to really write fan speed the first time */
- th->last_speed[0] = -2;
- th->last_speed[1] = -2;
- th->last_var[0] = -80;
- th->last_var[1] = -80;
-
- if (fan_speed != -1) {
- /* manual mode, stop fans */
- write_both_fan_speed(th, 0);
- } else {
- /* automatic mode */
- write_both_fan_speed(th, -1);
- }
-
- thread_therm = kthread_run(monitor_task, th, "kfand");
-
- if (thread_therm == ERR_PTR(-ENOMEM)) {
- printk(KERN_INFO "adt746x: Kthread creation failed\n");
- thread_therm = NULL;
- return -ENOMEM;
- }
-
- thermostat_create_files();
-
- return 0;
+#define BUILD_SHOW_FUNC_INT(name, data) \
+static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
+ return sprintf(buf, "%d\n", data); \
}
-static const struct i2c_device_id therm_adt746x_id[] = {
- { "therm_adt746x", 0 },
- { }
-};
-
-static struct i2c_driver thermostat_driver = {
- .driver = {
- .name = "therm_adt746x",
- },
- .attach_adapter = attach_thermostat,
- .probe = probe_thermostat,
- .remove = remove_thermostat,
- .id_table = therm_adt746x_id,
-};
-
-/*
- * Now, unfortunately, sysfs doesn't give us a nice void * we could
- * pass around to the attribute functions, so we don't really have
- * choice but implement a bunch of them...
- *
- * FIXME, it does now...
- */
-#define BUILD_SHOW_FUNC_INT(name, data) \
+#define BUILD_SHOW_FUNC_INT_LITE(name, data) \
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%d\n", data); \
@@ -494,22 +338,24 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch
#define BUILD_SHOW_FUNC_FAN(name, data) \
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
return sprintf(buf, "%d (%d rpm)\n", \
- thermostat->last_speed[data], \
- read_fan_speed(thermostat, FAN_SPEED[data]) \
+ th->last_speed[data], \
+ read_fan_speed(th, FAN_SPEED[data]) \
); \
}
#define BUILD_STORE_FUNC_DEG(name, data) \
static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
int val; \
int i; \
val = simple_strtol(buf, NULL, 10); \
printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \
limit_adjust = val; \
for (i=0; i < 3; i++) \
- set_limit(thermostat, i); \
+ set_limit(th, i); \
return n; \
}
@@ -525,20 +371,21 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c
return n; \
}
-BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(sensor1_limit, thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(sensor2_limit, thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(th, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(th, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit, th->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit, th->limits[2])
BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1])
BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2])
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+
BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0)
BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1)
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust, thermostat)
+BUILD_SHOW_FUNC_INT_LITE(limit_adjust, limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust, th)
static DEVICE_ATTR(sensor1_temperature, S_IRUGO,
show_sensor1_temperature,NULL);
@@ -564,53 +411,77 @@ static DEVICE_ATTR(sensor2_fan_speed, S_IRUGO,
static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
show_limit_adjust, store_limit_adjust);
-
-static int __init
-thermostat_init(void)
+static void thermostat_create_files(struct thermostat *th)
{
- struct device_node* np;
- const u32 *prop;
- int i = 0, offset = 0;
+ struct device_node *np = th->clt->dev.of_node;
+ struct device *dev;
+ int err;
- np = of_find_node_by_name(NULL, "fan");
- if (!np)
- return -ENODEV;
- if (of_device_is_compatible(np, "adt7460"))
- therm_type = ADT7460;
- else if (of_device_is_compatible(np, "adt7467"))
- therm_type = ADT7467;
- else {
- of_node_put(np);
- return -ENODEV;
- }
+ /* To maintain ABI compatibility with userspace, create
+ * the old style platform driver and attach the attributes
+ * to it here
+ */
+ th->pdev = of_platform_device_create(np, "temperatures", NULL);
+ if (!th->pdev)
+ return;
+ dev = &th->pdev->dev;
+ dev_set_drvdata(dev, th);
+ err = device_create_file(dev, &dev_attr_sensor1_temperature);
+ err |= device_create_file(dev, &dev_attr_sensor2_temperature);
+ err |= device_create_file(dev, &dev_attr_sensor1_limit);
+ err |= device_create_file(dev, &dev_attr_sensor2_limit);
+ err |= device_create_file(dev, &dev_attr_sensor1_location);
+ err |= device_create_file(dev, &dev_attr_sensor2_location);
+ err |= device_create_file(dev, &dev_attr_limit_adjust);
+ err |= device_create_file(dev, &dev_attr_specified_fan_speed);
+ err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
+ if(th->type == ADT7460)
+ err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
+ if (err)
+ printk(KERN_WARNING
+ "Failed to create temperature attribute file(s).\n");
+}
- prop = of_get_property(np, "hwsensor-params-version", NULL);
- printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
- (*prop == 1)?"":"un");
- if (*prop != 1) {
- of_node_put(np);
- return -ENODEV;
- }
+static void thermostat_remove_files(struct thermostat *th)
+{
+ struct device *dev;
- prop = of_get_property(np, "reg", NULL);
- if (!prop) {
- of_node_put(np);
- return -ENODEV;
- }
+ if (!th->pdev)
+ return;
+ dev = &th->pdev->dev;
+ device_remove_file(dev, &dev_attr_sensor1_temperature);
+ device_remove_file(dev, &dev_attr_sensor2_temperature);
+ device_remove_file(dev, &dev_attr_sensor1_limit);
+ device_remove_file(dev, &dev_attr_sensor2_limit);
+ device_remove_file(dev, &dev_attr_sensor1_location);
+ device_remove_file(dev, &dev_attr_sensor2_location);
+ device_remove_file(dev, &dev_attr_limit_adjust);
+ device_remove_file(dev, &dev_attr_specified_fan_speed);
+ device_remove_file(dev, &dev_attr_sensor1_fan_speed);
+ if (th->type == ADT7460)
+ device_remove_file(dev, &dev_attr_sensor2_fan_speed);
+ of_device_unregister(th->pdev);
- /* look for bus either by path or using "reg" */
- if (strstr(np->full_name, "/i2c-bus@") != NULL) {
- const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
- therm_bus = tmp_bus[0]-'0';
- } else {
- therm_bus = ((*prop) >> 8) & 0x0f;
- }
+}
- therm_address = ((*prop) & 0xff) >> 1;
+static int probe_thermostat(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct thermostat* th;
+ const __be32 *prop;
+ int i, rc, vers, offset = 0;
- printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
- "limit_adjust: %d, fan_speed: %d\n",
- therm_bus, therm_address, limit_adjust, fan_speed);
+ if (!np)
+ return -ENXIO;
+ prop = of_get_property(np, "hwsensor-params-version", NULL);
+ if (!prop)
+ return -ENXIO;
+ vers = be32_to_cpup(prop);
+ printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
+ vers, vers == 1 ? "" : "un");
+ if (vers != 1)
+ return -ENXIO;
if (of_get_property(np, "hwsensor-location", NULL)) {
for (i = 0; i < 3; i++) {
@@ -623,72 +494,129 @@ thermostat_init(void)
printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
offset += strlen(sensor_location[i]) + 1;
}
- } else {
- sensor_location[0] = "?";
- sensor_location[1] = "?";
- sensor_location[2] = "?";
}
- of_dev = of_platform_device_create(np, "temperatures", NULL);
- of_node_put(np);
+ th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
+ if (!th)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, th);
+ th->clt = client;
+ th->type = id->driver_data;
- if (of_dev == NULL) {
- printk(KERN_ERR "Can't register temperatures device !\n");
+ rc = read_reg(th, CONFIG_REG);
+ if (rc < 0) {
+ dev_err(&client->dev, "Thermostat failed to read config!\n");
+ kfree(th);
return -ENODEV;
}
-#ifndef CONFIG_I2C_POWERMAC
- request_module("i2c-powermac");
-#endif
+ /* force manual control to start the fan quieter */
+ if (fan_speed == -1)
+ fan_speed = 64;
+
+ if (th->type == ADT7460) {
+ printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+ /* The 7460 needs to be started explicitly */
+ write_reg(th, CONFIG_REG, 1);
+ } else
+ printk(KERN_INFO "adt746x: ADT7467 initializing\n");
- return i2c_add_driver(&thermostat_driver);
+ for (i = 0; i < 3; i++) {
+ th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+ set_limit(th, i);
+ }
+
+ printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+ " to %d, %d, %d\n",
+ th->initial_limits[0], th->initial_limits[1],
+ th->initial_limits[2], th->limits[0], th->limits[1],
+ th->limits[2]);
+
+ /* record invert bit status because fw can corrupt it after suspend */
+ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
+ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
+
+ /* be sure to really write fan speed the first time */
+ th->last_speed[0] = -2;
+ th->last_speed[1] = -2;
+ th->last_var[0] = -80;
+ th->last_var[1] = -80;
+
+ if (fan_speed != -1) {
+ /* manual mode, stop fans */
+ write_both_fan_speed(th, 0);
+ } else {
+ /* automatic mode */
+ write_both_fan_speed(th, -1);
+ }
+
+ th->thread = kthread_run(monitor_task, th, "kfand");
+ if (th->thread == ERR_PTR(-ENOMEM)) {
+ printk(KERN_INFO "adt746x: Kthread creation failed\n");
+ th->thread = NULL;
+ return -ENOMEM;
+ }
+
+ thermostat_create_files(th);
+
+ return 0;
}
-static void thermostat_create_files(void)
+static int remove_thermostat(struct i2c_client *client)
{
- int err;
+ struct thermostat *th = i2c_get_clientdata(client);
+ int i;
+
+ thermostat_remove_files(th);
- err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
- err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
- err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
- if(therm_type == ADT7460)
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
- if (err)
- printk(KERN_WARNING
- "Failed to create temperature attribute file(s).\n");
+ if (th->thread != NULL)
+ kthread_stop(th->thread);
+
+ printk(KERN_INFO "adt746x: Putting max temperatures back from "
+ "%d, %d, %d to %d, %d, %d\n",
+ th->limits[0], th->limits[1], th->limits[2],
+ th->initial_limits[0], th->initial_limits[1],
+ th->initial_limits[2]);
+
+ for (i = 0; i < 3; i++)
+ write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+ write_both_fan_speed(th, -1);
+
+ kfree(th);
+
+ return 0;
}
-static void thermostat_remove_files(void)
+static const struct i2c_device_id therm_adt746x_id[] = {
+ { "MAC,adt7460", ADT7460 },
+ { "MAC,adt7467", ADT7467 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
+
+static struct i2c_driver thermostat_driver = {
+ .driver = {
+ .name = "therm_adt746x",
+ },
+ .probe = probe_thermostat,
+ .remove = remove_thermostat,
+ .id_table = therm_adt746x_id,
+};
+
+static int __init thermostat_init(void)
{
- if (of_dev) {
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
- device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
- device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-
- if(therm_type == ADT7460)
- device_remove_file(&of_dev->dev,
- &dev_attr_sensor2_fan_speed);
+#ifndef CONFIG_I2C_POWERMAC
+ request_module("i2c-powermac");
+#endif
- }
+ return i2c_add_driver(&thermostat_driver);
}
-static void __exit
-thermostat_exit(void)
+static void __exit thermostat_exit(void)
{
i2c_del_driver(&thermostat_driver);
- of_device_unregister(of_dev);
}
module_init(thermostat_init);
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
index 7a2482c..028cdac 100644
--- a/drivers/macintosh/windfarm.h
+++ b/drivers/macintosh/windfarm.h
@@ -17,7 +17,7 @@
#include <linux/device.h>
/* Display a 16.16 fixed point value */
-#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+#define FIX32TOPRINT(f) (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
/*
* Control objects
@@ -35,12 +35,13 @@ struct wf_control_ops {
};
struct wf_control {
- struct list_head link;
- struct wf_control_ops *ops;
- char *name;
- int type;
- struct kref ref;
- struct device_attribute attr;
+ struct list_head link;
+ const struct wf_control_ops *ops;
+ const char *name;
+ int type;
+ struct kref ref;
+ struct device_attribute attr;
+ void *priv;
};
#define WF_CONTROL_TYPE_GENERIC 0
@@ -72,6 +73,26 @@ static inline int wf_control_set_min(struct wf_control *ct)
return ct->ops->set_value(ct, vmin);
}
+static inline int wf_control_set(struct wf_control *ct, s32 val)
+{
+ return ct->ops->set_value(ct, val);
+}
+
+static inline int wf_control_get(struct wf_control *ct, s32 *val)
+{
+ return ct->ops->get_value(ct, val);
+}
+
+static inline s32 wf_control_get_min(struct wf_control *ct)
+{
+ return ct->ops->get_min(ct);
+}
+
+static inline s32 wf_control_get_max(struct wf_control *ct)
+{
+ return ct->ops->get_max(ct);
+}
+
/*
* Sensor objects
*/
@@ -85,11 +106,12 @@ struct wf_sensor_ops {
};
struct wf_sensor {
- struct list_head link;
- struct wf_sensor_ops *ops;
- char *name;
- struct kref ref;
- struct device_attribute attr;
+ struct list_head link;
+ const struct wf_sensor_ops *ops;
+ const char *name;
+ struct kref ref;
+ struct device_attribute attr;
+ void *priv;
};
/* Same lifetime rules as controls */
@@ -99,6 +121,11 @@ extern struct wf_sensor * wf_find_sensor(const char *name);
extern int wf_get_sensor(struct wf_sensor *sr);
extern void wf_put_sensor(struct wf_sensor *sr);
+static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
+{
+ return sr->ops->get_value(sr, val);
+}
+
/* For use by clients. Note that we are a bit racy here since
* notifier_block doesn't have a module owner field. I may fix
* it one day ...
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c
new file mode 100644
index 0000000..ac3f243
--- /dev/null
+++ b/drivers/macintosh/windfarm_ad7417_sensor.c
@@ -0,0 +1,347 @@
+/*
+ * Windfarm PowerMac thermal control. AD7417 sensors
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+struct wf_ad7417_priv {
+ struct kref ref;
+ struct i2c_client *i2c;
+ u8 config;
+ u8 cpu;
+ const struct mpu_data *mpu;
+ struct wf_sensor sensors[5];
+ struct mutex lock;
+};
+
+static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+ u8 buf[2];
+ s16 raw;
+ int rc;
+
+ *value = 0;
+ mutex_lock(&pv->lock);
+
+ /* Read temp register */
+ buf[0] = 0;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc < 0)
+ goto error;
+ rc = i2c_master_recv(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Read a a 16-bit signed value */
+ raw = be16_to_cpup((__le16 *)buf);
+
+ /* Convert 8.8-bit to 16.16 fixed point */
+ *value = ((s32)raw) << 8;
+
+ mutex_unlock(&pv->lock);
+ return 0;
+
+error:
+ mutex_unlock(&pv->lock);
+ return -1;
+}
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE 0x0320 /* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE 0x00a0 /* _AD3 */
+#define ADC_CPU_CURRENT_SCALE 0x1f40 /* _AD4 */
+
+static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
+ int chan, s32 raw, s32 *value)
+{
+ switch(chan) {
+ case 1: /* Diode */
+ *value = (raw * (s32)pv->mpu->mdiode +
+ ((s32)pv->mpu->bdiode << 12)) >> 2;
+ break;
+ case 2: /* 12v current */
+ *value = raw * ADC_12V_CURRENT_SCALE;
+ break;
+ case 3: /* core voltage */
+ *value = raw * ADC_CPU_VOLTAGE_SCALE;
+ break;
+ case 4: /* core current */
+ *value = raw * ADC_CPU_CURRENT_SCALE;
+ break;
+ }
+}
+
+static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+ int chan = sr - pv->sensors;
+ int i, rc;
+ u8 buf[2];
+ u16 raw;
+
+ *value = 0;
+ mutex_lock(&pv->lock);
+ for (i = 0; i < 10; i++) {
+ /* Set channel */
+ buf[0] = 1;
+ buf[1] = (pv->config & 0x1f) | (chan << 5);
+ rc = i2c_master_send(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Wait for conversion */
+ msleep(1);
+
+ /* Switch to data register */
+ buf[0] = 4;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc < 0)
+ goto error;
+
+ /* Read result */
+ rc = i2c_master_recv(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Read a a 16-bit signed value */
+ raw = be16_to_cpup((__le16 *)buf) >> 6;
+ wf_ad7417_adc_convert(pv, chan, raw, value);
+
+ dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
+ " raw value: 0x%x, conv to: 0x%08x\n",
+ chan, sr->name, raw, *value);
+
+ mutex_unlock(&pv->lock);
+ return 0;
+
+ error:
+ dev_dbg(&pv->i2c->dev,
+ "Error reading ADC, try %d...\n", i);
+ if (i < 9)
+ msleep(10);
+ }
+ mutex_unlock(&pv->lock);
+ return -1;
+}
+
+static void wf_ad7417_release(struct kref *ref)
+{
+ struct wf_ad7417_priv *pv = container_of(ref,
+ struct wf_ad7417_priv, ref);
+ kfree(pv);
+}
+
+static void wf_ad7417_sensor_release(struct wf_sensor *sr)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+
+ kfree(sr->name);
+ kref_put(&pv->ref, wf_ad7417_release);
+}
+
+static const struct wf_sensor_ops wf_ad7417_temp_ops = {
+ .get_value = wf_ad7417_temp_get,
+ .release = wf_ad7417_sensor_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct wf_sensor_ops wf_ad7417_adc_ops = {
+ .get_value = wf_ad7417_adc_get,
+ .release = wf_ad7417_sensor_release,
+ .owner = THIS_MODULE,
+};
+
+static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+ int index, const char *name,
+ const struct wf_sensor_ops *ops)
+{
+ pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
+ pv->sensors[index].priv = pv;
+ pv->sensors[index].ops = ops;
+ if (!wf_register_sensor(&pv->sensors[index]))
+ kref_get(&pv->ref);
+}
+
+static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+{
+ int rc;
+ u8 buf[2];
+ u8 config = 0;
+
+ /*
+ * Read ADC the configuration register and cache it. We
+ * also make sure Config2 contains proper values, I've seen
+ * cases where we got stale grabage in there, thus preventing
+ * proper reading of conv. values
+ */
+
+ /* Clear Config2 */
+ buf[0] = 5;
+ buf[1] = 0;
+ i2c_master_send(pv->i2c, buf, 2);
+
+ /* Read & cache Config1 */
+ buf[0] = 1;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc > 0) {
+ rc = i2c_master_recv(pv->i2c, buf, 1);
+ if (rc > 0) {
+ config = buf[0];
+
+ dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
+ config);
+
+ /* Disable shutdown mode */
+ config &= 0xfe;
+ buf[0] = 1;
+ buf[1] = config;
+ rc = i2c_master_send(pv->i2c, buf, 2);
+ }
+ }
+ if (rc <= 0)
+ dev_err(&pv->i2c->dev, "Error reading ADC config\n");
+
+ pv->config = config;
+}
+
+static int __devinit wf_ad7417_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_ad7417_priv *pv;
+ const struct mpu_data *mpu;
+ const char *loc;
+ int cpu_nr;
+
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
+
+ /*
+ * Identify which CPU we belong to by looking at the first entry
+ * in the hwsensor-location list
+ */
+ if (!strncmp(loc, "CPU A", 5))
+ cpu_nr = 0;
+ else if (!strncmp(loc, "CPU B", 5))
+ cpu_nr = 1;
+ else {
+ pr_err("wf_ad7417: Can't identify location %s\n", loc);
+ return -ENXIO;
+ }
+ mpu = wf_get_mpu(cpu_nr);
+ if (!mpu) {
+ dev_err(&client->dev, "Failed to retrieve MPU data\n");
+ return -ENXIO;
+ }
+
+ pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
+ if (pv == NULL)
+ return -ENODEV;
+
+ kref_init(&pv->ref);
+ mutex_init(&pv->lock);
+ pv->i2c = client;
+ pv->cpu = cpu_nr;
+ pv->mpu = mpu;
+ dev_set_drvdata(&client->dev, pv);
+
+ /* Initialize the chip */
+ wf_ad7417_init_chip(pv);
+
+ /*
+ * We cannot rely on Apple device-tree giving us child
+ * node with the names of the individual sensors so we
+ * just hard code what we know about them
+ */
+ wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
+ wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
+
+ return 0;
+}
+
+static int __devexit wf_ad7417_remove(struct i2c_client *client)
+{
+ struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
+ int i;
+
+ /* Mark client detached */
+ pv->i2c = NULL;
+
+ /* Release sensor */
+ for (i = 0; i < 5; i++)
+ wf_unregister_sensor(&pv->sensors[i]);
+
+ kref_put(&pv->ref, wf_ad7417_release);
+
+ return 0;
+}
+
+static const struct i2c_device_id wf_ad7417_id[] = {
+ { "MAC,ad7417", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
+
+static struct i2c_driver wf_ad7417_driver = {
+ .driver = {
+ .name = "wf_ad7417",
+ },
+ .probe = wf_ad7417_probe,
+ .remove = wf_ad7417_remove,
+ .id_table = wf_ad7417_id,
+};
+
+static int __devinit wf_ad7417_init(void)
+{
+ /* This is only supported on these machines */
+ if (!of_machine_is_compatible("PowerMac7,2") &&
+ !of_machine_is_compatible("PowerMac7,3") &&
+ !of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ return i2c_add_driver(&wf_ad7417_driver);
+}
+
+static void __devexit wf_ad7417_exit(void)
+{
+ i2c_del_driver(&wf_ad7417_driver);
+}
+
+module_init(wf_ad7417_init);
+module_exit(wf_ad7417_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index ce88979..3ee198b 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -164,13 +164,27 @@ static ssize_t wf_show_control(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
+ const char *typestr;
s32 val = 0;
int err;
err = ctrl->ops->get_value(ctrl, &val);
- if (err < 0)
+ if (err < 0) {
+ if (err == -EFAULT)
+ return sprintf(buf, "<HW FAULT>\n");
return err;
- return sprintf(buf, "%d\n", val);
+ }
+ switch(ctrl->type) {
+ case WF_CONTROL_RPM_FAN:
+ typestr = " RPM";
+ break;
+ case WF_CONTROL_PWM_FAN:
+ typestr = " %";
+ break;
+ default:
+ typestr = "";
+ }
+ return sprintf(buf, "%d%s\n", val, typestr);
}
/* This is really only for debugging... */
@@ -470,11 +484,6 @@ static int __init windfarm_core_init(void)
{
DBG("wf: core loaded\n");
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
platform_device_register(&wf_platform_device);
return 0;
}
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 1a77a7c..72d1fdf 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -75,12 +75,6 @@ static int __init wf_cpufreq_clamp_init(void)
{
struct wf_control *clamp;
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
-
clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
if (clamp == NULL)
return -ENOMEM;
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c
new file mode 100644
index 0000000..b3411ed
--- /dev/null
+++ b/drivers/macintosh/windfarm_fcu_controls.c
@@ -0,0 +1,613 @@
+/*
+ * Windfarm PowerMac thermal control. FCU fan control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the actual RPM
+ * speed read from the FCU.
+ *
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm using 0 for now which is what therm_pm72 used to do and
+ * what Darwin -apparently- does based on observed behaviour.
+ */
+#define RPM_PID_USE_ACTUAL_SPEED 0
+
+/* Default min/max for pumps */
+#define CPU_PUMP_OUTPUT_MAX 3200
+#define CPU_PUMP_OUTPUT_MIN 1250
+
+#define FCU_FAN_RPM 0
+#define FCU_FAN_PWM 1
+
+struct wf_fcu_priv {
+ struct kref ref;
+ struct i2c_client *i2c;
+ struct mutex lock;
+ struct list_head fan_list;
+ int rpm_shift;
+};
+
+struct wf_fcu_fan {
+ struct list_head link;
+ int id;
+ s32 min, max, target;
+ struct wf_fcu_priv *fcu_priv;
+ struct wf_control ctrl;
+};
+
+static void wf_fcu_release(struct kref *ref)
+{
+ struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
+
+ kfree(pv);
+}
+
+static void wf_fcu_fan_release(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ kref_put(&fan->fcu_priv->ref, wf_fcu_release);
+ kfree(fan);
+}
+
+static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
+ unsigned char *buf, int nb)
+{
+ int tries, nr, nw;
+
+ mutex_lock(&pv->lock);
+
+ buf[0] = reg;
+ tries = 0;
+ for (;;) {
+ nw = i2c_master_send(pv->i2c, buf, 1);
+ if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nw <= 0) {
+ pr_err("Failure writing address to FCU: %d", nw);
+ nr = nw;
+ goto bail;
+ }
+ tries = 0;
+ for (;;) {
+ nr = i2c_master_recv(pv->i2c, buf, nb);
+ if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nr <= 0)
+ pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
+ bail:
+ mutex_unlock(&pv->lock);
+ return nr;
+}
+
+static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
+ const unsigned char *ptr, int nb)
+{
+ int tries, nw;
+ unsigned char buf[16];
+
+ buf[0] = reg;
+ memcpy(buf+1, ptr, nb);
+ ++nb;
+ tries = 0;
+ for (;;) {
+ nw = i2c_master_send(pv->i2c, buf, nb);
+ if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nw < 0)
+ pr_err("wf_fcu: Failure writing to FCU: %d", nw);
+ return nw;
+}
+
+static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ int rc, shift = pv->rpm_shift;
+ unsigned char buf[2];
+
+ if (value < fan->min)
+ value = fan->min;
+ if (value > fan->max)
+ value = fan->max;
+
+ fan->target = value;
+
+ buf[0] = value >> (8 - shift);
+ buf[1] = value << shift;
+ rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
+ if (rc < 0)
+ return -EIO;
+ return 0;
+}
+
+static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ int rc, reg_base, shift = pv->rpm_shift;
+ unsigned char failure;
+ unsigned char active;
+ unsigned char buf[2];
+
+ rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((failure & (1 << fan->id)) != 0)
+ return -EFAULT;
+ rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((active & (1 << fan->id)) == 0)
+ return -ENXIO;
+
+ /* Programmed value or real current speed */
+#if RPM_PID_USE_ACTUAL_SPEED
+ reg_base = 0x11;
+#else
+ reg_base = 0x10;
+#endif
+ rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
+ if (rc != 2)
+ return -EIO;
+
+ *value = (buf[0] << (8 - shift)) | buf[1] >> shift;
+
+ return 0;
+}
+
+static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ unsigned char buf[2];
+ int rc;
+
+ if (value < fan->min)
+ value = fan->min;
+ if (value > fan->max)
+ value = fan->max;
+
+ fan->target = value;
+
+ value = (value * 2559) / 1000;
+ buf[0] = value;
+ rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+ if (rc < 0)
+ return -EIO;
+ return 0;
+}
+
+static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ unsigned char failure;
+ unsigned char active;
+ unsigned char buf[2];
+ int rc;
+
+ rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((failure & (1 << fan->id)) != 0)
+ return -EFAULT;
+ rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((active & (1 << fan->id)) == 0)
+ return -ENXIO;
+
+ rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+ if (rc != 1)
+ return -EIO;
+
+ *value = (((s32)buf[0]) * 1000) / 2559;
+
+ return 0;
+}
+
+static s32 wf_fcu_fan_min(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ return fan->min;
+}
+
+static s32 wf_fcu_fan_max(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ return fan->max;
+}
+
+static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
+ .set_value = wf_fcu_fan_set_rpm,
+ .get_value = wf_fcu_fan_get_rpm,
+ .get_min = wf_fcu_fan_min,
+ .get_max = wf_fcu_fan_max,
+ .release = wf_fcu_fan_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
+ .set_value = wf_fcu_fan_set_pwm,
+ .get_value = wf_fcu_fan_get_pwm,
+ .get_min = wf_fcu_fan_min,
+ .get_max = wf_fcu_fan_max,
+ .release = wf_fcu_fan_release,
+ .owner = THIS_MODULE,
+};
+
+static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+{
+ const struct mpu_data *mpu = wf_get_mpu(0);
+ u16 pump_min = 0, pump_max = 0xffff;
+ u16 tmp[4];
+
+ /* Try to fetch pumps min/max infos from eeprom */
+ if (mpu) {
+ memcpy(&tmp, mpu->processor_part_num, 8);
+ if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+ pump_min = max(pump_min, tmp[0]);
+ pump_max = min(pump_max, tmp[1]);
+ }
+ if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+ pump_min = max(pump_min, tmp[2]);
+ pump_max = min(pump_max, tmp[3]);
+ }
+ }
+
+ /* Double check the values, this _IS_ needed as the EEPROM on
+ * some dual 2.5Ghz G5s seem, at least, to have both min & max
+ * same to the same value ... (grrrr)
+ */
+ if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+ pump_min = CPU_PUMP_OUTPUT_MIN;
+ pump_max = CPU_PUMP_OUTPUT_MAX;
+ }
+
+ fan->min = pump_min;
+ fan->max = pump_max;
+
+ DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
+ fan->ctrl.name, pump_min, pump_max);
+}
+
+static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+{
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ const struct mpu_data *mpu0 = wf_get_mpu(0);
+ const struct mpu_data *mpu1 = wf_get_mpu(1);
+
+ /* Default */
+ fan->min = 2400 >> pv->rpm_shift;
+ fan->max = 56000 >> pv->rpm_shift;
+
+ /* CPU fans have min/max in MPU */
+ if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+ goto bail;
+ }
+ if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
+ fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
+ goto bail;
+ }
+ if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
+ goto bail;
+ }
+ if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
+ fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
+ fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
+ goto bail;
+ }
+ /* Rackmac variants, we just use mpu0 intake */
+ if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+ goto bail;
+ }
+ bail:
+ DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
+ fan->ctrl.name, fan->min, fan->max);
+}
+
+static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
+ const char *name,
+ int type, int id)
+{
+ struct wf_fcu_fan *fan;
+
+ fan = kzalloc(sizeof(*fan), GFP_KERNEL);
+ if (!fan)
+ return;
+ fan->fcu_priv = pv;
+ fan->id = id;
+ fan->ctrl.name = name;
+ fan->ctrl.priv = fan;
+
+ /* min/max is oddball but the code comes from
+ * therm_pm72 which seems to work so ...
+ */
+ if (type == FCU_FAN_RPM) {
+ if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
+ wf_fcu_get_pump_minmax(fan);
+ else
+ wf_fcu_get_rpmfan_minmax(fan);
+ fan->ctrl.type = WF_CONTROL_RPM_FAN;
+ fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
+ } else {
+ fan->min = 10;
+ fan->max = 100;
+ fan->ctrl.type = WF_CONTROL_PWM_FAN;
+ fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
+ }
+
+ if (wf_register_control(&fan->ctrl)) {
+ pr_err("wf_fcu: Failed to register fan %s\n", name);
+ kfree(fan);
+ return;
+ }
+ list_add(&fan->link, &pv->fan_list);
+ kref_get(&pv->ref);
+}
+
+static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+{
+ /* Translation of device-tree location properties to
+ * windfarm fan names
+ */
+ static const struct {
+ const char *dt_name; /* Device-tree name */
+ const char *ct_name; /* Control name */
+ } loc_trans[] = {
+ { "BACKSIDE", "backside-fan", },
+ { "SYS CTRLR FAN", "backside-fan", },
+ { "DRIVE BAY", "drive-bay-fan", },
+ { "SLOT", "slots-fan", },
+ { "PCI FAN", "slots-fan", },
+ { "CPU A INTAKE", "cpu-front-fan-0", },
+ { "CPU A EXHAUST", "cpu-rear-fan-0", },
+ { "CPU B INTAKE", "cpu-front-fan-1", },
+ { "CPU B EXHAUST", "cpu-rear-fan-1", },
+ { "CPU A PUMP", "cpu-pump-0", },
+ { "CPU B PUMP", "cpu-pump-1", },
+ { "CPU A 1", "cpu-fan-a-0", },
+ { "CPU A 2", "cpu-fan-b-0", },
+ { "CPU A 3", "cpu-fan-c-0", },
+ { "CPU B 1", "cpu-fan-a-1", },
+ { "CPU B 2", "cpu-fan-b-1", },
+ { "CPU B 3", "cpu-fan-c-1", },
+ };
+ struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node;
+ int i;
+
+ DBG("Looking up FCU controls in device-tree...\n");
+
+ while ((np = of_get_next_child(fcu, np)) != NULL) {
+ int id, type = -1;
+ const char *loc;
+ const char *name;
+ const u32 *reg;
+
+ DBG(" control: %s, type: %s\n", np->name, np->type);
+
+ /* Detect control type */
+ if (!strcmp(np->type, "fan-rpm-control") ||
+ !strcmp(np->type, "fan-rpm"))
+ type = FCU_FAN_RPM;
+ if (!strcmp(np->type, "fan-pwm-control") ||
+ !strcmp(np->type, "fan-pwm"))
+ type = FCU_FAN_PWM;
+ /* Only care about fans for now */
+ if (type == -1)
+ continue;
+
+ /* Lookup for a matching location */
+ loc = of_get_property(np, "location", NULL);
+ reg = of_get_property(np, "reg", NULL);
+ if (loc == NULL || reg == NULL)
+ continue;
+ DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+
+ for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
+ if (strncmp(loc, loc_trans[i].dt_name,
+ strlen(loc_trans[i].dt_name)))
+ continue;
+ name = loc_trans[i].ct_name;
+
+ DBG(" location match, name: %s\n", name);
+
+ if (type == FCU_FAN_RPM)
+ id = ((*reg) - 0x10) / 2;
+ else
+ id = ((*reg) - 0x30) / 2;
+ if (id > 7) {
+ pr_warning("wf_fcu: Can't parse "
+ "fan ID in device-tree for %s\n",
+ np->full_name);
+ break;
+ }
+ wf_fcu_add_fan(pv, name, type, id);
+ break;
+ }
+ }
+}
+
+static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+{
+ /* We only support the default fans for PowerMac7,2 */
+ if (!of_machine_is_compatible("PowerMac7,2"))
+ return;
+
+ wf_fcu_add_fan(pv, "backside-fan", FCU_FAN_PWM, 1);
+ wf_fcu_add_fan(pv, "drive-bay-fan", FCU_FAN_RPM, 2);
+ wf_fcu_add_fan(pv, "slots-fan", FCU_FAN_PWM, 2);
+ wf_fcu_add_fan(pv, "cpu-front-fan-0", FCU_FAN_RPM, 3);
+ wf_fcu_add_fan(pv, "cpu-rear-fan-0", FCU_FAN_RPM, 4);
+ wf_fcu_add_fan(pv, "cpu-front-fan-1", FCU_FAN_RPM, 5);
+ wf_fcu_add_fan(pv, "cpu-rear-fan-1", FCU_FAN_RPM, 6);
+}
+
+static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+{
+ unsigned char buf = 0xff;
+ int rc;
+
+ rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ rc = wf_fcu_read_reg(pv, 0, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ pv->rpm_shift = (buf == 1) ? 2 : 3;
+
+ pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
+ pv->rpm_shift);
+
+ return 0;
+}
+
+static int __devinit wf_fcu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_fcu_priv *pv;
+
+ pv = kzalloc(sizeof(*pv), GFP_KERNEL);
+ if (!pv)
+ return -ENOMEM;
+
+ kref_init(&pv->ref);
+ mutex_init(&pv->lock);
+ INIT_LIST_HEAD(&pv->fan_list);
+ pv->i2c = client;
+
+ /*
+ * First we must start the FCU which will query the
+ * shift value to apply to RPMs
+ */
+ if (wf_fcu_init_chip(pv)) {
+ pr_err("wf_fcu: Initialization failed !\n");
+ kfree(pv);
+ return -ENXIO;
+ }
+
+ /* First lookup fans in the device-tree */
+ wf_fcu_lookup_fans(pv);
+
+ /*
+ * Older machines don't have the device-tree entries
+ * we are looking for, just hard code the list
+ */
+ if (list_empty(&pv->fan_list))
+ wf_fcu_default_fans(pv);
+
+ /* Still no fans ? FAIL */
+ if (list_empty(&pv->fan_list)) {
+ pr_err("wf_fcu: Failed to find fans for your machine\n");
+ kfree(pv);
+ return -ENODEV;
+ }
+
+ dev_set_drvdata(&client->dev, pv);
+
+ return 0;
+}
+
+static int __devexit wf_fcu_remove(struct i2c_client *client)
+{
+ struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
+ struct wf_fcu_fan *fan;
+
+ while (!list_empty(&pv->fan_list)) {
+ fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
+ list_del(&fan->link);
+ wf_unregister_control(&fan->ctrl);
+ }
+ kref_put(&pv->ref, wf_fcu_release);
+ return 0;
+}
+
+static const struct i2c_device_id wf_fcu_id[] = {
+ { "MAC,fcu", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
+
+static struct i2c_driver wf_fcu_driver = {
+ .driver = {
+ .name = "wf_fcu",
+ },
+ .probe = wf_fcu_probe,
+ .remove = wf_fcu_remove,
+ .id_table = wf_fcu_id,
+};
+
+static int __init wf_fcu_init(void)
+{
+ return i2c_add_driver(&wf_fcu_driver);
+}
+
+static void __exit wf_fcu_exit(void)
+{
+ i2c_del_driver(&wf_fcu_driver);
+}
+
+
+module_init(wf_fcu_init);
+module_exit(wf_fcu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 4d6a90a..b0c2d36 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -23,7 +23,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
#undef DEBUG
@@ -36,8 +36,8 @@
struct wf_lm75_sensor {
int ds1775 : 1;
int inited : 1;
- struct i2c_client *i2c;
- struct wf_sensor sens;
+ struct i2c_client *i2c;
+ struct wf_sensor sens;
};
#define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
@@ -90,40 +90,19 @@ static struct wf_sensor_ops wf_lm75_ops = {
static int wf_lm75_probe(struct i2c_client *client,
const struct i2c_device_id *id)
-{
+{
struct wf_lm75_sensor *lm;
- int rc;
-
- lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
- if (lm == NULL)
- return -ENODEV;
-
- lm->inited = 0;
- lm->ds1775 = id->driver_data;
- lm->i2c = client;
- lm->sens.name = client->dev.platform_data;
- lm->sens.ops = &wf_lm75_ops;
- i2c_set_clientdata(client, lm);
-
- rc = wf_register_sensor(&lm->sens);
- if (rc)
- kfree(lm);
-
- return rc;
-}
-
-static struct i2c_driver wf_lm75_driver;
-
-static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
- u8 addr, int ds1775,
- const char *loc)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- char *name;
+ int rc, ds1775 = id->driver_data;
+ const char *name, *loc;
DBG("wf_lm75: creating %s device at address 0x%02x\n",
- ds1775 ? "ds1775" : "lm75", addr);
+ ds1775 ? "ds1775" : "lm75", client->addr);
+
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
/* Usual rant about sensor names not beeing very consistent in
* the device-tree, oh well ...
@@ -137,68 +116,31 @@ static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
name = "optical-drive-temp";
else if (!strcmp(loc, "HD Temp"))
name = "hard-drive-temp";
+ else if (!strcmp(loc, "PCI SLOTS"))
+ name = "slots-temp";
+ else if (!strcmp(loc, "CPU A INLET"))
+ name = "cpu-inlet-temp-0";
+ else if (!strcmp(loc, "CPU B INLET"))
+ name = "cpu-inlet-temp-1";
else
- goto fail;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = (addr >> 1) & 0x7f;
- info.platform_data = name;
- strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
- ds1775 ? "ds1775" : "lm75", name);
- goto fail;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_lm75_driver.clients);
- return client;
- fail:
- return NULL;
-}
-
-static int wf_lm75_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev;
- struct pmac_i2c_bus *bus;
+ return -ENXIO;
+
- DBG("wf_lm75: adapter %s detected\n", adapter->name);
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
+ lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+ if (lm == NULL)
return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
- DBG("wf_lm75: bus found, looking for device...\n");
-
- /* Now look for lm75(s) in there */
- for (dev = NULL;
- (dev = of_get_next_child(busnode, dev)) != NULL;) {
- const char *loc =
- of_get_property(dev, "hwsensor-location", NULL);
- u8 addr;
+ lm->inited = 0;
+ lm->ds1775 = ds1775;
+ lm->i2c = client;
+ lm->sens.name = (char *)name; /* XXX fix constness in structure */
+ lm->sens.ops = &wf_lm75_ops;
+ i2c_set_clientdata(client, lm);
- /* We must re-match the adapter in order to properly check
- * the channel on multibus setups
- */
- if (!pmac_i2c_match_adapter(dev, adapter))
- continue;
- addr = pmac_i2c_get_dev_addr(dev);
- if (loc == NULL || addr == 0)
- continue;
- /* real lm75 */
- if (of_device_is_compatible(dev, "lm75"))
- wf_lm75_create(adapter, addr, 0, loc);
- /* ds1775 (compatible, better resolution */
- else if (of_device_is_compatible(dev, "ds1775"))
- wf_lm75_create(adapter, addr, 1, loc);
- }
- return 0;
+ rc = wf_register_sensor(&lm->sens);
+ if (rc)
+ kfree(lm);
+ return rc;
}
static int wf_lm75_remove(struct i2c_client *client)
@@ -217,16 +159,16 @@ static int wf_lm75_remove(struct i2c_client *client)
}
static const struct i2c_device_id wf_lm75_id[] = {
- { "wf_lm75", 0 },
- { "wf_ds1775", 1 },
+ { "MAC,lm75", 0 },
+ { "MAC,ds1775", 1 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
static struct i2c_driver wf_lm75_driver = {
.driver = {
.name = "wf_lm75",
},
- .attach_adapter = wf_lm75_attach,
.probe = wf_lm75_probe,
.remove = wf_lm75_remove,
.id_table = wf_lm75_id,
@@ -234,11 +176,6 @@ static struct i2c_driver wf_lm75_driver = {
static int __init wf_lm75_sensor_init(void)
{
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
return i2c_add_driver(&wf_lm75_driver);
}
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c
new file mode 100644
index 0000000..c071aab
--- /dev/null
+++ b/drivers/macintosh/windfarm_lm87_sensor.c
@@ -0,0 +1,201 @@
+/*
+ * Windfarm PowerMac thermal control. LM87 sensor
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
+
+#include "windfarm.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+struct wf_lm87_sensor {
+ struct i2c_client *i2c;
+ struct wf_sensor sens;
+};
+#define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
+
+
+static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
+{
+ int rc, tries = 0;
+ u8 buf;
+
+ for (;;) {
+ /* Set address */
+ buf = (u8)reg;
+ rc = i2c_master_send(chip, &buf, 1);
+ if (rc <= 0)
+ goto error;
+ rc = i2c_master_recv(chip, &buf, 1);
+ if (rc <= 0)
+ goto error;
+ return (int)buf;
+ error:
+ DBG("wf_lm87: Error reading LM87, retrying...\n");
+ if (++tries > 10) {
+ printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
+ return -EIO;
+ }
+ msleep(10);
+ }
+}
+
+static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_lm87_sensor *lm = sr->priv;
+ s32 temp;
+
+ if (lm->i2c == NULL)
+ return -ENODEV;
+
+#define LM87_INT_TEMP 0x27
+
+ /* Read temperature register */
+ temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
+ if (temp < 0)
+ return temp;
+ *value = temp << 16;
+
+ return 0;
+}
+
+static void wf_lm87_release(struct wf_sensor *sr)
+{
+ struct wf_lm87_sensor *lm = wf_to_lm87(sr);
+
+ kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm87_ops = {
+ .get_value = wf_lm87_get,
+ .release = wf_lm87_release,
+ .owner = THIS_MODULE,
+};
+
+static int wf_lm87_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_lm87_sensor *lm;
+ const char *name = NULL, *loc;
+ struct device_node *np = NULL;
+ int rc;
+
+ /*
+ * The lm87 contains a whole pile of sensors, additionally,
+ * the Xserve G5 has several lm87's. However, for now we only
+ * care about the internal temperature sensor
+ */
+ while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) {
+ if (strcmp(np->name, "int-temp"))
+ continue;
+ loc = of_get_property(np, "location", NULL);
+ if (!loc)
+ continue;
+ if (strstr(loc, "DIMM"))
+ name = "dimms-temp";
+ else if (strstr(loc, "Processors"))
+ name = "between-cpus-temp";
+ if (name) {
+ of_node_put(np);
+ break;
+ }
+ }
+ if (!name) {
+ pr_warning("wf_lm87: Unsupported sensor %s\n",
+ client->dev.of_node->full_name);
+ return -ENODEV;
+ }
+
+ lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
+ if (lm == NULL)
+ return -ENODEV;
+
+ lm->i2c = client;
+ lm->sens.name = name;
+ lm->sens.ops = &wf_lm87_ops;
+ lm->sens.priv = lm;
+ i2c_set_clientdata(client, lm);
+
+ rc = wf_register_sensor(&lm->sens);
+ if (rc)
+ kfree(lm);
+ return rc;
+}
+
+static int wf_lm87_remove(struct i2c_client *client)
+{
+ struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
+
+ DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
+
+ /* Mark client detached */
+ lm->i2c = NULL;
+
+ /* release sensor */
+ wf_unregister_sensor(&lm->sens);
+
+ return 0;
+}
+
+static const struct i2c_device_id wf_lm87_id[] = {
+ { "MAC,lm87cimt", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
+
+static struct i2c_driver wf_lm87_driver = {
+ .driver = {
+ .name = "wf_lm87",
+ },
+ .probe = wf_lm87_probe,
+ .remove = wf_lm87_remove,
+ .id_table = wf_lm87_id,
+};
+
+static int __init wf_lm87_sensor_init(void)
+{
+ /* We only support this on the Xserve */
+ if (!of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ return i2c_add_driver(&wf_lm87_driver);
+}
+
+static void __exit wf_lm87_sensor_exit(void)
+{
+ i2c_del_driver(&wf_lm87_driver);
+}
+
+
+module_init(wf_lm87_sensor_init);
+module_exit(wf_lm87_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 8204113..371b058 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -16,7 +16,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
/* This currently only exports the external temperature sensor,
since that's all the control loops need. */
@@ -64,9 +64,29 @@ static struct wf_sensor_ops wf_max6690_ops = {
static int wf_max6690_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ const char *name, *loc;
struct wf_6690_sensor *max;
int rc;
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
+
+ /*
+ * We only expose the external temperature register for
+ * now as this is all we need for our control loops
+ */
+ if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
+ name = "backside-temp";
+ else if (!strcmp(loc, "NB Ambient"))
+ name = "north-bridge-temp";
+ else if (!strcmp(loc, "GPU Ambient"))
+ name = "gpu-temp";
+ else
+ return -ENXIO;
+
max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
if (max == NULL) {
printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
@@ -75,90 +95,16 @@ static int wf_max6690_probe(struct i2c_client *client,
}
max->i2c = client;
- max->sens.name = client->dev.platform_data;
+ max->sens.name = (char *)name; /* XXX fix constness in structure */
max->sens.ops = &wf_max6690_ops;
i2c_set_clientdata(client, max);
rc = wf_register_sensor(&max->sens);
- if (rc) {
+ if (rc)
kfree(max);
- }
-
return rc;
}
-static struct i2c_driver wf_max6690_driver;
-
-static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
- u8 addr, const char *loc)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- char *name;
-
- if (!strcmp(loc, "BACKSIDE"))
- name = "backside-temp";
- else if (!strcmp(loc, "NB Ambient"))
- name = "north-bridge-temp";
- else if (!strcmp(loc, "GPU Ambient"))
- name = "gpu-temp";
- else
- goto fail;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = addr >> 1;
- info.platform_data = name;
- strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
- goto fail;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_max6690_driver.clients);
- return client;
-
- fail:
- return NULL;
-}
-
-static int wf_max6690_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev = NULL;
- struct pmac_i2c_bus *bus;
- const char *loc;
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
- return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
-
- while ((dev = of_get_next_child(busnode, dev)) != NULL) {
- u8 addr;
-
- /* We must re-match the adapter in order to properly check
- * the channel on multibus setups
- */
- if (!pmac_i2c_match_adapter(dev, adapter))
- continue;
- if (!of_device_is_compatible(dev, "max6690"))
- continue;
- addr = pmac_i2c_get_dev_addr(dev);
- loc = of_get_property(dev, "hwsensor-location", NULL);
- if (loc == NULL || addr == 0)
- continue;
- printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
- wf_max6690_create(adapter, addr, loc);
- }
-
- return 0;
-}
-
static int wf_max6690_remove(struct i2c_client *client)
{
struct wf_6690_sensor *max = i2c_get_clientdata(client);
@@ -170,15 +116,15 @@ static int wf_max6690_remove(struct i2c_client *client)
}
static const struct i2c_device_id wf_max6690_id[] = {
- { "wf_max6690", 0 },
+ { "MAC,max6690", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
static struct i2c_driver wf_max6690_driver = {
.driver = {
.name = "wf_max6690",
},
- .attach_adapter = wf_max6690_attach,
.probe = wf_max6690_probe,
.remove = wf_max6690_remove,
.id_table = wf_max6690_id,
@@ -186,11 +132,6 @@ static struct i2c_driver wf_max6690_driver = {
static int __init wf_max6690_sensor_init(void)
{
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
return i2c_add_driver(&wf_max6690_driver);
}
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h
new file mode 100644
index 0000000..046edc8
--- /dev/null
+++ b/drivers/macintosh/windfarm_mpu.h
@@ -0,0 +1,105 @@
+/*
+ * Windfarm PowerMac thermal control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#ifndef __WINDFARM_MPU_H
+#define __WINDFARM_MPU_H
+
+typedef unsigned short fu16;
+typedef int fs32;
+typedef short fs16;
+
+/* Definition of the MPU data structure which contains per CPU
+ * calibration information (among others) for the G5 machines
+ */
+struct mpu_data
+{
+ u8 signature; /* 0x00 - EEPROM sig. */
+ u8 bytes_used; /* 0x01 - Bytes used in eeprom (160 ?) */
+ u8 size; /* 0x02 - EEPROM size (256 ?) */
+ u8 version; /* 0x03 - EEPROM version */
+ u32 data_revision; /* 0x04 - Dataset revision */
+ u8 processor_bin_code[3]; /* 0x08 - Processor BIN code */
+ u8 bin_code_expansion; /* 0x0b - ??? (padding ?) */
+ u8 processor_num; /* 0x0c - Number of CPUs on this MPU */
+ u8 input_mul_bus_div; /* 0x0d - Clock input multiplier/bus divider */
+ u8 reserved1[2]; /* 0x0e - */
+ u32 input_clk_freq_high; /* 0x10 - Input clock frequency high */
+ u8 cpu_nb_target_cycles; /* 0x14 - ??? */
+ u8 cpu_statlat; /* 0x15 - ??? */
+ u8 cpu_snooplat; /* 0x16 - ??? */
+ u8 cpu_snoopacc; /* 0x17 - ??? */
+ u8 nb_paamwin; /* 0x18 - ??? */
+ u8 nb_statlat; /* 0x19 - ??? */
+ u8 nb_snooplat; /* 0x1a - ??? */
+ u8 nb_snoopwin; /* 0x1b - ??? */
+ u8 api_bus_mode; /* 0x1c - ??? */
+ u8 reserved2[3]; /* 0x1d - */
+ u32 input_clk_freq_low; /* 0x20 - Input clock frequency low */
+ u8 processor_card_slot; /* 0x24 - Processor card slot number */
+ u8 reserved3[2]; /* 0x25 - */
+ u8 padjmax; /* 0x27 - Max power adjustment (Not in OF!) */
+ u8 ttarget; /* 0x28 - Target temperature */
+ u8 tmax; /* 0x29 - Max temperature */
+ u8 pmaxh; /* 0x2a - Max power */
+ u8 tguardband; /* 0x2b - Guardband temp ??? Hist. len in OSX */
+ fs32 pid_gp; /* 0x2c - PID proportional gain */
+ fs32 pid_gr; /* 0x30 - PID reset gain */
+ fs32 pid_gd; /* 0x34 - PID derivative gain */
+ fu16 voph; /* 0x38 - Vop High */
+ fu16 vopl; /* 0x3a - Vop Low */
+ fs16 nactual_die; /* 0x3c - nActual Die */
+ fs16 nactual_heatsink; /* 0x3e - nActual Heatsink */
+ fs16 nactual_system; /* 0x40 - nActual System */
+ u16 calibration_flags; /* 0x42 - Calibration flags */
+ fu16 mdiode; /* 0x44 - Diode M value (scaling factor) */
+ fs16 bdiode; /* 0x46 - Diode B value (offset) */
+ fs32 theta_heat_sink; /* 0x48 - Theta heat sink */
+ u16 rminn_intake_fan; /* 0x4c - Intake fan min RPM */
+ u16 rmaxn_intake_fan; /* 0x4e - Intake fan max RPM */
+ u16 rminn_exhaust_fan; /* 0x50 - Exhaust fan min RPM */
+ u16 rmaxn_exhaust_fan; /* 0x52 - Exhaust fan max RPM */
+ u8 processor_part_num[8]; /* 0x54 - Processor part number XX pumps min/max */
+ u32 processor_lot_num; /* 0x5c - Processor lot number */
+ u8 orig_card_sernum[0x10]; /* 0x60 - Card original serial number */
+ u8 curr_card_sernum[0x10]; /* 0x70 - Card current serial number */
+ u8 mlb_sernum[0x18]; /* 0x80 - MLB serial number */
+ u32 checksum1; /* 0x98 - */
+ u32 checksum2; /* 0x9c - */
+}; /* Total size = 0xa0 */
+
+static inline const struct mpu_data *wf_get_mpu(int cpu)
+{
+ struct device_node *np;
+ char nodename[64];
+ const void *data;
+ int len;
+
+ /*
+ * prom.c routine for finding a node by path is a bit brain dead
+ * and requires exact @xxx unit numbers. This is a bit ugly but
+ * will work for these machines
+ */
+ sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
+ np = of_find_node_by_path(nodename);
+ if (!np)
+ return NULL;
+ data = of_get_property(np, "cpuid", &len);
+ of_node_put(np);
+ if (!data)
+ return NULL;
+
+ /*
+ * We are naughty, we have dropped the reference to the device
+ * node and still return a pointer to the content. We know we
+ * can do that though as this is only ever called on PowerMac
+ * which cannot remove those nodes
+ */
+ return data;
+}
+
+#endif /* __WINDFARM_MPU_H */
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
new file mode 100644
index 0000000..84ac913
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -0,0 +1,847 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for PowerMac7,2 and 7,3
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...) printk(args)
+#else
+#define DBG_LOTS(args...) do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS 2
+#define NR_CPU_FANS 3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *drives_temp;
+
+static struct wf_control *cpu_front_fans[NR_CHIPS];
+static struct wf_control *cpu_rear_fans[NR_CHIPS];
+static struct wf_control *cpu_pumps[NR_CHIPS];
+static struct wf_control *backside_fan;
+static struct wf_control *drives_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE 180
+
+/* Fixed speed for slot fan */
+#define SLOTS_FAN_DEFAULT_PWM 40
+
+/* Scale value for CPU intake fans */
+#define CPU_INTAKE_SCALE 0x0000f852
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static bool cpu_pid_combined;
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state drives_pid;
+static int drives_tick;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR 1
+#define FAILURE_FAN 2
+#define FAILURE_PERM 4
+#define FAILURE_LOW_OVERTEMP 8
+#define FAILURE_HIGH_OVERTEMP 16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE 0
+#define LOW_OVER_IMMEDIATE (10 << 16)
+#define LOW_OVER_CLEAR ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+#define HIGH_OVER_AVERAGE (10 << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+ int i;
+
+ /* We max all CPU fans in case of a sensor error. We also do the
+ * cpufreq clamping now, even if it's supposedly done later by the
+ * generic code anyway, we do it earlier here to react faster
+ */
+ if (cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ for (i = 0; i < nr_chips; i++) {
+ if (cpu_front_fans[i])
+ wf_control_set_max(cpu_front_fans[i]);
+ if (cpu_rear_fans[i])
+ wf_control_set_max(cpu_rear_fans[i]);
+ if (cpu_pumps[i])
+ wf_control_set_max(cpu_pumps[i]);
+ }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+ int new_state = 0;
+ s32 t_avg, t_old;
+ static bool first = true;
+
+ /* First check for immediate overtemps */
+ if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+ " temperature !\n");
+ }
+ if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " immediate CPU temperature !\n");
+ }
+
+ /*
+ * The first time around, initialize the array with the first
+ * temperature reading
+ */
+ if (first) {
+ int i;
+
+ cpu_thist_total = 0;
+ for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+ cpu_thist[i] = temp;
+ cpu_thist_total += temp;
+ }
+ first = false;
+ }
+
+ /*
+ * We calculate a history of max temperatures and use that for the
+ * overtemp management
+ */
+ t_old = cpu_thist[cpu_thist_pt];
+ cpu_thist[cpu_thist_pt] = temp;
+ cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+ cpu_thist_total -= t_old;
+ cpu_thist_total += temp;
+ t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+ DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+ FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+ /* Now check for average overtemps */
+ if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+ " temperature !\n");
+ }
+ if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " average CPU temperature !\n");
+ }
+
+ /* Now handle overtemp conditions. We don't currently use the windfarm
+ * overtemp handling core as it's not fully suited to the needs of those
+ * new machine. This will be fixed later.
+ */
+ if (new_state) {
+ /* High overtemp -> immediate shutdown */
+ if (new_state & FAILURE_HIGH_OVERTEMP)
+ machine_power_off();
+ if ((failure_state & new_state) != new_state)
+ cpu_max_all_fans();
+ failure_state |= new_state;
+ } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+ (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+ printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+ failure_state &= ~FAILURE_LOW_OVERTEMP;
+ }
+
+ return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+ s32 dtemp, volts, amps;
+ int rc;
+
+ /* Get diode temperature */
+ rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+ if (rc) {
+ DBG(" CPU%d: temp reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+ *temp = dtemp;
+
+ /* Get voltage */
+ rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+ if (rc) {
+ DBG(" CPU%d, volts reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+ /* Get current */
+ rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+ if (rc) {
+ DBG(" CPU%d, current reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+ /* Calculate power */
+
+ /* Scale voltage and current raw sensor values according to fixed scales
+ * obtained in Darwin and calculate power from I and V
+ */
+ *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+ DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+ return 0;
+
+}
+
+static void cpu_fans_tick_split(void)
+{
+ int err, cpu;
+ s32 intake, temp, power, t_max = 0;
+
+ DBG_LOTS("* cpu fans_tick_split()\n");
+
+ for (cpu = 0; cpu < nr_chips; ++cpu) {
+ struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+ /* Read current speed */
+ wf_control_get(cpu_rear_fans[cpu], &sp->target);
+
+ DBG_LOTS(" CPU%d: cur_target = %d RPM\n", cpu, sp->target);
+
+ err = read_one_cpu_vals(cpu, &temp, &power);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, temp);
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target);
+
+ /* Apply result directly to exhaust fan */
+ err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_rear_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ break;
+ }
+
+ /* Scale result for intake fan */
+ intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+ DBG_LOTS(" CPU%d: intake = %d RPM\n", cpu, intake);
+ err = wf_control_set(cpu_front_fans[cpu], intake);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_front_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ break;
+ }
+ }
+}
+
+static void cpu_fans_tick_combined(void)
+{
+ s32 temp0, power0, temp1, power1, t_max = 0;
+ s32 temp, power, intake, pump;
+ struct wf_control *pump0, *pump1;
+ struct wf_cpu_pid_state *sp = &cpu_pid[0];
+ int err, cpu;
+
+ DBG_LOTS("* cpu fans_tick_combined()\n");
+
+ /* Read current speed from cpu 0 */
+ wf_control_get(cpu_rear_fans[0], &sp->target);
+
+ DBG_LOTS(" CPUs: cur_target = %d RPM\n", sp->target);
+
+ /* Read values for both CPUs */
+ err = read_one_cpu_vals(0, &temp0, &power0);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+ err = read_one_cpu_vals(1, &temp1, &power1);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, max(temp0, temp1));
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Use the max temp & power of both */
+ temp = max(temp0, temp1);
+ power = max(power0, power1);
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ /* Scale result for intake fan */
+ intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+
+ /* Same deal with pump speed */
+ pump0 = cpu_pumps[0];
+ pump1 = cpu_pumps[1];
+ if (!pump0) {
+ pump0 = pump1;
+ pump1 = NULL;
+ }
+ pump = (sp->target * wf_control_get_max(pump0)) /
+ cpu_mpu_data[0]->rmaxn_exhaust_fan;
+
+ DBG_LOTS(" CPUs: target = %d RPM\n", sp->target);
+ DBG_LOTS(" CPUs: intake = %d RPM\n", intake);
+ DBG_LOTS(" CPUs: pump = %d RPM\n", pump);
+
+ for (cpu = 0; cpu < nr_chips; cpu++) {
+ err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_rear_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ err = wf_control_set(cpu_front_fans[cpu], intake);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_front_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ err = 0;
+ if (cpu_pumps[cpu])
+ err = wf_control_set(cpu_pumps[cpu], pump);
+ if (err) {
+ pr_warning("wf_pm72: Pump %s reports error %d\n",
+ cpu_pumps[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+ struct wf_cpu_pid_param pid;
+ const struct mpu_data *mpu = cpu_mpu_data[cpu];
+ s32 tmax, ttarget, ptarget;
+ int fmin, fmax, hsize;
+
+ /* Get PID params from the appropriate MPU EEPROM */
+ tmax = mpu->tmax << 16;
+ ttarget = mpu->ttarget << 16;
+ ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+ DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+ cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+ /* We keep a global tmax for overtemp calculations */
+ if (tmax < cpu_all_tmax)
+ cpu_all_tmax = tmax;
+
+ /* Set PID min/max by using the rear fan min/max */
+ fmin = wf_control_get_min(cpu_rear_fans[cpu]);
+ fmax = wf_control_get_max(cpu_rear_fans[cpu]);
+ DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+ /* History size */
+ hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+ DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+ /* Initialize PID loop */
+ pid.interval = 1; /* seconds */
+ pid.history_len = hsize;
+ pid.gd = mpu->pid_gd;
+ pid.gp = mpu->pid_gp;
+ pid.gr = mpu->pid_gr;
+ pid.tmax = tmax;
+ pid.ttarget = ttarget;
+ pid.pmaxadj = ptarget;
+ pid.min = fmin;
+ pid.max = fmax;
+
+ wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+ cpu_pid[cpu].target = 1000;
+
+ return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_u3_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 40 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 65 << 16,
+ .additive = 1,
+ .min = 20,
+ .max = 100,
+};
+
+static struct wf_pid_param backside_u3h_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 20 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 75 << 16,
+ .additive = 1,
+ .min = 20,
+ .max = 100,
+};
+
+static void backside_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!backside_fan || !backside_temp || !backside_tick)
+ return;
+ if (--backside_tick > 0)
+ return;
+ backside_tick = backside_pid.param.interval;
+
+ DBG_LOTS("* backside fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(backside_fan, &speed);
+ if (!err)
+ backside_pid.target = speed;
+
+ err = wf_sensor_get(backside_temp, &temp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ speed = wf_pid_run(&backside_pid, temp);
+
+ DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_control_set(backside_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void backside_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(backside_fan);
+ s32 fmax = wf_control_get_max(backside_fan);
+ struct wf_pid_param param;
+ struct device_node *u3;
+ int u3h = 1; /* conservative by default */
+
+ u3 = of_find_node_by_path("/u3@0,f8000000");
+ if (u3 != NULL) {
+ const u32 *vers = of_get_property(u3, "device-rev", NULL);
+ if (vers)
+ if (((*vers) & 0x3f) < 0x34)
+ u3h = 0;
+ of_node_put(u3);
+ }
+
+ param = u3h ? backside_u3h_param : backside_u3_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&backside_pid, &param);
+ backside_tick = 1;
+
+ pr_info("wf_pm72: Backside control loop started.\n");
+}
+
+/* Drive bay fan */
+static const struct wf_pid_param drives_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 30 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 40 << 16,
+ .additive = 1,
+ .min = 300,
+ .max = 4000,
+};
+
+static void drives_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!drives_fan || !drives_temp || !drives_tick)
+ return;
+ if (--drives_tick > 0)
+ return;
+ drives_tick = drives_pid.param.interval;
+
+ DBG_LOTS("* drives fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(drives_fan, &speed);
+ if (!err)
+ drives_pid.target = speed;
+
+ err = wf_sensor_get(drives_temp, &temp);
+ if (err) {
+ pr_warning("wf_pm72: drive bay temp sensor error %d\n", err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(drives_fan);
+ return;
+ }
+ speed = wf_pid_run(&drives_pid, temp);
+
+ DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_control_set(drives_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void drives_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(drives_fan);
+ s32 fmax = wf_control_get_max(drives_fan);
+ struct wf_pid_param param = drives_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&drives_pid, &param);
+ drives_tick = 1;
+
+ pr_info("wf_pm72: Drive bay control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+ cpu_max_all_fans();
+
+ if (backside_fan)
+ wf_control_set_max(backside_fan);
+ if (slots_fan)
+ wf_control_set_max(slots_fan);
+ if (drives_fan)
+ wf_control_set_max(drives_fan);
+}
+
+static void pm72_tick(void)
+{
+ int i, last_failure;
+
+ if (!started) {
+ started = 1;
+ printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+ for (i = 0; i < nr_chips; ++i) {
+ if (cpu_setup_pid(i) < 0) {
+ failure_state = FAILURE_PERM;
+ set_fail_state();
+ break;
+ }
+ }
+ DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+ backside_setup_pid();
+ drives_setup_pid();
+
+ /*
+ * We don't have the right stuff to drive the PCI fan
+ * so we fix it to a default value
+ */
+ wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM);
+
+#ifdef HACKED_OVERTEMP
+ cpu_all_tmax = 60 << 16;
+#endif
+ }
+
+ /* Permanent failure, bail out */
+ if (failure_state & FAILURE_PERM)
+ return;
+
+ /*
+ * Clear all failure bits except low overtemp which will be eventually
+ * cleared by the control loop itself
+ */
+ last_failure = failure_state;
+ failure_state &= FAILURE_LOW_OVERTEMP;
+ if (cpu_pid_combined)
+ cpu_fans_tick_combined();
+ else
+ cpu_fans_tick_split();
+ backside_fan_tick();
+ drives_fan_tick();
+
+ DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n",
+ last_failure, failure_state);
+
+ /* Check for failures. Any failure causes cpufreq clamping */
+ if (failure_state && last_failure == 0 && cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ if (failure_state == 0 && last_failure && cpufreq_clamp)
+ wf_control_set_min(cpufreq_clamp);
+
+ /* That's it for now, we might want to deal with other failures
+ * differently in the future though
+ */
+}
+
+static void pm72_new_control(struct wf_control *ct)
+{
+ bool all_controls;
+ bool had_pump = cpu_pumps[0] || cpu_pumps[1];
+
+ if (!strcmp(ct->name, "cpu-front-fan-0"))
+ cpu_front_fans[0] = ct;
+ else if (!strcmp(ct->name, "cpu-front-fan-1"))
+ cpu_front_fans[1] = ct;
+ else if (!strcmp(ct->name, "cpu-rear-fan-0"))
+ cpu_rear_fans[0] = ct;
+ else if (!strcmp(ct->name, "cpu-rear-fan-1"))
+ cpu_rear_fans[1] = ct;
+ else if (!strcmp(ct->name, "cpu-pump-0"))
+ cpu_pumps[0] = ct;
+ else if (!strcmp(ct->name, "cpu-pump-1"))
+ cpu_pumps[1] = ct;
+ else if (!strcmp(ct->name, "backside-fan"))
+ backside_fan = ct;
+ else if (!strcmp(ct->name, "slots-fan"))
+ slots_fan = ct;
+ else if (!strcmp(ct->name, "drive-bay-fan"))
+ drives_fan = ct;
+ else if (!strcmp(ct->name, "cpufreq-clamp"))
+ cpufreq_clamp = ct;
+
+ all_controls =
+ cpu_front_fans[0] &&
+ cpu_rear_fans[0] &&
+ backside_fan &&
+ slots_fan &&
+ drives_fan;
+ if (nr_chips > 1)
+ all_controls &=
+ cpu_front_fans[1] &&
+ cpu_rear_fans[1];
+ have_all_controls = all_controls;
+
+ if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) {
+ pr_info("wf_pm72: Liquid cooling pump(s) detected,"
+ " using new algorithm !\n");
+ cpu_pid_combined = true;
+ }
+}
+
+
+static void pm72_new_sensor(struct wf_sensor *sr)
+{
+ bool all_sensors;
+
+ if (!strcmp(sr->name, "cpu-diode-temp-0"))
+ sens_cpu_temp[0] = sr;
+ else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+ sens_cpu_temp[1] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-0"))
+ sens_cpu_volts[0] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-1"))
+ sens_cpu_volts[1] = sr;
+ else if (!strcmp(sr->name, "cpu-current-0"))
+ sens_cpu_amps[0] = sr;
+ else if (!strcmp(sr->name, "cpu-current-1"))
+ sens_cpu_amps[1] = sr;
+ else if (!strcmp(sr->name, "backside-temp"))
+ backside_temp = sr;
+ else if (!strcmp(sr->name, "hd-temp"))
+ drives_temp = sr;
+
+ all_sensors =
+ sens_cpu_temp[0] &&
+ sens_cpu_volts[0] &&
+ sens_cpu_amps[0] &&
+ backside_temp &&
+ drives_temp;
+ if (nr_chips > 1)
+ all_sensors &=
+ sens_cpu_temp[1] &&
+ sens_cpu_volts[1] &&
+ sens_cpu_amps[1];
+
+ have_all_sensors = all_sensors;
+}
+
+static int pm72_wf_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_SENSOR:
+ pm72_new_sensor(data);
+ break;
+ case WF_EVENT_NEW_CONTROL:
+ pm72_new_control(data);
+ break;
+ case WF_EVENT_TICK:
+ if (have_all_controls && have_all_sensors)
+ pm72_tick();
+ }
+ return 0;
+}
+
+static struct notifier_block pm72_events = {
+ .notifier_call = pm72_wf_notify,
+};
+
+static int wf_pm72_probe(struct platform_device *dev)
+{
+ wf_register_client(&pm72_events);
+ return 0;
+}
+
+static int __devexit wf_pm72_remove(struct platform_device *dev)
+{
+ wf_unregister_client(&pm72_events);
+
+ /* should release all sensors and controls */
+ return 0;
+}
+
+static struct platform_driver wf_pm72_driver = {
+ .probe = wf_pm72_probe,
+ .remove = wf_pm72_remove,
+ .driver = {
+ .name = "windfarm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wf_pm72_init(void)
+{
+ struct device_node *cpu;
+ int i;
+
+ if (!of_machine_is_compatible("PowerMac7,2") &&
+ !of_machine_is_compatible("PowerMac7,3"))
+ return -ENODEV;
+
+ /* Count the number of CPU cores */
+ nr_chips = 0;
+ for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ ++nr_chips;
+ if (nr_chips > NR_CHIPS)
+ nr_chips = NR_CHIPS;
+
+ pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+ nr_chips);
+
+ /* Get MPU data for each CPU */
+ for (i = 0; i < nr_chips; i++) {
+ cpu_mpu_data[i] = wf_get_mpu(i);
+ if (!cpu_mpu_data[i]) {
+ pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i);
+ return -ENXIO;
+ }
+ }
+
+#ifdef MODULE
+ request_module("windfarm_fcu_controls");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_ad7417_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+ platform_driver_register(&wf_pm72_driver);
+ return 0;
+}
+
+static void __exit wf_pm72_exit(void)
+{
+ platform_driver_unregister(&wf_pm72_driver);
+}
+
+module_init(wf_pm72_init);
+module_exit(wf_pm72_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index fc13d0f..990c876 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -302,13 +302,13 @@ static void wf_smu_create_sys_fans(void)
pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
pid_param.itarget = param->itarget;
- pid_param.min = fan_system->ops->get_min(fan_system);
- pid_param.max = fan_system->ops->get_max(fan_system);
+ pid_param.min = wf_control_get_min(fan_system);
+ pid_param.max = wf_control_get_max(fan_system);
if (fan_hd) {
pid_param.min =
- max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+ max(pid_param.min, wf_control_get_min(fan_hd));
pid_param.max =
- min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+ min(pid_param.max, wf_control_get_max(fan_hd));
}
wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
@@ -337,7 +337,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
}
st->ticks = WF_SMU_SYS_FANS_INTERVAL;
- rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+ rc = wf_sensor_get(sensor_hd_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
rc);
@@ -373,7 +373,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
st->hd_setpoint = new_setpoint;
readjust:
if (fan_system && wf_smu_failure_state == 0) {
- rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+ rc = wf_control_set(fan_system, st->sys_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: Sys fan error %d\n",
rc);
@@ -381,7 +381,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
}
}
if (fan_hd && wf_smu_failure_state == 0) {
- rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+ rc = wf_control_set(fan_hd, st->hd_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: HD fan error %d\n",
rc);
@@ -447,8 +447,8 @@ static void wf_smu_create_cpu_fans(void)
pid_param.ttarget = tmax - tdelta;
pid_param.pmaxadj = maxpow - powadj;
- pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
- pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+ pid_param.min = wf_control_get_min(fan_cpu_main);
+ pid_param.max = wf_control_get_max(fan_cpu_main);
wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
@@ -481,7 +481,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
st->ticks = WF_SMU_CPU_FANS_INTERVAL;
- rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ rc = wf_sensor_get(sensor_cpu_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
rc);
@@ -489,7 +489,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
return;
}
- rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ rc = wf_sensor_get(sensor_cpu_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
rc);
@@ -525,8 +525,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
st->cpu_setpoint = new_setpoint;
readjust:
if (fan_cpu_main && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_main,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU main fan"
" error %d\n", rc);
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index a9430ed..7653603 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -192,8 +192,8 @@ static void wf_smu_create_cpu_fans(void)
pid_param.ttarget = tmax - tdelta;
pid_param.pmaxadj = maxpow - powadj;
- pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
- pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+ pid_param.min = wf_control_get_min(fan_cpu_main);
+ pid_param.max = wf_control_get_max(fan_cpu_main);
wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
@@ -226,7 +226,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
st->ticks = WF_SMU_CPU_FANS_INTERVAL;
- rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ rc = wf_sensor_get(sensor_cpu_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
rc);
@@ -234,7 +234,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
return;
}
- rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ rc = wf_sensor_get(sensor_cpu_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
rc);
@@ -261,8 +261,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
st->cpu_setpoint = new_setpoint;
readjust:
if (fan_cpu_main && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_main,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU main fan"
" error %d\n", rc);
@@ -270,8 +269,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
}
if (fan_cpu_second && wf_smu_failure_state == 0) {
- rc = fan_cpu_second->ops->set_value(fan_cpu_second,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU second fan"
" error %d\n", rc);
@@ -279,8 +277,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
}
if (fan_cpu_third && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_third,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU third fan"
" error %d\n", rc);
@@ -312,8 +309,8 @@ static void wf_smu_create_drive_fans(void)
/* Fill PID params */
param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
- param.min = fan_hd->ops->get_min(fan_hd);
- param.max = fan_hd->ops->get_max(fan_hd);
+ param.min = wf_control_get_min(fan_hd);
+ param.max = wf_control_get_max(fan_hd);
wf_pid_init(&wf_smu_drive_fans->pid, &param);
DBG("wf: Drive Fan control initialized.\n");
@@ -338,7 +335,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
}
st->ticks = st->pid.param.interval;
- rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+ rc = wf_sensor_get(sensor_hd_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
rc);
@@ -361,7 +358,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
st->setpoint = new_setpoint;
readjust:
if (fan_hd && wf_smu_failure_state == 0) {
- rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+ rc = wf_control_set(fan_hd, st->setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: HD fan error %d\n",
rc);
@@ -393,8 +390,8 @@ static void wf_smu_create_slots_fans(void)
/* Fill PID params */
param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
- param.min = fan_slots->ops->get_min(fan_slots);
- param.max = fan_slots->ops->get_max(fan_slots);
+ param.min = wf_control_get_min(fan_slots);
+ param.max = wf_control_get_max(fan_slots);
wf_pid_init(&wf_smu_slots_fans->pid, &param);
DBG("wf: Slots Fan control initialized.\n");
@@ -419,7 +416,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
}
st->ticks = st->pid.param.interval;
- rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+ rc = wf_sensor_get(sensor_slots_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
rc);
@@ -444,7 +441,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
st->setpoint = new_setpoint;
readjust:
if (fan_slots && wf_smu_failure_state == 0) {
- rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+ rc = wf_control_set(fan_slots, st->setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: Slots fan error %d\n",
rc);
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
new file mode 100644
index 0000000..3eca6d4
--- /dev/null
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -0,0 +1,740 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for RackMack3,1 (Xserve G5)
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...) printk(args)
+#else
+#define DBG_LOTS(args...) do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS 2
+#define NR_CPU_FANS 3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *slots_temp;
+static struct wf_sensor *dimms_temp;
+
+static struct wf_control *cpu_fans[NR_CHIPS][3];
+static struct wf_control *backside_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE 180
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state slots_pid;
+static int slots_tick;
+static int slots_speed;
+static struct wf_pid_state dimms_pid;
+static int dimms_output_clamp;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR 1
+#define FAILURE_FAN 2
+#define FAILURE_PERM 4
+#define FAILURE_LOW_OVERTEMP 8
+#define FAILURE_HIGH_OVERTEMP 16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE 0
+#define LOW_OVER_IMMEDIATE (10 << 16)
+#define LOW_OVER_CLEAR ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+#define HIGH_OVER_AVERAGE (10 << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+ int i;
+
+ /* We max all CPU fans in case of a sensor error. We also do the
+ * cpufreq clamping now, even if it's supposedly done later by the
+ * generic code anyway, we do it earlier here to react faster
+ */
+ if (cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ for (i = 0; i < nr_chips; i++) {
+ if (cpu_fans[i][0])
+ wf_control_set_max(cpu_fans[i][0]);
+ if (cpu_fans[i][1])
+ wf_control_set_max(cpu_fans[i][1]);
+ if (cpu_fans[i][2])
+ wf_control_set_max(cpu_fans[i][2]);
+ }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+ int new_state = 0;
+ s32 t_avg, t_old;
+ static bool first = true;
+
+ /* First check for immediate overtemps */
+ if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+ " temperature !\n");
+ }
+ if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " immediate CPU temperature !\n");
+ }
+
+ /*
+ * The first time around, initialize the array with the first
+ * temperature reading
+ */
+ if (first) {
+ int i;
+
+ cpu_thist_total = 0;
+ for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+ cpu_thist[i] = temp;
+ cpu_thist_total += temp;
+ }
+ first = false;
+ }
+
+ /*
+ * We calculate a history of max temperatures and use that for the
+ * overtemp management
+ */
+ t_old = cpu_thist[cpu_thist_pt];
+ cpu_thist[cpu_thist_pt] = temp;
+ cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+ cpu_thist_total -= t_old;
+ cpu_thist_total += temp;
+ t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+ DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+ FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+ /* Now check for average overtemps */
+ if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+ " temperature !\n");
+ }
+ if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " average CPU temperature !\n");
+ }
+
+ /* Now handle overtemp conditions. We don't currently use the windfarm
+ * overtemp handling core as it's not fully suited to the needs of those
+ * new machine. This will be fixed later.
+ */
+ if (new_state) {
+ /* High overtemp -> immediate shutdown */
+ if (new_state & FAILURE_HIGH_OVERTEMP)
+ machine_power_off();
+ if ((failure_state & new_state) != new_state)
+ cpu_max_all_fans();
+ failure_state |= new_state;
+ } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+ (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+ printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+ failure_state &= ~FAILURE_LOW_OVERTEMP;
+ }
+
+ return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+ s32 dtemp, volts, amps;
+ int rc;
+
+ /* Get diode temperature */
+ rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+ if (rc) {
+ DBG(" CPU%d: temp reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+ *temp = dtemp;
+
+ /* Get voltage */
+ rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+ if (rc) {
+ DBG(" CPU%d, volts reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+ /* Get current */
+ rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+ if (rc) {
+ DBG(" CPU%d, current reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+ /* Calculate power */
+
+ /* Scale voltage and current raw sensor values according to fixed scales
+ * obtained in Darwin and calculate power from I and V
+ */
+ *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+ DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+ return 0;
+
+}
+
+static void cpu_fans_tick(void)
+{
+ int err, cpu, i;
+ s32 speed, temp, power, t_max = 0;
+
+ DBG_LOTS("* cpu fans_tick_split()\n");
+
+ for (cpu = 0; cpu < nr_chips; ++cpu) {
+ struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+ /* Read current speed */
+ wf_control_get(cpu_fans[cpu][0], &sp->target);
+
+ err = read_one_cpu_vals(cpu, &temp, &power);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, temp);
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target);
+
+ /* Apply DIMMs clamp */
+ speed = max(sp->target, dimms_output_clamp);
+
+ /* Apply result to all cpu fans */
+ for (i = 0; i < 3; i++) {
+ err = wf_control_set(cpu_fans[cpu][i], speed);
+ if (err) {
+ pr_warning("wf_rm31: Fan %s reports error %d\n",
+ cpu_fans[cpu][i]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ }
+ }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+ struct wf_cpu_pid_param pid;
+ const struct mpu_data *mpu = cpu_mpu_data[cpu];
+ s32 tmax, ttarget, ptarget;
+ int fmin, fmax, hsize;
+
+ /* Get PID params from the appropriate MPU EEPROM */
+ tmax = mpu->tmax << 16;
+ ttarget = mpu->ttarget << 16;
+ ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+ DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+ cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+ /* We keep a global tmax for overtemp calculations */
+ if (tmax < cpu_all_tmax)
+ cpu_all_tmax = tmax;
+
+ /* Set PID min/max by using the rear fan min/max */
+ fmin = wf_control_get_min(cpu_fans[cpu][0]);
+ fmax = wf_control_get_max(cpu_fans[cpu][0]);
+ DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+ /* History size */
+ hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+ DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+ /* Initialize PID loop */
+ pid.interval = 1; /* seconds */
+ pid.history_len = hsize;
+ pid.gd = mpu->pid_gd;
+ pid.gp = mpu->pid_gp;
+ pid.gr = mpu->pid_gr;
+ pid.tmax = tmax;
+ pid.ttarget = ttarget;
+ pid.pmaxadj = ptarget;
+ pid.min = fmin;
+ pid.max = fmax;
+
+ wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+ cpu_pid[cpu].target = 4000;
+
+ return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_param = {
+ .interval = 1,
+ .history_len = 2,
+ .gd = 0x00500000,
+ .gp = 0x0004cccc,
+ .gr = 0,
+ .itarget = 70 << 16,
+ .additive = 0,
+ .min = 20,
+ .max = 100,
+};
+
+/* DIMMs temperature (clamp the backside fan) */
+static struct wf_pid_param dimms_param = {
+ .interval = 1,
+ .history_len = 20,
+ .gd = 0,
+ .gp = 0,
+ .gr = 0x06553600,
+ .itarget = 50 << 16,
+ .additive = 0,
+ .min = 4000,
+ .max = 14000,
+};
+
+static void backside_fan_tick(void)
+{
+ s32 temp, dtemp;
+ int speed, dspeed, fan_min;
+ int err;
+
+ if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick)
+ return;
+ if (--backside_tick > 0)
+ return;
+ backside_tick = backside_pid.param.interval;
+
+ DBG_LOTS("* backside fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(backside_fan, &speed);
+ if (!err)
+ backside_pid.target = speed;
+
+ err = wf_sensor_get(backside_temp, &temp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ speed = wf_pid_run(&backside_pid, temp);
+
+ DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_sensor_get(dimms_temp, &dtemp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ dspeed = wf_pid_run(&dimms_pid, dtemp);
+ dimms_output_clamp = dspeed;
+
+ fan_min = (dspeed * 100) / 14000;
+ fan_min = max(fan_min, backside_param.min);
+ speed = max(speed, fan_min);
+
+ err = wf_control_set(backside_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void backside_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(backside_fan);
+ s32 fmax = wf_control_get_max(backside_fan);
+ struct wf_pid_param param;
+
+ param = backside_param;
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&backside_pid, &param);
+
+ param = dimms_param;
+ wf_pid_init(&dimms_pid, &param);
+
+ backside_tick = 1;
+
+ pr_info("wf_rm31: Backside control loop started.\n");
+}
+
+/* Slots fan */
+static const struct wf_pid_param slots_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 30 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 40 << 16,
+ .additive = 1,
+ .min = 300,
+ .max = 4000,
+};
+
+static void slots_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!slots_fan || !slots_temp || !slots_tick)
+ return;
+ if (--slots_tick > 0)
+ return;
+ slots_tick = slots_pid.param.interval;
+
+ DBG_LOTS("* slots fans tick\n");
+
+ err = wf_sensor_get(slots_temp, &temp);
+ if (err) {
+ pr_warning("wf_rm31: slots temp sensor error %d\n", err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(slots_fan);
+ return;
+ }
+ speed = wf_pid_run(&slots_pid, temp);
+
+ DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ slots_speed = speed;
+ err = wf_control_set(slots_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void slots_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(slots_fan);
+ s32 fmax = wf_control_get_max(slots_fan);
+ struct wf_pid_param param = slots_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&slots_pid, &param);
+ slots_tick = 1;
+
+ pr_info("wf_rm31: Slots control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+ cpu_max_all_fans();
+
+ if (backside_fan)
+ wf_control_set_max(backside_fan);
+ if (slots_fan)
+ wf_control_set_max(slots_fan);
+}
+
+static void rm31_tick(void)
+{
+ int i, last_failure;
+
+ if (!started) {
+ started = 1;
+ printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+ for (i = 0; i < nr_chips; ++i) {
+ if (cpu_setup_pid(i) < 0) {
+ failure_state = FAILURE_PERM;
+ set_fail_state();
+ break;
+ }
+ }
+ DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+ backside_setup_pid();
+ slots_setup_pid();
+
+#ifdef HACKED_OVERTEMP
+ cpu_all_tmax = 60 << 16;
+#endif
+ }
+
+ /* Permanent failure, bail out */
+ if (failure_state & FAILURE_PERM)
+ return;
+
+ /*
+ * Clear all failure bits except low overtemp which will be eventually
+ * cleared by the control loop itself
+ */
+ last_failure = failure_state;
+ failure_state &= FAILURE_LOW_OVERTEMP;
+ backside_fan_tick();
+ slots_fan_tick();
+
+ /* We do CPUs last because they can be clamped high by
+ * DIMM temperature
+ */
+ cpu_fans_tick();
+
+ DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n",
+ last_failure, failure_state);
+
+ /* Check for failures. Any failure causes cpufreq clamping */
+ if (failure_state && last_failure == 0 && cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ if (failure_state == 0 && last_failure && cpufreq_clamp)
+ wf_control_set_min(cpufreq_clamp);
+
+ /* That's it for now, we might want to deal with other failures
+ * differently in the future though
+ */
+}
+
+static void rm31_new_control(struct wf_control *ct)
+{
+ bool all_controls;
+
+ if (!strcmp(ct->name, "cpu-fan-a-0"))
+ cpu_fans[0][0] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-b-0"))
+ cpu_fans[0][1] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-c-0"))
+ cpu_fans[0][2] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-a-1"))
+ cpu_fans[1][0] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-b-1"))
+ cpu_fans[1][1] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-c-1"))
+ cpu_fans[1][2] = ct;
+ else if (!strcmp(ct->name, "backside-fan"))
+ backside_fan = ct;
+ else if (!strcmp(ct->name, "slots-fan"))
+ slots_fan = ct;
+ else if (!strcmp(ct->name, "cpufreq-clamp"))
+ cpufreq_clamp = ct;
+
+ all_controls =
+ cpu_fans[0][0] &&
+ cpu_fans[0][1] &&
+ cpu_fans[0][2] &&
+ backside_fan &&
+ slots_fan;
+ if (nr_chips > 1)
+ all_controls &=
+ cpu_fans[1][0] &&
+ cpu_fans[1][1] &&
+ cpu_fans[1][2];
+ have_all_controls = all_controls;
+}
+
+
+static void rm31_new_sensor(struct wf_sensor *sr)
+{
+ bool all_sensors;
+
+ if (!strcmp(sr->name, "cpu-diode-temp-0"))
+ sens_cpu_temp[0] = sr;
+ else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+ sens_cpu_temp[1] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-0"))
+ sens_cpu_volts[0] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-1"))
+ sens_cpu_volts[1] = sr;
+ else if (!strcmp(sr->name, "cpu-current-0"))
+ sens_cpu_amps[0] = sr;
+ else if (!strcmp(sr->name, "cpu-current-1"))
+ sens_cpu_amps[1] = sr;
+ else if (!strcmp(sr->name, "backside-temp"))
+ backside_temp = sr;
+ else if (!strcmp(sr->name, "slots-temp"))
+ slots_temp = sr;
+ else if (!strcmp(sr->name, "dimms-temp"))
+ dimms_temp = sr;
+
+ all_sensors =
+ sens_cpu_temp[0] &&
+ sens_cpu_volts[0] &&
+ sens_cpu_amps[0] &&
+ backside_temp &&
+ slots_temp &&
+ dimms_temp;
+ if (nr_chips > 1)
+ all_sensors &=
+ sens_cpu_temp[1] &&
+ sens_cpu_volts[1] &&
+ sens_cpu_amps[1];
+
+ have_all_sensors = all_sensors;
+}
+
+static int rm31_wf_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_SENSOR:
+ rm31_new_sensor(data);
+ break;
+ case WF_EVENT_NEW_CONTROL:
+ rm31_new_control(data);
+ break;
+ case WF_EVENT_TICK:
+ if (have_all_controls && have_all_sensors)
+ rm31_tick();
+ }
+ return 0;
+}
+
+static struct notifier_block rm31_events = {
+ .notifier_call = rm31_wf_notify,
+};
+
+static int wf_rm31_probe(struct platform_device *dev)
+{
+ wf_register_client(&rm31_events);
+ return 0;
+}
+
+static int __devexit wf_rm31_remove(struct platform_device *dev)
+{
+ wf_unregister_client(&rm31_events);
+
+ /* should release all sensors and controls */
+ return 0;
+}
+
+static struct platform_driver wf_rm31_driver = {
+ .probe = wf_rm31_probe,
+ .remove = wf_rm31_remove,
+ .driver = {
+ .name = "windfarm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wf_rm31_init(void)
+{
+ struct device_node *cpu;
+ int i;
+
+ if (!of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ /* Count the number of CPU cores */
+ nr_chips = 0;
+ for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ ++nr_chips;
+ if (nr_chips > NR_CHIPS)
+ nr_chips = NR_CHIPS;
+
+ pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+ nr_chips);
+
+ /* Get MPU data for each CPU */
+ for (i = 0; i < nr_chips; i++) {
+ cpu_mpu_data[i] = wf_get_mpu(i);
+ if (!cpu_mpu_data[i]) {
+ pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i);
+ return -ENXIO;
+ }
+ }
+
+#ifdef MODULE
+ request_module("windfarm_fcu_controls");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_lm87_sensor");
+ request_module("windfarm_ad7417_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+ platform_driver_register(&wf_rm31_driver);
+ return 0;
+}
+
+static void __exit wf_rm31_exit(void)
+{
+ platform_driver_unregister(&wf_rm31_driver);
+}
+
+module_init(wf_rm31_init);
+module_exit(wf_rm31_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for Xserve G5");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 3c2be51..c155a54 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -172,7 +172,6 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->fan_type = pwm_fan;
fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
- sysfs_attr_init(&fct->ctrl.attr.attr);
/* We use the name & location here the same way we do for SMU sensors,
* see the comment in windfarm_smu_sensors.c. The locations are a bit
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 65a8ff3..426e810 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -20,7 +20,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
#define DEBUG
@@ -34,11 +34,12 @@
#define MAX_AGE msecs_to_jiffies(800)
struct wf_sat {
+ struct kref ref;
int nr;
- atomic_t refcnt;
struct mutex mutex;
unsigned long last_read; /* jiffies when cache last updated */
u8 cache[16];
+ struct list_head sensors;
struct i2c_client *i2c;
struct device_node *node;
};
@@ -46,11 +47,12 @@ struct wf_sat {
static struct wf_sat *sats[2];
struct wf_sat_sensor {
- int index;
- int index2; /* used for power sensors */
- int shift;
- struct wf_sat *sat;
- struct wf_sensor sens;
+ struct list_head link;
+ int index;
+ int index2; /* used for power sensors */
+ int shift;
+ struct wf_sat *sat;
+ struct wf_sensor sens;
};
#define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens)
@@ -142,7 +144,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
return 0;
}
-static int wf_sat_get(struct wf_sensor *sr, s32 *value)
+static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
{
struct wf_sat_sensor *sens = wf_to_sat(sr);
struct wf_sat *sat = sens->sat;
@@ -175,62 +177,34 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
return err;
}
-static void wf_sat_release(struct wf_sensor *sr)
+static void wf_sat_release(struct kref *ref)
+{
+ struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
+
+ if (sat->nr >= 0)
+ sats[sat->nr] = NULL;
+ kfree(sat);
+}
+
+static void wf_sat_sensor_release(struct wf_sensor *sr)
{
struct wf_sat_sensor *sens = wf_to_sat(sr);
struct wf_sat *sat = sens->sat;
- if (atomic_dec_and_test(&sat->refcnt)) {
- if (sat->nr >= 0)
- sats[sat->nr] = NULL;
- kfree(sat);
- }
kfree(sens);
+ kref_put(&sat->ref, wf_sat_release);
}
static struct wf_sensor_ops wf_sat_ops = {
- .get_value = wf_sat_get,
- .release = wf_sat_release,
+ .get_value = wf_sat_sensor_get,
+ .release = wf_sat_sensor_release,
.owner = THIS_MODULE,
};
-static struct i2c_driver wf_sat_driver;
-
-static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- const u32 *reg;
- u8 addr;
-
- reg = of_get_property(dev, "reg", NULL);
- if (reg == NULL)
- return;
- addr = *reg;
- DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = (addr >> 1) & 0x7f;
- info.platform_data = dev;
- strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
- return;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_sat_driver.clients);
-}
-
static int wf_sat_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct device_node *dev = client->dev.platform_data;
+ struct device_node *dev = client->dev.of_node;
struct wf_sat *sat;
struct wf_sat_sensor *sens;
const u32 *reg;
@@ -246,9 +220,10 @@ static int wf_sat_probe(struct i2c_client *client,
return -ENOMEM;
sat->nr = -1;
sat->node = of_node_get(dev);
- atomic_set(&sat->refcnt, 0);
+ kref_init(&sat->ref);
mutex_init(&sat->mutex);
sat->i2c = client;
+ INIT_LIST_HEAD(&sat->sensors);
i2c_set_clientdata(client, sat);
vsens[0] = vsens[1] = -1;
@@ -310,14 +285,15 @@ static int wf_sat_probe(struct i2c_client *client,
sens->index2 = -1;
sens->shift = shift;
sens->sat = sat;
- atomic_inc(&sat->refcnt);
sens->sens.ops = &wf_sat_ops;
sens->sens.name = (char *) (sens + 1);
- snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
+ snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
- if (wf_register_sensor(&sens->sens)) {
- atomic_dec(&sat->refcnt);
+ if (wf_register_sensor(&sens->sens))
kfree(sens);
+ else {
+ list_add(&sens->link, &sat->sensors);
+ kref_get(&sat->ref);
}
}
@@ -336,14 +312,15 @@ static int wf_sat_probe(struct i2c_client *client,
sens->index2 = isens[core];
sens->shift = 0;
sens->sat = sat;
- atomic_inc(&sat->refcnt);
sens->sens.ops = &wf_sat_ops;
sens->sens.name = (char *) (sens + 1);
- snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
+ snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
- if (wf_register_sensor(&sens->sens)) {
- atomic_dec(&sat->refcnt);
+ if (wf_register_sensor(&sens->sens))
kfree(sens);
+ else {
+ list_add(&sens->link, &sat->sensors);
+ kref_get(&sat->ref);
}
}
@@ -353,42 +330,35 @@ static int wf_sat_probe(struct i2c_client *client,
return 0;
}
-static int wf_sat_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev = NULL;
- struct pmac_i2c_bus *bus;
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
- return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
-
- while ((dev = of_get_next_child(busnode, dev)) != NULL)
- if (of_device_is_compatible(dev, "smu-sat"))
- wf_sat_create(adapter, dev);
- return 0;
-}
-
static int wf_sat_remove(struct i2c_client *client)
{
struct wf_sat *sat = i2c_get_clientdata(client);
+ struct wf_sat_sensor *sens;
- /* XXX TODO */
-
+ /* release sensors */
+ while(!list_empty(&sat->sensors)) {
+ sens = list_first_entry(&sat->sensors,
+ struct wf_sat_sensor, link);
+ list_del(&sens->link);
+ wf_unregister_sensor(&sens->sens);
+ }
sat->i2c = NULL;
+ i2c_set_clientdata(client, NULL);
+ kref_put(&sat->ref, wf_sat_release);
+
return 0;
}
static const struct i2c_device_id wf_sat_id[] = {
- { "wf_sat", 0 },
+ { "MAC,smu-sat", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_sat_id);
static struct i2c_driver wf_sat_driver = {
.driver = {
.name = "wf_smu_sat",
},
- .attach_adapter = wf_sat_attach,
.probe = wf_sat_probe,
.remove = wf_sat_remove,
.id_table = wf_sat_id,
@@ -399,15 +369,13 @@ static int __init sat_sensors_init(void)
return i2c_add_driver(&wf_sat_driver);
}
-#if 0 /* uncomment when module_exit() below is uncommented */
static void __exit sat_sensors_exit(void)
{
i2c_del_driver(&wf_sat_driver);
}
-#endif
module_init(sat_sensors_init);
-/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
+module_exit(sat_sensors_exit);
MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 17e2b47..15dbe03 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -45,7 +45,7 @@ static inline char *bmname(struct bitmap *bitmap)
* if we find our page, we increment the page's refcount so that it stays
* allocated while we're using it
*/
-static int bitmap_checkpage(struct bitmap *bitmap,
+static int bitmap_checkpage(struct bitmap_counts *bitmap,
unsigned long page, int create)
__releases(bitmap->lock)
__acquires(bitmap->lock)
@@ -76,8 +76,7 @@ __acquires(bitmap->lock)
spin_lock_irq(&bitmap->lock);
if (mappage == NULL) {
- pr_debug("%s: bitmap map page allocation failed, hijacking\n",
- bmname(bitmap));
+ pr_debug("md/bitmap: map page allocation failed, hijacking\n");
/* failed - set the hijacked flag so that we can use the
* pointer as a counter */
if (!bitmap->bp[page].map)
@@ -100,7 +99,7 @@ __acquires(bitmap->lock)
/* if page is completely empty, put it back on the free list, or dealloc it */
/* if page was hijacked, unmark the flag so it might get alloced next time */
/* Note: lock should be held when calling this */
-static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+static void bitmap_checkfree(struct bitmap_counts *bitmap, unsigned long page)
{
char *ptr;
@@ -130,22 +129,14 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
*/
/* IO operations when bitmap is stored near all superblocks */
-static struct page *read_sb_page(struct mddev *mddev, loff_t offset,
- struct page *page,
- unsigned long index, int size)
+static int read_sb_page(struct mddev *mddev, loff_t offset,
+ struct page *page,
+ unsigned long index, int size)
{
/* choose a good rdev and read the page from there */
struct md_rdev *rdev;
sector_t target;
- int did_alloc = 0;
-
- if (!page) {
- page = alloc_page(GFP_KERNEL);
- if (!page)
- return ERR_PTR(-ENOMEM);
- did_alloc = 1;
- }
rdev_for_each(rdev, mddev) {
if (! test_bit(In_sync, &rdev->flags)
@@ -158,15 +149,10 @@ static struct page *read_sb_page(struct mddev *mddev, loff_t offset,
roundup(size, bdev_logical_block_size(rdev->bdev)),
page, READ, true)) {
page->index = index;
- attach_page_buffers(page, NULL); /* so that free_buffer will
- * quietly no-op */
- return page;
+ return 0;
}
}
- if (did_alloc)
- put_page(page);
- return ERR_PTR(-EIO);
-
+ return -EIO;
}
static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddev)
@@ -208,6 +194,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
struct md_rdev *rdev = NULL;
struct block_device *bdev;
struct mddev *mddev = bitmap->mddev;
+ struct bitmap_storage *store = &bitmap->storage;
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
int size = PAGE_SIZE;
@@ -215,9 +202,13 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
- if (page->index == bitmap->file_pages-1)
- size = roundup(bitmap->last_page_size,
+ if (page->index == store->file_pages-1) {
+ int last_page_size = store->bytes & (PAGE_SIZE-1);
+ if (last_page_size == 0)
+ last_page_size = PAGE_SIZE;
+ size = roundup(last_page_size,
bdev_logical_block_size(bdev));
+ }
/* Just make sure we aren't corrupting data or
* metadata
*/
@@ -276,10 +267,10 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
{
struct buffer_head *bh;
- if (bitmap->file == NULL) {
+ if (bitmap->storage.file == NULL) {
switch (write_sb_page(bitmap, page, wait)) {
case -EINVAL:
- bitmap->flags |= BITMAP_WRITE_ERROR;
+ set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
}
} else {
@@ -297,20 +288,16 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
}
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
bitmap_file_kick(bitmap);
}
static void end_bitmap_write(struct buffer_head *bh, int uptodate)
{
struct bitmap *bitmap = bh->b_private;
- unsigned long flags;
- if (!uptodate) {
- spin_lock_irqsave(&bitmap->lock, flags);
- bitmap->flags |= BITMAP_WRITE_ERROR;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- }
+ if (!uptodate)
+ set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
if (atomic_dec_and_test(&bitmap->pending_writes))
wake_up(&bitmap->write_wait);
}
@@ -325,8 +312,12 @@ __clear_page_buffers(struct page *page)
}
static void free_buffers(struct page *page)
{
- struct buffer_head *bh = page_buffers(page);
+ struct buffer_head *bh;
+ if (!PagePrivate(page))
+ return;
+
+ bh = page_buffers(page);
while (bh) {
struct buffer_head *next = bh->b_this_page;
free_buffer_head(bh);
@@ -343,11 +334,12 @@ static void free_buffers(struct page *page)
* This usage is similar to how swap files are handled, and allows us
* to write to a file with no concerns of memory allocation failing.
*/
-static struct page *read_page(struct file *file, unsigned long index,
- struct bitmap *bitmap,
- unsigned long count)
+static int read_page(struct file *file, unsigned long index,
+ struct bitmap *bitmap,
+ unsigned long count,
+ struct page *page)
{
- struct page *page = NULL;
+ int ret = 0;
struct inode *inode = file->f_path.dentry->d_inode;
struct buffer_head *bh;
sector_t block;
@@ -355,16 +347,9 @@ static struct page *read_page(struct file *file, unsigned long index,
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT);
- page = alloc_page(GFP_KERNEL);
- if (!page)
- page = ERR_PTR(-ENOMEM);
- if (IS_ERR(page))
- goto out;
-
bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
if (!bh) {
- put_page(page);
- page = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
goto out;
}
attach_page_buffers(page, bh);
@@ -376,8 +361,7 @@ static struct page *read_page(struct file *file, unsigned long index,
bh->b_blocknr = bmap(inode, block);
if (bh->b_blocknr == 0) {
/* Cannot use this file! */
- free_buffers(page);
- page = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
goto out;
}
bh->b_bdev = inode->i_sb->s_bdev;
@@ -400,17 +384,15 @@ static struct page *read_page(struct file *file, unsigned long index,
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
- if (bitmap->flags & BITMAP_WRITE_ERROR) {
- free_buffers(page);
- page = ERR_PTR(-EIO);
- }
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
+ ret = -EIO;
out:
- if (IS_ERR(page))
- printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %ld\n",
+ if (ret)
+ printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %d\n",
(int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT,
- PTR_ERR(page));
- return page;
+ ret);
+ return ret;
}
/*
@@ -426,9 +408,9 @@ void bitmap_update_sb(struct bitmap *bitmap)
return;
if (bitmap->mddev->bitmap_info.external)
return;
- if (!bitmap->sb_page) /* no superblock */
+ if (!bitmap->storage.sb_page) /* no superblock */
return;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
sb->events = cpu_to_le64(bitmap->mddev->events);
if (bitmap->mddev->events < bitmap->events_cleared)
/* rocking back to read-only */
@@ -438,8 +420,13 @@ void bitmap_update_sb(struct bitmap *bitmap)
/* Just in case these have been changed via sysfs: */
sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
+ /* This might have been changed by a reshape */
+ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
+ sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize);
+ sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
+ bitmap_info.space);
kunmap_atomic(sb);
- write_page(bitmap, bitmap->sb_page, 1);
+ write_page(bitmap, bitmap->storage.sb_page, 1);
}
/* print out the bitmap file superblock */
@@ -447,9 +434,9 @@ void bitmap_print_sb(struct bitmap *bitmap)
{
bitmap_super_t *sb;
- if (!bitmap || !bitmap->sb_page)
+ if (!bitmap || !bitmap->storage.sb_page)
return;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap));
printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic));
printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version));
@@ -488,15 +475,15 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
unsigned long chunksize, daemon_sleep, write_behind;
int err = -EINVAL;
- bitmap->sb_page = alloc_page(GFP_KERNEL);
- if (IS_ERR(bitmap->sb_page)) {
- err = PTR_ERR(bitmap->sb_page);
- bitmap->sb_page = NULL;
+ bitmap->storage.sb_page = alloc_page(GFP_KERNEL);
+ if (IS_ERR(bitmap->storage.sb_page)) {
+ err = PTR_ERR(bitmap->storage.sb_page);
+ bitmap->storage.sb_page = NULL;
return err;
}
- bitmap->sb_page->index = 0;
+ bitmap->storage.sb_page->index = 0;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
sb->magic = cpu_to_le32(BITMAP_MAGIC);
sb->version = cpu_to_le32(BITMAP_MAJOR_HI);
@@ -534,8 +521,8 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
memcpy(sb->uuid, bitmap->mddev->uuid, 16);
- bitmap->flags |= BITMAP_STALE;
- sb->state |= cpu_to_le32(BITMAP_STALE);
+ set_bit(BITMAP_STALE, &bitmap->flags);
+ sb->state = cpu_to_le32(bitmap->flags);
bitmap->events_cleared = bitmap->mddev->events;
sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
@@ -551,31 +538,45 @@ static int bitmap_read_sb(struct bitmap *bitmap)
bitmap_super_t *sb;
unsigned long chunksize, daemon_sleep, write_behind;
unsigned long long events;
+ unsigned long sectors_reserved = 0;
int err = -EINVAL;
+ struct page *sb_page;
+ if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
+ chunksize = 128 * 1024 * 1024;
+ daemon_sleep = 5 * HZ;
+ write_behind = 0;
+ set_bit(BITMAP_STALE, &bitmap->flags);
+ err = 0;
+ goto out_no_sb;
+ }
/* page 0 is the superblock, read it... */
- if (bitmap->file) {
- loff_t isize = i_size_read(bitmap->file->f_mapping->host);
+ sb_page = alloc_page(GFP_KERNEL);
+ if (!sb_page)
+ return -ENOMEM;
+ bitmap->storage.sb_page = sb_page;
+
+ if (bitmap->storage.file) {
+ loff_t isize = i_size_read(bitmap->storage.file->f_mapping->host);
int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize;
- bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
+ err = read_page(bitmap->storage.file, 0,
+ bitmap, bytes, sb_page);
} else {
- bitmap->sb_page = read_sb_page(bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- NULL,
- 0, sizeof(bitmap_super_t));
+ err = read_sb_page(bitmap->mddev,
+ bitmap->mddev->bitmap_info.offset,
+ sb_page,
+ 0, sizeof(bitmap_super_t));
}
- if (IS_ERR(bitmap->sb_page)) {
- err = PTR_ERR(bitmap->sb_page);
- bitmap->sb_page = NULL;
+ if (err)
return err;
- }
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(sb_page);
chunksize = le32_to_cpu(sb->chunksize);
daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
write_behind = le32_to_cpu(sb->write_behind);
+ sectors_reserved = le32_to_cpu(sb->sectors_reserved);
/* verify that the bitmap-specific fields are valid */
if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -618,60 +619,32 @@ static int bitmap_read_sb(struct bitmap *bitmap)
"-- forcing full recovery\n",
bmname(bitmap), events,
(unsigned long long) bitmap->mddev->events);
- sb->state |= cpu_to_le32(BITMAP_STALE);
+ set_bit(BITMAP_STALE, &bitmap->flags);
}
}
/* assign fields using values from superblock */
- bitmap->mddev->bitmap_info.chunksize = chunksize;
- bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
- bitmap->mddev->bitmap_info.max_write_behind = write_behind;
bitmap->flags |= le32_to_cpu(sb->state);
if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
- bitmap->flags |= BITMAP_HOSTENDIAN;
+ set_bit(BITMAP_HOSTENDIAN, &bitmap->flags);
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
- if (bitmap->flags & BITMAP_STALE)
- bitmap->events_cleared = bitmap->mddev->events;
err = 0;
out:
kunmap_atomic(sb);
+out_no_sb:
+ if (test_bit(BITMAP_STALE, &bitmap->flags))
+ bitmap->events_cleared = bitmap->mddev->events;
+ bitmap->mddev->bitmap_info.chunksize = chunksize;
+ bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+ bitmap->mddev->bitmap_info.max_write_behind = write_behind;
+ if (bitmap->mddev->bitmap_info.space == 0 ||
+ bitmap->mddev->bitmap_info.space > sectors_reserved)
+ bitmap->mddev->bitmap_info.space = sectors_reserved;
if (err)
bitmap_print_sb(bitmap);
return err;
}
-enum bitmap_mask_op {
- MASK_SET,
- MASK_UNSET
-};
-
-/* record the state of the bitmap in the superblock. Return the old value */
-static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
- enum bitmap_mask_op op)
-{
- bitmap_super_t *sb;
- int old;
-
- if (!bitmap->sb_page) /* can't set the state */
- return 0;
- sb = kmap_atomic(bitmap->sb_page);
- old = le32_to_cpu(sb->state) & bits;
- switch (op) {
- case MASK_SET:
- sb->state |= cpu_to_le32(bits);
- bitmap->flags |= bits;
- break;
- case MASK_UNSET:
- sb->state &= cpu_to_le32(~bits);
- bitmap->flags &= ~bits;
- break;
- default:
- BUG();
- }
- kunmap_atomic(sb);
- return old;
-}
-
/*
* general bitmap file operations
*/
@@ -683,17 +656,19 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
* file a page at a time. There's a superblock at the start of the file.
*/
/* calculate the index of the page that contains this bit */
-static inline unsigned long file_page_index(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_index(struct bitmap_storage *store,
+ unsigned long chunk)
{
- if (!bitmap->mddev->bitmap_info.external)
+ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3;
return chunk >> PAGE_BIT_SHIFT;
}
/* calculate the (bit) offset of this bit within a page */
-static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_offset(struct bitmap_storage *store,
+ unsigned long chunk)
{
- if (!bitmap->mddev->bitmap_info.external)
+ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3;
return chunk & (PAGE_BITS - 1);
}
@@ -705,57 +680,86 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon
* 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page
* 0 or page 1
*/
-static inline struct page *filemap_get_page(struct bitmap *bitmap,
+static inline struct page *filemap_get_page(struct bitmap_storage *store,
unsigned long chunk)
{
- if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
+ if (file_page_index(store, chunk) >= store->file_pages)
return NULL;
- return bitmap->filemap[file_page_index(bitmap, chunk)
- - file_page_index(bitmap, 0)];
+ return store->filemap[file_page_index(store, chunk)
+ - file_page_index(store, 0)];
}
-static void bitmap_file_unmap(struct bitmap *bitmap)
+static int bitmap_storage_alloc(struct bitmap_storage *store,
+ unsigned long chunks, int with_super)
+{
+ int pnum;
+ unsigned long num_pages;
+ unsigned long bytes;
+
+ bytes = DIV_ROUND_UP(chunks, 8);
+ if (with_super)
+ bytes += sizeof(bitmap_super_t);
+
+ num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
+
+ store->filemap = kmalloc(sizeof(struct page *)
+ * num_pages, GFP_KERNEL);
+ if (!store->filemap)
+ return -ENOMEM;
+
+ if (with_super && !store->sb_page) {
+ store->sb_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ if (store->sb_page == NULL)
+ return -ENOMEM;
+ store->sb_page->index = 0;
+ }
+ pnum = 0;
+ if (store->sb_page) {
+ store->filemap[0] = store->sb_page;
+ pnum = 1;
+ }
+ for ( ; pnum < num_pages; pnum++) {
+ store->filemap[pnum] = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ if (!store->filemap[pnum]) {
+ store->file_pages = pnum;
+ return -ENOMEM;
+ }
+ store->filemap[pnum]->index = pnum;
+ }
+ store->file_pages = pnum;
+
+ /* We need 4 bits per page, rounded up to a multiple
+ * of sizeof(unsigned long) */
+ store->filemap_attr = kzalloc(
+ roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
+ GFP_KERNEL);
+ if (!store->filemap_attr)
+ return -ENOMEM;
+
+ store->bytes = bytes;
+
+ return 0;
+}
+
+static void bitmap_file_unmap(struct bitmap_storage *store)
{
struct page **map, *sb_page;
- unsigned long *attr;
int pages;
- unsigned long flags;
+ struct file *file;
- spin_lock_irqsave(&bitmap->lock, flags);
- map = bitmap->filemap;
- bitmap->filemap = NULL;
- attr = bitmap->filemap_attr;
- bitmap->filemap_attr = NULL;
- pages = bitmap->file_pages;
- bitmap->file_pages = 0;
- sb_page = bitmap->sb_page;
- bitmap->sb_page = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ file = store->file;
+ map = store->filemap;
+ pages = store->file_pages;
+ sb_page = store->sb_page;
while (pages--)
if (map[pages] != sb_page) /* 0 is sb_page, release it below */
free_buffers(map[pages]);
kfree(map);
- kfree(attr);
+ kfree(store->filemap_attr);
if (sb_page)
free_buffers(sb_page);
-}
-
-static void bitmap_file_put(struct bitmap *bitmap)
-{
- struct file *file;
- unsigned long flags;
-
- spin_lock_irqsave(&bitmap->lock, flags);
- file = bitmap->file;
- bitmap->file = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- if (file)
- wait_event(bitmap->write_wait,
- atomic_read(&bitmap->pending_writes)==0);
- bitmap_file_unmap(bitmap);
if (file) {
struct inode *inode = file->f_path.dentry->d_inode;
@@ -773,14 +777,14 @@ static void bitmap_file_kick(struct bitmap *bitmap)
{
char *path, *ptr = NULL;
- if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) {
+ if (!test_and_set_bit(BITMAP_STALE, &bitmap->flags)) {
bitmap_update_sb(bitmap);
- if (bitmap->file) {
+ if (bitmap->storage.file) {
path = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (path)
- ptr = d_path(&bitmap->file->f_path, path,
- PAGE_SIZE);
+ ptr = d_path(&bitmap->storage.file->f_path,
+ path, PAGE_SIZE);
printk(KERN_ALERT
"%s: kicking failed bitmap file %s from array!\n",
@@ -792,10 +796,6 @@ static void bitmap_file_kick(struct bitmap *bitmap)
"%s: disabling internal bitmap due to errors\n",
bmname(bitmap));
}
-
- bitmap_file_put(bitmap);
-
- return;
}
enum bitmap_page_attr {
@@ -805,24 +805,30 @@ enum bitmap_page_attr {
BITMAP_PAGE_NEEDWRITE = 2, /* there are cleared bits that need to be synced */
};
-static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline void set_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- __set_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
-static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline void clear_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- __clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
-static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline int test_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ return test_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
+static inline int test_and_clear_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
+{
+ return test_and_clear_bit((pnum<<2) + attr,
+ bitmap->storage.filemap_attr);
+}
/*
* bitmap_file_set_bit -- called before performing a write to the md device
* to set (and eventually sync) a particular bit in the bitmap file
@@ -835,26 +841,46 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
unsigned long bit;
struct page *page;
void *kaddr;
- unsigned long chunk = block >> bitmap->chunkshift;
+ unsigned long chunk = block >> bitmap->counts.chunkshift;
- if (!bitmap->filemap)
- return;
-
- page = filemap_get_page(bitmap, chunk);
+ page = filemap_get_page(&bitmap->storage, chunk);
if (!page)
return;
- bit = file_page_offset(bitmap, chunk);
+ bit = file_page_offset(&bitmap->storage, chunk);
/* set the bit */
kaddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
set_bit(bit, kaddr);
else
- __set_bit_le(bit, kaddr);
+ test_and_set_bit_le(bit, kaddr);
kunmap_atomic(kaddr);
pr_debug("set file bit %lu page %lu\n", bit, page->index);
/* record page number so it gets flushed to disk when unplug occurs */
- set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+ set_page_attr(bitmap, page->index, BITMAP_PAGE_DIRTY);
+}
+
+static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
+{
+ unsigned long bit;
+ struct page *page;
+ void *paddr;
+ unsigned long chunk = block >> bitmap->counts.chunkshift;
+
+ page = filemap_get_page(&bitmap->storage, chunk);
+ if (!page)
+ return;
+ bit = file_page_offset(&bitmap->storage, chunk);
+ paddr = kmap_atomic(page);
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
+ clear_bit(bit, paddr);
+ else
+ test_and_clear_bit_le(bit, paddr);
+ kunmap_atomic(paddr);
+ if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) {
+ set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING);
+ bitmap->allclean = 0;
+ }
}
/* this gets called when the md device is ready to unplug its underlying
@@ -862,42 +888,37 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
* sync the dirty pages of the bitmap file to disk */
void bitmap_unplug(struct bitmap *bitmap)
{
- unsigned long i, flags;
+ unsigned long i;
int dirty, need_write;
- struct page *page;
int wait = 0;
- if (!bitmap)
+ if (!bitmap || !bitmap->storage.filemap ||
+ test_bit(BITMAP_STALE, &bitmap->flags))
return;
/* look at each page to see if there are any set bits that need to be
* flushed out to disk */
- for (i = 0; i < bitmap->file_pages; i++) {
- spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->filemap) {
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ for (i = 0; i < bitmap->storage.file_pages; i++) {
+ if (!bitmap->storage.filemap)
return;
+ dirty = test_and_clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+ need_write = test_and_clear_page_attr(bitmap, i,
+ BITMAP_PAGE_NEEDWRITE);
+ if (dirty || need_write) {
+ clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
+ write_page(bitmap, bitmap->storage.filemap[i], 0);
}
- page = bitmap->filemap[i];
- dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
- need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
- clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
if (dirty)
wait = 1;
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- if (dirty || need_write)
- write_page(bitmap, page, 0);
}
if (wait) { /* if any writes were performed, we need to wait on them */
- if (bitmap->file)
+ if (bitmap->storage.file)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
else
md_super_wait(bitmap->mddev);
}
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
bitmap_file_kick(bitmap);
}
EXPORT_SYMBOL(bitmap_unplug);
@@ -917,98 +938,77 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n
static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{
unsigned long i, chunks, index, oldindex, bit;
- struct page *page = NULL, *oldpage = NULL;
- unsigned long num_pages, bit_cnt = 0;
+ struct page *page = NULL;
+ unsigned long bit_cnt = 0;
struct file *file;
- unsigned long bytes, offset;
+ unsigned long offset;
int outofdate;
int ret = -ENOSPC;
void *paddr;
+ struct bitmap_storage *store = &bitmap->storage;
- chunks = bitmap->chunks;
- file = bitmap->file;
+ chunks = bitmap->counts.chunks;
+ file = store->file;
- BUG_ON(!file && !bitmap->mddev->bitmap_info.offset);
+ if (!file && !bitmap->mddev->bitmap_info.offset) {
+ /* No permanent bitmap - fill with '1s'. */
+ store->filemap = NULL;
+ store->file_pages = 0;
+ for (i = 0; i < chunks ; i++) {
+ /* if the disk bit is set, set the memory bit */
+ int needed = ((sector_t)(i+1) << (bitmap->counts.chunkshift)
+ >= start);
+ bitmap_set_memory_bits(bitmap,
+ (sector_t)i << bitmap->counts.chunkshift,
+ needed);
+ }
+ return 0;
+ }
- outofdate = bitmap->flags & BITMAP_STALE;
+ outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
if (outofdate)
printk(KERN_INFO "%s: bitmap file is out of date, doing full "
"recovery\n", bmname(bitmap));
- bytes = DIV_ROUND_UP(bitmap->chunks, 8);
- if (!bitmap->mddev->bitmap_info.external)
- bytes += sizeof(bitmap_super_t);
-
- num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
-
- if (file && i_size_read(file->f_mapping->host) < bytes) {
+ if (file && i_size_read(file->f_mapping->host) < store->bytes) {
printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
- bmname(bitmap),
- (unsigned long) i_size_read(file->f_mapping->host),
- bytes);
+ bmname(bitmap),
+ (unsigned long) i_size_read(file->f_mapping->host),
+ store->bytes);
goto err;
}
- ret = -ENOMEM;
-
- bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
- if (!bitmap->filemap)
- goto err;
-
- /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
- bitmap->filemap_attr = kzalloc(
- roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
- GFP_KERNEL);
- if (!bitmap->filemap_attr)
- goto err;
-
oldindex = ~0L;
+ offset = 0;
+ if (!bitmap->mddev->bitmap_info.external)
+ offset = sizeof(bitmap_super_t);
for (i = 0; i < chunks; i++) {
int b;
- index = file_page_index(bitmap, i);
- bit = file_page_offset(bitmap, i);
+ index = file_page_index(&bitmap->storage, i);
+ bit = file_page_offset(&bitmap->storage, i);
if (index != oldindex) { /* this is a new page, read it in */
int count;
/* unmap the old page, we're done with it */
- if (index == num_pages-1)
- count = bytes - index * PAGE_SIZE;
+ if (index == store->file_pages-1)
+ count = store->bytes - index * PAGE_SIZE;
else
count = PAGE_SIZE;
- if (index == 0 && bitmap->sb_page) {
- /*
- * if we're here then the superblock page
- * contains some bits (PAGE_SIZE != sizeof sb)
- * we've already read it in, so just use it
- */
- page = bitmap->sb_page;
- offset = sizeof(bitmap_super_t);
- if (!file)
- page = read_sb_page(
- bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- page,
- index, count);
- } else if (file) {
- page = read_page(file, index, bitmap, count);
- offset = 0;
- } else {
- page = read_sb_page(bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- NULL,
- index, count);
- offset = 0;
- }
- if (IS_ERR(page)) { /* read error */
- ret = PTR_ERR(page);
+ page = store->filemap[index];
+ if (file)
+ ret = read_page(file, index, bitmap,
+ count, page);
+ else
+ ret = read_sb_page(
+ bitmap->mddev,
+ bitmap->mddev->bitmap_info.offset,
+ page,
+ index, count);
+
+ if (ret)
goto err;
- }
oldindex = index;
- oldpage = page;
-
- bitmap->filemap[bitmap->file_pages++] = page;
- bitmap->last_page_size = count;
if (outofdate) {
/*
@@ -1022,39 +1022,33 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
write_page(bitmap, page, 1);
ret = -EIO;
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR,
+ &bitmap->flags))
goto err;
}
}
paddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
b = test_bit(bit, paddr);
else
b = test_bit_le(bit, paddr);
kunmap_atomic(paddr);
if (b) {
/* if the disk bit is set, set the memory bit */
- int needed = ((sector_t)(i+1) << bitmap->chunkshift
+ int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
>= start);
bitmap_set_memory_bits(bitmap,
- (sector_t)i << bitmap->chunkshift,
+ (sector_t)i << bitmap->counts.chunkshift,
needed);
bit_cnt++;
}
- }
-
- /* everything went OK */
- ret = 0;
- bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET);
-
- if (bit_cnt) { /* Kick recovery if any bits were set */
- set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
- md_wakeup_thread(bitmap->mddev->thread);
+ offset = 0;
}
printk(KERN_INFO "%s: bitmap initialized from disk: "
- "read %lu/%lu pages, set %lu of %lu bits\n",
- bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks);
+ "read %lu pages, set %lu of %lu bits\n",
+ bmname(bitmap), store->file_pages,
+ bit_cnt, chunks);
return 0;
@@ -1071,22 +1065,38 @@ void bitmap_write_all(struct bitmap *bitmap)
*/
int i;
- spin_lock_irq(&bitmap->lock);
- for (i = 0; i < bitmap->file_pages; i++)
- set_page_attr(bitmap, bitmap->filemap[i],
+ if (!bitmap || !bitmap->storage.filemap)
+ return;
+ if (bitmap->storage.file)
+ /* Only one copy, so nothing needed */
+ return;
+
+ for (i = 0; i < bitmap->storage.file_pages; i++)
+ set_page_attr(bitmap, i,
BITMAP_PAGE_NEEDWRITE);
bitmap->allclean = 0;
- spin_unlock_irq(&bitmap->lock);
}
-static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
+static void bitmap_count_page(struct bitmap_counts *bitmap,
+ sector_t offset, int inc)
{
sector_t chunk = offset >> bitmap->chunkshift;
unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
bitmap->bp[page].count += inc;
bitmap_checkfree(bitmap, page);
}
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+
+static void bitmap_set_pending(struct bitmap_counts *bitmap, sector_t offset)
+{
+ sector_t chunk = offset >> bitmap->chunkshift;
+ unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
+ struct bitmap_page *bp = &bitmap->bp[page];
+
+ if (!bp->pending)
+ bp->pending = 1;
+}
+
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
sector_t offset, sector_t *blocks,
int create);
@@ -1099,10 +1109,9 @@ void bitmap_daemon_work(struct mddev *mddev)
{
struct bitmap *bitmap;
unsigned long j;
- unsigned long flags;
- struct page *page = NULL, *lastpage = NULL;
+ unsigned long nextpage;
sector_t blocks;
- void *paddr;
+ struct bitmap_counts *counts;
/* Use a mutex to guard daemon_work against
* bitmap_destroy.
@@ -1124,112 +1133,90 @@ void bitmap_daemon_work(struct mddev *mddev)
}
bitmap->allclean = 1;
- spin_lock_irqsave(&bitmap->lock, flags);
- for (j = 0; j < bitmap->chunks; j++) {
+ /* Any file-page which is PENDING now needs to be written.
+ * So set NEEDWRITE now, then after we make any last-minute changes
+ * we will write it.
+ */
+ for (j = 0; j < bitmap->storage.file_pages; j++)
+ if (test_and_clear_page_attr(bitmap, j,
+ BITMAP_PAGE_PENDING))
+ set_page_attr(bitmap, j,
+ BITMAP_PAGE_NEEDWRITE);
+
+ if (bitmap->need_sync &&
+ mddev->bitmap_info.external == 0) {
+ /* Arrange for superblock update as well as
+ * other changes */
+ bitmap_super_t *sb;
+ bitmap->need_sync = 0;
+ if (bitmap->storage.filemap) {
+ sb = kmap_atomic(bitmap->storage.sb_page);
+ sb->events_cleared =
+ cpu_to_le64(bitmap->events_cleared);
+ kunmap_atomic(sb);
+ set_page_attr(bitmap, 0,
+ BITMAP_PAGE_NEEDWRITE);
+ }
+ }
+ /* Now look at the bitmap counters and if any are '2' or '1',
+ * decrement and handle accordingly.
+ */
+ counts = &bitmap->counts;
+ spin_lock_irq(&counts->lock);
+ nextpage = 0;
+ for (j = 0; j < counts->chunks; j++) {
bitmap_counter_t *bmc;
- if (!bitmap->filemap)
- /* error or shutdown */
- break;
+ sector_t block = (sector_t)j << counts->chunkshift;
- page = filemap_get_page(bitmap, j);
-
- if (page != lastpage) {
- /* skip this page unless it's marked as needing cleaning */
- if (!test_page_attr(bitmap, page, BITMAP_PAGE_PENDING)) {
- int need_write = test_page_attr(bitmap, page,
- BITMAP_PAGE_NEEDWRITE);
- if (need_write)
- clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-
- spin_unlock_irqrestore(&bitmap->lock, flags);
- if (need_write)
- write_page(bitmap, page, 0);
- spin_lock_irqsave(&bitmap->lock, flags);
- j |= (PAGE_BITS - 1);
+ if (j == nextpage) {
+ nextpage += PAGE_COUNTER_RATIO;
+ if (!counts->bp[j >> PAGE_COUNTER_SHIFT].pending) {
+ j |= PAGE_COUNTER_MASK;
continue;
}
-
- /* grab the new page, sync and release the old */
- if (lastpage != NULL) {
- if (test_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE)) {
- clear_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE);
- spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(bitmap, lastpage, 0);
- } else {
- set_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE);
- bitmap->allclean = 0;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- }
- } else
- spin_unlock_irqrestore(&bitmap->lock, flags);
- lastpage = page;
-
- /* We are possibly going to clear some bits, so make
- * sure that events_cleared is up-to-date.
- */
- if (bitmap->need_sync &&
- mddev->bitmap_info.external == 0) {
- bitmap_super_t *sb;
- bitmap->need_sync = 0;
- sb = kmap_atomic(bitmap->sb_page);
- sb->events_cleared =
- cpu_to_le64(bitmap->events_cleared);
- kunmap_atomic(sb);
- write_page(bitmap, bitmap->sb_page, 1);
- }
- spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->need_sync)
- clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
- else
- bitmap->allclean = 0;
+ counts->bp[j >> PAGE_COUNTER_SHIFT].pending = 0;
}
- bmc = bitmap_get_counter(bitmap,
- (sector_t)j << bitmap->chunkshift,
+ bmc = bitmap_get_counter(counts,
+ block,
&blocks, 0);
- if (!bmc)
+
+ if (!bmc) {
j |= PAGE_COUNTER_MASK;
- else if (*bmc) {
- if (*bmc == 1 && !bitmap->need_sync) {
- /* we can clear the bit */
- *bmc = 0;
- bitmap_count_page(bitmap,
- (sector_t)j << bitmap->chunkshift,
- -1);
-
- /* clear the bit */
- paddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
- clear_bit(file_page_offset(bitmap, j),
- paddr);
- else
- __clear_bit_le(
- file_page_offset(bitmap,
- j),
- paddr);
- kunmap_atomic(paddr);
- } else if (*bmc <= 2) {
- *bmc = 1; /* maybe clear the bit next time */
- set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
- bitmap->allclean = 0;
- }
+ continue;
}
- }
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- /* now sync the final page */
- if (lastpage != NULL) {
- spin_lock_irqsave(&bitmap->lock, flags);
- if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
- clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
- spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(bitmap, lastpage, 0);
- } else {
- set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ if (*bmc == 1 && !bitmap->need_sync) {
+ /* We can clear the bit */
+ *bmc = 0;
+ bitmap_count_page(counts, block, -1);
+ bitmap_file_clear_bit(bitmap, block);
+ } else if (*bmc && *bmc <= 2) {
+ *bmc = 1;
+ bitmap_set_pending(counts, block);
bitmap->allclean = 0;
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+ }
+ spin_unlock_irq(&counts->lock);
+
+ /* Now start writeout on any page in NEEDWRITE that isn't DIRTY.
+ * DIRTY pages need to be written by bitmap_unplug so it can wait
+ * for them.
+ * If we find any DIRTY page we stop there and let bitmap_unplug
+ * handle all the rest. This is important in the case where
+ * the first blocking holds the superblock and it has been updated.
+ * We mustn't write any other blocks before the superblock.
+ */
+ for (j = 0;
+ j < bitmap->storage.file_pages
+ && !test_bit(BITMAP_STALE, &bitmap->flags);
+ j++) {
+
+ if (test_page_attr(bitmap, j,
+ BITMAP_PAGE_DIRTY))
+ /* bitmap_unplug will handle the rest */
+ break;
+ if (test_and_clear_page_attr(bitmap, j,
+ BITMAP_PAGE_NEEDWRITE)) {
+ write_page(bitmap, bitmap->storage.filemap[j], 0);
}
}
@@ -1240,7 +1227,7 @@ void bitmap_daemon_work(struct mddev *mddev)
mutex_unlock(&mddev->bitmap_info.mutex);
}
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
sector_t offset, sector_t *blocks,
int create)
__releases(bitmap->lock)
@@ -1302,10 +1289,10 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
sector_t blocks;
bitmap_counter_t *bmc;
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, &blocks, 1);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 1);
if (!bmc) {
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return 0;
}
@@ -1317,7 +1304,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
*/
prepare_to_wait(&bitmap->overflow_wait, &__wait,
TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
io_schedule();
finish_wait(&bitmap->overflow_wait, &__wait);
continue;
@@ -1326,7 +1313,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
switch (*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
- bitmap_count_page(bitmap, offset, 1);
+ bitmap_count_page(&bitmap->counts, offset, 1);
/* fall through */
case 1:
*bmc = 2;
@@ -1334,7 +1321,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
(*bmc)++;
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
offset += blocks;
if (sectors > blocks)
@@ -1364,10 +1351,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
unsigned long flags;
bitmap_counter_t *bmc;
- spin_lock_irqsave(&bitmap->lock, flags);
- bmc = bitmap_get_counter(bitmap, offset, &blocks, 0);
+ spin_lock_irqsave(&bitmap->counts.lock, flags);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 0);
if (!bmc) {
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
return;
}
@@ -1386,14 +1373,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
(*bmc)--;
if (*bmc <= 2) {
- set_page_attr(bitmap,
- filemap_get_page(
- bitmap,
- offset >> bitmap->chunkshift),
- BITMAP_PAGE_PENDING);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
offset += blocks;
if (sectors > blocks)
sectors -= blocks;
@@ -1412,8 +1395,8 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t
*blocks = 1024;
return 1; /* always resync if no bitmap */
}
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
rv = 0;
if (bmc) {
/* locked */
@@ -1427,7 +1410,7 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t
}
}
}
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return rv;
}
@@ -1464,8 +1447,8 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i
*blocks = 1024;
return;
}
- spin_lock_irqsave(&bitmap->lock, flags);
- bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ spin_lock_irqsave(&bitmap->counts.lock, flags);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
if (bmc == NULL)
goto unlock;
/* locked */
@@ -1476,15 +1459,13 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i
*bmc |= NEEDED_MASK;
else {
if (*bmc <= 2) {
- set_page_attr(bitmap,
- filemap_get_page(bitmap, offset >> bitmap->chunkshift),
- BITMAP_PAGE_PENDING);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
}
}
unlock:
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
}
EXPORT_SYMBOL(bitmap_end_sync);
@@ -1524,7 +1505,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
bitmap->mddev->curr_resync_completed = sector;
set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
- sector &= ~((1ULL << bitmap->chunkshift) - 1);
+ sector &= ~((1ULL << bitmap->counts.chunkshift) - 1);
s = 0;
while (s < sector && s < bitmap->mddev->resync_max_sectors) {
bitmap_end_sync(bitmap, s, &blocks, 0);
@@ -1538,27 +1519,25 @@ EXPORT_SYMBOL(bitmap_cond_end_sync);
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
{
/* For each chunk covered by any of these sectors, set the
- * counter to 1 and set resync_needed. They should all
+ * counter to 2 and possibly set resync_needed. They should all
* be 0 at this point
*/
sector_t secs;
bitmap_counter_t *bmc;
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &secs, 1);
if (!bmc) {
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return;
}
if (!*bmc) {
- struct page *page;
*bmc = 2 | (needed ? NEEDED_MASK : 0);
- bitmap_count_page(bitmap, offset, 1);
- page = filemap_get_page(bitmap, offset >> bitmap->chunkshift);
- set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
+ bitmap_count_page(&bitmap->counts, offset, 1);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
}
/* dirty the memory and file bits for bitmap chunks "s" to "e" */
@@ -1567,11 +1546,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
unsigned long chunk;
for (chunk = s; chunk <= e; chunk++) {
- sector_t sec = (sector_t)chunk << bitmap->chunkshift;
+ sector_t sec = (sector_t)chunk << bitmap->counts.chunkshift;
bitmap_set_memory_bits(bitmap, sec, 1);
- spin_lock_irq(&bitmap->lock);
bitmap_file_set_bit(bitmap, sec);
- spin_unlock_irq(&bitmap->lock);
if (sec < bitmap->mddev->recovery_cp)
/* We are asserting that the array is dirty,
* so move the recovery_cp address back so
@@ -1616,11 +1593,15 @@ static void bitmap_free(struct bitmap *bitmap)
if (!bitmap) /* there was no bitmap */
return;
- /* release the bitmap file and kill the daemon */
- bitmap_file_put(bitmap);
+ /* Shouldn't be needed - but just in case.... */
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes) == 0);
+
+ /* release the bitmap file */
+ bitmap_file_unmap(&bitmap->storage);
- bp = bitmap->bp;
- pages = bitmap->pages;
+ bp = bitmap->counts.bp;
+ pages = bitmap->counts.pages;
/* free all allocated memory */
@@ -1659,25 +1640,19 @@ int bitmap_create(struct mddev *mddev)
{
struct bitmap *bitmap;
sector_t blocks = mddev->resync_max_sectors;
- unsigned long chunks;
- unsigned long pages;
struct file *file = mddev->bitmap_info.file;
int err;
struct sysfs_dirent *bm = NULL;
BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
- if (!file
- && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
- return 0;
-
BUG_ON(file && mddev->bitmap_info.offset);
bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
- spin_lock_init(&bitmap->lock);
+ spin_lock_init(&bitmap->counts.lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
init_waitqueue_head(&bitmap->overflow_wait);
@@ -1693,7 +1668,7 @@ int bitmap_create(struct mddev *mddev)
} else
bitmap->sysfs_can_clear = NULL;
- bitmap->file = file;
+ bitmap->storage.file = file;
if (file) {
get_file(file);
/* As future accesses to this file will use bmap,
@@ -1724,32 +1699,15 @@ int bitmap_create(struct mddev *mddev)
goto error;
bitmap->daemon_lastrun = jiffies;
- bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize)
- - BITMAP_BLOCK_SHIFT);
-
- chunks = (blocks + (1 << bitmap->chunkshift) - 1) >>
- bitmap->chunkshift;
- pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
-
- BUG_ON(!pages);
-
- bitmap->chunks = chunks;
- bitmap->pages = pages;
- bitmap->missing_pages = pages;
-
- bitmap->bp = kzalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);
-
- err = -ENOMEM;
- if (!bitmap->bp)
+ err = bitmap_resize(bitmap, blocks, mddev->bitmap_info.chunksize, 1);
+ if (err)
goto error;
printk(KERN_INFO "created bitmap (%lu pages) for device %s\n",
- pages, bmname(bitmap));
+ bitmap->counts.pages, bmname(bitmap));
mddev->bitmap = bitmap;
-
-
- return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
+ return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0;
error:
bitmap_free(bitmap);
@@ -1790,13 +1748,17 @@ int bitmap_load(struct mddev *mddev)
if (err)
goto out;
+ clear_bit(BITMAP_STALE, &bitmap->flags);
+
+ /* Kick recovery in case any bits were set */
+ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
mddev->thread->timeout = mddev->bitmap_info.daemon_sleep;
md_wakeup_thread(mddev->thread);
bitmap_update_sb(bitmap);
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
err = -EIO;
out:
return err;
@@ -1806,30 +1768,194 @@ EXPORT_SYMBOL_GPL(bitmap_load);
void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
{
unsigned long chunk_kb;
- unsigned long flags;
+ struct bitmap_counts *counts;
if (!bitmap)
return;
- spin_lock_irqsave(&bitmap->lock, flags);
+ counts = &bitmap->counts;
+
chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10;
seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
"%lu%s chunk",
- bitmap->pages - bitmap->missing_pages,
- bitmap->pages,
- (bitmap->pages - bitmap->missing_pages)
+ counts->pages - counts->missing_pages,
+ counts->pages,
+ (counts->pages - counts->missing_pages)
<< (PAGE_SHIFT - 10),
chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
chunk_kb ? "KB" : "B");
- if (bitmap->file) {
+ if (bitmap->storage.file) {
seq_printf(seq, ", file: ");
- seq_path(seq, &bitmap->file->f_path, " \t\n");
+ seq_path(seq, &bitmap->storage.file->f_path, " \t\n");
}
seq_printf(seq, "\n");
- spin_unlock_irqrestore(&bitmap->lock, flags);
}
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+ int chunksize, int init)
+{
+ /* If chunk_size is 0, choose an appropriate chunk size.
+ * Then possibly allocate new storage space.
+ * Then quiesce, copy bits, replace bitmap, and re-start
+ *
+ * This function is called both to set up the initial bitmap
+ * and to resize the bitmap while the array is active.
+ * If this happens as a result of the array being resized,
+ * chunksize will be zero, and we need to choose a suitable
+ * chunksize, otherwise we use what we are given.
+ */
+ struct bitmap_storage store;
+ struct bitmap_counts old_counts;
+ unsigned long chunks;
+ sector_t block;
+ sector_t old_blocks, new_blocks;
+ int chunkshift;
+ int ret = 0;
+ long pages;
+ struct bitmap_page *new_bp;
+
+ if (chunksize == 0) {
+ /* If there is enough space, leave the chunk size unchanged,
+ * else increase by factor of two until there is enough space.
+ */
+ long bytes;
+ long space = bitmap->mddev->bitmap_info.space;
+
+ if (space == 0) {
+ /* We don't know how much space there is, so limit
+ * to current size - in sectors.
+ */
+ bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8);
+ if (!bitmap->mddev->bitmap_info.external)
+ bytes += sizeof(bitmap_super_t);
+ space = DIV_ROUND_UP(bytes, 512);
+ bitmap->mddev->bitmap_info.space = space;
+ }
+ chunkshift = bitmap->counts.chunkshift;
+ chunkshift--;
+ do {
+ /* 'chunkshift' is shift from block size to chunk size */
+ chunkshift++;
+ chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+ bytes = DIV_ROUND_UP(chunks, 8);
+ if (!bitmap->mddev->bitmap_info.external)
+ bytes += sizeof(bitmap_super_t);
+ } while (bytes > (space << 9));
+ } else
+ chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
+
+ chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+ memset(&store, 0, sizeof(store));
+ if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file)
+ ret = bitmap_storage_alloc(&store, chunks,
+ !bitmap->mddev->bitmap_info.external);
+ if (ret)
+ goto err;
+
+ pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO);
+
+ new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!new_bp) {
+ bitmap_file_unmap(&store);
+ goto err;
+ }
+
+ if (!init)
+ bitmap->mddev->pers->quiesce(bitmap->mddev, 1);
+
+ store.file = bitmap->storage.file;
+ bitmap->storage.file = NULL;
+
+ if (store.sb_page && bitmap->storage.sb_page)
+ memcpy(page_address(store.sb_page),
+ page_address(bitmap->storage.sb_page),
+ sizeof(bitmap_super_t));
+ bitmap_file_unmap(&bitmap->storage);
+ bitmap->storage = store;
+
+ old_counts = bitmap->counts;
+ bitmap->counts.bp = new_bp;
+ bitmap->counts.pages = pages;
+ bitmap->counts.missing_pages = pages;
+ bitmap->counts.chunkshift = chunkshift;
+ bitmap->counts.chunks = chunks;
+ bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
+ BITMAP_BLOCK_SHIFT);
+
+ blocks = min(old_counts.chunks << old_counts.chunkshift,
+ chunks << chunkshift);
+
+ spin_lock_irq(&bitmap->counts.lock);
+ for (block = 0; block < blocks; ) {
+ bitmap_counter_t *bmc_old, *bmc_new;
+ int set;
+
+ bmc_old = bitmap_get_counter(&old_counts, block,
+ &old_blocks, 0);
+ set = bmc_old && NEEDED(*bmc_old);
+
+ if (set) {
+ bmc_new = bitmap_get_counter(&bitmap->counts, block,
+ &new_blocks, 1);
+ if (*bmc_new == 0) {
+ /* need to set on-disk bits too. */
+ sector_t end = block + new_blocks;
+ sector_t start = block >> chunkshift;
+ start <<= chunkshift;
+ while (start < end) {
+ bitmap_file_set_bit(bitmap, block);
+ start += 1 << chunkshift;
+ }
+ *bmc_new = 2;
+ bitmap_count_page(&bitmap->counts,
+ block, 1);
+ bitmap_set_pending(&bitmap->counts,
+ block);
+ }
+ *bmc_new |= NEEDED_MASK;
+ if (new_blocks < old_blocks)
+ old_blocks = new_blocks;
+ }
+ block += old_blocks;
+ }
+
+ if (!init) {
+ int i;
+ while (block < (chunks << chunkshift)) {
+ bitmap_counter_t *bmc;
+ bmc = bitmap_get_counter(&bitmap->counts, block,
+ &new_blocks, 1);
+ if (bmc) {
+ /* new space. It needs to be resynced, so
+ * we set NEEDED_MASK.
+ */
+ if (*bmc == 0) {
+ *bmc = NEEDED_MASK | 2;
+ bitmap_count_page(&bitmap->counts,
+ block, 1);
+ bitmap_set_pending(&bitmap->counts,
+ block);
+ }
+ }
+ block += new_blocks;
+ }
+ for (i = 0; i < bitmap->storage.file_pages; i++)
+ set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+ }
+ spin_unlock_irq(&bitmap->counts.lock);
+
+ if (!init) {
+ bitmap_unplug(bitmap);
+ bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
+ }
+ ret = 0;
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(bitmap_resize);
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -1923,6 +2049,43 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
static struct md_sysfs_entry bitmap_location =
__ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
+/* 'bitmap/space' is the space available at 'location' for the
+ * bitmap. This allows the kernel to know when it is safe to
+ * resize the bitmap to match a resized array.
+ */
+static ssize_t
+space_show(struct mddev *mddev, char *page)
+{
+ return sprintf(page, "%lu\n", mddev->bitmap_info.space);
+}
+
+static ssize_t
+space_store(struct mddev *mddev, const char *buf, size_t len)
+{
+ unsigned long sectors;
+ int rv;
+
+ rv = kstrtoul(buf, 10, &sectors);
+ if (rv)
+ return rv;
+
+ if (sectors == 0)
+ return -EINVAL;
+
+ if (mddev->bitmap &&
+ sectors < (mddev->bitmap->storage.bytes + 511) >> 9)
+ return -EFBIG; /* Bitmap is too big for this small space */
+
+ /* could make sure it isn't too big, but that isn't really
+ * needed - user-space should be careful.
+ */
+ mddev->bitmap_info.space = sectors;
+ return len;
+}
+
+static struct md_sysfs_entry bitmap_space =
+__ATTR(space, S_IRUGO|S_IWUSR, space_show, space_store);
+
static ssize_t
timeout_show(struct mddev *mddev, char *page)
{
@@ -2098,6 +2261,7 @@ __ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
static struct attribute *md_bitmap_attrs[] = {
&bitmap_location.attr,
+ &bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
&bitmap_chunksize.attr,
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index b44b0aba..df4aeb6 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -111,9 +111,9 @@ typedef __u16 bitmap_counter_t;
/* use these for bitmap->flags and bitmap->sb->state bit-fields */
enum bitmap_state {
- BITMAP_STALE = 0x002, /* the bitmap file is out of date or had -EIO */
- BITMAP_WRITE_ERROR = 0x004, /* A write error has occurred */
- BITMAP_HOSTENDIAN = 0x8000,
+ BITMAP_STALE = 1, /* the bitmap file is out of date or had -EIO */
+ BITMAP_WRITE_ERROR = 2, /* A write error has occurred */
+ BITMAP_HOSTENDIAN =15,
};
/* the superblock at the front of the bitmap file -- little endian */
@@ -128,8 +128,10 @@ typedef struct bitmap_super_s {
__le32 chunksize; /* 52 the bitmap chunk size in bytes */
__le32 daemon_sleep; /* 56 seconds between disk flushes */
__le32 write_behind; /* 60 number of outstanding write-behind writes */
+ __le32 sectors_reserved; /* 64 number of 512-byte sectors that are
+ * reserved for the bitmap. */
- __u8 pad[256 - 64]; /* set to zero */
+ __u8 pad[256 - 68]; /* set to zero */
} bitmap_super_t;
/* notes:
@@ -160,35 +162,48 @@ struct bitmap_page {
*/
unsigned int hijacked:1;
/*
+ * If any counter in this page is '1' or '2' - and so could be
+ * cleared then that page is marked as 'pending'
+ */
+ unsigned int pending:1;
+ /*
* count of dirty bits on the page
*/
- unsigned int count:31;
+ unsigned int count:30;
};
/* the main bitmap structure - one per mddev */
struct bitmap {
- struct bitmap_page *bp;
- unsigned long pages; /* total number of pages in the bitmap */
- unsigned long missing_pages; /* number of pages not yet allocated */
- struct mddev *mddev; /* the md device that the bitmap is for */
+ struct bitmap_counts {
+ spinlock_t lock;
+ struct bitmap_page *bp;
+ unsigned long pages; /* total number of pages
+ * in the bitmap */
+ unsigned long missing_pages; /* number of pages
+ * not yet allocated */
+ unsigned long chunkshift; /* chunksize = 2^chunkshift
+ * (for bitops) */
+ unsigned long chunks; /* Total number of data
+ * chunks for the array */
+ } counts;
- /* bitmap chunksize -- how much data does each bit represent? */
- unsigned long chunkshift; /* chunksize = 2^(chunkshift+9) (for bitops) */
- unsigned long chunks; /* total number of data chunks for the array */
+ struct mddev *mddev; /* the md device that the bitmap is for */
__u64 events_cleared;
int need_sync;
- /* bitmap spinlock */
- spinlock_t lock;
-
- struct file *file; /* backing disk file */
- struct page *sb_page; /* cached copy of the bitmap file superblock */
- struct page **filemap; /* list of cache pages for the file */
- unsigned long *filemap_attr; /* attributes associated w/ filemap pages */
- unsigned long file_pages; /* number of pages in the file */
- int last_page_size; /* bytes in the last page */
+ struct bitmap_storage {
+ struct file *file; /* backing disk file */
+ struct page *sb_page; /* cached copy of the bitmap
+ * file superblock */
+ struct page **filemap; /* list of cache pages for
+ * the file */
+ unsigned long *filemap_attr; /* attributes associated
+ * w/ filemap pages */
+ unsigned long file_pages; /* number of pages in the file*/
+ unsigned long bytes; /* total bytes in the bitmap */
+ } storage;
unsigned long flags;
@@ -242,6 +257,9 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
void bitmap_unplug(struct bitmap *bitmap);
void bitmap_daemon_work(struct mddev *mddev);
+
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+ int chunksize, int init);
#endif
#endif
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 68965e6..017c34d 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -155,10 +155,7 @@ static void context_free(struct raid_set *rs)
for (i = 0; i < rs->md.raid_disks; i++) {
if (rs->dev[i].meta_dev)
dm_put_device(rs->ti, rs->dev[i].meta_dev);
- if (rs->dev[i].rdev.sb_page)
- put_page(rs->dev[i].rdev.sb_page);
- rs->dev[i].rdev.sb_page = NULL;
- rs->dev[i].rdev.sb_loaded = 0;
+ md_rdev_clear(&rs->dev[i].rdev);
if (rs->dev[i].data_dev)
dm_put_device(rs->ti, rs->dev[i].data_dev);
}
@@ -606,7 +603,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
DMERR("Failed to read superblock of device at position %d",
rdev->raid_disk);
- set_bit(Faulty, &rdev->flags);
+ md_error(rdev->mddev, rdev);
return -EINVAL;
}
@@ -617,16 +614,18 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
{
- struct md_rdev *r;
+ int i;
uint64_t failed_devices;
struct dm_raid_superblock *sb;
+ struct raid_set *rs = container_of(mddev, struct raid_set, md);
sb = page_address(rdev->sb_page);
failed_devices = le64_to_cpu(sb->failed_devices);
- rdev_for_each(r, mddev)
- if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
- failed_devices |= (1ULL << r->raid_disk);
+ for (i = 0; i < mddev->raid_disks; i++)
+ if (!rs->dev[i].data_dev ||
+ test_bit(Faulty, &(rs->dev[i].rdev.flags)))
+ failed_devices |= (1ULL << i);
memset(sb, 0, sizeof(*sb));
@@ -1252,12 +1251,13 @@ static void raid_resume(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ set_bit(MD_CHANGE_DEVS, &rs->md.flags);
if (!rs->bitmap_loaded) {
bitmap_load(&rs->md);
rs->bitmap_loaded = 1;
- } else
- md_wakeup_thread(rs->md.thread);
+ }
+ clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
mddev_resume(&rs->md);
}
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 2fd87b5..eb3d138 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1632,6 +1632,21 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
pool->low_water_blocks = pt->low_water_blocks;
pool->pf = pt->pf;
+ /*
+ * If discard_passdown was enabled verify that the data device
+ * supports discards. Disable discard_passdown if not; otherwise
+ * -EOPNOTSUPP will be returned.
+ */
+ if (pt->pf.discard_passdown) {
+ struct request_queue *q = bdev_get_queue(pt->data_dev->bdev);
+ if (!q || !blk_queue_discard(q)) {
+ char buf[BDEVNAME_SIZE];
+ DMWARN("Discard unsupported by data device (%s): Disabling discard passdown.",
+ bdevname(pt->data_dev->bdev, buf));
+ pool->pf.discard_passdown = 0;
+ }
+ }
+
return 0;
}
@@ -1988,19 +2003,6 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto out_flags_changed;
}
- /*
- * If discard_passdown was enabled verify that the data device
- * supports discards. Disable discard_passdown if not; otherwise
- * -EOPNOTSUPP will be returned.
- */
- if (pf.discard_passdown) {
- struct request_queue *q = bdev_get_queue(data_dev->bdev);
- if (!q || !blk_queue_discard(q)) {
- DMWARN("Discard unsupported by data device: Disabling discard passdown.");
- pf.discard_passdown = 0;
- }
- }
-
pt->pool = pool;
pt->ti = ti;
pt->metadata_dev = metadata_dev;
@@ -2385,7 +2387,7 @@ static int pool_status(struct dm_target *ti, status_type_t type,
(unsigned long long)pt->low_water_blocks);
count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
- !pool->pf.discard_passdown;
+ !pt->pf.discard_passdown;
DMEMIT("%u ", count);
if (!pool->pf.zero_new_blocks)
@@ -2394,7 +2396,7 @@ static int pool_status(struct dm_target *ti, status_type_t type,
if (!pool->pf.discard_enabled)
DMEMIT("ignore_discard ");
- if (!pool->pf.discard_passdown)
+ if (!pt->pf.discard_passdown)
DMEMIT("no_discard_passdown ");
break;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 477eb2e..1c2f904 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -391,6 +391,8 @@ void mddev_suspend(struct mddev *mddev)
synchronize_rcu();
wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
mddev->pers->quiesce(mddev, 1);
+
+ del_timer_sync(&mddev->safemode_timer);
}
EXPORT_SYMBOL_GPL(mddev_suspend);
@@ -400,6 +402,7 @@ void mddev_resume(struct mddev *mddev)
wake_up(&mddev->sb_wait);
mddev->pers->quiesce(mddev, 0);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
}
@@ -450,7 +453,7 @@ static void submit_flushes(struct work_struct *ws)
atomic_inc(&rdev->nr_pending);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev);
+ bi = bio_alloc_mddev(GFP_NOIO, 0, mddev);
bi->bi_end_io = md_end_flush;
bi->bi_private = rdev;
bi->bi_bdev = rdev->bdev;
@@ -605,6 +608,7 @@ void mddev_init(struct mddev *mddev)
init_waitqueue_head(&mddev->sb_wait);
init_waitqueue_head(&mddev->recovery_wait);
mddev->reshape_position = MaxSector;
+ mddev->reshape_backwards = 0;
mddev->resync_min = 0;
mddev->resync_max = MaxSector;
mddev->level = LEVEL_NONE;
@@ -800,7 +804,7 @@ static int alloc_disk_sb(struct md_rdev * rdev)
return 0;
}
-static void free_disk_sb(struct md_rdev * rdev)
+void md_rdev_clear(struct md_rdev *rdev)
{
if (rdev->sb_page) {
put_page(rdev->sb_page);
@@ -813,8 +817,10 @@ static void free_disk_sb(struct md_rdev * rdev)
put_page(rdev->bb_page);
rdev->bb_page = NULL;
}
+ kfree(rdev->badblocks.page);
+ rdev->badblocks.page = NULL;
}
-
+EXPORT_SYMBOL_GPL(md_rdev_clear);
static void super_written(struct bio *bio, int error)
{
@@ -885,6 +891,10 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
rdev->meta_bdev : rdev->bdev;
if (metadata_op)
bio->bi_sector = sector + rdev->sb_start;
+ else if (rdev->mddev->reshape_position != MaxSector &&
+ (rdev->mddev->reshape_backwards ==
+ (sector >= rdev->mddev->reshape_position)))
+ bio->bi_sector = sector + rdev->new_data_offset;
else
bio->bi_sector = sector + rdev->data_offset;
bio_add_page(bio, page, size, 0);
@@ -1032,12 +1042,17 @@ static unsigned int calc_sb_csum(mdp_super_t * sb)
struct super_type {
char *name;
struct module *owner;
- int (*load_super)(struct md_rdev *rdev, struct md_rdev *refdev,
+ int (*load_super)(struct md_rdev *rdev,
+ struct md_rdev *refdev,
int minor_version);
- int (*validate_super)(struct mddev *mddev, struct md_rdev *rdev);
- void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
+ int (*validate_super)(struct mddev *mddev,
+ struct md_rdev *rdev);
+ void (*sync_super)(struct mddev *mddev,
+ struct md_rdev *rdev);
unsigned long long (*rdev_size_change)(struct md_rdev *rdev,
sector_t num_sectors);
+ int (*allow_new_offset)(struct md_rdev *rdev,
+ unsigned long long new_offset);
};
/*
@@ -1109,6 +1124,7 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
rdev->preferred_minor = sb->md_minor;
rdev->data_offset = 0;
+ rdev->new_data_offset = 0;
rdev->sb_size = MD_SB_BYTES;
rdev->badblocks.shift = -1;
@@ -1182,7 +1198,11 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->dev_sectors = ((sector_t)sb->size) * 2;
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
+ mddev->bitmap_info.space = 0;
+ /* bitmap can use 60 K after the 4K superblocks */
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+ mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
+ mddev->reshape_backwards = 0;
if (mddev->minor_version >= 91) {
mddev->reshape_position = sb->reshape_position;
@@ -1190,6 +1210,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_level = sb->new_level;
mddev->new_layout = sb->new_layout;
mddev->new_chunk_sectors = sb->new_chunk >> 9;
+ if (mddev->delta_disks < 0)
+ mddev->reshape_backwards = 1;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
@@ -1216,9 +1238,12 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->max_disks = MD_SB_DISKS;
if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
- mddev->bitmap_info.file == NULL)
+ mddev->bitmap_info.file == NULL) {
mddev->bitmap_info.offset =
mddev->bitmap_info.default_offset;
+ mddev->bitmap_info.space =
+ mddev->bitmap_info.space;
+ }
} else if (mddev->pers == NULL) {
/* Insist on good event counter while assembling, except
@@ -1432,6 +1457,12 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
return num_sectors;
}
+static int
+super_90_allow_new_offset(struct md_rdev *rdev, unsigned long long new_offset)
+{
+ /* non-zero offset changes not possible with v0.90 */
+ return new_offset == 0;
+}
/*
* version 1 superblock
@@ -1467,6 +1498,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
struct mdp_superblock_1 *sb;
int ret;
sector_t sb_start;
+ sector_t sectors;
char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
int bmask;
@@ -1521,9 +1553,18 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
bdevname(rdev->bdev,b));
return -EINVAL;
}
+ if (sb->pad0 ||
+ sb->pad3[0] ||
+ memcmp(sb->pad3, sb->pad3+1, sizeof(sb->pad3) - sizeof(sb->pad3[1])))
+ /* Some padding is non-zero, might be a new feature */
+ return -EINVAL;
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
+ rdev->new_data_offset = rdev->data_offset;
+ if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE) &&
+ (le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
+ rdev->new_data_offset += (s32)le32_to_cpu(sb->new_offset);
atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
@@ -1534,6 +1575,9 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
if (minor_version
&& rdev->data_offset < sb_start + (rdev->sb_size/512))
return -EINVAL;
+ if (minor_version
+ && rdev->new_data_offset < sb_start + (rdev->sb_size/512))
+ return -EINVAL;
if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
rdev->desc_nr = -1;
@@ -1605,16 +1649,14 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
else
ret = 0;
}
- if (minor_version)
- rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
- le64_to_cpu(sb->data_offset);
- else
- rdev->sectors = rdev->sb_start;
- if (rdev->sectors < le64_to_cpu(sb->data_size))
+ if (minor_version) {
+ sectors = (i_size_read(rdev->bdev->bd_inode) >> 9);
+ sectors -= rdev->data_offset;
+ } else
+ sectors = rdev->sb_start;
+ if (sectors < le64_to_cpu(sb->data_size))
return -EINVAL;
rdev->sectors = le64_to_cpu(sb->data_size);
- if (le64_to_cpu(sb->size) > rdev->sectors)
- return -EINVAL;
return ret;
}
@@ -1642,17 +1684,37 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->dev_sectors = le64_to_cpu(sb->size);
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
+ mddev->bitmap_info.space = 0;
+ /* Default location for bitmap is 1K after superblock
+ * using 3K - total of 4K
+ */
mddev->bitmap_info.default_offset = 1024 >> 9;
-
+ mddev->bitmap_info.default_space = (4096-1024) >> 9;
+ mddev->reshape_backwards = 0;
+
mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
memcpy(mddev->uuid, sb->set_uuid, 16);
mddev->max_disks = (4096-256)/2;
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
- mddev->bitmap_info.file == NULL )
+ mddev->bitmap_info.file == NULL) {
mddev->bitmap_info.offset =
(__s32)le32_to_cpu(sb->bitmap_offset);
+ /* Metadata doesn't record how much space is available.
+ * For 1.0, we assume we can use up to the superblock
+ * if before, else to 4K beyond superblock.
+ * For others, assume no change is possible.
+ */
+ if (mddev->minor_version > 0)
+ mddev->bitmap_info.space = 0;
+ else if (mddev->bitmap_info.offset > 0)
+ mddev->bitmap_info.space =
+ 8 - mddev->bitmap_info.offset;
+ else
+ mddev->bitmap_info.space =
+ -mddev->bitmap_info.offset;
+ }
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
@@ -1660,6 +1722,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_level = le32_to_cpu(sb->new_level);
mddev->new_layout = le32_to_cpu(sb->new_layout);
mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
+ if (mddev->delta_disks < 0 ||
+ (mddev->delta_disks == 0 &&
+ (le32_to_cpu(sb->feature_map)
+ & MD_FEATURE_RESHAPE_BACKWARDS)))
+ mddev->reshape_backwards = 1;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
@@ -1733,7 +1800,6 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->feature_map = 0;
sb->pad0 = 0;
sb->recovery_offset = cpu_to_le64(0);
- memset(sb->pad1, 0, sizeof(sb->pad1));
memset(sb->pad3, 0, sizeof(sb->pad3));
sb->utime = cpu_to_le64((__u64)mddev->utime);
@@ -1755,6 +1821,8 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->devflags |= WriteMostly1;
else
sb->devflags &= ~WriteMostly1;
+ sb->data_offset = cpu_to_le64(rdev->data_offset);
+ sb->data_size = cpu_to_le64(rdev->sectors);
if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
@@ -1779,6 +1847,16 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->delta_disks = cpu_to_le32(mddev->delta_disks);
sb->new_level = cpu_to_le32(mddev->new_level);
sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
+ if (mddev->delta_disks == 0 &&
+ mddev->reshape_backwards)
+ sb->feature_map
+ |= cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);
+ if (rdev->new_data_offset != rdev->data_offset) {
+ sb->feature_map
+ |= cpu_to_le32(MD_FEATURE_NEW_OFFSET);
+ sb->new_offset = cpu_to_le32((__u32)(rdev->new_data_offset
+ - rdev->data_offset));
+ }
}
if (rdev->badblocks.count == 0)
@@ -1855,6 +1933,8 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
sector_t max_sectors;
if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
return 0; /* component must fit device */
+ if (rdev->data_offset != rdev->new_data_offset)
+ return 0; /* too confusing */
if (rdev->sb_start < rdev->data_offset) {
/* minor versions 1 and 2; superblock before data */
max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
@@ -1882,6 +1962,40 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
rdev->sb_page);
md_super_wait(rdev->mddev);
return num_sectors;
+
+}
+
+static int
+super_1_allow_new_offset(struct md_rdev *rdev,
+ unsigned long long new_offset)
+{
+ /* All necessary checks on new >= old have been done */
+ struct bitmap *bitmap;
+ if (new_offset >= rdev->data_offset)
+ return 1;
+
+ /* with 1.0 metadata, there is no metadata to tread on
+ * so we can always move back */
+ if (rdev->mddev->minor_version == 0)
+ return 1;
+
+ /* otherwise we must be sure not to step on
+ * any metadata, so stay:
+ * 36K beyond start of superblock
+ * beyond end of badblocks
+ * beyond write-intent bitmap
+ */
+ if (rdev->sb_start + (32+4)*2 > new_offset)
+ return 0;
+ bitmap = rdev->mddev->bitmap;
+ if (bitmap && !rdev->mddev->bitmap_info.file &&
+ rdev->sb_start + rdev->mddev->bitmap_info.offset +
+ bitmap->storage.file_pages * (PAGE_SIZE>>9) > new_offset)
+ return 0;
+ if (rdev->badblocks.sector + rdev->badblocks.size > new_offset)
+ return 0;
+
+ return 1;
}
static struct super_type super_types[] = {
@@ -1892,6 +2006,7 @@ static struct super_type super_types[] = {
.validate_super = super_90_validate,
.sync_super = super_90_sync,
.rdev_size_change = super_90_rdev_size_change,
+ .allow_new_offset = super_90_allow_new_offset,
},
[1] = {
.name = "md-1",
@@ -1900,6 +2015,7 @@ static struct super_type super_types[] = {
.validate_super = super_1_validate,
.sync_super = super_1_sync,
.rdev_size_change = super_1_rdev_size_change,
+ .allow_new_offset = super_1_allow_new_offset,
},
};
@@ -2103,9 +2219,7 @@ static void unbind_rdev_from_array(struct md_rdev * rdev)
sysfs_remove_link(&rdev->kobj, "block");
sysfs_put(rdev->sysfs_state);
rdev->sysfs_state = NULL;
- kfree(rdev->badblocks.page);
rdev->badblocks.count = 0;
- rdev->badblocks.page = NULL;
/* We need to delay this, otherwise we can deadlock when
* writing to 'remove' to "dev/state". We also need
* to delay it due to rcu usage.
@@ -2156,7 +2270,7 @@ static void export_rdev(struct md_rdev * rdev)
bdevname(rdev->bdev,b));
if (rdev->mddev)
MD_BUG();
- free_disk_sb(rdev);
+ md_rdev_clear(rdev);
#ifndef MODULE
if (test_bit(AutoDetected, &rdev->flags))
md_autodetect_dev(rdev->bdev->bd_dev);
@@ -2807,9 +2921,8 @@ offset_show(struct md_rdev *rdev, char *page)
static ssize_t
offset_store(struct md_rdev *rdev, const char *buf, size_t len)
{
- char *e;
- unsigned long long offset = simple_strtoull(buf, &e, 10);
- if (e==buf || (*e && *e != '\n'))
+ unsigned long long offset;
+ if (strict_strtoull(buf, 10, &offset) < 0)
return -EINVAL;
if (rdev->mddev->pers && rdev->raid_disk >= 0)
return -EBUSY;
@@ -2824,6 +2937,63 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len)
static struct rdev_sysfs_entry rdev_offset =
__ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
+static ssize_t new_offset_show(struct md_rdev *rdev, char *page)
+{
+ return sprintf(page, "%llu\n",
+ (unsigned long long)rdev->new_data_offset);
+}
+
+static ssize_t new_offset_store(struct md_rdev *rdev,
+ const char *buf, size_t len)
+{
+ unsigned long long new_offset;
+ struct mddev *mddev = rdev->mddev;
+
+ if (strict_strtoull(buf, 10, &new_offset) < 0)
+ return -EINVAL;
+
+ if (mddev->sync_thread)
+ return -EBUSY;
+ if (new_offset == rdev->data_offset)
+ /* reset is always permitted */
+ ;
+ else if (new_offset > rdev->data_offset) {
+ /* must not push array size beyond rdev_sectors */
+ if (new_offset - rdev->data_offset
+ + mddev->dev_sectors > rdev->sectors)
+ return -E2BIG;
+ }
+ /* Metadata worries about other space details. */
+
+ /* decreasing the offset is inconsistent with a backwards
+ * reshape.
+ */
+ if (new_offset < rdev->data_offset &&
+ mddev->reshape_backwards)
+ return -EINVAL;
+ /* Increasing offset is inconsistent with forwards
+ * reshape. reshape_direction should be set to
+ * 'backwards' first.
+ */
+ if (new_offset > rdev->data_offset &&
+ !mddev->reshape_backwards)
+ return -EINVAL;
+
+ if (mddev->pers && mddev->persistent &&
+ !super_types[mddev->major_version]
+ .allow_new_offset(rdev, new_offset))
+ return -E2BIG;
+ rdev->new_data_offset = new_offset;
+ if (new_offset > rdev->data_offset)
+ mddev->reshape_backwards = 1;
+ else if (new_offset < rdev->data_offset)
+ mddev->reshape_backwards = 0;
+
+ return len;
+}
+static struct rdev_sysfs_entry rdev_new_offset =
+__ATTR(new_offset, S_IRUGO|S_IWUSR, new_offset_show, new_offset_store);
+
static ssize_t
rdev_size_show(struct md_rdev *rdev, char *page)
{
@@ -2868,6 +3038,8 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
if (strict_blocks_to_sectors(buf, &sectors) < 0)
return -EINVAL;
+ if (rdev->data_offset != rdev->new_data_offset)
+ return -EINVAL; /* too confusing */
if (my_mddev->pers && rdev->raid_disk >= 0) {
if (my_mddev->persistent) {
sectors = super_types[my_mddev->major_version].
@@ -3004,6 +3176,7 @@ static struct attribute *rdev_default_attrs[] = {
&rdev_errors.attr,
&rdev_slot.attr,
&rdev_offset.attr,
+ &rdev_new_offset.attr,
&rdev_size.attr,
&rdev_recovery_start.attr,
&rdev_bad_blocks.attr,
@@ -3078,6 +3251,7 @@ int md_rdev_init(struct md_rdev *rdev)
rdev->raid_disk = -1;
rdev->flags = 0;
rdev->data_offset = 0;
+ rdev->new_data_offset = 0;
rdev->sb_events = 0;
rdev->last_read_error.tv_sec = 0;
rdev->last_read_error.tv_nsec = 0;
@@ -3176,8 +3350,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
abort_free:
if (rdev->bdev)
unlock_rdev(rdev);
- free_disk_sb(rdev);
- kfree(rdev->badblocks.page);
+ md_rdev_clear(rdev);
kfree(rdev);
return ERR_PTR(err);
}
@@ -3417,6 +3590,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->raid_disks -= mddev->delta_disks;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
module_put(pers->owner);
printk(KERN_WARNING "md: %s: %s would not accept array\n",
mdname(mddev), clevel);
@@ -3490,6 +3664,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
mddev->layout = mddev->new_layout;
mddev->chunk_sectors = mddev->new_chunk_sectors;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->degraded = 0;
if (mddev->pers->sync_request == NULL) {
/* this is now an array without redundancy, so
@@ -3499,10 +3674,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
del_timer_sync(&mddev->safemode_timer);
}
pers->run(mddev);
- mddev_resume(mddev);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
+ mddev_resume(mddev);
sysfs_notify(&mddev->kobj, NULL, "level");
md_new_event(mddev);
return rv;
@@ -3580,9 +3753,20 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->pers)
rv = update_raid_disks(mddev, n);
else if (mddev->reshape_position != MaxSector) {
+ struct md_rdev *rdev;
int olddisks = mddev->raid_disks - mddev->delta_disks;
+
+ rdev_for_each(rdev, mddev) {
+ if (olddisks < n &&
+ rdev->data_offset < rdev->new_data_offset)
+ return -EINVAL;
+ if (olddisks > n &&
+ rdev->data_offset > rdev->new_data_offset)
+ return -EINVAL;
+ }
mddev->delta_disks = n - olddisks;
mddev->raid_disks = n;
+ mddev->reshape_backwards = (mddev->delta_disks < 0);
} else
mddev->raid_disks = n;
return rv ? rv : len;
@@ -4264,7 +4448,8 @@ sync_completed_show(struct mddev *mddev, char *page)
if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return sprintf(page, "none\n");
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->resync_max_sectors;
else
max_sectors = mddev->dev_sectors;
@@ -4426,6 +4611,7 @@ reshape_position_show(struct mddev *mddev, char *page)
static ssize_t
reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
{
+ struct md_rdev *rdev;
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
if (mddev->pers)
@@ -4434,9 +4620,12 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
return -EINVAL;
mddev->reshape_position = new;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->new_level = mddev->level;
mddev->new_layout = mddev->layout;
mddev->new_chunk_sectors = mddev->chunk_sectors;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
return len;
}
@@ -4445,6 +4634,42 @@ __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
reshape_position_store);
static ssize_t
+reshape_direction_show(struct mddev *mddev, char *page)
+{
+ return sprintf(page, "%s\n",
+ mddev->reshape_backwards ? "backwards" : "forwards");
+}
+
+static ssize_t
+reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
+{
+ int backwards = 0;
+ if (cmd_match(buf, "forwards"))
+ backwards = 0;
+ else if (cmd_match(buf, "backwards"))
+ backwards = 1;
+ else
+ return -EINVAL;
+ if (mddev->reshape_backwards == backwards)
+ return len;
+
+ /* check if we are allowed to change */
+ if (mddev->delta_disks)
+ return -EBUSY;
+
+ if (mddev->persistent &&
+ mddev->major_version == 0)
+ return -EINVAL;
+
+ mddev->reshape_backwards = backwards;
+ return len;
+}
+
+static struct md_sysfs_entry md_reshape_direction =
+__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
+ reshape_direction_store);
+
+static ssize_t
array_size_show(struct mddev *mddev, char *page)
{
if (mddev->external_size)
@@ -4499,6 +4724,7 @@ static struct attribute *md_default_attrs[] = {
&md_safe_delay.attr,
&md_array_state.attr,
&md_reshape_position.attr,
+ &md_reshape_direction.attr,
&md_array_size.attr,
&max_corr_read_errors.attr,
NULL,
@@ -4912,7 +5138,8 @@ int md_run(struct mddev *mddev)
err = -EINVAL;
mddev->pers->stop(mddev);
}
- if (err == 0 && mddev->pers->sync_request) {
+ if (err == 0 && mddev->pers->sync_request &&
+ (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
err = bitmap_create(mddev);
if (err) {
printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
@@ -5062,6 +5289,7 @@ static void md_clean(struct mddev *mddev)
mddev->events = 0;
mddev->can_decrease_events = 0;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->new_level = LEVEL_NONE;
mddev->new_layout = 0;
mddev->new_chunk_sectors = 0;
@@ -5077,6 +5305,7 @@ static void md_clean(struct mddev *mddev)
mddev->merge_check_needed = 0;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = 0;
+ mddev->bitmap_info.default_space = 0;
mddev->bitmap_info.chunksize = 0;
mddev->bitmap_info.daemon_sleep = 0;
mddev->bitmap_info.max_write_behind = 0;
@@ -5419,7 +5648,7 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
goto out;
/* bitmap disabled, zero the first byte and copy out */
- if (!mddev->bitmap || !mddev->bitmap->file) {
+ if (!mddev->bitmap || !mddev->bitmap->storage.file) {
file->pathname[0] = '\0';
goto copy_out;
}
@@ -5428,7 +5657,8 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
if (!buf)
goto out;
- ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname));
+ ptr = d_path(&mddev->bitmap->storage.file->f_path,
+ buf, sizeof(file->pathname));
if (IS_ERR(ptr))
goto out;
@@ -5873,6 +6103,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+ mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
mddev->bitmap_info.offset = 0;
mddev->reshape_position = MaxSector;
@@ -5886,6 +6117,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->new_layout = mddev->layout;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
return 0;
}
@@ -5920,11 +6152,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
*/
if (mddev->sync_thread)
return -EBUSY;
- if (mddev->bitmap)
- /* Sorry, cannot grow a bitmap yet, just remove it,
- * grow, and re-add.
- */
- return -EBUSY;
+
rdev_for_each(rdev, mddev) {
sector_t avail = rdev->sectors;
@@ -5942,6 +6170,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
static int update_raid_disks(struct mddev *mddev, int raid_disks)
{
int rv;
+ struct md_rdev *rdev;
/* change the number of raid disks */
if (mddev->pers->check_reshape == NULL)
return -EINVAL;
@@ -5950,11 +6179,27 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
return -EINVAL;
if (mddev->sync_thread || mddev->reshape_position != MaxSector)
return -EBUSY;
+
+ rdev_for_each(rdev, mddev) {
+ if (mddev->raid_disks < raid_disks &&
+ rdev->data_offset < rdev->new_data_offset)
+ return -EINVAL;
+ if (mddev->raid_disks > raid_disks &&
+ rdev->data_offset > rdev->new_data_offset)
+ return -EINVAL;
+ }
+
mddev->delta_disks = raid_disks - mddev->raid_disks;
+ if (mddev->delta_disks < 0)
+ mddev->reshape_backwards = 1;
+ else if (mddev->delta_disks > 0)
+ mddev->reshape_backwards = 0;
rv = mddev->pers->check_reshape(mddev);
- if (rv < 0)
+ if (rv < 0) {
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
+ }
return rv;
}
@@ -6037,6 +6282,8 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
return -EINVAL;
mddev->bitmap_info.offset =
mddev->bitmap_info.default_offset;
+ mddev->bitmap_info.space =
+ mddev->bitmap_info.default_space;
mddev->pers->quiesce(mddev, 1);
rv = bitmap_create(mddev);
if (!rv)
@@ -6048,7 +6295,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
/* remove the bitmap */
if (!mddev->bitmap)
return -ENOENT;
- if (mddev->bitmap->file)
+ if (mddev->bitmap->storage.file)
return -EINVAL;
mddev->pers->quiesce(mddev, 1);
bitmap_destroy(mddev);
@@ -6371,6 +6618,9 @@ static int md_open(struct block_device *bdev, fmode_t mode)
struct mddev *mddev = mddev_find(bdev->bd_dev);
int err;
+ if (!mddev)
+ return -ENODEV;
+
if (mddev->gendisk != bdev->bd_disk) {
/* we are racing with mddev_put which is discarding this
* bd_disk.
@@ -6582,7 +6832,8 @@ static void status_resync(struct seq_file *seq, struct mddev * mddev)
resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->resync_max_sectors;
else
max_sectors = mddev->dev_sectors;
@@ -7145,7 +7396,7 @@ void md_do_sync(struct mddev *mddev)
j = mddev->recovery_cp;
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
- max_sectors = mddev->dev_sectors;
+ max_sectors = mddev->resync_max_sectors;
else {
/* recovery follows the physical size of devices */
max_sectors = mddev->dev_sectors;
@@ -7596,7 +7847,7 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
if (mddev->pers->sync_request) {
- if (spares && mddev->bitmap && ! mddev->bitmap->file) {
+ if (spares) {
/* We are adding a device or devices to an array
* which has the bitmap stored on all devices.
* So make sure all bitmap pages get written
@@ -7644,6 +7895,20 @@ void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev)
}
EXPORT_SYMBOL(md_wait_for_blocked_rdev);
+void md_finish_reshape(struct mddev *mddev)
+{
+ /* called be personality module when reshape completes. */
+ struct md_rdev *rdev;
+
+ rdev_for_each(rdev, mddev) {
+ if (rdev->data_offset > rdev->new_data_offset)
+ rdev->sectors += rdev->data_offset - rdev->new_data_offset;
+ else
+ rdev->sectors -= rdev->new_data_offset - rdev->data_offset;
+ rdev->data_offset = rdev->new_data_offset;
+ }
+}
+EXPORT_SYMBOL(md_finish_reshape);
/* Bad block management.
* We can record which blocks on each device are 'bad' and so just
@@ -7892,10 +8157,15 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
}
int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
- int acknowledged)
+ int is_new)
{
- int rv = md_set_badblocks(&rdev->badblocks,
- s + rdev->data_offset, sectors, acknowledged);
+ int rv;
+ if (is_new)
+ s += rdev->new_data_offset;
+ else
+ s += rdev->data_offset;
+ rv = md_set_badblocks(&rdev->badblocks,
+ s, sectors, 0);
if (rv) {
/* Make sure they get written out promptly */
sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8001,11 +8271,15 @@ out:
return rv;
}
-int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors)
+int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+ int is_new)
{
+ if (is_new)
+ s += rdev->new_data_offset;
+ else
+ s += rdev->data_offset;
return md_clear_badblocks(&rdev->badblocks,
- s + rdev->data_offset,
- sectors);
+ s, sectors);
}
EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1c2063c..7b4a3c3 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -55,6 +55,7 @@ struct md_rdev {
int sb_loaded;
__u64 sb_events;
sector_t data_offset; /* start of data in array */
+ sector_t new_data_offset;/* only relevant while reshaping */
sector_t sb_start; /* offset of the super block (in 512byte sectors) */
int sb_size; /* bytes in the superblock */
int preferred_minor; /* autorun support */
@@ -193,8 +194,9 @@ static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
return 0;
}
extern int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
- int acknowledged);
-extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors);
+ int is_new);
+extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+ int is_new);
extern void md_ack_all_badblocks(struct badblocks *bb);
struct mddev {
@@ -262,6 +264,7 @@ struct mddev {
sector_t reshape_position;
int delta_disks, new_level, new_layout;
int new_chunk_sectors;
+ int reshape_backwards;
atomic_t plug_cnt; /* If device is expecting
* more bios soon.
@@ -390,10 +393,13 @@ struct mddev {
* For external metadata, offset
* from start of device.
*/
+ unsigned long space; /* space available at this offset */
loff_t default_offset; /* this is the offset to use when
* hot-adding a bitmap. It should
* eventually be settable by sysfs.
*/
+ unsigned long default_space; /* space available at
+ * default offset */
struct mutex mutex;
unsigned long chunksize;
unsigned long daemon_sleep; /* how many jiffies between updates? */
@@ -591,6 +597,7 @@ extern void md_write_start(struct mddev *mddev, struct bio *bi);
extern void md_write_end(struct mddev *mddev);
extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
+extern void md_finish_reshape(struct mddev *mddev);
extern int mddev_congested(struct mddev *mddev, int bits);
extern void md_flush_request(struct mddev *mddev, struct bio *bio);
@@ -615,6 +622,7 @@ extern int md_run(struct mddev *mddev);
extern void md_stop(struct mddev *mddev);
extern void md_stop_writes(struct mddev *mddev);
extern int md_rdev_init(struct md_rdev *rdev);
+extern void md_rdev_clear(struct md_rdev *rdev);
extern void mddev_suspend(struct mddev *mddev);
extern void mddev_resume(struct mddev *mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 15dd59b..835de71 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1859,7 +1859,9 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
rdev = conf->mirrors[d].rdev;
if (rdev &&
- test_bit(In_sync, &rdev->flags) &&
+ (test_bit(In_sync, &rdev->flags) ||
+ (!test_bit(Faulty, &rdev->flags) &&
+ rdev->recovery_offset >= sect + s)) &&
is_badblock(rdev, sect, s,
&first_bad, &bad_sectors) == 0 &&
sync_page_io(rdev, sect, s<<9,
@@ -2024,7 +2026,7 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio
continue;
if (test_bit(BIO_UPTODATE, &bio->bi_flags) &&
test_bit(R1BIO_MadeGood, &r1_bio->state)) {
- rdev_clear_badblocks(rdev, r1_bio->sector, s);
+ rdev_clear_badblocks(rdev, r1_bio->sector, s, 0);
}
if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
test_bit(R1BIO_WriteError, &r1_bio->state)) {
@@ -2044,7 +2046,7 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
struct md_rdev *rdev = conf->mirrors[m].rdev;
rdev_clear_badblocks(rdev,
r1_bio->sector,
- r1_bio->sectors);
+ r1_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
} else if (r1_bio->bios[m] != NULL) {
/* This drive got a write error. We need to
@@ -2598,7 +2600,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
if (!disk->rdev ||
!test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
- if (disk->rdev)
+ if (disk->rdev &&
+ (disk->rdev->saved_raid_disk < 0))
conf->fullsync = 1;
} else if (conf->last_used < 0)
/*
@@ -2750,9 +2753,16 @@ static int raid1_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
- md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0));
- if (mddev->array_sectors > raid1_size(mddev, sectors, 0))
+ sector_t newsize = raid1_size(mddev, sectors, 0);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, newsize, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index c8dbb84..987db37 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
+#include <linux/kthread.h>
#include "md.h"
#include "raid10.h"
#include "raid0.h"
@@ -68,6 +69,11 @@ static int max_queued_requests = 1024;
static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
static int enough(struct r10conf *conf, int ignore);
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+ int *skipped);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
+static void end_reshape_write(struct bio *bio, int error);
+static void end_reshape(struct r10conf *conf);
static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
{
@@ -112,7 +118,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
if (!r10_bio)
return NULL;
- if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &conf->mddev->recovery))
nalloc = conf->copies; /* resync */
else
nalloc = 2; /* recovery */
@@ -140,9 +147,10 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
struct bio *rbio = r10_bio->devs[j].repl_bio;
bio = r10_bio->devs[j].bio;
for (i = 0; i < RESYNC_PAGES; i++) {
- if (j == 1 && !test_bit(MD_RECOVERY_SYNC,
- &conf->mddev->recovery)) {
- /* we can share bv_page's during recovery */
+ if (j > 0 && !test_bit(MD_RECOVERY_SYNC,
+ &conf->mddev->recovery)) {
+ /* we can share bv_page's during recovery
+ * and reshape */
struct bio *rbio = r10_bio->devs[0].bio;
page = rbio->bi_io_vec[i].bv_page;
get_page(page);
@@ -165,10 +173,11 @@ out_free_pages:
while (j--)
for (i = 0; i < RESYNC_PAGES ; i++)
safe_put_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
- j = -1;
+ j = 0;
out_free_bio:
- while (++j < nalloc) {
- bio_put(r10_bio->devs[j].bio);
+ for ( ; j < nalloc; j++) {
+ if (r10_bio->devs[j].bio)
+ bio_put(r10_bio->devs[j].bio);
if (r10_bio->devs[j].repl_bio)
bio_put(r10_bio->devs[j].repl_bio);
}
@@ -504,79 +513,96 @@ static void raid10_end_write_request(struct bio *bio, int error)
* sector offset to a virtual address
*/
-static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio)
{
int n,f;
sector_t sector;
sector_t chunk;
sector_t stripe;
int dev;
-
int slot = 0;
/* now calculate first sector/dev */
- chunk = r10bio->sector >> conf->chunk_shift;
- sector = r10bio->sector & conf->chunk_mask;
+ chunk = r10bio->sector >> geo->chunk_shift;
+ sector = r10bio->sector & geo->chunk_mask;
- chunk *= conf->near_copies;
+ chunk *= geo->near_copies;
stripe = chunk;
- dev = sector_div(stripe, conf->raid_disks);
- if (conf->far_offset)
- stripe *= conf->far_copies;
+ dev = sector_div(stripe, geo->raid_disks);
+ if (geo->far_offset)
+ stripe *= geo->far_copies;
- sector += stripe << conf->chunk_shift;
+ sector += stripe << geo->chunk_shift;
/* and calculate all the others */
- for (n=0; n < conf->near_copies; n++) {
+ for (n = 0; n < geo->near_copies; n++) {
int d = dev;
sector_t s = sector;
r10bio->devs[slot].addr = sector;
r10bio->devs[slot].devnum = d;
slot++;
- for (f = 1; f < conf->far_copies; f++) {
- d += conf->near_copies;
- if (d >= conf->raid_disks)
- d -= conf->raid_disks;
- s += conf->stride;
+ for (f = 1; f < geo->far_copies; f++) {
+ d += geo->near_copies;
+ if (d >= geo->raid_disks)
+ d -= geo->raid_disks;
+ s += geo->stride;
r10bio->devs[slot].devnum = d;
r10bio->devs[slot].addr = s;
slot++;
}
dev++;
- if (dev >= conf->raid_disks) {
+ if (dev >= geo->raid_disks) {
dev = 0;
- sector += (conf->chunk_mask + 1);
+ sector += (geo->chunk_mask + 1);
}
}
- BUG_ON(slot != conf->copies);
+}
+
+static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+{
+ struct geom *geo = &conf->geo;
+
+ if (conf->reshape_progress != MaxSector &&
+ ((r10bio->sector >= conf->reshape_progress) !=
+ conf->mddev->reshape_backwards)) {
+ set_bit(R10BIO_Previous, &r10bio->state);
+ geo = &conf->prev;
+ } else
+ clear_bit(R10BIO_Previous, &r10bio->state);
+
+ __raid10_find_phys(geo, r10bio);
}
static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
{
sector_t offset, chunk, vchunk;
+ /* Never use conf->prev as this is only called during resync
+ * or recovery, so reshape isn't happening
+ */
+ struct geom *geo = &conf->geo;
- offset = sector & conf->chunk_mask;
- if (conf->far_offset) {
+ offset = sector & geo->chunk_mask;
+ if (geo->far_offset) {
int fc;
- chunk = sector >> conf->chunk_shift;
- fc = sector_div(chunk, conf->far_copies);
- dev -= fc * conf->near_copies;
+ chunk = sector >> geo->chunk_shift;
+ fc = sector_div(chunk, geo->far_copies);
+ dev -= fc * geo->near_copies;
if (dev < 0)
- dev += conf->raid_disks;
+ dev += geo->raid_disks;
} else {
- while (sector >= conf->stride) {
- sector -= conf->stride;
- if (dev < conf->near_copies)
- dev += conf->raid_disks - conf->near_copies;
+ while (sector >= geo->stride) {
+ sector -= geo->stride;
+ if (dev < geo->near_copies)
+ dev += geo->raid_disks - geo->near_copies;
else
- dev -= conf->near_copies;
+ dev -= geo->near_copies;
}
- chunk = sector >> conf->chunk_shift;
+ chunk = sector >> geo->chunk_shift;
}
- vchunk = chunk * conf->raid_disks + dev;
- sector_div(vchunk, conf->near_copies);
- return (vchunk << conf->chunk_shift) + offset;
+ vchunk = chunk * geo->raid_disks + dev;
+ sector_div(vchunk, geo->near_copies);
+ return (vchunk << geo->chunk_shift) + offset;
}
/**
@@ -597,10 +623,17 @@ static int raid10_mergeable_bvec(struct request_queue *q,
struct r10conf *conf = mddev->private;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int max;
- unsigned int chunk_sectors = mddev->chunk_sectors;
+ unsigned int chunk_sectors;
unsigned int bio_sectors = bvm->bi_size >> 9;
+ struct geom *geo = &conf->geo;
+
+ chunk_sectors = (conf->geo.chunk_mask & conf->prev.chunk_mask) + 1;
+ if (conf->reshape_progress != MaxSector &&
+ ((sector >= conf->reshape_progress) !=
+ conf->mddev->reshape_backwards))
+ geo = &conf->prev;
- if (conf->near_copies < conf->raid_disks) {
+ if (geo->near_copies < geo->raid_disks) {
max = (chunk_sectors - ((sector & (chunk_sectors - 1))
+ bio_sectors)) << 9;
if (max < 0)
@@ -614,6 +647,12 @@ static int raid10_mergeable_bvec(struct request_queue *q,
if (mddev->merge_check_needed) {
struct r10bio r10_bio;
int s;
+ if (conf->reshape_progress != MaxSector) {
+ /* Cannot give any guidance during reshape */
+ if (max <= biovec->bv_len && bio_sectors == 0)
+ return biovec->bv_len;
+ return 0;
+ }
r10_bio.sector = sector;
raid10_find_phys(conf, &r10_bio);
rcu_read_lock();
@@ -681,6 +720,7 @@ static struct md_rdev *read_balance(struct r10conf *conf,
struct md_rdev *rdev, *best_rdev;
int do_balance;
int best_slot;
+ struct geom *geo = &conf->geo;
raid10_find_phys(conf, r10_bio);
rcu_read_lock();
@@ -761,11 +801,11 @@ retry:
* sequential read speed for 'far copies' arrays. So only
* keep it for 'near' arrays, and review those later.
*/
- if (conf->near_copies > 1 && !atomic_read(&rdev->nr_pending))
+ if (geo->near_copies > 1 && !atomic_read(&rdev->nr_pending))
break;
/* for far > 1 always use the lowest address */
- if (conf->far_copies > 1)
+ if (geo->far_copies > 1)
new_distance = r10_bio->devs[slot].addr;
else
new_distance = abs(r10_bio->devs[slot].addr -
@@ -812,7 +852,10 @@ static int raid10_congested(void *data, int bits)
if (mddev_congested(mddev, bits))
return 1;
rcu_read_lock();
- for (i = 0; i < conf->raid_disks && ret == 0; i++) {
+ for (i = 0;
+ (i < conf->geo.raid_disks || i < conf->prev.raid_disks)
+ && ret == 0;
+ i++) {
struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = bdev_get_queue(rdev->bdev);
@@ -973,13 +1016,24 @@ static void unfreeze_array(struct r10conf *conf)
spin_unlock_irq(&conf->resync_lock);
}
+static sector_t choose_data_offset(struct r10bio *r10_bio,
+ struct md_rdev *rdev)
+{
+ if (!test_bit(MD_RECOVERY_RESHAPE, &rdev->mddev->recovery) ||
+ test_bit(R10BIO_Previous, &r10_bio->state))
+ return rdev->data_offset;
+ else
+ return rdev->new_data_offset;
+}
+
static void make_request(struct mddev *mddev, struct bio * bio)
{
struct r10conf *conf = mddev->private;
struct r10bio *r10_bio;
struct bio *read_bio;
int i;
- int chunk_sects = conf->chunk_mask + 1;
+ sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
+ int chunk_sects = chunk_mask + 1;
const int rw = bio_data_dir(bio);
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
@@ -988,6 +1042,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
int plugged;
int sectors_handled;
int max_sectors;
+ int sectors;
if (unlikely(bio->bi_rw & REQ_FLUSH)) {
md_flush_request(mddev, bio);
@@ -997,9 +1052,10 @@ static void make_request(struct mddev *mddev, struct bio * bio)
/* If this request crosses a chunk boundary, we need to
* split it. This will only happen for 1 PAGE (or less) requests.
*/
- if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
- > chunk_sects &&
- conf->near_copies < conf->raid_disks)) {
+ if (unlikely((bio->bi_sector & chunk_mask) + (bio->bi_size >> 9)
+ > chunk_sects
+ && (conf->geo.near_copies < conf->geo.raid_disks
+ || conf->prev.near_copies < conf->prev.raid_disks))) {
struct bio_pair *bp;
/* Sanity check -- queue functions should prevent this happening */
if (bio->bi_vcnt != 1 ||
@@ -1051,10 +1107,41 @@ static void make_request(struct mddev *mddev, struct bio * bio)
*/
wait_barrier(conf);
+ sectors = bio->bi_size >> 9;
+ while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ bio->bi_sector < conf->reshape_progress &&
+ bio->bi_sector + sectors > conf->reshape_progress) {
+ /* IO spans the reshape position. Need to wait for
+ * reshape to pass
+ */
+ allow_barrier(conf);
+ wait_event(conf->wait_barrier,
+ conf->reshape_progress <= bio->bi_sector ||
+ conf->reshape_progress >= bio->bi_sector + sectors);
+ wait_barrier(conf);
+ }
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ bio_data_dir(bio) == WRITE &&
+ (mddev->reshape_backwards
+ ? (bio->bi_sector < conf->reshape_safe &&
+ bio->bi_sector + sectors > conf->reshape_progress)
+ : (bio->bi_sector + sectors > conf->reshape_safe &&
+ bio->bi_sector < conf->reshape_progress))) {
+ /* Need to update reshape_position in metadata */
+ mddev->reshape_position = conf->reshape_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ set_bit(MD_CHANGE_PENDING, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_PENDING, &mddev->flags));
+
+ conf->reshape_safe = mddev->reshape_position;
+ }
+
r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
r10_bio->master_bio = bio;
- r10_bio->sectors = bio->bi_size >> 9;
+ r10_bio->sectors = sectors;
r10_bio->mddev = mddev;
r10_bio->sector = bio->bi_sector;
@@ -1093,7 +1180,7 @@ read_again:
r10_bio->devs[slot].rdev = rdev;
read_bio->bi_sector = r10_bio->devs[slot].addr +
- rdev->data_offset;
+ choose_data_offset(r10_bio, rdev);
read_bio->bi_bdev = rdev->bdev;
read_bio->bi_end_io = raid10_end_read_request;
read_bio->bi_rw = READ | do_sync;
@@ -1297,7 +1384,8 @@ retry_write:
r10_bio->devs[i].bio = mbio;
mbio->bi_sector = (r10_bio->devs[i].addr+
- conf->mirrors[d].rdev->data_offset);
+ choose_data_offset(r10_bio,
+ conf->mirrors[d].rdev));
mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1321,8 +1409,10 @@ retry_write:
* so it cannot disappear, so the replacement cannot
* become NULL here
*/
- mbio->bi_sector = (r10_bio->devs[i].addr+
- conf->mirrors[d].replacement->data_offset);
+ mbio->bi_sector = (r10_bio->devs[i].addr +
+ choose_data_offset(
+ r10_bio,
+ conf->mirrors[d].replacement));
mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1368,19 +1458,19 @@ static void status(struct seq_file *seq, struct mddev *mddev)
struct r10conf *conf = mddev->private;
int i;
- if (conf->near_copies < conf->raid_disks)
+ if (conf->geo.near_copies < conf->geo.raid_disks)
seq_printf(seq, " %dK chunks", mddev->chunk_sectors / 2);
- if (conf->near_copies > 1)
- seq_printf(seq, " %d near-copies", conf->near_copies);
- if (conf->far_copies > 1) {
- if (conf->far_offset)
- seq_printf(seq, " %d offset-copies", conf->far_copies);
+ if (conf->geo.near_copies > 1)
+ seq_printf(seq, " %d near-copies", conf->geo.near_copies);
+ if (conf->geo.far_copies > 1) {
+ if (conf->geo.far_offset)
+ seq_printf(seq, " %d offset-copies", conf->geo.far_copies);
else
- seq_printf(seq, " %d far-copies", conf->far_copies);
+ seq_printf(seq, " %d far-copies", conf->geo.far_copies);
}
- seq_printf(seq, " [%d/%d] [", conf->raid_disks,
- conf->raid_disks - mddev->degraded);
- for (i = 0; i < conf->raid_disks; i++)
+ seq_printf(seq, " [%d/%d] [", conf->geo.raid_disks,
+ conf->geo.raid_disks - mddev->degraded);
+ for (i = 0; i < conf->geo.raid_disks; i++)
seq_printf(seq, "%s",
conf->mirrors[i].rdev &&
test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
@@ -1392,7 +1482,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
* Don't consider the device numbered 'ignore'
* as we might be about to remove it.
*/
-static int enough(struct r10conf *conf, int ignore)
+static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
{
int first = 0;
@@ -1403,7 +1493,7 @@ static int enough(struct r10conf *conf, int ignore)
if (conf->mirrors[first].rdev &&
first != ignore)
cnt++;
- first = (first+1) % conf->raid_disks;
+ first = (first+1) % geo->raid_disks;
}
if (cnt == 0)
return 0;
@@ -1411,6 +1501,12 @@ static int enough(struct r10conf *conf, int ignore)
return 1;
}
+static int enough(struct r10conf *conf, int ignore)
+{
+ return _enough(conf, &conf->geo, ignore) &&
+ _enough(conf, &conf->prev, ignore);
+}
+
static void error(struct mddev *mddev, struct md_rdev *rdev)
{
char b[BDEVNAME_SIZE];
@@ -1445,7 +1541,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
"md/raid10:%s: Disk failure on %s, disabling device.\n"
"md/raid10:%s: Operation continuing on %d devices.\n",
mdname(mddev), bdevname(rdev->bdev, b),
- mdname(mddev), conf->raid_disks - mddev->degraded);
+ mdname(mddev), conf->geo.raid_disks - mddev->degraded);
}
static void print_conf(struct r10conf *conf)
@@ -1458,10 +1554,10 @@ static void print_conf(struct r10conf *conf)
printk(KERN_DEBUG "(!conf)\n");
return;
}
- printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
- conf->raid_disks);
+ printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->geo.raid_disks - conf->mddev->degraded,
+ conf->geo.raid_disks);
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < conf->geo.raid_disks; i++) {
char b[BDEVNAME_SIZE];
tmp = conf->mirrors + i;
if (tmp->rdev)
@@ -1493,7 +1589,7 @@ static int raid10_spare_active(struct mddev *mddev)
* Find all non-in_sync disks within the RAID10 configuration
* and mark them in_sync
*/
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < conf->geo.raid_disks; i++) {
tmp = conf->mirrors + i;
if (tmp->replacement
&& tmp->replacement->recovery_offset == MaxSector
@@ -1535,7 +1631,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
int err = -EEXIST;
int mirror;
int first = 0;
- int last = conf->raid_disks - 1;
+ int last = conf->geo.raid_disks - 1;
struct request_queue *q = bdev_get_queue(rdev->bdev);
if (mddev->recovery_cp < MaxSector)
@@ -1543,7 +1639,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* very different from resync
*/
return -EBUSY;
- if (rdev->saved_raid_disk < 0 && !enough(conf, -1))
+ if (rdev->saved_raid_disk < 0 && !_enough(conf, &conf->prev, -1))
return -EINVAL;
if (rdev->raid_disk >= 0)
@@ -1635,6 +1731,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
if (!test_bit(Faulty, &rdev->flags) &&
mddev->recovery_disabled != p->recovery_disabled &&
(!p->replacement || p->replacement == rdev) &&
+ number < conf->geo.raid_disks &&
enough(conf, -1)) {
err = -EBUSY;
goto abort;
@@ -1676,7 +1773,11 @@ static void end_sync_read(struct bio *bio, int error)
struct r10conf *conf = r10_bio->mddev->private;
int d;
- d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
+ if (bio == r10_bio->master_bio) {
+ /* this is a reshape read */
+ d = r10_bio->read_slot; /* really the read dev */
+ } else
+ d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
set_bit(R10BIO_Uptodate, &r10_bio->state);
@@ -2218,7 +2319,9 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio,
+ rdev)),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing "
"drive\n",
@@ -2256,7 +2359,8 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio, rdev)),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing "
"drive\n",
@@ -2269,7 +2373,8 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio, rdev)),
bdevname(rdev->bdev, b));
atomic_add(s, &rdev->corrected_errors);
}
@@ -2343,7 +2448,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i)
wbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
md_trim_bio(wbio, sector - bio->bi_sector, sectors);
wbio->bi_sector = (r10_bio->devs[i].addr+
- rdev->data_offset+
+ choose_data_offset(r10_bio, rdev) +
(sector - r10_bio->sector));
wbio->bi_bdev = rdev->bdev;
if (submit_bio_wait(WRITE, wbio) == 0)
@@ -2420,7 +2525,7 @@ read_more:
r10_bio->devs[slot].bio = bio;
r10_bio->devs[slot].rdev = rdev;
bio->bi_sector = r10_bio->devs[slot].addr
- + rdev->data_offset;
+ + choose_data_offset(r10_bio, rdev);
bio->bi_bdev = rdev->bdev;
bio->bi_rw = READ | do_sync;
bio->bi_private = r10_bio;
@@ -2480,7 +2585,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
} else {
if (!rdev_set_badblocks(
rdev,
@@ -2496,7 +2601,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
} else {
if (!rdev_set_badblocks(
rdev,
@@ -2515,7 +2620,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
} else if (bio != NULL &&
!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
@@ -2532,7 +2637,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
}
}
@@ -2573,6 +2678,8 @@ static void raid10d(struct mddev *mddev)
if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
test_bit(R10BIO_WriteError, &r10_bio->state))
handle_write_completed(conf, r10_bio);
+ else if (test_bit(R10BIO_IsReshape, &r10_bio->state))
+ reshape_request_write(mddev, r10_bio);
else if (test_bit(R10BIO_IsSync, &r10_bio->state))
sync_request_write(mddev, r10_bio);
else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
@@ -2603,7 +2710,7 @@ static int init_resync(struct r10conf *conf)
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
BUG_ON(conf->r10buf_pool);
conf->have_replacement = 0;
- for (i = 0; i < conf->raid_disks; i++)
+ for (i = 0; i < conf->geo.raid_disks; i++)
if (conf->mirrors[i].replacement)
conf->have_replacement = 1;
conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
@@ -2657,6 +2764,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
sector_t sync_blocks;
sector_t sectors_skipped = 0;
int chunks_skipped = 0;
+ sector_t chunk_mask = conf->geo.chunk_mask;
if (!conf->r10buf_pool)
if (init_resync(conf))
@@ -2664,7 +2772,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
skipped:
max_sector = mddev->dev_sectors;
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sector = mddev->resync_max_sectors;
if (sector_nr >= max_sector) {
/* If we aborted, we need to abort the
@@ -2676,11 +2785,16 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
* we need to convert that to several
* virtual addresses.
*/
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
+ end_reshape(conf);
+ return 0;
+ }
+
if (mddev->curr_resync < max_sector) { /* aborted */
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
&sync_blocks, 1);
- else for (i=0; i<conf->raid_disks; i++) {
+ else for (i = 0; i < conf->geo.raid_disks; i++) {
sector_t sect =
raid10_find_virt(conf, mddev->curr_resync, i);
bitmap_end_sync(mddev->bitmap, sect,
@@ -2694,7 +2808,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* Completed a full sync so the replacements
* are now fully recovered.
*/
- for (i = 0; i < conf->raid_disks; i++)
+ for (i = 0; i < conf->geo.raid_disks; i++)
if (conf->mirrors[i].replacement)
conf->mirrors[i].replacement
->recovery_offset
@@ -2707,7 +2821,11 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
*skipped = 1;
return sectors_skipped;
}
- if (chunks_skipped >= conf->raid_disks) {
+
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ return reshape_request(mddev, sector_nr, skipped);
+
+ if (chunks_skipped >= conf->geo.raid_disks) {
/* if there has been nothing to do on any drive,
* then there is nothing to do at all..
*/
@@ -2721,9 +2839,9 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* make sure whole request will fit in a chunk - if chunks
* are meaningful
*/
- if (conf->near_copies < conf->raid_disks &&
- max_sector > (sector_nr | conf->chunk_mask))
- max_sector = (sector_nr | conf->chunk_mask) + 1;
+ if (conf->geo.near_copies < conf->geo.raid_disks &&
+ max_sector > (sector_nr | chunk_mask))
+ max_sector = (sector_nr | chunk_mask) + 1;
/*
* If there is non-resync activity waiting for us then
* put in a delay to throttle resync.
@@ -2752,7 +2870,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
int j;
r10_bio = NULL;
- for (i=0 ; i<conf->raid_disks; i++) {
+ for (i = 0 ; i < conf->geo.raid_disks; i++) {
int still_degraded;
struct r10bio *rb2;
sector_t sect;
@@ -2806,7 +2924,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* Need to check if the array will still be
* degraded
*/
- for (j=0; j<conf->raid_disks; j++)
+ for (j = 0; j < conf->geo.raid_disks; j++)
if (conf->mirrors[j].rdev == NULL ||
test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
still_degraded = 1;
@@ -2984,9 +3102,9 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
r10_bio->sector = sector_nr;
set_bit(R10BIO_IsSync, &r10_bio->state);
raid10_find_phys(conf, r10_bio);
- r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1;
+ r10_bio->sectors = (sector_nr | chunk_mask) - sector_nr + 1;
- for (i=0; i<conf->copies; i++) {
+ for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
sector_t first_bad, sector;
int bad_sectors;
@@ -3152,40 +3270,107 @@ raid10_size(struct mddev *mddev, sector_t sectors, int raid_disks)
struct r10conf *conf = mddev->private;
if (!raid_disks)
- raid_disks = conf->raid_disks;
+ raid_disks = min(conf->geo.raid_disks,
+ conf->prev.raid_disks);
if (!sectors)
sectors = conf->dev_sectors;
- size = sectors >> conf->chunk_shift;
- sector_div(size, conf->far_copies);
+ size = sectors >> conf->geo.chunk_shift;
+ sector_div(size, conf->geo.far_copies);
size = size * raid_disks;
- sector_div(size, conf->near_copies);
+ sector_div(size, conf->geo.near_copies);
+
+ return size << conf->geo.chunk_shift;
+}
+
+static void calc_sectors(struct r10conf *conf, sector_t size)
+{
+ /* Calculate the number of sectors-per-device that will
+ * actually be used, and set conf->dev_sectors and
+ * conf->stride
+ */
- return size << conf->chunk_shift;
+ size = size >> conf->geo.chunk_shift;
+ sector_div(size, conf->geo.far_copies);
+ size = size * conf->geo.raid_disks;
+ sector_div(size, conf->geo.near_copies);
+ /* 'size' is now the number of chunks in the array */
+ /* calculate "used chunks per device" */
+ size = size * conf->copies;
+
+ /* We need to round up when dividing by raid_disks to
+ * get the stride size.
+ */
+ size = DIV_ROUND_UP_SECTOR_T(size, conf->geo.raid_disks);
+
+ conf->dev_sectors = size << conf->geo.chunk_shift;
+
+ if (conf->geo.far_offset)
+ conf->geo.stride = 1 << conf->geo.chunk_shift;
+ else {
+ sector_div(size, conf->geo.far_copies);
+ conf->geo.stride = size << conf->geo.chunk_shift;
+ }
}
+enum geo_type {geo_new, geo_old, geo_start};
+static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
+{
+ int nc, fc, fo;
+ int layout, chunk, disks;
+ switch (new) {
+ case geo_old:
+ layout = mddev->layout;
+ chunk = mddev->chunk_sectors;
+ disks = mddev->raid_disks - mddev->delta_disks;
+ break;
+ case geo_new:
+ layout = mddev->new_layout;
+ chunk = mddev->new_chunk_sectors;
+ disks = mddev->raid_disks;
+ break;
+ default: /* avoid 'may be unused' warnings */
+ case geo_start: /* new when starting reshape - raid_disks not
+ * updated yet. */
+ layout = mddev->new_layout;
+ chunk = mddev->new_chunk_sectors;
+ disks = mddev->raid_disks + mddev->delta_disks;
+ break;
+ }
+ if (layout >> 17)
+ return -1;
+ if (chunk < (PAGE_SIZE >> 9) ||
+ !is_power_of_2(chunk))
+ return -2;
+ nc = layout & 255;
+ fc = (layout >> 8) & 255;
+ fo = layout & (1<<16);
+ geo->raid_disks = disks;
+ geo->near_copies = nc;
+ geo->far_copies = fc;
+ geo->far_offset = fo;
+ geo->chunk_mask = chunk - 1;
+ geo->chunk_shift = ffz(~chunk);
+ return nc*fc;
+}
static struct r10conf *setup_conf(struct mddev *mddev)
{
struct r10conf *conf = NULL;
- int nc, fc, fo;
- sector_t stride, size;
int err = -EINVAL;
+ struct geom geo;
+ int copies;
- if (mddev->new_chunk_sectors < (PAGE_SIZE >> 9) ||
- !is_power_of_2(mddev->new_chunk_sectors)) {
+ copies = setup_geo(&geo, mddev, geo_new);
+
+ if (copies == -2) {
printk(KERN_ERR "md/raid10:%s: chunk size must be "
"at least PAGE_SIZE(%ld) and be a power of 2.\n",
mdname(mddev), PAGE_SIZE);
goto out;
}
- nc = mddev->new_layout & 255;
- fc = (mddev->new_layout >> 8) & 255;
- fo = mddev->new_layout & (1<<16);
-
- if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
- (mddev->new_layout >> 17)) {
+ if (copies < 2 || copies > mddev->raid_disks) {
printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
mdname(mddev), mddev->new_layout);
goto out;
@@ -3196,7 +3381,9 @@ static struct r10conf *setup_conf(struct mddev *mddev)
if (!conf)
goto out;
- conf->mirrors = kzalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+ /* FIXME calc properly */
+ conf->mirrors = kzalloc(sizeof(struct mirror_info)*(mddev->raid_disks +
+ max(0,mddev->delta_disks)),
GFP_KERNEL);
if (!conf->mirrors)
goto out;
@@ -3205,43 +3392,29 @@ static struct r10conf *setup_conf(struct mddev *mddev)
if (!conf->tmppage)
goto out;
-
- conf->raid_disks = mddev->raid_disks;
- conf->near_copies = nc;
- conf->far_copies = fc;
- conf->copies = nc*fc;
- conf->far_offset = fo;
- conf->chunk_mask = mddev->new_chunk_sectors - 1;
- conf->chunk_shift = ffz(~mddev->new_chunk_sectors);
-
+ conf->geo = geo;
+ conf->copies = copies;
conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
r10bio_pool_free, conf);
if (!conf->r10bio_pool)
goto out;
- size = mddev->dev_sectors >> conf->chunk_shift;
- sector_div(size, fc);
- size = size * conf->raid_disks;
- sector_div(size, nc);
- /* 'size' is now the number of chunks in the array */
- /* calculate "used chunks per device" in 'stride' */
- stride = size * conf->copies;
-
- /* We need to round up when dividing by raid_disks to
- * get the stride size.
- */
- stride += conf->raid_disks - 1;
- sector_div(stride, conf->raid_disks);
-
- conf->dev_sectors = stride << conf->chunk_shift;
-
- if (fo)
- stride = 1;
- else
- sector_div(stride, fc);
- conf->stride = stride << conf->chunk_shift;
-
-
+ calc_sectors(conf, mddev->dev_sectors);
+ if (mddev->reshape_position == MaxSector) {
+ conf->prev = conf->geo;
+ conf->reshape_progress = MaxSector;
+ } else {
+ if (setup_geo(&conf->prev, mddev, geo_old) != conf->copies) {
+ err = -EINVAL;
+ goto out;
+ }
+ conf->reshape_progress = mddev->reshape_position;
+ if (conf->prev.far_offset)
+ conf->prev.stride = 1 << conf->prev.chunk_shift;
+ else
+ /* far_copies must be 1 */
+ conf->prev.stride = conf->dev_sectors;
+ }
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
@@ -3256,8 +3429,9 @@ static struct r10conf *setup_conf(struct mddev *mddev)
return conf;
out:
- printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
- mdname(mddev));
+ if (err == -ENOMEM)
+ printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
+ mdname(mddev));
if (conf) {
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
@@ -3275,12 +3449,8 @@ static int run(struct mddev *mddev)
struct mirror_info *disk;
struct md_rdev *rdev;
sector_t size;
-
- /*
- * copy the already verified devices into our private RAID10
- * bookkeeping area. [whatever we allocate in run(),
- * should be freed in stop()]
- */
+ sector_t min_offset_diff = 0;
+ int first = 1;
if (mddev->private == NULL) {
conf = setup_conf(mddev);
@@ -3297,17 +3467,20 @@ static int run(struct mddev *mddev)
chunk_size = mddev->chunk_sectors << 9;
blk_queue_io_min(mddev->queue, chunk_size);
- if (conf->raid_disks % conf->near_copies)
- blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+ if (conf->geo.raid_disks % conf->geo.near_copies)
+ blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
else
blk_queue_io_opt(mddev->queue, chunk_size *
- (conf->raid_disks / conf->near_copies));
+ (conf->geo.raid_disks / conf->geo.near_copies));
rdev_for_each(rdev, mddev) {
+ long long diff;
disk_idx = rdev->raid_disk;
- if (disk_idx >= conf->raid_disks
- || disk_idx < 0)
+ if (disk_idx < 0)
+ continue;
+ if (disk_idx >= conf->geo.raid_disks &&
+ disk_idx >= conf->prev.raid_disks)
continue;
disk = conf->mirrors + disk_idx;
@@ -3320,12 +3493,20 @@ static int run(struct mddev *mddev)
goto out_free_conf;
disk->rdev = rdev;
}
+ diff = (rdev->new_data_offset - rdev->data_offset);
+ if (!mddev->reshape_backwards)
+ diff = -diff;
+ if (diff < 0)
+ diff = 0;
+ if (first || diff < min_offset_diff)
+ min_offset_diff = diff;
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
disk->head_position = 0;
}
+
/* need to check that every block has at least one working mirror */
if (!enough(conf, -1)) {
printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
@@ -3333,8 +3514,21 @@ static int run(struct mddev *mddev)
goto out_free_conf;
}
+ if (conf->reshape_progress != MaxSector) {
+ /* must ensure that shape change is supported */
+ if (conf->geo.far_copies != 1 &&
+ conf->geo.far_offset == 0)
+ goto out_free_conf;
+ if (conf->prev.far_copies != 1 &&
+ conf->geo.far_offset == 0)
+ goto out_free_conf;
+ }
+
mddev->degraded = 0;
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0;
+ i < conf->geo.raid_disks
+ || i < conf->prev.raid_disks;
+ i++) {
disk = conf->mirrors + i;
@@ -3361,8 +3555,8 @@ static int run(struct mddev *mddev)
mdname(mddev));
printk(KERN_INFO
"md/raid10:%s: active with %d out of %d devices\n",
- mdname(mddev), conf->raid_disks - mddev->degraded,
- conf->raid_disks);
+ mdname(mddev), conf->geo.raid_disks - mddev->degraded,
+ conf->geo.raid_disks);
/*
* Ok, everything is just fine now
*/
@@ -3379,11 +3573,11 @@ static int run(struct mddev *mddev)
* maybe...
*/
{
- int stripe = conf->raid_disks *
+ int stripe = conf->geo.raid_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
- stripe /= conf->near_copies;
- if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
- mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+ stripe /= conf->geo.near_copies;
+ if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+ mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
}
blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
@@ -3391,6 +3585,30 @@ static int run(struct mddev *mddev)
if (md_integrity_register(mddev))
goto out_free_conf;
+ if (conf->reshape_progress != MaxSector) {
+ unsigned long before_length, after_length;
+
+ before_length = ((1 << conf->prev.chunk_shift) *
+ conf->prev.far_copies);
+ after_length = ((1 << conf->geo.chunk_shift) *
+ conf->geo.far_copies);
+
+ if (max(before_length, after_length) > min_offset_diff) {
+ /* This cannot work */
+ printk("md/raid10: offset difference not enough to continue reshape\n");
+ goto out_free_conf;
+ }
+ conf->offset_diff = min_offset_diff;
+
+ conf->reshape_safe = conf->reshape_progress;
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+ "reshape");
+ }
+
return 0;
out_free_conf:
@@ -3453,14 +3671,23 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)
struct r10conf *conf = mddev->private;
sector_t oldsize, size;
- if (conf->far_copies > 1 && !conf->far_offset)
+ if (mddev->reshape_position != MaxSector)
+ return -EBUSY;
+
+ if (conf->geo.far_copies > 1 && !conf->geo.far_offset)
return -EINVAL;
oldsize = raid10_size(mddev, 0, 0);
size = raid10_size(mddev, sectors, 0);
- md_set_array_sectors(mddev, size);
- if (mddev->array_sectors > size)
+ if (mddev->external_size &&
+ mddev->array_sectors > size)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, size, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, size);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
@@ -3468,7 +3695,8 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)
mddev->recovery_cp = oldsize;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
}
- mddev->dev_sectors = sectors;
+ calc_sectors(conf, sectors);
+ mddev->dev_sectors = conf->dev_sectors;
mddev->resync_max_sectors = size;
return 0;
}
@@ -3526,6 +3754,758 @@ static void *raid10_takeover(struct mddev *mddev)
return ERR_PTR(-EINVAL);
}
+static int raid10_check_reshape(struct mddev *mddev)
+{
+ /* Called when there is a request to change
+ * - layout (to ->new_layout)
+ * - chunk size (to ->new_chunk_sectors)
+ * - raid_disks (by delta_disks)
+ * or when trying to restart a reshape that was ongoing.
+ *
+ * We need to validate the request and possibly allocate
+ * space if that might be an issue later.
+ *
+ * Currently we reject any reshape of a 'far' mode array,
+ * allow chunk size to change if new is generally acceptable,
+ * allow raid_disks to increase, and allow
+ * a switch between 'near' mode and 'offset' mode.
+ */
+ struct r10conf *conf = mddev->private;
+ struct geom geo;
+
+ if (conf->geo.far_copies != 1 && !conf->geo.far_offset)
+ return -EINVAL;
+
+ if (setup_geo(&geo, mddev, geo_start) != conf->copies)
+ /* mustn't change number of copies */
+ return -EINVAL;
+ if (geo.far_copies > 1 && !geo.far_offset)
+ /* Cannot switch to 'far' mode */
+ return -EINVAL;
+
+ if (mddev->array_sectors & geo.chunk_mask)
+ /* not factor of array size */
+ return -EINVAL;
+
+ if (!enough(conf, -1))
+ return -EINVAL;
+
+ kfree(conf->mirrors_new);
+ conf->mirrors_new = NULL;
+ if (mddev->delta_disks > 0) {
+ /* allocate new 'mirrors' list */
+ conf->mirrors_new = kzalloc(
+ sizeof(struct mirror_info)
+ *(mddev->raid_disks +
+ mddev->delta_disks),
+ GFP_KERNEL);
+ if (!conf->mirrors_new)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * Need to check if array has failed when deciding whether to:
+ * - start an array
+ * - remove non-faulty devices
+ * - add a spare
+ * - allow a reshape
+ * This determination is simple when no reshape is happening.
+ * However if there is a reshape, we need to carefully check
+ * both the before and after sections.
+ * This is because some failed devices may only affect one
+ * of the two sections, and some non-in_sync devices may
+ * be insync in the section most affected by failed devices.
+ */
+static int calc_degraded(struct r10conf *conf)
+{
+ int degraded, degraded2;
+ int i;
+
+ rcu_read_lock();
+ degraded = 0;
+ /* 'prev' section first */
+ for (i = 0; i < conf->prev.raid_disks; i++) {
+ struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ degraded++;
+ else if (!test_bit(In_sync, &rdev->flags))
+ /* When we can reduce the number of devices in
+ * an array, this might not contribute to
+ * 'degraded'. It does now.
+ */
+ degraded++;
+ }
+ rcu_read_unlock();
+ if (conf->geo.raid_disks == conf->prev.raid_disks)
+ return degraded;
+ rcu_read_lock();
+ degraded2 = 0;
+ for (i = 0; i < conf->geo.raid_disks; i++) {
+ struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ degraded2++;
+ else if (!test_bit(In_sync, &rdev->flags)) {
+ /* If reshape is increasing the number of devices,
+ * this section has already been recovered, so
+ * it doesn't contribute to degraded.
+ * else it does.
+ */
+ if (conf->geo.raid_disks <= conf->prev.raid_disks)
+ degraded2++;
+ }
+ }
+ rcu_read_unlock();
+ if (degraded2 > degraded)
+ return degraded2;
+ return degraded;
+}
+
+static int raid10_start_reshape(struct mddev *mddev)
+{
+ /* A 'reshape' has been requested. This commits
+ * the various 'new' fields and sets MD_RECOVER_RESHAPE
+ * This also checks if there are enough spares and adds them
+ * to the array.
+ * We currently require enough spares to make the final
+ * array non-degraded. We also require that the difference
+ * between old and new data_offset - on each device - is
+ * enough that we never risk over-writing.
+ */
+
+ unsigned long before_length, after_length;
+ sector_t min_offset_diff = 0;
+ int first = 1;
+ struct geom new;
+ struct r10conf *conf = mddev->private;
+ struct md_rdev *rdev;
+ int spares = 0;
+ int ret;
+
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ return -EBUSY;
+
+ if (setup_geo(&new, mddev, geo_start) != conf->copies)
+ return -EINVAL;
+
+ before_length = ((1 << conf->prev.chunk_shift) *
+ conf->prev.far_copies);
+ after_length = ((1 << conf->geo.chunk_shift) *
+ conf->geo.far_copies);
+
+ rdev_for_each(rdev, mddev) {
+ if (!test_bit(In_sync, &rdev->flags)
+ && !test_bit(Faulty, &rdev->flags))
+ spares++;
+ if (rdev->raid_disk >= 0) {
+ long long diff = (rdev->new_data_offset
+ - rdev->data_offset);
+ if (!mddev->reshape_backwards)
+ diff = -diff;
+ if (diff < 0)
+ diff = 0;
+ if (first || diff < min_offset_diff)
+ min_offset_diff = diff;
+ }
+ }
+
+ if (max(before_length, after_length) > min_offset_diff)
+ return -EINVAL;
+
+ if (spares < mddev->delta_disks)
+ return -EINVAL;
+
+ conf->offset_diff = min_offset_diff;
+ spin_lock_irq(&conf->device_lock);
+ if (conf->mirrors_new) {
+ memcpy(conf->mirrors_new, conf->mirrors,
+ sizeof(struct mirror_info)*conf->prev.raid_disks);
+ smp_mb();
+ kfree(conf->mirrors_old); /* FIXME and elsewhere */
+ conf->mirrors_old = conf->mirrors;
+ conf->mirrors = conf->mirrors_new;
+ conf->mirrors_new = NULL;
+ }
+ setup_geo(&conf->geo, mddev, geo_start);
+ smp_mb();
+ if (mddev->reshape_backwards) {
+ sector_t size = raid10_size(mddev, 0, 0);
+ if (size < mddev->array_sectors) {
+ spin_unlock_irq(&conf->device_lock);
+ printk(KERN_ERR "md/raid10:%s: array size must be reduce before number of disks\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ mddev->resync_max_sectors = size;
+ conf->reshape_progress = size;
+ } else
+ conf->reshape_progress = 0;
+ spin_unlock_irq(&conf->device_lock);
+
+ if (mddev->delta_disks && mddev->bitmap) {
+ ret = bitmap_resize(mddev->bitmap,
+ raid10_size(mddev, 0,
+ conf->geo.raid_disks),
+ 0, 0);
+ if (ret)
+ goto abort;
+ }
+ if (mddev->delta_disks > 0) {
+ rdev_for_each(rdev, mddev)
+ if (rdev->raid_disk < 0 &&
+ !test_bit(Faulty, &rdev->flags)) {
+ if (raid10_add_disk(mddev, rdev) == 0) {
+ if (rdev->raid_disk >=
+ conf->prev.raid_disks)
+ set_bit(In_sync, &rdev->flags);
+ else
+ rdev->recovery_offset = 0;
+
+ if (sysfs_link_rdev(mddev, rdev))
+ /* Failure here is OK */;
+ }
+ } else if (rdev->raid_disk >= conf->prev.raid_disks
+ && !test_bit(Faulty, &rdev->flags)) {
+ /* This is a spare that was manually added */
+ set_bit(In_sync, &rdev->flags);
+ }
+ }
+ /* When a reshape changes the number of devices,
+ * ->degraded is measured against the larger of the
+ * pre and post numbers.
+ */
+ spin_lock_irq(&conf->device_lock);
+ mddev->degraded = calc_degraded(conf);
+ spin_unlock_irq(&conf->device_lock);
+ mddev->raid_disks = conf->geo.raid_disks;
+ mddev->reshape_position = conf->reshape_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+
+ mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+ "reshape");
+ if (!mddev->sync_thread) {
+ ret = -EAGAIN;
+ goto abort;
+ }
+ conf->reshape_checkpoint = jiffies;
+ md_wakeup_thread(mddev->sync_thread);
+ md_new_event(mddev);
+ return 0;
+
+abort:
+ mddev->recovery = 0;
+ spin_lock_irq(&conf->device_lock);
+ conf->geo = conf->prev;
+ mddev->raid_disks = conf->geo.raid_disks;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
+ smp_wmb();
+ conf->reshape_progress = MaxSector;
+ mddev->reshape_position = MaxSector;
+ spin_unlock_irq(&conf->device_lock);
+ return ret;
+}
+
+/* Calculate the last device-address that could contain
+ * any block from the chunk that includes the array-address 's'
+ * and report the next address.
+ * i.e. the address returned will be chunk-aligned and after
+ * any data that is in the chunk containing 's'.
+ */
+static sector_t last_dev_address(sector_t s, struct geom *geo)
+{
+ s = (s | geo->chunk_mask) + 1;
+ s >>= geo->chunk_shift;
+ s *= geo->near_copies;
+ s = DIV_ROUND_UP_SECTOR_T(s, geo->raid_disks);
+ s *= geo->far_copies;
+ s <<= geo->chunk_shift;
+ return s;
+}
+
+/* Calculate the first device-address that could contain
+ * any block from the chunk that includes the array-address 's'.
+ * This too will be the start of a chunk
+ */
+static sector_t first_dev_address(sector_t s, struct geom *geo)
+{
+ s >>= geo->chunk_shift;
+ s *= geo->near_copies;
+ sector_div(s, geo->raid_disks);
+ s *= geo->far_copies;
+ s <<= geo->chunk_shift;
+ return s;
+}
+
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+ int *skipped)
+{
+ /* We simply copy at most one chunk (smallest of old and new)
+ * at a time, possibly less if that exceeds RESYNC_PAGES,
+ * or we hit a bad block or something.
+ * This might mean we pause for normal IO in the middle of
+ * a chunk, but that is not a problem was mddev->reshape_position
+ * can record any location.
+ *
+ * If we will want to write to a location that isn't
+ * yet recorded as 'safe' (i.e. in metadata on disk) then
+ * we need to flush all reshape requests and update the metadata.
+ *
+ * When reshaping forwards (e.g. to more devices), we interpret
+ * 'safe' as the earliest block which might not have been copied
+ * down yet. We divide this by previous stripe size and multiply
+ * by previous stripe length to get lowest device offset that we
+ * cannot write to yet.
+ * We interpret 'sector_nr' as an address that we want to write to.
+ * From this we use last_device_address() to find where we might
+ * write to, and first_device_address on the 'safe' position.
+ * If this 'next' write position is after the 'safe' position,
+ * we must update the metadata to increase the 'safe' position.
+ *
+ * When reshaping backwards, we round in the opposite direction
+ * and perform the reverse test: next write position must not be
+ * less than current safe position.
+ *
+ * In all this the minimum difference in data offsets
+ * (conf->offset_diff - always positive) allows a bit of slack,
+ * so next can be after 'safe', but not by more than offset_disk
+ *
+ * We need to prepare all the bios here before we start any IO
+ * to ensure the size we choose is acceptable to all devices.
+ * The means one for each copy for write-out and an extra one for
+ * read-in.
+ * We store the read-in bio in ->master_bio and the others in
+ * ->devs[x].bio and ->devs[x].repl_bio.
+ */
+ struct r10conf *conf = mddev->private;
+ struct r10bio *r10_bio;
+ sector_t next, safe, last;
+ int max_sectors;
+ int nr_sectors;
+ int s;
+ struct md_rdev *rdev;
+ int need_flush = 0;
+ struct bio *blist;
+ struct bio *bio, *read_bio;
+ int sectors_done = 0;
+
+ if (sector_nr == 0) {
+ /* If restarting in the middle, skip the initial sectors */
+ if (mddev->reshape_backwards &&
+ conf->reshape_progress < raid10_size(mddev, 0, 0)) {
+ sector_nr = (raid10_size(mddev, 0, 0)
+ - conf->reshape_progress);
+ } else if (!mddev->reshape_backwards &&
+ conf->reshape_progress > 0)
+ sector_nr = conf->reshape_progress;
+ if (sector_nr) {
+ mddev->curr_resync_completed = sector_nr;
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+ *skipped = 1;
+ return sector_nr;
+ }
+ }
+
+ /* We don't use sector_nr to track where we are up to
+ * as that doesn't work well for ->reshape_backwards.
+ * So just use ->reshape_progress.
+ */
+ if (mddev->reshape_backwards) {
+ /* 'next' is the earliest device address that we might
+ * write to for this chunk in the new layout
+ */
+ next = first_dev_address(conf->reshape_progress - 1,
+ &conf->geo);
+
+ /* 'safe' is the last device address that we might read from
+ * in the old layout after a restart
+ */
+ safe = last_dev_address(conf->reshape_safe - 1,
+ &conf->prev);
+
+ if (next + conf->offset_diff < safe)
+ need_flush = 1;
+
+ last = conf->reshape_progress - 1;
+ sector_nr = last & ~(sector_t)(conf->geo.chunk_mask
+ & conf->prev.chunk_mask);
+ if (sector_nr + RESYNC_BLOCK_SIZE/512 < last)
+ sector_nr = last + 1 - RESYNC_BLOCK_SIZE/512;
+ } else {
+ /* 'next' is after the last device address that we
+ * might write to for this chunk in the new layout
+ */
+ next = last_dev_address(conf->reshape_progress, &conf->geo);
+
+ /* 'safe' is the earliest device address that we might
+ * read from in the old layout after a restart
+ */
+ safe = first_dev_address(conf->reshape_safe, &conf->prev);
+
+ /* Need to update metadata if 'next' might be beyond 'safe'
+ * as that would possibly corrupt data
+ */
+ if (next > safe + conf->offset_diff)
+ need_flush = 1;
+
+ sector_nr = conf->reshape_progress;
+ last = sector_nr | (conf->geo.chunk_mask
+ & conf->prev.chunk_mask);
+
+ if (sector_nr + RESYNC_BLOCK_SIZE/512 <= last)
+ last = sector_nr + RESYNC_BLOCK_SIZE/512 - 1;
+ }
+
+ if (need_flush ||
+ time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
+ /* Need to update reshape_position in metadata */
+ wait_barrier(conf);
+ mddev->reshape_position = conf->reshape_progress;
+ if (mddev->reshape_backwards)
+ mddev->curr_resync_completed = raid10_size(mddev, 0, 0)
+ - conf->reshape_progress;
+ else
+ mddev->curr_resync_completed = conf->reshape_progress;
+ conf->reshape_checkpoint = jiffies;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait, mddev->flags == 0 ||
+ kthread_should_stop());
+ conf->reshape_safe = mddev->reshape_position;
+ allow_barrier(conf);
+ }
+
+read_more:
+ /* Now schedule reads for blocks from sector_nr to last */
+ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+ raise_barrier(conf, sectors_done != 0);
+ atomic_set(&r10_bio->remaining, 0);
+ r10_bio->mddev = mddev;
+ r10_bio->sector = sector_nr;
+ set_bit(R10BIO_IsReshape, &r10_bio->state);
+ r10_bio->sectors = last - sector_nr + 1;
+ rdev = read_balance(conf, r10_bio, &max_sectors);
+ BUG_ON(!test_bit(R10BIO_Previous, &r10_bio->state));
+
+ if (!rdev) {
+ /* Cannot read from here, so need to record bad blocks
+ * on all the target devices.
+ */
+ // FIXME
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ return sectors_done;
+ }
+
+ read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev);
+
+ read_bio->bi_bdev = rdev->bdev;
+ read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
+ + rdev->data_offset);
+ read_bio->bi_private = r10_bio;
+ read_bio->bi_end_io = end_sync_read;
+ read_bio->bi_rw = READ;
+ read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ read_bio->bi_flags |= 1 << BIO_UPTODATE;
+ read_bio->bi_vcnt = 0;
+ read_bio->bi_idx = 0;
+ read_bio->bi_size = 0;
+ r10_bio->master_bio = read_bio;
+ r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum;
+
+ /* Now find the locations in the new layout */
+ __raid10_find_phys(&conf->geo, r10_bio);
+
+ blist = read_bio;
+ read_bio->bi_next = NULL;
+
+ for (s = 0; s < conf->copies*2; s++) {
+ struct bio *b;
+ int d = r10_bio->devs[s/2].devnum;
+ struct md_rdev *rdev2;
+ if (s&1) {
+ rdev2 = conf->mirrors[d].replacement;
+ b = r10_bio->devs[s/2].repl_bio;
+ } else {
+ rdev2 = conf->mirrors[d].rdev;
+ b = r10_bio->devs[s/2].bio;
+ }
+ if (!rdev2 || test_bit(Faulty, &rdev2->flags))
+ continue;
+ b->bi_bdev = rdev2->bdev;
+ b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset;
+ b->bi_private = r10_bio;
+ b->bi_end_io = end_reshape_write;
+ b->bi_rw = WRITE;
+ b->bi_flags &= ~(BIO_POOL_MASK - 1);
+ b->bi_flags |= 1 << BIO_UPTODATE;
+ b->bi_next = blist;
+ b->bi_vcnt = 0;
+ b->bi_idx = 0;
+ b->bi_size = 0;
+ blist = b;
+ }
+
+ /* Now add as many pages as possible to all of these bios. */
+
+ nr_sectors = 0;
+ for (s = 0 ; s < max_sectors; s += PAGE_SIZE >> 9) {
+ struct page *page = r10_bio->devs[0].bio->bi_io_vec[s/(PAGE_SIZE>>9)].bv_page;
+ int len = (max_sectors - s) << 9;
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+ for (bio = blist; bio ; bio = bio->bi_next) {
+ struct bio *bio2;
+ if (bio_add_page(bio, page, len, 0))
+ continue;
+
+ /* Didn't fit, must stop */
+ for (bio2 = blist;
+ bio2 && bio2 != bio;
+ bio2 = bio2->bi_next) {
+ /* Remove last page from this bio */
+ bio2->bi_vcnt--;
+ bio2->bi_size -= len;
+ bio2->bi_flags &= ~(1<<BIO_SEG_VALID);
+ }
+ goto bio_full;
+ }
+ sector_nr += len >> 9;
+ nr_sectors += len >> 9;
+ }
+bio_full:
+ r10_bio->sectors = nr_sectors;
+
+ /* Now submit the read */
+ md_sync_acct(read_bio->bi_bdev, r10_bio->sectors);
+ atomic_inc(&r10_bio->remaining);
+ read_bio->bi_next = NULL;
+ generic_make_request(read_bio);
+ sector_nr += nr_sectors;
+ sectors_done += nr_sectors;
+ if (sector_nr <= last)
+ goto read_more;
+
+ /* Now that we have done the whole section we can
+ * update reshape_progress
+ */
+ if (mddev->reshape_backwards)
+ conf->reshape_progress -= sectors_done;
+ else
+ conf->reshape_progress += sectors_done;
+
+ return sectors_done;
+}
+
+static void end_reshape_request(struct r10bio *r10_bio);
+static int handle_reshape_read_error(struct mddev *mddev,
+ struct r10bio *r10_bio);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
+{
+ /* Reshape read completed. Hopefully we have a block
+ * to write out.
+ * If we got a read error then we do sync 1-page reads from
+ * elsewhere until we find the data - or give up.
+ */
+ struct r10conf *conf = mddev->private;
+ int s;
+
+ if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
+ if (handle_reshape_read_error(mddev, r10_bio) < 0) {
+ /* Reshape has been aborted */
+ md_done_sync(mddev, r10_bio->sectors, 0);
+ return;
+ }
+
+ /* We definitely have the data in the pages, schedule the
+ * writes.
+ */
+ atomic_set(&r10_bio->remaining, 1);
+ for (s = 0; s < conf->copies*2; s++) {
+ struct bio *b;
+ int d = r10_bio->devs[s/2].devnum;
+ struct md_rdev *rdev;
+ if (s&1) {
+ rdev = conf->mirrors[d].replacement;
+ b = r10_bio->devs[s/2].repl_bio;
+ } else {
+ rdev = conf->mirrors[d].rdev;
+ b = r10_bio->devs[s/2].bio;
+ }
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ continue;
+ atomic_inc(&rdev->nr_pending);
+ md_sync_acct(b->bi_bdev, r10_bio->sectors);
+ atomic_inc(&r10_bio->remaining);
+ b->bi_next = NULL;
+ generic_make_request(b);
+ }
+ end_reshape_request(r10_bio);
+}
+
+static void end_reshape(struct r10conf *conf)
+{
+ if (test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery))
+ return;
+
+ spin_lock_irq(&conf->device_lock);
+ conf->prev = conf->geo;
+ md_finish_reshape(conf->mddev);
+ smp_wmb();
+ conf->reshape_progress = MaxSector;
+ spin_unlock_irq(&conf->device_lock);
+
+ /* read-ahead size must cover two whole stripes, which is
+ * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
+ */
+ if (conf->mddev->queue) {
+ int stripe = conf->geo.raid_disks *
+ ((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
+ stripe /= conf->geo.near_copies;
+ if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+ conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ }
+ conf->fullsync = 0;
+}
+
+
+static int handle_reshape_read_error(struct mddev *mddev,
+ struct r10bio *r10_bio)
+{
+ /* Use sync reads to get the blocks from somewhere else */
+ int sectors = r10_bio->sectors;
+ struct r10bio r10b;
+ struct r10conf *conf = mddev->private;
+ int slot = 0;
+ int idx = 0;
+ struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
+
+ r10b.sector = r10_bio->sector;
+ __raid10_find_phys(&conf->prev, &r10b);
+
+ while (sectors) {
+ int s = sectors;
+ int success = 0;
+ int first_slot = slot;
+
+ if (s > (PAGE_SIZE >> 9))
+ s = PAGE_SIZE >> 9;
+
+ while (!success) {
+ int d = r10b.devs[slot].devnum;
+ struct md_rdev *rdev = conf->mirrors[d].rdev;
+ sector_t addr;
+ if (rdev == NULL ||
+ test_bit(Faulty, &rdev->flags) ||
+ !test_bit(In_sync, &rdev->flags))
+ goto failed;
+
+ addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+ success = sync_page_io(rdev,
+ addr,
+ s << 9,
+ bvec[idx].bv_page,
+ READ, false);
+ if (success)
+ break;
+ failed:
+ slot++;
+ if (slot >= conf->copies)
+ slot = 0;
+ if (slot == first_slot)
+ break;
+ }
+ if (!success) {
+ /* couldn't read this block, must give up */
+ set_bit(MD_RECOVERY_INTR,
+ &mddev->recovery);
+ return -EIO;
+ }
+ sectors -= s;
+ idx++;
+ }
+ return 0;
+}
+
+static void end_reshape_write(struct bio *bio, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ struct r10bio *r10_bio = bio->bi_private;
+ struct mddev *mddev = r10_bio->mddev;
+ struct r10conf *conf = mddev->private;
+ int d;
+ int slot;
+ int repl;
+ struct md_rdev *rdev = NULL;
+
+ d = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
+ if (repl)
+ rdev = conf->mirrors[d].replacement;
+ if (!rdev) {
+ smp_mb();
+ rdev = conf->mirrors[d].rdev;
+ }
+
+ if (!uptodate) {
+ /* FIXME should record badblock */
+ md_error(mddev, rdev);
+ }
+
+ rdev_dec_pending(rdev, mddev);
+ end_reshape_request(r10_bio);
+}
+
+static void end_reshape_request(struct r10bio *r10_bio)
+{
+ if (!atomic_dec_and_test(&r10_bio->remaining))
+ return;
+ md_done_sync(r10_bio->mddev, r10_bio->sectors, 1);
+ bio_put(r10_bio->master_bio);
+ put_buf(r10_bio);
+}
+
+static void raid10_finish_reshape(struct mddev *mddev)
+{
+ struct r10conf *conf = mddev->private;
+
+ if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+ return;
+
+ if (mddev->delta_disks > 0) {
+ sector_t size = raid10_size(mddev, 0, 0);
+ md_set_array_sectors(mddev, size);
+ if (mddev->recovery_cp > mddev->resync_max_sectors) {
+ mddev->recovery_cp = mddev->resync_max_sectors;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ mddev->resync_max_sectors = size;
+ set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
+ } else {
+ int d;
+ for (d = conf->geo.raid_disks ;
+ d < conf->geo.raid_disks - mddev->delta_disks;
+ d++) {
+ struct md_rdev *rdev = conf->mirrors[d].rdev;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ rdev = conf->mirrors[d].replacement;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ }
+ }
+ mddev->layout = mddev->new_layout;
+ mddev->chunk_sectors = 1 << conf->geo.chunk_shift;
+ mddev->reshape_position = MaxSector;
+ mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
+}
+
static struct md_personality raid10_personality =
{
.name = "raid10",
@@ -3544,6 +4524,9 @@ static struct md_personality raid10_personality =
.size = raid10_size,
.resize = raid10_resize,
.takeover = raid10_takeover,
+ .check_reshape = raid10_check_reshape,
+ .start_reshape = raid10_start_reshape,
+ .finish_reshape = raid10_finish_reshape,
};
static int __init raid_init(void)
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 7c615613..135b1b0 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -14,32 +14,38 @@ struct mirror_info {
struct r10conf {
struct mddev *mddev;
struct mirror_info *mirrors;
- int raid_disks;
+ struct mirror_info *mirrors_new, *mirrors_old;
spinlock_t device_lock;
/* geometry */
- int near_copies; /* number of copies laid out
+ struct geom {
+ int raid_disks;
+ int near_copies; /* number of copies laid out
* raid0 style */
- int far_copies; /* number of copies laid out
+ int far_copies; /* number of copies laid out
* at large strides across drives
*/
- int far_offset; /* far_copies are offset by 1
+ int far_offset; /* far_copies are offset by 1
* stripe instead of many
*/
- int copies; /* near_copies * far_copies.
- * must be <= raid_disks
- */
- sector_t stride; /* distance between far copies.
+ sector_t stride; /* distance between far copies.
* This is size / far_copies unless
* far_offset, in which case it is
* 1 stripe.
*/
+ int chunk_shift; /* shift from chunks to sectors */
+ sector_t chunk_mask;
+ } prev, geo;
+ int copies; /* near_copies * far_copies.
+ * must be <= raid_disks
+ */
sector_t dev_sectors; /* temp copy of
* mddev->dev_sectors */
-
- int chunk_shift; /* shift from chunks to sectors */
- sector_t chunk_mask;
+ sector_t reshape_progress;
+ sector_t reshape_safe;
+ unsigned long reshape_checkpoint;
+ sector_t offset_diff;
struct list_head retry_list;
/* queue pending writes and submit them on unplug */
@@ -136,6 +142,7 @@ enum r10bio_state {
R10BIO_Uptodate,
R10BIO_IsSync,
R10BIO_IsRecover,
+ R10BIO_IsReshape,
R10BIO_Degraded,
/* Set ReadError on bios that experience a read error
* so that raid10d knows what to do with them.
@@ -146,5 +153,10 @@ enum r10bio_state {
*/
R10BIO_MadeGood,
R10BIO_WriteError,
+/* During a reshape we might be performing IO on the
+ * 'previous' part of the array, in which case this
+ * flag is set
+ */
+ R10BIO_Previous,
};
#endif
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f351422..d267672 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -488,6 +488,27 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
return sh;
}
+/* Determine if 'data_offset' or 'new_data_offset' should be used
+ * in this stripe_head.
+ */
+static int use_new_offset(struct r5conf *conf, struct stripe_head *sh)
+{
+ sector_t progress = conf->reshape_progress;
+ /* Need a memory barrier to make sure we see the value
+ * of conf->generation, or ->data_offset that was set before
+ * reshape_progress was updated.
+ */
+ smp_rmb();
+ if (progress == MaxSector)
+ return 0;
+ if (sh->generation == conf->generation - 1)
+ return 0;
+ /* We are in a reshape, and this is a new-generation stripe,
+ * so use new_data_offset.
+ */
+ return 1;
+}
+
static void
raid5_end_read_request(struct bio *bi, int error);
static void
@@ -518,6 +539,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
replace_only = 1;
} else
continue;
+ if (test_and_clear_bit(R5_SyncIO, &sh->dev[i].flags))
+ rw |= REQ_SYNC;
bi = &sh->dev[i].req;
rbi = &sh->dev[i].rreq; /* For writing to replacement */
@@ -603,7 +626,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
__func__, (unsigned long long)sh->sector,
bi->bi_rw, i);
atomic_inc(&sh->count);
- bi->bi_sector = sh->sector + rdev->data_offset;
+ if (use_new_offset(conf, sh))
+ bi->bi_sector = (sh->sector
+ + rdev->new_data_offset);
+ else
+ bi->bi_sector = (sh->sector
+ + rdev->data_offset);
bi->bi_flags = 1 << BIO_UPTODATE;
bi->bi_idx = 0;
bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -627,7 +655,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
__func__, (unsigned long long)sh->sector,
rbi->bi_rw, i);
atomic_inc(&sh->count);
- rbi->bi_sector = sh->sector + rrdev->data_offset;
+ if (use_new_offset(conf, sh))
+ rbi->bi_sector = (sh->sector
+ + rrdev->new_data_offset);
+ else
+ rbi->bi_sector = (sh->sector
+ + rrdev->data_offset);
rbi->bi_flags = 1 << BIO_UPTODATE;
rbi->bi_idx = 0;
rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -1114,6 +1147,8 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
dev->sector + STRIPE_SECTORS) {
if (wbi->bi_rw & REQ_FUA)
set_bit(R5_WantFUA, &dev->flags);
+ if (wbi->bi_rw & REQ_SYNC)
+ set_bit(R5_SyncIO, &dev->flags);
tx = async_copy_data(1, wbi, dev->page,
dev->sector, tx);
wbi = r5_next_bio(wbi, dev->sector);
@@ -1131,13 +1166,15 @@ static void ops_complete_reconstruct(void *stripe_head_ref)
int pd_idx = sh->pd_idx;
int qd_idx = sh->qd_idx;
int i;
- bool fua = false;
+ bool fua = false, sync = false;
pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
- for (i = disks; i--; )
+ for (i = disks; i--; ) {
fua |= test_bit(R5_WantFUA, &sh->dev[i].flags);
+ sync |= test_bit(R5_SyncIO, &sh->dev[i].flags);
+ }
for (i = disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
@@ -1146,6 +1183,8 @@ static void ops_complete_reconstruct(void *stripe_head_ref)
set_bit(R5_UPTODATE, &dev->flags);
if (fua)
set_bit(R5_WantFUA, &dev->flags);
+ if (sync)
+ set_bit(R5_SyncIO, &dev->flags);
}
}
@@ -1648,7 +1687,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
char b[BDEVNAME_SIZE];
struct md_rdev *rdev = NULL;
-
+ sector_t s;
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
@@ -1671,6 +1710,10 @@ static void raid5_end_read_request(struct bio * bi, int error)
if (!rdev)
rdev = conf->disks[i].rdev;
+ if (use_new_offset(conf, sh))
+ s = sh->sector + rdev->new_data_offset;
+ else
+ s = sh->sector + rdev->data_offset;
if (uptodate) {
set_bit(R5_UPTODATE, &sh->dev[i].flags);
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
@@ -1683,8 +1726,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error corrected"
" (%lu sectors at %llu on %s)\n",
mdname(conf->mddev), STRIPE_SECTORS,
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdevname(rdev->bdev, b));
atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
clear_bit(R5_ReadError, &sh->dev[i].flags);
@@ -1704,8 +1746,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error on replacement device "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (conf->mddev->degraded >= conf->max_degraded)
printk_ratelimited(
@@ -1713,8 +1754,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error not correctable "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
/* Oh, no!!! */
@@ -1723,8 +1763,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error NOT corrected!! "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
@@ -3561,7 +3600,7 @@ finish:
if (test_and_clear_bit(R5_MadeGood, &dev->flags)) {
rdev = conf->disks[i].rdev;
rdev_clear_badblocks(rdev, sh->sector,
- STRIPE_SECTORS);
+ STRIPE_SECTORS, 0);
rdev_dec_pending(rdev, conf->mddev);
}
if (test_and_clear_bit(R5_MadeGoodRepl, &dev->flags)) {
@@ -3570,7 +3609,7 @@ finish:
/* rdev have been moved down */
rdev = conf->disks[i].rdev;
rdev_clear_badblocks(rdev, sh->sector,
- STRIPE_SECTORS);
+ STRIPE_SECTORS, 0);
rdev_dec_pending(rdev, conf->mddev);
}
}
@@ -3842,6 +3881,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
raid_bio->bi_next = (void*)rdev;
align_bi->bi_bdev = rdev->bdev;
align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+ /* No reshape active, so we can trust rdev->data_offset */
align_bi->bi_sector += rdev->data_offset;
if (!bio_fits_rdev(align_bi) ||
@@ -3953,12 +3993,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
plugged = mddev_check_plugged(mddev);
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
- int disks, data_disks;
int previous;
retry:
previous = 0;
- disks = conf->raid_disks;
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
if (unlikely(conf->reshape_progress != MaxSector)) {
/* spinlock is needed as reshape_progress may be
@@ -3970,13 +4008,12 @@ static void make_request(struct mddev *mddev, struct bio * bi)
* to check again.
*/
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector < conf->reshape_progress
: logical_sector >= conf->reshape_progress) {
- disks = conf->previous_raid_disks;
previous = 1;
} else {
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector < conf->reshape_safe
: logical_sector >= conf->reshape_safe) {
spin_unlock_irq(&conf->device_lock);
@@ -3986,7 +4023,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
}
spin_unlock_irq(&conf->device_lock);
}
- data_disks = disks - conf->max_degraded;
new_sector = raid5_compute_sector(conf, logical_sector,
previous,
@@ -4009,7 +4045,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
*/
int must_retry = 0;
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector >= conf->reshape_progress
: logical_sector < conf->reshape_progress)
/* mismatch, need to try again */
@@ -4108,11 +4144,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
if (sector_nr == 0) {
/* If restarting in the middle, skip the initial sectors */
- if (mddev->delta_disks < 0 &&
+ if (mddev->reshape_backwards &&
conf->reshape_progress < raid5_size(mddev, 0, 0)) {
sector_nr = raid5_size(mddev, 0, 0)
- conf->reshape_progress;
- } else if (mddev->delta_disks >= 0 &&
+ } else if (!mddev->reshape_backwards &&
conf->reshape_progress > 0)
sector_nr = conf->reshape_progress;
sector_div(sector_nr, new_data_disks);
@@ -4133,13 +4169,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
else
reshape_sectors = mddev->chunk_sectors;
- /* we update the metadata when there is more than 3Meg
- * in the block range (that is rather arbitrary, should
- * probably be time based) or when the data about to be
- * copied would over-write the source of the data at
- * the front of the range.
- * i.e. one new_stripe along from reshape_progress new_maps
- * to after where reshape_safe old_maps to
+ /* We update the metadata at least every 10 seconds, or when
+ * the data about to be copied would over-write the source of
+ * the data at the front of the range. i.e. one new_stripe
+ * along from reshape_progress new_maps to after where
+ * reshape_safe old_maps to
*/
writepos = conf->reshape_progress;
sector_div(writepos, new_data_disks);
@@ -4147,7 +4181,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
sector_div(readpos, data_disks);
safepos = conf->reshape_safe;
sector_div(safepos, data_disks);
- if (mddev->delta_disks < 0) {
+ if (mddev->reshape_backwards) {
writepos -= min_t(sector_t, reshape_sectors, writepos);
readpos += reshape_sectors;
safepos += reshape_sectors;
@@ -4157,11 +4191,29 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
safepos -= min_t(sector_t, reshape_sectors, safepos);
}
+ /* Having calculated the 'writepos' possibly use it
+ * to set 'stripe_addr' which is where we will write to.
+ */
+ if (mddev->reshape_backwards) {
+ BUG_ON(conf->reshape_progress == 0);
+ stripe_addr = writepos;
+ BUG_ON((mddev->dev_sectors &
+ ~((sector_t)reshape_sectors - 1))
+ - reshape_sectors - stripe_addr
+ != sector_nr);
+ } else {
+ BUG_ON(writepos != sector_nr + reshape_sectors);
+ stripe_addr = sector_nr;
+ }
+
/* 'writepos' is the most advanced device address we might write.
* 'readpos' is the least advanced device address we might read.
* 'safepos' is the least address recorded in the metadata as having
* been reshaped.
- * If 'readpos' is behind 'writepos', then there is no way that we can
+ * If there is a min_offset_diff, these are adjusted either by
+ * increasing the safepos/readpos if diff is negative, or
+ * increasing writepos if diff is positive.
+ * If 'readpos' is then behind 'writepos', there is no way that we can
* ensure safety in the face of a crash - that must be done by userspace
* making a backup of the data. So in that case there is no particular
* rush to update metadata.
@@ -4174,7 +4226,13 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
* Maybe that number should be configurable, but I'm not sure it is
* worth it.... maybe it could be a multiple of safemode_delay???
*/
- if ((mddev->delta_disks < 0
+ if (conf->min_offset_diff < 0) {
+ safepos += -conf->min_offset_diff;
+ readpos += -conf->min_offset_diff;
+ } else
+ writepos += conf->min_offset_diff;
+
+ if ((mddev->reshape_backwards
? (safepos > writepos && readpos < writepos)
: (safepos < writepos && readpos > writepos)) ||
time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
@@ -4195,17 +4253,6 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
}
- if (mddev->delta_disks < 0) {
- BUG_ON(conf->reshape_progress == 0);
- stripe_addr = writepos;
- BUG_ON((mddev->dev_sectors &
- ~((sector_t)reshape_sectors - 1))
- - reshape_sectors - stripe_addr
- != sector_nr);
- } else {
- BUG_ON(writepos != sector_nr + reshape_sectors);
- stripe_addr = sector_nr;
- }
INIT_LIST_HEAD(&stripes);
for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) {
int j;
@@ -4239,7 +4286,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
list_add(&sh->lru, &stripes);
}
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0)
+ if (mddev->reshape_backwards)
conf->reshape_progress -= reshape_sectors * new_data_disks;
else
conf->reshape_progress += reshape_sectors * new_data_disks;
@@ -4952,16 +4999,42 @@ static int run(struct mddev *mddev)
struct md_rdev *rdev;
sector_t reshape_offset = 0;
int i;
+ long long min_offset_diff = 0;
+ int first = 1;
if (mddev->recovery_cp != MaxSector)
printk(KERN_NOTICE "md/raid:%s: not clean"
" -- starting background reconstruction\n",
mdname(mddev));
+
+ rdev_for_each(rdev, mddev) {
+ long long diff;
+ if (rdev->raid_disk < 0)
+ continue;
+ diff = (rdev->new_data_offset - rdev->data_offset);
+ if (first) {
+ min_offset_diff = diff;
+ first = 0;
+ } else if (mddev->reshape_backwards &&
+ diff < min_offset_diff)
+ min_offset_diff = diff;
+ else if (!mddev->reshape_backwards &&
+ diff > min_offset_diff)
+ min_offset_diff = diff;
+ }
+
if (mddev->reshape_position != MaxSector) {
/* Check that we can continue the reshape.
- * Currently only disks can change, it must
- * increase, and we must be past the point where
- * a stripe over-writes itself
+ * Difficulties arise if the stripe we would write to
+ * next is at or after the stripe we would read from next.
+ * For a reshape that changes the number of devices, this
+ * is only possible for a very short time, and mdadm makes
+ * sure that time appears to have past before assembling
+ * the array. So we fail if that time hasn't passed.
+ * For a reshape that keeps the number of devices the same
+ * mdadm must be monitoring the reshape can keeping the
+ * critical areas read-only and backed up. It will start
+ * the array in read-only mode, so we check for that.
*/
sector_t here_new, here_old;
int old_disks;
@@ -4993,26 +5066,34 @@ static int run(struct mddev *mddev)
/* here_old is the first stripe that we might need to read
* from */
if (mddev->delta_disks == 0) {
+ if ((here_new * mddev->new_chunk_sectors !=
+ here_old * mddev->chunk_sectors)) {
+ printk(KERN_ERR "md/raid:%s: reshape position is"
+ " confused - aborting\n", mdname(mddev));
+ return -EINVAL;
+ }
/* We cannot be sure it is safe to start an in-place
- * reshape. It is only safe if user-space if monitoring
+ * reshape. It is only safe if user-space is monitoring
* and taking constant backups.
* mdadm always starts a situation like this in
* readonly mode so it can take control before
* allowing any writes. So just check for that.
*/
- if ((here_new * mddev->new_chunk_sectors !=
- here_old * mddev->chunk_sectors) ||
- mddev->ro == 0) {
- printk(KERN_ERR "md/raid:%s: in-place reshape must be started"
- " in read-only mode - aborting\n",
+ if (abs(min_offset_diff) >= mddev->chunk_sectors &&
+ abs(min_offset_diff) >= mddev->new_chunk_sectors)
+ /* not really in-place - so OK */;
+ else if (mddev->ro == 0) {
+ printk(KERN_ERR "md/raid:%s: in-place reshape "
+ "must be started in read-only mode "
+ "- aborting\n",
mdname(mddev));
return -EINVAL;
}
- } else if (mddev->delta_disks < 0
- ? (here_new * mddev->new_chunk_sectors <=
+ } else if (mddev->reshape_backwards
+ ? (here_new * mddev->new_chunk_sectors + min_offset_diff <=
here_old * mddev->chunk_sectors)
: (here_new * mddev->new_chunk_sectors >=
- here_old * mddev->chunk_sectors)) {
+ here_old * mddev->chunk_sectors + (-min_offset_diff))) {
/* Reading from the same stripe as writing to - bad */
printk(KERN_ERR "md/raid:%s: reshape_position too early for "
"auto-recovery - aborting.\n",
@@ -5037,6 +5118,7 @@ static int run(struct mddev *mddev)
if (IS_ERR(conf))
return PTR_ERR(conf);
+ conf->min_offset_diff = min_offset_diff;
mddev->thread = conf->thread;
conf->thread = NULL;
mddev->private = conf;
@@ -5182,9 +5264,12 @@ static int run(struct mddev *mddev)
blk_queue_io_opt(mddev->queue, chunk_size *
(conf->raid_disks - conf->max_degraded));
- rdev_for_each(rdev, mddev)
+ rdev_for_each(rdev, mddev) {
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->new_data_offset << 9);
+ }
}
return 0;
@@ -5418,12 +5503,18 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
+ sector_t newsize;
sectors &= ~((sector_t)mddev->chunk_sectors - 1);
- md_set_array_sectors(mddev, raid5_size(mddev, sectors,
- mddev->raid_disks));
- if (mddev->array_sectors >
- raid5_size(mddev, sectors, mddev->raid_disks))
+ newsize = raid5_size(mddev, sectors, mddev->raid_disks);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, sectors, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
@@ -5468,9 +5559,6 @@ static int check_reshape(struct mddev *mddev)
mddev->new_layout == mddev->layout &&
mddev->new_chunk_sectors == mddev->chunk_sectors)
return 0; /* nothing to do */
- if (mddev->bitmap)
- /* Cannot grow a bitmap yet */
- return -EBUSY;
if (has_failed(conf))
return -EINVAL;
if (mddev->delta_disks < 0) {
@@ -5505,10 +5593,14 @@ static int raid5_start_reshape(struct mddev *mddev)
if (!check_stripe_cache(mddev))
return -ENOSPC;
- rdev_for_each(rdev, mddev)
+ if (has_failed(conf))
+ return -EINVAL;
+
+ rdev_for_each(rdev, mddev) {
if (!test_bit(In_sync, &rdev->flags)
&& !test_bit(Faulty, &rdev->flags))
spares++;
+ }
if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
/* Not enough devices even to make a degraded array
@@ -5535,12 +5627,16 @@ static int raid5_start_reshape(struct mddev *mddev)
conf->chunk_sectors = mddev->new_chunk_sectors;
conf->prev_algo = conf->algorithm;
conf->algorithm = mddev->new_layout;
- if (mddev->delta_disks < 0)
+ conf->generation++;
+ /* Code that selects data_offset needs to see the generation update
+ * if reshape_progress has been set - so a memory barrier needed.
+ */
+ smp_mb();
+ if (mddev->reshape_backwards)
conf->reshape_progress = raid5_size(mddev, 0, 0);
else
conf->reshape_progress = 0;
conf->reshape_safe = conf->reshape_progress;
- conf->generation++;
spin_unlock_irq(&conf->device_lock);
/* Add some new drives, as many as will fit.
@@ -5592,6 +5688,9 @@ static int raid5_start_reshape(struct mddev *mddev)
mddev->recovery = 0;
spin_lock_irq(&conf->device_lock);
mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
+ smp_wmb();
conf->reshape_progress = MaxSector;
mddev->reshape_position = MaxSector;
spin_unlock_irq(&conf->device_lock);
@@ -5610,9 +5709,13 @@ static void end_reshape(struct r5conf *conf)
{
if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
+ struct md_rdev *rdev;
spin_lock_irq(&conf->device_lock);
conf->previous_raid_disks = conf->raid_disks;
+ rdev_for_each(rdev, conf->mddev)
+ rdev->data_offset = rdev->new_data_offset;
+ smp_wmb();
conf->reshape_progress = MaxSector;
spin_unlock_irq(&conf->device_lock);
wake_up(&conf->wait_for_overlap);
@@ -5652,17 +5755,18 @@ static void raid5_finish_reshape(struct mddev *mddev)
d < conf->raid_disks - mddev->delta_disks;
d++) {
struct md_rdev *rdev = conf->disks[d].rdev;
- if (rdev &&
- raid5_remove_disk(mddev, rdev) == 0) {
- sysfs_unlink_rdev(mddev, rdev);
- rdev->raid_disk = -1;
- }
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ rdev = conf->disks[d].replacement;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
}
}
mddev->layout = conf->algorithm;
mddev->chunk_sectors = conf->chunk_sectors;
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
}
}
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 8d8e139..2164021 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -285,6 +285,7 @@ enum r5dev_flags {
*/
R5_Wantdrain, /* dev->towrite needs to be drained */
R5_WantFUA, /* Write should be FUA */
+ R5_SyncIO, /* The IO is sync */
R5_WriteError, /* got a write error - need to record it */
R5_MadeGood, /* A bad block has been fixed by writing to it */
R5_ReadRepl, /* Will/did read from replacement rather than orig */
@@ -385,6 +386,12 @@ struct r5conf {
short generation; /* increments with every reshape */
unsigned long reshape_checkpoint; /* Time we last updated
* metadata */
+ long long min_offset_diff; /* minimum difference between
+ * data_offset and
+ * new_data_offset across all
+ * devices. May be negative,
+ * but is closest to zero.
+ */
struct list_head handle_list; /* stripes needing handling */
struct list_head hold_list; /* preread ready stripes */
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index e6601b8..b579730 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1376,7 +1376,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
ARRAY_SIZE(ov562x_init_2));
reg_w(gspca_dev, 0xe0, 0x00);
} else {
- err("Unknown sensor %04x", sensor_id);
+ pr_err("Unknown sensor %04x", sensor_id);
return -EINVAL;
}
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 6510110..304f43e 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -303,7 +303,7 @@ static int hdpvr_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
@@ -311,7 +311,7 @@ static int hdpvr_probe(struct usb_interface *interface,
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
- err("v4l2_device_register failed");
+ dev_err(&interface->dev, "v4l2_device_register failed\n");
goto error;
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
new file mode 100644
index 0000000..067f311
--- /dev/null
+++ b/drivers/memory/Kconfig
@@ -0,0 +1,43 @@
+#
+# Memory devices
+#
+
+menuconfig MEMORY
+ bool "Memory Controller drivers"
+
+if MEMORY
+
+config TI_EMIF
+ tristate "Texas Instruments EMIF driver"
+ depends on ARCH_OMAP2PLUS
+ select DDR
+ help
+ This driver is for the EMIF module available in Texas Instruments
+ SoCs. EMIF is an SDRAM controller that, based on its revision,
+ supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+ This driver takes care of only LPDDR2 memories presently. The
+ functions of the driver includes re-configuring AC timing
+ parameters and other settings during frequency, voltage and
+ temperature changes
+
+config TEGRA20_MC
+ bool "Tegra20 Memory Controller(MC) driver"
+ default y
+ depends on ARCH_TEGRA_2x_SOC
+ help
+ This driver is for the Memory Controller(MC) module available
+ in Tegra20 SoCs, mainly for a address translation fault
+ analysis, especially for IOMMU/GART(Graphics Address
+ Relocation Table) module.
+
+config TEGRA30_MC
+ bool "Tegra30 Memory Controller(MC) driver"
+ default y
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ This driver is for the Memory Controller(MC) module available
+ in Tegra30 SoCs, mainly for a address translation fault
+ analysis, especially for IOMMU/SMMU(System Memory Management
+ Unit) module.
+
+endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
new file mode 100644
index 0000000..42b3ce9
--- /dev/null
+++ b/drivers/memory/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for memory devices
+#
+
+obj-$(CONFIG_TI_EMIF) += emif.o
+obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
+obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
new file mode 100644
index 0000000..33a4396
--- /dev/null
+++ b/drivers/memory/emif.c
@@ -0,0 +1,1670 @@
+/*
+ * EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.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/reboot.h>
+#include <linux/platform_data/emif_plat.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <memory/jedec_ddr.h>
+#include "emif.h"
+
+/**
+ * struct emif_data - Per device static data for driver's use
+ * @duplicate: Whether the DDR devices attached to this EMIF
+ * instance are exactly same as that on EMIF1. In
+ * this case we can save some memory and processing
+ * @temperature_level: Maximum temperature of LPDDR2 devices attached
+ * to this EMIF - read from MR4 register. If there
+ * are two devices attached to this EMIF, this
+ * value is the maximum of the two temperature
+ * levels.
+ * @node: node in the device list
+ * @base: base address of memory-mapped IO registers.
+ * @dev: device pointer.
+ * @addressing table with addressing information from the spec
+ * @regs_cache: An array of 'struct emif_regs' that stores
+ * calculated register values for different
+ * frequencies, to avoid re-calculating them on
+ * each DVFS transition.
+ * @curr_regs: The set of register values used in the last
+ * frequency change (i.e. corresponding to the
+ * frequency in effect at the moment)
+ * @plat_data: Pointer to saved platform data.
+ * @debugfs_root: dentry to the root folder for EMIF in debugfs
+ */
+struct emif_data {
+ u8 duplicate;
+ u8 temperature_level;
+ u8 lpmode;
+ struct list_head node;
+ unsigned long irq_state;
+ void __iomem *base;
+ struct device *dev;
+ const struct lpddr2_addressing *addressing;
+ struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
+ struct emif_regs *curr_regs;
+ struct emif_platform_data *plat_data;
+ struct dentry *debugfs_root;
+};
+
+static struct emif_data *emif1;
+static spinlock_t emif_lock;
+static unsigned long irq_state;
+static u32 t_ck; /* DDR clock period in ps */
+static LIST_HEAD(device_list);
+
+static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
+ struct emif_regs *regs)
+{
+ u32 type = emif->plat_data->device_info->type;
+ u32 ip_rev = emif->plat_data->ip_rev;
+
+ seq_printf(s, "EMIF register cache dump for %dMHz\n",
+ regs->freq/1000000);
+
+ seq_printf(s, "ref_ctrl_shdw\t: 0x%08x\n", regs->ref_ctrl_shdw);
+ seq_printf(s, "sdram_tim1_shdw\t: 0x%08x\n", regs->sdram_tim1_shdw);
+ seq_printf(s, "sdram_tim2_shdw\t: 0x%08x\n", regs->sdram_tim2_shdw);
+ seq_printf(s, "sdram_tim3_shdw\t: 0x%08x\n", regs->sdram_tim3_shdw);
+
+ if (ip_rev == EMIF_4D) {
+ seq_printf(s, "read_idle_ctrl_shdw_normal\t: 0x%08x\n",
+ regs->read_idle_ctrl_shdw_normal);
+ seq_printf(s, "read_idle_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+ regs->read_idle_ctrl_shdw_volt_ramp);
+ } else if (ip_rev == EMIF_4D5) {
+ seq_printf(s, "dll_calib_ctrl_shdw_normal\t: 0x%08x\n",
+ regs->dll_calib_ctrl_shdw_normal);
+ seq_printf(s, "dll_calib_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+ regs->dll_calib_ctrl_shdw_volt_ramp);
+ }
+
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+ seq_printf(s, "ref_ctrl_shdw_derated\t: 0x%08x\n",
+ regs->ref_ctrl_shdw_derated);
+ seq_printf(s, "sdram_tim1_shdw_derated\t: 0x%08x\n",
+ regs->sdram_tim1_shdw_derated);
+ seq_printf(s, "sdram_tim3_shdw_derated\t: 0x%08x\n",
+ regs->sdram_tim3_shdw_derated);
+ }
+}
+
+static int emif_regdump_show(struct seq_file *s, void *unused)
+{
+ struct emif_data *emif = s->private;
+ struct emif_regs **regs_cache;
+ int i;
+
+ if (emif->duplicate)
+ regs_cache = emif1->regs_cache;
+ else
+ regs_cache = emif->regs_cache;
+
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+ do_emif_regdump_show(s, emif, regs_cache[i]);
+ seq_printf(s, "\n");
+ }
+
+ return 0;
+}
+
+static int emif_regdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, emif_regdump_show, inode->i_private);
+}
+
+static const struct file_operations emif_regdump_fops = {
+ .open = emif_regdump_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static int emif_mr4_show(struct seq_file *s, void *unused)
+{
+ struct emif_data *emif = s->private;
+
+ seq_printf(s, "MR4=%d\n", emif->temperature_level);
+ return 0;
+}
+
+static int emif_mr4_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, emif_mr4_show, inode->i_private);
+}
+
+static const struct file_operations emif_mr4_fops = {
+ .open = emif_mr4_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static int __init_or_module emif_debugfs_init(struct emif_data *emif)
+{
+ struct dentry *dentry;
+ int ret;
+
+ dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err0;
+ }
+ emif->debugfs_root = dentry;
+
+ dentry = debugfs_create_file("regcache_dump", S_IRUGO,
+ emif->debugfs_root, emif, &emif_regdump_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err1;
+ }
+
+ dentry = debugfs_create_file("mr4", S_IRUGO,
+ emif->debugfs_root, emif, &emif_mr4_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err1;
+ }
+
+ return 0;
+err1:
+ debugfs_remove_recursive(emif->debugfs_root);
+err0:
+ return ret;
+}
+
+static void __exit emif_debugfs_exit(struct emif_data *emif)
+{
+ debugfs_remove_recursive(emif->debugfs_root);
+ emif->debugfs_root = NULL;
+}
+
+/*
+ * Calculate the period of DDR clock from frequency value
+ */
+static void set_ddr_clk_period(u32 freq)
+{
+ /* Divide 10^12 by frequency to get period in ps */
+ t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq);
+}
+
+/*
+ * Get bus width used by EMIF. Note that this may be different from the
+ * bus width of the DDR devices used. For instance two 16-bit DDR devices
+ * may be connected to a given CS of EMIF. In this case bus width as far
+ * as EMIF is concerned is 32, where as the DDR bus width is 16 bits.
+ */
+static u32 get_emif_bus_width(struct emif_data *emif)
+{
+ u32 width;
+ void __iomem *base = emif->base;
+
+ width = (readl(base + EMIF_SDRAM_CONFIG) & NARROW_MODE_MASK)
+ >> NARROW_MODE_SHIFT;
+ width = width == 0 ? 32 : 16;
+
+ return width;
+}
+
+/*
+ * Get the CL from SDRAM_CONFIG register
+ */
+static u32 get_cl(struct emif_data *emif)
+{
+ u32 cl;
+ void __iomem *base = emif->base;
+
+ cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT;
+
+ return cl;
+}
+
+static void set_lpmode(struct emif_data *emif, u8 lpmode)
+{
+ u32 temp;
+ void __iomem *base = emif->base;
+
+ temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
+ temp &= ~LP_MODE_MASK;
+ temp |= (lpmode << LP_MODE_SHIFT);
+ writel(temp, base + EMIF_POWER_MANAGEMENT_CONTROL);
+}
+
+static void do_freq_update(void)
+{
+ struct emif_data *emif;
+
+ /*
+ * Workaround for errata i728: Disable LPMODE during FREQ_UPDATE
+ *
+ * i728 DESCRIPTION:
+ * The EMIF automatically puts the SDRAM into self-refresh mode
+ * after the EMIF has not performed accesses during
+ * EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM number of DDR clock cycles
+ * and the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set
+ * to 0x2. If during a small window the following three events
+ * occur:
+ * - The SR_TIMING counter expires
+ * - And frequency change is requested
+ * - And OCP access is requested
+ * Then it causes instable clock on the DDR interface.
+ *
+ * WORKAROUND
+ * To avoid the occurrence of the three events, the workaround
+ * is to disable the self-refresh when requesting a frequency
+ * change. Before requesting a frequency change the software must
+ * program EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0. When the
+ * frequency change has been done, the software can reprogram
+ * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2
+ */
+ list_for_each_entry(emif, &device_list, node) {
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+ }
+
+ /*
+ * TODO: Do FREQ_UPDATE here when an API
+ * is available for this as part of the new
+ * clock framework
+ */
+
+ list_for_each_entry(emif, &device_list, node) {
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+ }
+}
+
+/* Find addressing table entry based on the device's type and density */
+static const struct lpddr2_addressing *get_addressing_table(
+ const struct ddr_device_info *device_info)
+{
+ u32 index, type, density;
+
+ type = device_info->type;
+ density = device_info->density;
+
+ switch (type) {
+ case DDR_TYPE_LPDDR2_S4:
+ index = density - 1;
+ break;
+ case DDR_TYPE_LPDDR2_S2:
+ switch (density) {
+ case DDR_DENSITY_1Gb:
+ case DDR_DENSITY_2Gb:
+ index = density + 3;
+ break;
+ default:
+ index = density - 1;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return &lpddr2_jedec_addressing_table[index];
+}
+
+/*
+ * Find the the right timing table from the array of timing
+ * tables of the device using DDR clock frequency
+ */
+static const struct lpddr2_timings *get_timings_table(struct emif_data *emif,
+ u32 freq)
+{
+ u32 i, min, max, freq_nearest;
+ const struct lpddr2_timings *timings = NULL;
+ const struct lpddr2_timings *timings_arr = emif->plat_data->timings;
+ struct device *dev = emif->dev;
+
+ /* Start with a very high frequency - 1GHz */
+ freq_nearest = 1000000000;
+
+ /*
+ * Find the timings table such that:
+ * 1. the frequency range covers the required frequency(safe) AND
+ * 2. the max_freq is closest to the required frequency(optimal)
+ */
+ for (i = 0; i < emif->plat_data->timings_arr_size; i++) {
+ max = timings_arr[i].max_freq;
+ min = timings_arr[i].min_freq;
+ if ((freq >= min) && (freq <= max) && (max < freq_nearest)) {
+ freq_nearest = max;
+ timings = &timings_arr[i];
+ }
+ }
+
+ if (!timings)
+ dev_err(dev, "%s: couldn't find timings for - %dHz\n",
+ __func__, freq);
+
+ dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n",
+ __func__, freq, freq_nearest);
+
+ return timings;
+}
+
+static u32 get_sdram_ref_ctrl_shdw(u32 freq,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi;
+
+ /* Scale down frequency and t_refi to avoid overflow */
+ freq_khz = freq / 1000;
+ t_refi = addressing->tREFI_ns / 100;
+
+ /*
+ * refresh rate to be set is 'tREFI(in us) * freq in MHz
+ * division by 10000 to account for change in units
+ */
+ val = t_refi * freq_khz / 10000;
+ ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT;
+
+ return ref_ctrl_shdw;
+}
+
+static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim1 = 0, val = 0;
+
+ val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+ tim1 |= val << T_WTR_SHIFT;
+
+ if (addressing->num_banks == B8)
+ val = DIV_ROUND_UP(timings->tFAW, t_ck*4);
+ else
+ val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck));
+ tim1 |= (val - 1) << T_RRD_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1;
+ tim1 |= val << T_RC_SHIFT;
+
+ val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck));
+ tim1 |= (val - 1) << T_RAS_SHIFT;
+
+ val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+ tim1 |= val << T_WR_SHIFT;
+
+ val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1;
+ tim1 |= val << T_RCD_SHIFT;
+
+ val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1;
+ tim1 |= val << T_RP_SHIFT;
+
+ return tim1;
+}
+
+static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim1 = 0, val = 0;
+
+ val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+ tim1 = val << T_WTR_SHIFT;
+
+ /*
+ * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps
+ * to tFAW for de-rating
+ */
+ if (addressing->num_banks == B8) {
+ val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1;
+ } else {
+ val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck);
+ val = max(min_tck->tRRD, val) - 1;
+ }
+ tim1 |= val << T_RRD_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck);
+ tim1 |= (val - 1) << T_RC_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck);
+ val = max(min_tck->tRASmin, val) - 1;
+ tim1 |= val << T_RAS_SHIFT;
+
+ val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+ tim1 |= val << T_WR_SHIFT;
+
+ val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck));
+ tim1 |= (val - 1) << T_RCD_SHIFT;
+
+ val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck));
+ tim1 |= (val - 1) << T_RP_SHIFT;
+
+ return tim1;
+}
+
+static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing,
+ u32 type)
+{
+ u32 tim2 = 0, val = 0;
+
+ val = min_tck->tCKE - 1;
+ tim2 |= val << T_CKE_SHIFT;
+
+ val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1;
+ tim2 |= val << T_RTP_SHIFT;
+
+ /* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */
+ val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1;
+ tim2 |= val << T_XSNR_SHIFT;
+
+ /* XSRD same as XSNR for LPDDR2 */
+ tim2 |= val << T_XSRD_SHIFT;
+
+ val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1;
+ tim2 |= val << T_XP_SHIFT;
+
+ return tim2;
+}
+
+static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing,
+ u32 type, u32 ip_rev, u32 derated)
+{
+ u32 tim3 = 0, val = 0, t_dqsck;
+
+ val = timings->tRAS_max_ns / addressing->tREFI_ns - 1;
+ val = val > 0xF ? 0xF : val;
+ tim3 |= val << T_RAS_MAX_SHIFT;
+
+ val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1;
+ tim3 |= val << T_RFC_SHIFT;
+
+ t_dqsck = (derated == EMIF_DERATED_TIMINGS) ?
+ timings->tDQSCK_max_derated : timings->tDQSCK_max;
+ if (ip_rev == EMIF_4D5)
+ val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1;
+ else
+ val = DIV_ROUND_UP(t_dqsck, t_ck) - 1;
+
+ tim3 |= val << T_TDQSCKMAX_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1;
+ tim3 |= val << ZQ_ZQCS_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tCKESR, t_ck);
+ val = max(min_tck->tCKESR, val) - 1;
+ tim3 |= val << T_CKESR_SHIFT;
+
+ if (ip_rev == EMIF_4D5) {
+ tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT;
+
+ val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1;
+ tim3 |= val << T_PDLL_UL_SHIFT;
+ }
+
+ return tim3;
+}
+
+static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing,
+ bool cs1_used, bool cal_resistors_per_cs)
+{
+ u32 zq = 0, val = 0;
+
+ val = EMIF_ZQCS_INTERVAL_US * 1000 / addressing->tREFI_ns;
+ zq |= val << ZQ_REFINTERVAL_SHIFT;
+
+ val = DIV_ROUND_UP(T_ZQCL_DEFAULT_NS, T_ZQCS_DEFAULT_NS) - 1;
+ zq |= val << ZQ_ZQCL_MULT_SHIFT;
+
+ val = DIV_ROUND_UP(T_ZQINIT_DEFAULT_NS, T_ZQCL_DEFAULT_NS) - 1;
+ zq |= val << ZQ_ZQINIT_MULT_SHIFT;
+
+ zq |= ZQ_SFEXITEN_ENABLE << ZQ_SFEXITEN_SHIFT;
+
+ if (cal_resistors_per_cs)
+ zq |= ZQ_DUALCALEN_ENABLE << ZQ_DUALCALEN_SHIFT;
+ else
+ zq |= ZQ_DUALCALEN_DISABLE << ZQ_DUALCALEN_SHIFT;
+
+ zq |= ZQ_CS0EN_MASK; /* CS0 is used for sure */
+
+ val = cs1_used ? 1 : 0;
+ zq |= val << ZQ_CS1EN_SHIFT;
+
+ return zq;
+}
+
+static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing,
+ const struct emif_custom_configs *custom_configs, bool cs1_used,
+ u32 sdram_io_width, u32 emif_bus_width)
+{
+ u32 alert = 0, interval, devcnt;
+
+ if (custom_configs && (custom_configs->mask &
+ EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL))
+ interval = custom_configs->temp_alert_poll_interval_ms;
+ else
+ interval = TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS;
+
+ interval *= 1000000; /* Convert to ns */
+ interval /= addressing->tREFI_ns; /* Convert to refresh cycles */
+ alert |= (interval << TA_REFINTERVAL_SHIFT);
+
+ /*
+ * sdram_io_width is in 'log2(x) - 1' form. Convert emif_bus_width
+ * also to this form and subtract to get TA_DEVCNT, which is
+ * in log2(x) form.
+ */
+ emif_bus_width = __fls(emif_bus_width) - 1;
+ devcnt = emif_bus_width - sdram_io_width;
+ alert |= devcnt << TA_DEVCNT_SHIFT;
+
+ /* DEVWDT is in 'log2(x) - 3' form */
+ alert |= (sdram_io_width - 2) << TA_DEVWDT_SHIFT;
+
+ alert |= 1 << TA_SFEXITEN_SHIFT;
+ alert |= 1 << TA_CS0EN_SHIFT;
+ alert |= (cs1_used ? 1 : 0) << TA_CS1EN_SHIFT;
+
+ return alert;
+}
+
+static u32 get_read_idle_ctrl_shdw(u8 volt_ramp)
+{
+ u32 idle = 0, val = 0;
+
+ /*
+ * Maximum value in normal conditions and increased frequency
+ * when voltage is ramping
+ */
+ if (volt_ramp)
+ val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1;
+ else
+ val = 0x1FF;
+
+ /*
+ * READ_IDLE_CTRL register in EMIF4D has same offset and fields
+ * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts
+ */
+ idle |= val << DLL_CALIB_INTERVAL_SHIFT;
+ idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT;
+
+ return idle;
+}
+
+static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp)
+{
+ u32 calib = 0, val = 0;
+
+ if (volt_ramp == DDR_VOLTAGE_RAMPING)
+ val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1;
+ else
+ val = 0; /* Disabled when voltage is stable */
+
+ calib |= val << DLL_CALIB_INTERVAL_SHIFT;
+ calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT;
+
+ return calib;
+}
+
+static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings,
+ u32 freq, u8 RL)
+{
+ u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0;
+
+ val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1;
+ phy |= val << READ_LATENCY_SHIFT_4D;
+
+ if (freq <= 100000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY;
+ else if (freq <= 200000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY;
+ else
+ val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY;
+
+ phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D;
+
+ return phy;
+}
+
+static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl)
+{
+ u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay;
+
+ /*
+ * DLL operates at 266 MHz. If DDR frequency is near 266 MHz,
+ * half-delay is not needed else set half-delay
+ */
+ if (freq >= 265000000 && freq < 267000000)
+ half_delay = 0;
+ else
+ half_delay = 1;
+
+ phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5;
+ phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS,
+ t_ck) - 1) << READ_LATENCY_SHIFT_4D5);
+
+ return phy;
+}
+
+static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 |
+ fifo_we_slave_ratio << 22;
+}
+
+static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 |
+ fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23;
+}
+
+static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 |
+ fifo_we_slave_ratio << 13;
+}
+
+static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
+{
+ u32 pwr_mgmt_ctrl = 0, timeout;
+ u32 lpmode = EMIF_LP_MODE_SELF_REFRESH;
+ u32 timeout_perf = EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
+ u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER;
+ u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD;
+
+ struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
+
+ if (cust_cfgs && (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE)) {
+ lpmode = cust_cfgs->lpmode;
+ timeout_perf = cust_cfgs->lpmode_timeout_performance;
+ timeout_pwr = cust_cfgs->lpmode_timeout_power;
+ freq_threshold = cust_cfgs->lpmode_freq_threshold;
+ }
+
+ /* Timeout based on DDR frequency */
+ timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
+
+ /* The value to be set in register is "log2(timeout) - 3" */
+ if (timeout < 16) {
+ timeout = 0;
+ } else {
+ timeout = __fls(timeout) - 3;
+ if (timeout & (timeout - 1))
+ timeout++;
+ }
+
+ switch (lpmode) {
+ case EMIF_LP_MODE_CLOCK_STOP:
+ pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
+ SR_TIM_MASK | PD_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_SELF_REFRESH:
+ /* Workaround for errata i735 */
+ if (timeout < 6)
+ timeout = 6;
+
+ pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
+ CS_TIM_MASK | PD_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_PWR_DN:
+ pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
+ CS_TIM_MASK | SR_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_DISABLE:
+ default:
+ pwr_mgmt_ctrl = CS_TIM_MASK |
+ PD_TIM_MASK | SR_TIM_MASK;
+ }
+
+ /* No CS_TIM in EMIF_4D5 */
+ if (ip_rev == EMIF_4D5)
+ pwr_mgmt_ctrl &= ~CS_TIM_MASK;
+
+ pwr_mgmt_ctrl |= lpmode << LP_MODE_SHIFT;
+
+ return pwr_mgmt_ctrl;
+}
+
+/*
+ * Get the temperature level of the EMIF instance:
+ * Reads the MR4 register of attached SDRAM parts to find out the temperature
+ * level. If there are two parts attached(one on each CS), then the temperature
+ * level for the EMIF instance is the higher of the two temperatures.
+ */
+static void get_temperature_level(struct emif_data *emif)
+{
+ u32 temp, temperature_level;
+ void __iomem *base;
+
+ base = emif->base;
+
+ /* Read mode register 4 */
+ writel(DDR_MR4, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+ temperature_level = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+ temperature_level = (temperature_level & MR4_SDRAM_REF_RATE_MASK) >>
+ MR4_SDRAM_REF_RATE_SHIFT;
+
+ if (emif->plat_data->device_info->cs1_used) {
+ writel(DDR_MR4 | CS_MASK, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+ temp = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+ temp = (temp & MR4_SDRAM_REF_RATE_MASK)
+ >> MR4_SDRAM_REF_RATE_SHIFT;
+ temperature_level = max(temp, temperature_level);
+ }
+
+ /* treat everything less than nominal(3) in MR4 as nominal */
+ if (unlikely(temperature_level < SDRAM_TEMP_NOMINAL))
+ temperature_level = SDRAM_TEMP_NOMINAL;
+
+ /* if we get reserved value in MR4 persist with the existing value */
+ if (likely(temperature_level != SDRAM_TEMP_RESERVED_4))
+ emif->temperature_level = temperature_level;
+}
+
+/*
+ * Program EMIF shadow registers that are not dependent on temperature
+ * or voltage
+ */
+static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
+{
+ void __iomem *base = emif->base;
+
+ writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
+ writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+
+ /* Settings specific for EMIF4D5 */
+ if (emif->plat_data->ip_rev != EMIF_4D5)
+ return;
+ writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW);
+ writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW);
+ writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW);
+}
+
+/*
+ * When voltage ramps dll calibration and forced read idle should
+ * happen more often
+ */
+static void setup_volt_sensitive_regs(struct emif_data *emif,
+ struct emif_regs *regs, u32 volt_state)
+{
+ u32 calib_ctrl;
+ void __iomem *base = emif->base;
+
+ /*
+ * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as
+ * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_*
+ * is an alias of the respective read_idle_ctrl_shdw_* (members of
+ * a union). So, the below code takes care of both cases
+ */
+ if (volt_state == DDR_VOLTAGE_RAMPING)
+ calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp;
+ else
+ calib_ctrl = regs->dll_calib_ctrl_shdw_normal;
+
+ writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW);
+}
+
+/*
+ * setup_temperature_sensitive_regs() - set the timings for temperature
+ * sensitive registers. This happens once at initialisation time based
+ * on the temperature at boot time and subsequently based on the temperature
+ * alert interrupt. Temperature alert can happen when the temperature
+ * increases or drops. So this function can have the effect of either
+ * derating the timings or going back to nominal values.
+ */
+static void setup_temperature_sensitive_regs(struct emif_data *emif,
+ struct emif_regs *regs)
+{
+ u32 tim1, tim3, ref_ctrl, type;
+ void __iomem *base = emif->base;
+ u32 temperature;
+
+ type = emif->plat_data->device_info->type;
+
+ tim1 = regs->sdram_tim1_shdw;
+ tim3 = regs->sdram_tim3_shdw;
+ ref_ctrl = regs->ref_ctrl_shdw;
+
+ /* No de-rating for non-lpddr2 devices */
+ if (type != DDR_TYPE_LPDDR2_S2 && type != DDR_TYPE_LPDDR2_S4)
+ goto out;
+
+ temperature = emif->temperature_level;
+ if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH) {
+ ref_ctrl = regs->ref_ctrl_shdw_derated;
+ } else if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS) {
+ tim1 = regs->sdram_tim1_shdw_derated;
+ tim3 = regs->sdram_tim3_shdw_derated;
+ ref_ctrl = regs->ref_ctrl_shdw_derated;
+ }
+
+out:
+ writel(tim1, base + EMIF_SDRAM_TIMING_1_SHDW);
+ writel(tim3, base + EMIF_SDRAM_TIMING_3_SHDW);
+ writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW);
+}
+
+static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
+{
+ u32 old_temp_level;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+ old_temp_level = emif->temperature_level;
+ get_temperature_level(emif);
+
+ if (unlikely(emif->temperature_level == old_temp_level)) {
+ goto out;
+ } else if (!emif->curr_regs) {
+ dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+ goto out;
+ }
+
+ if (emif->temperature_level < old_temp_level ||
+ emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+ /*
+ * Temperature coming down - defer handling to thread OR
+ * Temperature far too high - do kernel_power_off() from
+ * thread context
+ */
+ ret = IRQ_WAKE_THREAD;
+ } else {
+ /* Temperature is going up - handle immediately */
+ setup_temperature_sensitive_regs(emif, emif->curr_regs);
+ do_freq_update();
+ }
+
+out:
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+ return ret;
+}
+
+static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
+{
+ u32 interrupts;
+ struct emif_data *emif = dev_id;
+ void __iomem *base = emif->base;
+ struct device *dev = emif->dev;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ /* Save the status and clear it */
+ interrupts = readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+ writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+
+ /*
+ * Handle temperature alert
+ * Temperature alert should be same for all ports
+ * So, it's enough to process it only for one of the ports
+ */
+ if (interrupts & TA_SYS_MASK)
+ ret = handle_temp_alert(base, emif);
+
+ if (interrupts & ERR_SYS_MASK)
+ dev_err(dev, "Access error from SYS port - %x\n", interrupts);
+
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+ /* Save the status and clear it */
+ interrupts = readl(base + EMIF_LL_OCP_INTERRUPT_STATUS);
+ writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_STATUS);
+
+ if (interrupts & ERR_LL_MASK)
+ dev_err(dev, "Access error from LL port - %x\n",
+ interrupts);
+ }
+
+ return ret;
+}
+
+static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
+{
+ struct emif_data *emif = dev_id;
+
+ if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+ dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+ kernel_power_off();
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ if (emif->curr_regs) {
+ setup_temperature_sensitive_regs(emif, emif->curr_regs);
+ do_freq_update();
+ } else {
+ dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+ }
+
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+
+ return IRQ_HANDLED;
+}
+
+static void clear_all_interrupts(struct emif_data *emif)
+{
+ void __iomem *base = emif->base;
+
+ writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS),
+ base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+ writel(readl(base + EMIF_LL_OCP_INTERRUPT_STATUS),
+ base + EMIF_LL_OCP_INTERRUPT_STATUS);
+}
+
+static void disable_and_clear_all_interrupts(struct emif_data *emif)
+{
+ void __iomem *base = emif->base;
+
+ /* Disable all interrupts */
+ writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET),
+ base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR);
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+ writel(readl(base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET),
+ base + EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR);
+
+ /* Clear all interrupts */
+ clear_all_interrupts(emif);
+}
+
+static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
+{
+ u32 interrupts, type;
+ void __iomem *base = emif->base;
+
+ type = emif->plat_data->device_info->type;
+
+ clear_all_interrupts(emif);
+
+ /* Enable interrupts for SYS interface */
+ interrupts = EN_ERR_SYS_MASK;
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4)
+ interrupts |= EN_TA_SYS_MASK;
+ writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET);
+
+ /* Enable interrupts for LL interface */
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+ /* TA need not be enabled for LL */
+ interrupts = EN_ERR_LL_MASK;
+ writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET);
+ }
+
+ /* setup IRQ handlers */
+ return devm_request_threaded_irq(emif->dev, irq,
+ emif_interrupt_handler,
+ emif_threaded_isr,
+ 0, dev_name(emif->dev),
+ emif);
+
+}
+
+static void __init_or_module emif_onetime_settings(struct emif_data *emif)
+{
+ u32 pwr_mgmt_ctrl, zq, temp_alert_cfg;
+ void __iomem *base = emif->base;
+ const struct lpddr2_addressing *addressing;
+ const struct ddr_device_info *device_info;
+
+ device_info = emif->plat_data->device_info;
+ addressing = get_addressing_table(device_info);
+
+ /*
+ * Init power management settings
+ * We don't know the frequency yet. Use a high frequency
+ * value for a conservative timeout setting
+ */
+ pwr_mgmt_ctrl = get_pwr_mgmt_ctrl(1000000000, emif,
+ emif->plat_data->ip_rev);
+ emif->lpmode = (pwr_mgmt_ctrl & LP_MODE_MASK) >> LP_MODE_SHIFT;
+ writel(pwr_mgmt_ctrl, base + EMIF_POWER_MANAGEMENT_CONTROL);
+
+ /* Init ZQ calibration settings */
+ zq = get_zq_config_reg(addressing, device_info->cs1_used,
+ device_info->cal_resistors_per_cs);
+ writel(zq, base + EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG);
+
+ /* Check temperature level temperature level*/
+ get_temperature_level(emif);
+ if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN)
+ dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+
+ /* Init temperature polling */
+ temp_alert_cfg = get_temp_alert_config(addressing,
+ emif->plat_data->custom_configs, device_info->cs1_used,
+ device_info->io_width, get_emif_bus_width(emif));
+ writel(temp_alert_cfg, base + EMIF_TEMPERATURE_ALERT_CONFIG);
+
+ /*
+ * Program external PHY control registers that are not frequency
+ * dependent
+ */
+ if (emif->plat_data->phy_type != EMIF_PHY_TYPE_INTELLIPHY)
+ return;
+ writel(EMIF_EXT_PHY_CTRL_1_VAL, base + EMIF_EXT_PHY_CTRL_1_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_5_VAL, base + EMIF_EXT_PHY_CTRL_5_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_6_VAL, base + EMIF_EXT_PHY_CTRL_6_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_7_VAL, base + EMIF_EXT_PHY_CTRL_7_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_8_VAL, base + EMIF_EXT_PHY_CTRL_8_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_9_VAL, base + EMIF_EXT_PHY_CTRL_9_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_10_VAL, base + EMIF_EXT_PHY_CTRL_10_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_11_VAL, base + EMIF_EXT_PHY_CTRL_11_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_12_VAL, base + EMIF_EXT_PHY_CTRL_12_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_13_VAL, base + EMIF_EXT_PHY_CTRL_13_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_14_VAL, base + EMIF_EXT_PHY_CTRL_14_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_15_VAL, base + EMIF_EXT_PHY_CTRL_15_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_16_VAL, base + EMIF_EXT_PHY_CTRL_16_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_17_VAL, base + EMIF_EXT_PHY_CTRL_17_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_18_VAL, base + EMIF_EXT_PHY_CTRL_18_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_19_VAL, base + EMIF_EXT_PHY_CTRL_19_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_20_VAL, base + EMIF_EXT_PHY_CTRL_20_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_21_VAL, base + EMIF_EXT_PHY_CTRL_21_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_22_VAL, base + EMIF_EXT_PHY_CTRL_22_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_23_VAL, base + EMIF_EXT_PHY_CTRL_23_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_24_VAL, base + EMIF_EXT_PHY_CTRL_24_SHDW);
+}
+
+static void get_default_timings(struct emif_data *emif)
+{
+ struct emif_platform_data *pd = emif->plat_data;
+
+ pd->timings = lpddr2_jedec_timings;
+ pd->timings_arr_size = ARRAY_SIZE(lpddr2_jedec_timings);
+
+ dev_warn(emif->dev, "%s: using default timings\n", __func__);
+}
+
+static int is_dev_data_valid(u32 type, u32 density, u32 io_width, u32 phy_type,
+ u32 ip_rev, struct device *dev)
+{
+ int valid;
+
+ valid = (type == DDR_TYPE_LPDDR2_S4 ||
+ type == DDR_TYPE_LPDDR2_S2)
+ && (density >= DDR_DENSITY_64Mb
+ && density <= DDR_DENSITY_8Gb)
+ && (io_width >= DDR_IO_WIDTH_8
+ && io_width <= DDR_IO_WIDTH_32);
+
+ /* Combinations of EMIF and PHY revisions that we support today */
+ switch (ip_rev) {
+ case EMIF_4D:
+ valid = valid && (phy_type == EMIF_PHY_TYPE_ATTILAPHY);
+ break;
+ case EMIF_4D5:
+ valid = valid && (phy_type == EMIF_PHY_TYPE_INTELLIPHY);
+ break;
+ default:
+ valid = 0;
+ }
+
+ if (!valid)
+ dev_err(dev, "%s: invalid DDR details\n", __func__);
+ return valid;
+}
+
+static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
+ struct device *dev)
+{
+ int valid = 1;
+
+ if ((cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE) &&
+ (cust_cfgs->lpmode != EMIF_LP_MODE_DISABLE))
+ valid = cust_cfgs->lpmode_freq_threshold &&
+ cust_cfgs->lpmode_timeout_performance &&
+ cust_cfgs->lpmode_timeout_power;
+
+ if (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL)
+ valid = valid && cust_cfgs->temp_alert_poll_interval_ms;
+
+ if (!valid)
+ dev_warn(dev, "%s: invalid custom configs\n", __func__);
+
+ return valid;
+}
+
+static struct emif_data *__init_or_module get_device_details(
+ struct platform_device *pdev)
+{
+ u32 size;
+ struct emif_data *emif = NULL;
+ struct ddr_device_info *dev_info;
+ struct emif_custom_configs *cust_cfgs;
+ struct emif_platform_data *pd;
+ struct device *dev;
+ void *temp;
+
+ pd = pdev->dev.platform_data;
+ dev = &pdev->dev;
+
+ if (!(pd && pd->device_info && is_dev_data_valid(pd->device_info->type,
+ pd->device_info->density, pd->device_info->io_width,
+ pd->phy_type, pd->ip_rev, dev))) {
+ dev_err(dev, "%s: invalid device data\n", __func__);
+ goto error;
+ }
+
+ emif = devm_kzalloc(dev, sizeof(*emif), GFP_KERNEL);
+ temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
+
+ if (!emif || !pd || !dev_info) {
+ dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
+ goto error;
+ }
+
+ memcpy(temp, pd, sizeof(*pd));
+ pd = temp;
+ memcpy(dev_info, pd->device_info, sizeof(*dev_info));
+
+ pd->device_info = dev_info;
+ emif->plat_data = pd;
+ emif->dev = dev;
+ emif->temperature_level = SDRAM_TEMP_NOMINAL;
+
+ /*
+ * For EMIF instances other than EMIF1 see if the devices connected
+ * are exactly same as on EMIF1(which is typically the case). If so,
+ * mark it as a duplicate of EMIF1 and skip copying timings data.
+ * This will save some memory and some computation later.
+ */
+ emif->duplicate = emif1 && (memcmp(dev_info,
+ emif1->plat_data->device_info,
+ sizeof(struct ddr_device_info)) == 0);
+
+ if (emif->duplicate) {
+ pd->timings = NULL;
+ pd->min_tck = NULL;
+ goto out;
+ } else if (emif1) {
+ dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
+ __func__);
+ }
+
+ /*
+ * Copy custom configs - ignore allocation error, if any, as
+ * custom_configs is not very critical
+ */
+ cust_cfgs = pd->custom_configs;
+ if (cust_cfgs && is_custom_config_valid(cust_cfgs, dev)) {
+ temp = devm_kzalloc(dev, sizeof(*cust_cfgs), GFP_KERNEL);
+ if (temp)
+ memcpy(temp, cust_cfgs, sizeof(*cust_cfgs));
+ else
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ pd->custom_configs = temp;
+ }
+
+ /*
+ * Copy timings and min-tck values from platform data. If it is not
+ * available or if memory allocation fails, use JEDEC defaults
+ */
+ size = sizeof(struct lpddr2_timings) * pd->timings_arr_size;
+ if (pd->timings) {
+ temp = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (temp) {
+ memcpy(temp, pd->timings, sizeof(*pd->timings));
+ pd->timings = temp;
+ } else {
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ get_default_timings(emif);
+ }
+ } else {
+ get_default_timings(emif);
+ }
+
+ if (pd->min_tck) {
+ temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL);
+ if (temp) {
+ memcpy(temp, pd->min_tck, sizeof(*pd->min_tck));
+ pd->min_tck = temp;
+ } else {
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ pd->min_tck = &lpddr2_jedec_min_tck;
+ }
+ } else {
+ pd->min_tck = &lpddr2_jedec_min_tck;
+ }
+
+out:
+ return emif;
+
+error:
+ return NULL;
+}
+
+static int __init_or_module emif_probe(struct platform_device *pdev)
+{
+ struct emif_data *emif;
+ struct resource *res;
+ int irq;
+
+ emif = get_device_details(pdev);
+ if (!emif) {
+ pr_err("%s: error getting device data\n", __func__);
+ goto error;
+ }
+
+ list_add(&emif->node, &device_list);
+ emif->addressing = get_addressing_table(emif->plat_data->device_info);
+
+ /* Save pointers to each other in emif and device structures */
+ emif->dev = &pdev->dev;
+ platform_set_drvdata(pdev, emif);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(emif->dev, "%s: error getting memory resource\n",
+ __func__);
+ goto error;
+ }
+
+ emif->base = devm_request_and_ioremap(emif->dev, res);
+ if (!emif->base) {
+ dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n",
+ __func__);
+ goto error;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(emif->dev, "%s: error getting IRQ resource - %d\n",
+ __func__, irq);
+ goto error;
+ }
+
+ emif_onetime_settings(emif);
+ emif_debugfs_init(emif);
+ disable_and_clear_all_interrupts(emif);
+ setup_interrupts(emif, irq);
+
+ /* One-time actions taken on probing the first device */
+ if (!emif1) {
+ emif1 = emif;
+ spin_lock_init(&emif_lock);
+
+ /*
+ * TODO: register notifiers for frequency and voltage
+ * change here once the respective frameworks are
+ * available
+ */
+ }
+
+ dev_info(&pdev->dev, "%s: device configured with addr = %p and IRQ%d\n",
+ __func__, emif->base, irq);
+
+ return 0;
+error:
+ return -ENODEV;
+}
+
+static int __exit emif_remove(struct platform_device *pdev)
+{
+ struct emif_data *emif = platform_get_drvdata(pdev);
+
+ emif_debugfs_exit(emif);
+
+ return 0;
+}
+
+static void emif_shutdown(struct platform_device *pdev)
+{
+ struct emif_data *emif = platform_get_drvdata(pdev);
+
+ disable_and_clear_all_interrupts(emif);
+}
+
+static int get_emif_reg_values(struct emif_data *emif, u32 freq,
+ struct emif_regs *regs)
+{
+ u32 cs1_used, ip_rev, phy_type;
+ u32 cl, type;
+ const struct lpddr2_timings *timings;
+ const struct lpddr2_min_tck *min_tck;
+ const struct ddr_device_info *device_info;
+ const struct lpddr2_addressing *addressing;
+ struct emif_data *emif_for_calc;
+ struct device *dev;
+ const struct emif_custom_configs *custom_configs;
+
+ dev = emif->dev;
+ /*
+ * If the devices on this EMIF instance is duplicate of EMIF1,
+ * use EMIF1 details for the calculation
+ */
+ emif_for_calc = emif->duplicate ? emif1 : emif;
+ timings = get_timings_table(emif_for_calc, freq);
+ addressing = emif_for_calc->addressing;
+ if (!timings || !addressing) {
+ dev_err(dev, "%s: not enough data available for %dHz",
+ __func__, freq);
+ return -1;
+ }
+
+ device_info = emif_for_calc->plat_data->device_info;
+ type = device_info->type;
+ cs1_used = device_info->cs1_used;
+ ip_rev = emif_for_calc->plat_data->ip_rev;
+ phy_type = emif_for_calc->plat_data->phy_type;
+
+ min_tck = emif_for_calc->plat_data->min_tck;
+ custom_configs = emif_for_calc->plat_data->custom_configs;
+
+ set_ddr_clk_period(freq);
+
+ regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing);
+ regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck,
+ addressing);
+ regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck,
+ addressing, type);
+ regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck,
+ addressing, type, ip_rev, EMIF_NORMAL_TIMINGS);
+
+ cl = get_cl(emif);
+
+ if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) {
+ regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d(
+ timings, freq, cl);
+ } else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) {
+ regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl);
+ regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5();
+ regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5();
+ regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5();
+ } else {
+ return -1;
+ }
+
+ /* Only timeout values in pwr_mgmt_ctrl_shdw register */
+ regs->pwr_mgmt_ctrl_shdw =
+ get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) &
+ (CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK);
+
+ if (ip_rev & EMIF_4D) {
+ regs->read_idle_ctrl_shdw_normal =
+ get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+ regs->read_idle_ctrl_shdw_volt_ramp =
+ get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+ } else if (ip_rev & EMIF_4D5) {
+ regs->dll_calib_ctrl_shdw_normal =
+ get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+ regs->dll_calib_ctrl_shdw_volt_ramp =
+ get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+ }
+
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+ regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4,
+ addressing);
+
+ regs->sdram_tim1_shdw_derated =
+ get_sdram_tim_1_shdw_derated(timings, min_tck,
+ addressing);
+
+ regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings,
+ min_tck, addressing, type, ip_rev,
+ EMIF_DERATED_TIMINGS);
+ }
+
+ regs->freq = freq;
+
+ return 0;
+}
+
+/*
+ * get_regs() - gets the cached emif_regs structure for a given EMIF instance
+ * given frequency(freq):
+ *
+ * As an optimisation, every EMIF instance other than EMIF1 shares the
+ * register cache with EMIF1 if the devices connected on this instance
+ * are same as that on EMIF1(indicated by the duplicate flag)
+ *
+ * If we do not have an entry corresponding to the frequency given, we
+ * allocate a new entry and calculate the values
+ *
+ * Upon finding the right reg dump, save it in curr_regs. It can be
+ * directly used for thermal de-rating and voltage ramping changes.
+ */
+static struct emif_regs *get_regs(struct emif_data *emif, u32 freq)
+{
+ int i;
+ struct emif_regs **regs_cache;
+ struct emif_regs *regs = NULL;
+ struct device *dev;
+
+ dev = emif->dev;
+ if (emif->curr_regs && emif->curr_regs->freq == freq) {
+ dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq);
+ return emif->curr_regs;
+ }
+
+ if (emif->duplicate)
+ regs_cache = emif1->regs_cache;
+ else
+ regs_cache = emif->regs_cache;
+
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+ if (regs_cache[i]->freq == freq) {
+ regs = regs_cache[i];
+ dev_dbg(dev,
+ "%s: reg dump found in reg cache for %u Hz\n",
+ __func__, freq);
+ break;
+ }
+ }
+
+ /*
+ * If we don't have an entry for this frequency in the cache create one
+ * and calculate the values
+ */
+ if (!regs) {
+ regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC);
+ if (!regs)
+ return NULL;
+
+ if (get_emif_reg_values(emif, freq, regs)) {
+ devm_kfree(emif->dev, regs);
+ return NULL;
+ }
+
+ /*
+ * Now look for an un-used entry in the cache and save the
+ * newly created struct. If there are no free entries
+ * over-write the last entry
+ */
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++)
+ ;
+
+ if (i >= EMIF_MAX_NUM_FREQUENCIES) {
+ dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n",
+ __func__);
+ i = EMIF_MAX_NUM_FREQUENCIES - 1;
+ devm_kfree(emif->dev, regs_cache[i]);
+ }
+ regs_cache[i] = regs;
+ }
+
+ return regs;
+}
+
+static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state)
+{
+ dev_dbg(emif->dev, "%s: voltage notification : %d", __func__,
+ volt_state);
+
+ if (!emif->curr_regs) {
+ dev_err(emif->dev,
+ "%s: volt-notify before registers are ready: %d\n",
+ __func__, volt_state);
+ return;
+ }
+
+ setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state);
+}
+
+/*
+ * TODO: voltage notify handling should be hooked up to
+ * regulator framework as soon as the necessary support
+ * is available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) volt_notify_handling(u32 volt_state)
+{
+ struct emif_data *emif;
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ list_for_each_entry(emif, &device_list, node)
+ do_volt_notify_handling(emif, volt_state);
+ do_freq_update();
+
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq)
+{
+ struct emif_regs *regs;
+
+ regs = get_regs(emif, new_freq);
+ if (!regs)
+ return;
+
+ emif->curr_regs = regs;
+
+ /*
+ * Update the shadow registers:
+ * Temperature and voltage-ramp sensitive settings are also configured
+ * in terms of DDR cycles. So, we need to update them too when there
+ * is a freq change
+ */
+ dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz",
+ __func__, new_freq);
+ setup_registers(emif, regs);
+ setup_temperature_sensitive_regs(emif, regs);
+ setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE);
+
+ /*
+ * Part of workaround for errata i728. See do_freq_update()
+ * for more details
+ */
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq)
+{
+ struct emif_data *emif;
+
+ /*
+ * NOTE: we are taking the spin-lock here and releases it
+ * only in post-notifier. This doesn't look good and
+ * Sparse complains about it, but this seems to be
+ * un-avoidable. We need to lock a sequence of events
+ * that is split between EMIF and clock framework.
+ *
+ * 1. EMIF driver updates EMIF timings in shadow registers in the
+ * frequency pre-notify callback from clock framework
+ * 2. clock framework sets up the registers for the new frequency
+ * 3. clock framework initiates a hw-sequence that updates
+ * the frequency EMIF timings synchronously.
+ *
+ * All these 3 steps should be performed as an atomic operation
+ * vis-a-vis similar sequence in the EMIF interrupt handler
+ * for temperature events. Otherwise, there could be race
+ * conditions that could result in incorrect EMIF timings for
+ * a given frequency
+ */
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ list_for_each_entry(emif, &device_list, node)
+ do_freq_pre_notify_handling(emif, new_freq);
+}
+
+static void do_freq_post_notify_handling(struct emif_data *emif)
+{
+ /*
+ * Part of workaround for errata i728. See do_freq_update()
+ * for more details
+ */
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_post_notify_handling(void)
+{
+ struct emif_data *emif;
+
+ list_for_each_entry(emif, &device_list, node)
+ do_freq_post_notify_handling(emif);
+
+ /*
+ * Lock is done in pre-notify handler. See freq_pre_notify_handling()
+ * for more details
+ */
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static struct platform_driver emif_driver = {
+ .remove = __exit_p(emif_remove),
+ .shutdown = emif_shutdown,
+ .driver = {
+ .name = "emif",
+ },
+};
+
+static int __init_or_module emif_register(void)
+{
+ return platform_driver_probe(&emif_driver, emif_probe);
+}
+
+static void __exit emif_unregister(void)
+{
+ platform_driver_unregister(&emif_driver);
+}
+
+module_init(emif_register);
+module_exit(emif_unregister);
+MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:emif");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
new file mode 100644
index 0000000..bfe08ba
--- /dev/null
+++ b/drivers/memory/emif.h
@@ -0,0 +1,589 @@
+/*
+ * Defines for the EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.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.
+ */
+#ifndef __EMIF_H
+#define __EMIF_H
+
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES 6
+
+/* State of the core voltage */
+#define DDR_VOLTAGE_STABLE 0
+#define DDR_VOLTAGE_RAMPING 1
+
+/* Defines for timing De-rating */
+#define EMIF_NORMAL_TIMINGS 0
+#define EMIF_DERATED_TIMINGS 1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_READ_IDLE_LEN_VAL 5
+
+/*
+ * forced read idle interval to be used when voltage
+ * is changed as part of DVFS/DPS - 1ms
+ */
+#define READ_IDLE_INTERVAL_DVFS (1*1000000)
+
+/*
+ * Forced read idle interval to be used when voltage is stable
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL (50*1000000)
+
+/* DLL calibration interval when voltage is NOT stable - 1us */
+#define DLL_CALIB_INTERVAL_DVFS (1*1000000)
+
+#define DLL_CALIB_ACK_WAIT_VAL 5
+
+/* Interval between ZQCS commands - hw team recommended value */
+#define EMIF_ZQCS_INTERVAL_US (50*1000)
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define ZQ_SFEXITEN_ENABLE 1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ */
+#define ZQ_DUALCALEN_DISABLE 0
+#define ZQ_DUALCALEN_ENABLE 1
+
+#define T_ZQCS_DEFAULT_NS 90
+#define T_ZQCL_DEFAULT_NS 360
+#define T_ZQINIT_DEFAULT_NS 1000
+
+/* DPD_EN */
+#define DPD_DISABLE 0
+#define DPD_ENABLE 1
+
+/*
+ * Default values for the low-power entry to be used if not provided by user.
+ * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
+ * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
+ */
+#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE 2048
+#define EMIF_LP_MODE_TIMEOUT_POWER 512
+#define EMIF_LP_MODE_FREQ_THRESHOLD 400000000
+
+/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY 0x049FF000
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY 0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY 0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
+
+/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY 0x0E084200
+#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS 10000
+
+/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
+#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS 360
+
+#define EMIF_T_CSTA 3
+#define EMIF_T_PDLL_UL 128
+
+/* External PHY control registers magic values */
+#define EMIF_EXT_PHY_CTRL_1_VAL 0x04020080
+#define EMIF_EXT_PHY_CTRL_5_VAL 0x04010040
+#define EMIF_EXT_PHY_CTRL_6_VAL 0x01004010
+#define EMIF_EXT_PHY_CTRL_7_VAL 0x00001004
+#define EMIF_EXT_PHY_CTRL_8_VAL 0x04010040
+#define EMIF_EXT_PHY_CTRL_9_VAL 0x01004010
+#define EMIF_EXT_PHY_CTRL_10_VAL 0x00001004
+#define EMIF_EXT_PHY_CTRL_11_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_12_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_13_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_14_VAL 0x80080080
+#define EMIF_EXT_PHY_CTRL_15_VAL 0x00800800
+#define EMIF_EXT_PHY_CTRL_16_VAL 0x08102040
+#define EMIF_EXT_PHY_CTRL_17_VAL 0x00000001
+#define EMIF_EXT_PHY_CTRL_18_VAL 0x540A8150
+#define EMIF_EXT_PHY_CTRL_19_VAL 0xA81502A0
+#define EMIF_EXT_PHY_CTRL_20_VAL 0x002A0540
+#define EMIF_EXT_PHY_CTRL_21_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_22_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_23_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_24_VAL 0x00000077
+
+#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS 1200
+
+/* Registers offset */
+#define EMIF_MODULE_ID_AND_REVISION 0x0000
+#define EMIF_STATUS 0x0004
+#define EMIF_SDRAM_CONFIG 0x0008
+#define EMIF_SDRAM_CONFIG_2 0x000c
+#define EMIF_SDRAM_REFRESH_CONTROL 0x0010
+#define EMIF_SDRAM_REFRESH_CTRL_SHDW 0x0014
+#define EMIF_SDRAM_TIMING_1 0x0018
+#define EMIF_SDRAM_TIMING_1_SHDW 0x001c
+#define EMIF_SDRAM_TIMING_2 0x0020
+#define EMIF_SDRAM_TIMING_2_SHDW 0x0024
+#define EMIF_SDRAM_TIMING_3 0x0028
+#define EMIF_SDRAM_TIMING_3_SHDW 0x002c
+#define EMIF_LPDDR2_NVM_TIMING 0x0030
+#define EMIF_LPDDR2_NVM_TIMING_SHDW 0x0034
+#define EMIF_POWER_MANAGEMENT_CONTROL 0x0038
+#define EMIF_POWER_MANAGEMENT_CTRL_SHDW 0x003c
+#define EMIF_LPDDR2_MODE_REG_DATA 0x0040
+#define EMIF_LPDDR2_MODE_REG_CONFIG 0x0050
+#define EMIF_OCP_CONFIG 0x0054
+#define EMIF_OCP_CONFIG_VALUE_1 0x0058
+#define EMIF_OCP_CONFIG_VALUE_2 0x005c
+#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL 0x0060
+#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT 0x0064
+#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT 0x0068
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1 0x006c
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2 0x0070
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3 0x0074
+#define EMIF_PERFORMANCE_COUNTER_1 0x0080
+#define EMIF_PERFORMANCE_COUNTER_2 0x0084
+#define EMIF_PERFORMANCE_COUNTER_CONFIG 0x0088
+#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT 0x008c
+#define EMIF_PERFORMANCE_COUNTER_TIME 0x0090
+#define EMIF_MISC_REG 0x0094
+#define EMIF_DLL_CALIB_CTRL 0x0098
+#define EMIF_DLL_CALIB_CTRL_SHDW 0x009c
+#define EMIF_END_OF_INTERRUPT 0x00a0
+#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS 0x00a4
+#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS 0x00a8
+#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS 0x00ac
+#define EMIF_LL_OCP_INTERRUPT_STATUS 0x00b0
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET 0x00b4
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET 0x00b8
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR 0x00bc
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR 0x00c0
+#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG 0x00c8
+#define EMIF_TEMPERATURE_ALERT_CONFIG 0x00cc
+#define EMIF_OCP_ERROR_LOG 0x00d0
+#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW 0x00d4
+#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL 0x00d8
+#define EMIF_READ_WRITE_LEVELING_CONTROL 0x00dc
+#define EMIF_DDR_PHY_CTRL_1 0x00e4
+#define EMIF_DDR_PHY_CTRL_1_SHDW 0x00e8
+#define EMIF_DDR_PHY_CTRL_2 0x00ec
+#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING 0x0100
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
+#define EMIF_READ_WRITE_EXECUTION_THRESHOLD 0x0120
+#define EMIF_COS_CONFIG 0x0124
+#define EMIF_PHY_STATUS_1 0x0140
+#define EMIF_PHY_STATUS_2 0x0144
+#define EMIF_PHY_STATUS_3 0x0148
+#define EMIF_PHY_STATUS_4 0x014c
+#define EMIF_PHY_STATUS_5 0x0150
+#define EMIF_PHY_STATUS_6 0x0154
+#define EMIF_PHY_STATUS_7 0x0158
+#define EMIF_PHY_STATUS_8 0x015c
+#define EMIF_PHY_STATUS_9 0x0160
+#define EMIF_PHY_STATUS_10 0x0164
+#define EMIF_PHY_STATUS_11 0x0168
+#define EMIF_PHY_STATUS_12 0x016c
+#define EMIF_PHY_STATUS_13 0x0170
+#define EMIF_PHY_STATUS_14 0x0174
+#define EMIF_PHY_STATUS_15 0x0178
+#define EMIF_PHY_STATUS_16 0x017c
+#define EMIF_PHY_STATUS_17 0x0180
+#define EMIF_PHY_STATUS_18 0x0184
+#define EMIF_PHY_STATUS_19 0x0188
+#define EMIF_PHY_STATUS_20 0x018c
+#define EMIF_PHY_STATUS_21 0x0190
+#define EMIF_EXT_PHY_CTRL_1 0x0200
+#define EMIF_EXT_PHY_CTRL_1_SHDW 0x0204
+#define EMIF_EXT_PHY_CTRL_2 0x0208
+#define EMIF_EXT_PHY_CTRL_2_SHDW 0x020c
+#define EMIF_EXT_PHY_CTRL_3 0x0210
+#define EMIF_EXT_PHY_CTRL_3_SHDW 0x0214
+#define EMIF_EXT_PHY_CTRL_4 0x0218
+#define EMIF_EXT_PHY_CTRL_4_SHDW 0x021c
+#define EMIF_EXT_PHY_CTRL_5 0x0220
+#define EMIF_EXT_PHY_CTRL_5_SHDW 0x0224
+#define EMIF_EXT_PHY_CTRL_6 0x0228
+#define EMIF_EXT_PHY_CTRL_6_SHDW 0x022c
+#define EMIF_EXT_PHY_CTRL_7 0x0230
+#define EMIF_EXT_PHY_CTRL_7_SHDW 0x0234
+#define EMIF_EXT_PHY_CTRL_8 0x0238
+#define EMIF_EXT_PHY_CTRL_8_SHDW 0x023c
+#define EMIF_EXT_PHY_CTRL_9 0x0240
+#define EMIF_EXT_PHY_CTRL_9_SHDW 0x0244
+#define EMIF_EXT_PHY_CTRL_10 0x0248
+#define EMIF_EXT_PHY_CTRL_10_SHDW 0x024c
+#define EMIF_EXT_PHY_CTRL_11 0x0250
+#define EMIF_EXT_PHY_CTRL_11_SHDW 0x0254
+#define EMIF_EXT_PHY_CTRL_12 0x0258
+#define EMIF_EXT_PHY_CTRL_12_SHDW 0x025c
+#define EMIF_EXT_PHY_CTRL_13 0x0260
+#define EMIF_EXT_PHY_CTRL_13_SHDW 0x0264
+#define EMIF_EXT_PHY_CTRL_14 0x0268
+#define EMIF_EXT_PHY_CTRL_14_SHDW 0x026c
+#define EMIF_EXT_PHY_CTRL_15 0x0270
+#define EMIF_EXT_PHY_CTRL_15_SHDW 0x0274
+#define EMIF_EXT_PHY_CTRL_16 0x0278
+#define EMIF_EXT_PHY_CTRL_16_SHDW 0x027c
+#define EMIF_EXT_PHY_CTRL_17 0x0280
+#define EMIF_EXT_PHY_CTRL_17_SHDW 0x0284
+#define EMIF_EXT_PHY_CTRL_18 0x0288
+#define EMIF_EXT_PHY_CTRL_18_SHDW 0x028c
+#define EMIF_EXT_PHY_CTRL_19 0x0290
+#define EMIF_EXT_PHY_CTRL_19_SHDW 0x0294
+#define EMIF_EXT_PHY_CTRL_20 0x0298
+#define EMIF_EXT_PHY_CTRL_20_SHDW 0x029c
+#define EMIF_EXT_PHY_CTRL_21 0x02a0
+#define EMIF_EXT_PHY_CTRL_21_SHDW 0x02a4
+#define EMIF_EXT_PHY_CTRL_22 0x02a8
+#define EMIF_EXT_PHY_CTRL_22_SHDW 0x02ac
+#define EMIF_EXT_PHY_CTRL_23 0x02b0
+#define EMIF_EXT_PHY_CTRL_23_SHDW 0x02b4
+#define EMIF_EXT_PHY_CTRL_24 0x02b8
+#define EMIF_EXT_PHY_CTRL_24_SHDW 0x02bc
+#define EMIF_EXT_PHY_CTRL_25 0x02c0
+#define EMIF_EXT_PHY_CTRL_25_SHDW 0x02c4
+#define EMIF_EXT_PHY_CTRL_26 0x02c8
+#define EMIF_EXT_PHY_CTRL_26_SHDW 0x02cc
+#define EMIF_EXT_PHY_CTRL_27 0x02d0
+#define EMIF_EXT_PHY_CTRL_27_SHDW 0x02d4
+#define EMIF_EXT_PHY_CTRL_28 0x02d8
+#define EMIF_EXT_PHY_CTRL_28_SHDW 0x02dc
+#define EMIF_EXT_PHY_CTRL_29 0x02e0
+#define EMIF_EXT_PHY_CTRL_29_SHDW 0x02e4
+#define EMIF_EXT_PHY_CTRL_30 0x02e8
+#define EMIF_EXT_PHY_CTRL_30_SHDW 0x02ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MODULE_ID_AND_REVISION */
+#define SCHEME_SHIFT 30
+#define SCHEME_MASK (0x3 << 30)
+#define MODULE_ID_SHIFT 16
+#define MODULE_ID_MASK (0xfff << 16)
+#define RTL_VERSION_SHIFT 11
+#define RTL_VERSION_MASK (0x1f << 11)
+#define MAJOR_REVISION_SHIFT 8
+#define MAJOR_REVISION_MASK (0x7 << 8)
+#define MINOR_REVISION_SHIFT 0
+#define MINOR_REVISION_MASK (0x3f << 0)
+
+/* STATUS */
+#define BE_SHIFT 31
+#define BE_MASK (1 << 31)
+#define DUAL_CLK_MODE_SHIFT 30
+#define DUAL_CLK_MODE_MASK (1 << 30)
+#define FAST_INIT_SHIFT 29
+#define FAST_INIT_MASK (1 << 29)
+#define RDLVLGATETO_SHIFT 6
+#define RDLVLGATETO_MASK (1 << 6)
+#define RDLVLTO_SHIFT 5
+#define RDLVLTO_MASK (1 << 5)
+#define WRLVLTO_SHIFT 4
+#define WRLVLTO_MASK (1 << 4)
+#define PHY_DLL_READY_SHIFT 2
+#define PHY_DLL_READY_MASK (1 << 2)
+
+/* SDRAM_CONFIG */
+#define SDRAM_TYPE_SHIFT 29
+#define SDRAM_TYPE_MASK (0x7 << 29)
+#define IBANK_POS_SHIFT 27
+#define IBANK_POS_MASK (0x3 << 27)
+#define DDR_TERM_SHIFT 24
+#define DDR_TERM_MASK (0x7 << 24)
+#define DDR2_DDQS_SHIFT 23
+#define DDR2_DDQS_MASK (1 << 23)
+#define DYN_ODT_SHIFT 21
+#define DYN_ODT_MASK (0x3 << 21)
+#define DDR_DISABLE_DLL_SHIFT 20
+#define DDR_DISABLE_DLL_MASK (1 << 20)
+#define SDRAM_DRIVE_SHIFT 18
+#define SDRAM_DRIVE_MASK (0x3 << 18)
+#define CWL_SHIFT 16
+#define CWL_MASK (0x3 << 16)
+#define NARROW_MODE_SHIFT 14
+#define NARROW_MODE_MASK (0x3 << 14)
+#define CL_SHIFT 10
+#define CL_MASK (0xf << 10)
+#define ROWSIZE_SHIFT 7
+#define ROWSIZE_MASK (0x7 << 7)
+#define IBANK_SHIFT 4
+#define IBANK_MASK (0x7 << 4)
+#define EBANK_SHIFT 3
+#define EBANK_MASK (1 << 3)
+#define PAGESIZE_SHIFT 0
+#define PAGESIZE_MASK (0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define CS1NVMEN_SHIFT 30
+#define CS1NVMEN_MASK (1 << 30)
+#define EBANK_POS_SHIFT 27
+#define EBANK_POS_MASK (1 << 27)
+#define RDBNUM_SHIFT 4
+#define RDBNUM_MASK (0x3 << 4)
+#define RDBSIZE_SHIFT 0
+#define RDBSIZE_MASK (0x7 << 0)
+
+/* SDRAM_REFRESH_CONTROL */
+#define INITREF_DIS_SHIFT 31
+#define INITREF_DIS_MASK (1 << 31)
+#define SRT_SHIFT 29
+#define SRT_MASK (1 << 29)
+#define ASR_SHIFT 28
+#define ASR_MASK (1 << 28)
+#define PASR_SHIFT 24
+#define PASR_MASK (0x7 << 24)
+#define REFRESH_RATE_SHIFT 0
+#define REFRESH_RATE_MASK (0xffff << 0)
+
+/* SDRAM_TIMING_1 */
+#define T_RTW_SHIFT 29
+#define T_RTW_MASK (0x7 << 29)
+#define T_RP_SHIFT 25
+#define T_RP_MASK (0xf << 25)
+#define T_RCD_SHIFT 21
+#define T_RCD_MASK (0xf << 21)
+#define T_WR_SHIFT 17
+#define T_WR_MASK (0xf << 17)
+#define T_RAS_SHIFT 12
+#define T_RAS_MASK (0x1f << 12)
+#define T_RC_SHIFT 6
+#define T_RC_MASK (0x3f << 6)
+#define T_RRD_SHIFT 3
+#define T_RRD_MASK (0x7 << 3)
+#define T_WTR_SHIFT 0
+#define T_WTR_MASK (0x7 << 0)
+
+/* SDRAM_TIMING_2 */
+#define T_XP_SHIFT 28
+#define T_XP_MASK (0x7 << 28)
+#define T_ODT_SHIFT 25
+#define T_ODT_MASK (0x7 << 25)
+#define T_XSNR_SHIFT 16
+#define T_XSNR_MASK (0x1ff << 16)
+#define T_XSRD_SHIFT 6
+#define T_XSRD_MASK (0x3ff << 6)
+#define T_RTP_SHIFT 3
+#define T_RTP_MASK (0x7 << 3)
+#define T_CKE_SHIFT 0
+#define T_CKE_MASK (0x7 << 0)
+
+/* SDRAM_TIMING_3 */
+#define T_PDLL_UL_SHIFT 28
+#define T_PDLL_UL_MASK (0xf << 28)
+#define T_CSTA_SHIFT 24
+#define T_CSTA_MASK (0xf << 24)
+#define T_CKESR_SHIFT 21
+#define T_CKESR_MASK (0x7 << 21)
+#define ZQ_ZQCS_SHIFT 15
+#define ZQ_ZQCS_MASK (0x3f << 15)
+#define T_TDQSCKMAX_SHIFT 13
+#define T_TDQSCKMAX_MASK (0x3 << 13)
+#define T_RFC_SHIFT 4
+#define T_RFC_MASK (0x1ff << 4)
+#define T_RAS_MAX_SHIFT 0
+#define T_RAS_MAX_MASK (0xf << 0)
+
+/* POWER_MANAGEMENT_CONTROL */
+#define PD_TIM_SHIFT 12
+#define PD_TIM_MASK (0xf << 12)
+#define DPD_EN_SHIFT 11
+#define DPD_EN_MASK (1 << 11)
+#define LP_MODE_SHIFT 8
+#define LP_MODE_MASK (0x7 << 8)
+#define SR_TIM_SHIFT 4
+#define SR_TIM_MASK (0xf << 4)
+#define CS_TIM_SHIFT 0
+#define CS_TIM_MASK (0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define VALUE_0_SHIFT 0
+#define VALUE_0_MASK (0x7f << 0)
+
+/* LPDDR2_MODE_REG_CONFIG */
+#define CS_SHIFT 31
+#define CS_MASK (1 << 31)
+#define REFRESH_EN_SHIFT 30
+#define REFRESH_EN_MASK (1 << 30)
+#define ADDRESS_SHIFT 0
+#define ADDRESS_MASK (0xff << 0)
+
+/* OCP_CONFIG */
+#define SYS_THRESH_MAX_SHIFT 24
+#define SYS_THRESH_MAX_MASK (0xf << 24)
+#define MPU_THRESH_MAX_SHIFT 20
+#define MPU_THRESH_MAX_MASK (0xf << 20)
+#define LL_THRESH_MAX_SHIFT 16
+#define LL_THRESH_MAX_MASK (0xf << 16)
+
+/* PERFORMANCE_COUNTER_1 */
+#define COUNTER1_SHIFT 0
+#define COUNTER1_MASK (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_2 */
+#define COUNTER2_SHIFT 0
+#define COUNTER2_MASK (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_CONFIG */
+#define CNTR2_MCONNID_EN_SHIFT 31
+#define CNTR2_MCONNID_EN_MASK (1 << 31)
+#define CNTR2_REGION_EN_SHIFT 30
+#define CNTR2_REGION_EN_MASK (1 << 30)
+#define CNTR2_CFG_SHIFT 16
+#define CNTR2_CFG_MASK (0xf << 16)
+#define CNTR1_MCONNID_EN_SHIFT 15
+#define CNTR1_MCONNID_EN_MASK (1 << 15)
+#define CNTR1_REGION_EN_SHIFT 14
+#define CNTR1_REGION_EN_MASK (1 << 14)
+#define CNTR1_CFG_SHIFT 0
+#define CNTR1_CFG_MASK (0xf << 0)
+
+/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
+#define MCONNID2_SHIFT 24
+#define MCONNID2_MASK (0xff << 24)
+#define REGION_SEL2_SHIFT 16
+#define REGION_SEL2_MASK (0x3 << 16)
+#define MCONNID1_SHIFT 8
+#define MCONNID1_MASK (0xff << 8)
+#define REGION_SEL1_SHIFT 0
+#define REGION_SEL1_MASK (0x3 << 0)
+
+/* PERFORMANCE_COUNTER_TIME */
+#define TOTAL_TIME_SHIFT 0
+#define TOTAL_TIME_MASK (0xffffffff << 0)
+
+/* DLL_CALIB_CTRL */
+#define ACK_WAIT_SHIFT 16
+#define ACK_WAIT_MASK (0xf << 16)
+#define DLL_CALIB_INTERVAL_SHIFT 0
+#define DLL_CALIB_INTERVAL_MASK (0x1ff << 0)
+
+/* END_OF_INTERRUPT */
+#define EOI_SHIFT 0
+#define EOI_MASK (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_SYS_SHIFT 2
+#define DNV_SYS_MASK (1 << 2)
+#define TA_SYS_SHIFT 1
+#define TA_SYS_MASK (1 << 1)
+#define ERR_SYS_SHIFT 0
+#define ERR_SYS_MASK (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_LL_SHIFT 2
+#define DNV_LL_MASK (1 << 2)
+#define TA_LL_SHIFT 1
+#define TA_LL_MASK (1 << 1)
+#define ERR_LL_SHIFT 0
+#define ERR_LL_MASK (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_SYS_SHIFT 2
+#define EN_DNV_SYS_MASK (1 << 2)
+#define EN_TA_SYS_SHIFT 1
+#define EN_TA_SYS_MASK (1 << 1)
+#define EN_ERR_SYS_SHIFT 0
+#define EN_ERR_SYS_MASK (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_LL_SHIFT 2
+#define EN_DNV_LL_MASK (1 << 2)
+#define EN_TA_LL_SHIFT 1
+#define EN_TA_LL_MASK (1 << 1)
+#define EN_ERR_LL_SHIFT 0
+#define EN_ERR_LL_MASK (1 << 0)
+
+/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
+#define ZQ_CS1EN_SHIFT 31
+#define ZQ_CS1EN_MASK (1 << 31)
+#define ZQ_CS0EN_SHIFT 30
+#define ZQ_CS0EN_MASK (1 << 30)
+#define ZQ_DUALCALEN_SHIFT 29
+#define ZQ_DUALCALEN_MASK (1 << 29)
+#define ZQ_SFEXITEN_SHIFT 28
+#define ZQ_SFEXITEN_MASK (1 << 28)
+#define ZQ_ZQINIT_MULT_SHIFT 18
+#define ZQ_ZQINIT_MULT_MASK (0x3 << 18)
+#define ZQ_ZQCL_MULT_SHIFT 16
+#define ZQ_ZQCL_MULT_MASK (0x3 << 16)
+#define ZQ_REFINTERVAL_SHIFT 0
+#define ZQ_REFINTERVAL_MASK (0xffff << 0)
+
+/* TEMPERATURE_ALERT_CONFIG */
+#define TA_CS1EN_SHIFT 31
+#define TA_CS1EN_MASK (1 << 31)
+#define TA_CS0EN_SHIFT 30
+#define TA_CS0EN_MASK (1 << 30)
+#define TA_SFEXITEN_SHIFT 28
+#define TA_SFEXITEN_MASK (1 << 28)
+#define TA_DEVWDT_SHIFT 26
+#define TA_DEVWDT_MASK (0x3 << 26)
+#define TA_DEVCNT_SHIFT 24
+#define TA_DEVCNT_MASK (0x3 << 24)
+#define TA_REFINTERVAL_SHIFT 0
+#define TA_REFINTERVAL_MASK (0x3fffff << 0)
+
+/* OCP_ERROR_LOG */
+#define MADDRSPACE_SHIFT 14
+#define MADDRSPACE_MASK (0x3 << 14)
+#define MBURSTSEQ_SHIFT 11
+#define MBURSTSEQ_MASK (0x7 << 11)
+#define MCMD_SHIFT 8
+#define MCMD_MASK (0x7 << 8)
+#define MCONNID_SHIFT 0
+#define MCONNID_MASK (0xff << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D */
+#define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4
+#define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4)
+#define READ_LATENCY_SHIFT_4D 0
+#define READ_LATENCY_MASK_4D (0xf << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D5 */
+#define DLL_HALF_DELAY_SHIFT_4D5 21
+#define DLL_HALF_DELAY_MASK_4D5 (1 << 21)
+#define READ_LATENCY_SHIFT_4D5 0
+#define READ_LATENCY_MASK_4D5 (0x1f << 0)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define DDR_PHY_CTRL_1_SHDW_SHIFT 5
+#define DDR_PHY_CTRL_1_SHDW_MASK (0x7ffffff << 5)
+#define READ_LATENCY_SHDW_SHIFT 0
+#define READ_LATENCY_SHDW_MASK (0x1f << 0)
+
+#ifndef __ASSEMBLY__
+/*
+ * Structure containing shadow of important registers in EMIF
+ * The calculation function fills in this structure to be later used for
+ * initialisation and DVFS
+ */
+struct emif_regs {
+ u32 freq;
+ u32 ref_ctrl_shdw;
+ u32 ref_ctrl_shdw_derated;
+ u32 sdram_tim1_shdw;
+ u32 sdram_tim1_shdw_derated;
+ u32 sdram_tim2_shdw;
+ u32 sdram_tim3_shdw;
+ u32 sdram_tim3_shdw_derated;
+ u32 pwr_mgmt_ctrl_shdw;
+ union {
+ u32 read_idle_ctrl_shdw_normal;
+ u32 dll_calib_ctrl_shdw_normal;
+ };
+ union {
+ u32 read_idle_ctrl_shdw_volt_ramp;
+ u32 dll_calib_ctrl_shdw_volt_ramp;
+ };
+
+ u32 phy_ctrl_1_shdw;
+ u32 ext_phy_ctrl_2_shdw;
+ u32 ext_phy_ctrl_3_shdw;
+ u32 ext_phy_ctrl_4_shdw;
+};
+#endif /* __ASSEMBLY__ */
+#endif /* __EMIF_H */
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
new file mode 100644
index 0000000..3ed49c1
--- /dev/null
+++ b/drivers/memory/tegra20-mc.c
@@ -0,0 +1,257 @@
+/*
+ * Tegra20 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra20-mc"
+
+#define MC_INTSTATUS 0x0
+#define MC_INTMASK 0x4
+
+#define MC_INT_ERR_SHIFT 6
+#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_INVALID_GART_PAGE BIT(MC_INT_ERR_SHIFT + 1)
+#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
+
+#define MC_GART_ERROR_REQ 0x30
+#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
+#define MC_SECURITY_VIOLATION_STATUS 0x74
+
+#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_CLIENT_ID_MASK 0x3f
+
+#define NUM_MC_REG_BANKS 2
+
+struct tegra20_mc {
+ void __iomem *regs[NUM_MC_REG_BANKS];
+ struct device *dev;
+};
+
+static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs)
+{
+ u32 val = 0;
+
+ if (offs < 0x24)
+ val = readl(mc->regs[0] + offs);
+ if (offs < 0x400)
+ val = readl(mc->regs[1] + offs - 0x3c);
+
+ return val;
+}
+
+static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs)
+{
+ if (offs < 0x24) {
+ writel(val, mc->regs[0] + offs);
+ return;
+ }
+ if (offs < 0x400) {
+ writel(val, mc->regs[1] + offs - 0x3c);
+ return;
+ }
+}
+
+static const char * const tegra20_mc_client[] = {
+ "cbr_display0a",
+ "cbr_display0ab",
+ "cbr_display0b",
+ "cbr_display0bb",
+ "cbr_display0c",
+ "cbr_display0cb",
+ "cbr_display1b",
+ "cbr_display1bb",
+ "cbr_eppup",
+ "cbr_g2pr",
+ "cbr_g2sr",
+ "cbr_mpeunifbr",
+ "cbr_viruv",
+ "csr_avpcarm7r",
+ "csr_displayhc",
+ "csr_displayhcb",
+ "csr_fdcdrd",
+ "csr_g2dr",
+ "csr_host1xdmar",
+ "csr_host1xr",
+ "csr_idxsrd",
+ "csr_mpcorer",
+ "csr_mpe_ipred",
+ "csr_mpeamemrd",
+ "csr_mpecsrd",
+ "csr_ppcsahbdmar",
+ "csr_ppcsahbslvr",
+ "csr_texsrd",
+ "csr_vdebsevr",
+ "csr_vdember",
+ "csr_vdemcer",
+ "csr_vdetper",
+ "cbw_eppu",
+ "cbw_eppv",
+ "cbw_eppy",
+ "cbw_mpeunifbw",
+ "cbw_viwsb",
+ "cbw_viwu",
+ "cbw_viwv",
+ "cbw_viwy",
+ "ccw_g2dw",
+ "csw_avpcarm7w",
+ "csw_fdcdwr",
+ "csw_host1xw",
+ "csw_ispw",
+ "csw_mpcorew",
+ "csw_mpecswr",
+ "csw_ppcsahbdmaw",
+ "csw_ppcsahbslvw",
+ "csw_vdebsevw",
+ "csw_vdembew",
+ "csw_vdetpmw",
+};
+
+static void tegra20_mc_decode(struct tegra20_mc *mc, int n)
+{
+ u32 addr, req;
+ const char *client = "Unknown";
+ int idx, cid;
+ const struct reg_info {
+ u32 offset;
+ u32 write_bit; /* 0=READ, 1=WRITE */
+ int cid_shift;
+ char *message;
+ } reg[] = {
+ {
+ .offset = MC_DECERR_EMEM_OTHERS_STATUS,
+ .write_bit = 31,
+ .message = "MC_DECERR",
+ },
+ {
+ .offset = MC_GART_ERROR_REQ,
+ .cid_shift = 1,
+ .message = "MC_GART_ERR",
+
+ },
+ {
+ .offset = MC_SECURITY_VIOLATION_STATUS,
+ .write_bit = 31,
+ .message = "MC_SECURITY_ERR",
+ },
+ };
+
+ idx = n - MC_INT_ERR_SHIFT;
+ if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) {
+ dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+ BIT(n));
+ return;
+ }
+
+ req = mc_readl(mc, reg[idx].offset);
+ cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK;
+ if (cid < ARRAY_SIZE(tegra20_mc_client))
+ client = tegra20_mc_client[cid];
+
+ addr = mc_readl(mc, reg[idx].offset + sizeof(u32));
+
+ dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n",
+ reg[idx].message, req, addr, client,
+ (req & BIT(reg[idx].write_bit)) ? "write" : "read",
+ (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ?
+ ((req & SECURITY_VIOLATION_TYPE) ?
+ "carveout" : "trustzone") : "");
+}
+
+static const struct of_device_id tegra20_mc_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-mc", },
+ {},
+};
+
+static irqreturn_t tegra20_mc_isr(int irq, void *data)
+{
+ u32 stat, mask, bit;
+ struct tegra20_mc *mc = data;
+
+ stat = mc_readl(mc, MC_INTSTATUS);
+ mask = mc_readl(mc, MC_INTMASK);
+ mask &= stat;
+ if (!mask)
+ return IRQ_NONE;
+ while ((bit = ffs(mask)) != 0)
+ tegra20_mc_decode(mc, bit - 1);
+ mc_writel(mc, stat, MC_INTSTATUS);
+ return IRQ_HANDLED;
+}
+
+static int __devinit tegra20_mc_probe(struct platform_device *pdev)
+{
+ struct resource *irq;
+ struct tegra20_mc *mc;
+ int i, err;
+ u32 intmask;
+
+ mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+ mc->dev = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ return -ENODEV;
+ mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mc->regs[i])
+ return -EBUSY;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq)
+ return -ENODEV;
+ err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), mc);
+ if (err)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, mc);
+
+ intmask = MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+ mc_writel(mc, intmask, MC_INTMASK);
+ return 0;
+}
+
+static struct platform_driver tegra20_mc_driver = {
+ .probe = tegra20_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_mc_of_match,
+ },
+};
+module_platform_driver(tegra20_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
new file mode 100644
index 0000000..e56ff04
--- /dev/null
+++ b/drivers/memory/tegra30-mc.c
@@ -0,0 +1,382 @@
+/*
+ * Tegra30 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra30-mc"
+
+#define MC_INTSTATUS 0x0
+#define MC_INTMASK 0x4
+
+#define MC_INT_ERR_SHIFT 6
+#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
+#define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4)
+
+#define MC_ERR_STATUS 0x8
+#define MC_ERR_ADR 0xc
+
+#define MC_ERR_TYPE_SHIFT 28
+#define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT)
+#define MC_ERR_TYPE_DECERR_EMEM 2
+#define MC_ERR_TYPE_SECURITY_TRUSTZONE 3
+#define MC_ERR_TYPE_SECURITY_CARVEOUT 4
+#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6
+
+#define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25
+#define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
+#define MC_ERR_RW_SHIFT 16
+#define MC_ERR_RW BIT(MC_ERR_RW_SHIFT)
+#define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1)
+
+#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
+#define MC_EMEM_ARB_TIMING_RCD 0x98
+#define MC_EMEM_ARB_TIMING_RP 0x9c
+#define MC_EMEM_ARB_TIMING_RC 0xa0
+#define MC_EMEM_ARB_TIMING_RAS 0xa4
+#define MC_EMEM_ARB_TIMING_FAW 0xa8
+#define MC_EMEM_ARB_TIMING_RRD 0xac
+#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
+#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
+#define MC_EMEM_ARB_TIMING_R2R 0xb8
+#define MC_EMEM_ARB_TIMING_W2W 0xbc
+#define MC_EMEM_ARB_TIMING_R2W 0xc0
+#define MC_EMEM_ARB_TIMING_W2R 0xc4
+
+#define MC_EMEM_ARB_DA_TURNS 0xd0
+#define MC_EMEM_ARB_DA_COVERS 0xd4
+#define MC_EMEM_ARB_MISC0 0xd8
+#define MC_EMEM_ARB_MISC1 0xdc
+
+#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
+#define MC_EMEM_ARB_OVERRIDE 0xe8
+
+#define MC_TIMING_CONTROL 0xfc
+
+#define MC_CLIENT_ID_MASK 0x7f
+
+#define NUM_MC_REG_BANKS 4
+
+struct tegra30_mc {
+ void __iomem *regs[NUM_MC_REG_BANKS];
+ struct device *dev;
+ u32 ctx[0];
+};
+
+static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
+{
+ u32 val = 0;
+
+ if (offs < 0x10)
+ val = readl(mc->regs[0] + offs);
+ if (offs < 0x1f0)
+ val = readl(mc->regs[1] + offs - 0x3c);
+ if (offs < 0x228)
+ val = readl(mc->regs[2] + offs - 0x200);
+ if (offs < 0x400)
+ val = readl(mc->regs[3] + offs - 0x284);
+
+ return val;
+}
+
+static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
+{
+ if (offs < 0x10) {
+ writel(val, mc->regs[0] + offs);
+ return;
+ }
+ if (offs < 0x1f0) {
+ writel(val, mc->regs[1] + offs - 0x3c);
+ return;
+ }
+ if (offs < 0x228) {
+ writel(val, mc->regs[2] + offs - 0x200);
+ return;
+ }
+ if (offs < 0x400) {
+ writel(val, mc->regs[3] + offs - 0x284);
+ return;
+ }
+}
+
+static const char * const tegra30_mc_client[] = {
+ "csr_ptcr",
+ "cbr_display0a",
+ "cbr_display0ab",
+ "cbr_display0b",
+ "cbr_display0bb",
+ "cbr_display0c",
+ "cbr_display0cb",
+ "cbr_display1b",
+ "cbr_display1bb",
+ "cbr_eppup",
+ "cbr_g2pr",
+ "cbr_g2sr",
+ "cbr_mpeunifbr",
+ "cbr_viruv",
+ "csr_afir",
+ "csr_avpcarm7r",
+ "csr_displayhc",
+ "csr_displayhcb",
+ "csr_fdcdrd",
+ "csr_fdcdrd2",
+ "csr_g2dr",
+ "csr_hdar",
+ "csr_host1xdmar",
+ "csr_host1xr",
+ "csr_idxsrd",
+ "csr_idxsrd2",
+ "csr_mpe_ipred",
+ "csr_mpeamemrd",
+ "csr_mpecsrd",
+ "csr_ppcsahbdmar",
+ "csr_ppcsahbslvr",
+ "csr_satar",
+ "csr_texsrd",
+ "csr_texsrd2",
+ "csr_vdebsevr",
+ "csr_vdember",
+ "csr_vdemcer",
+ "csr_vdetper",
+ "csr_mpcorelpr",
+ "csr_mpcorer",
+ "cbw_eppu",
+ "cbw_eppv",
+ "cbw_eppy",
+ "cbw_mpeunifbw",
+ "cbw_viwsb",
+ "cbw_viwu",
+ "cbw_viwv",
+ "cbw_viwy",
+ "ccw_g2dw",
+ "csw_afiw",
+ "csw_avpcarm7w",
+ "csw_fdcdwr",
+ "csw_fdcdwr2",
+ "csw_hdaw",
+ "csw_host1xw",
+ "csw_ispw",
+ "csw_mpcorelpw",
+ "csw_mpcorew",
+ "csw_mpecswr",
+ "csw_ppcsahbdmaw",
+ "csw_ppcsahbslvw",
+ "csw_sataw",
+ "csw_vdebsevw",
+ "csw_vdedbgw",
+ "csw_vdembew",
+ "csw_vdetpmw",
+};
+
+static void tegra30_mc_decode(struct tegra30_mc *mc, int n)
+{
+ u32 err, addr;
+ const char * const mc_int_err[] = {
+ "MC_DECERR",
+ "Unknown",
+ "MC_SECURITY_ERR",
+ "MC_ARBITRATION_EMEM",
+ "MC_SMMU_ERR",
+ };
+ const char * const err_type[] = {
+ "Unknown",
+ "Unknown",
+ "DECERR_EMEM",
+ "SECURITY_TRUSTZONE",
+ "SECURITY_CARVEOUT",
+ "Unknown",
+ "INVALID_SMMU_PAGE",
+ "Unknown",
+ };
+ char attr[6];
+ int cid, perm, type, idx;
+ const char *client = "Unknown";
+
+ idx = n - MC_INT_ERR_SHIFT;
+ if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
+ dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+ BIT(n));
+ return;
+ }
+
+ err = readl(mc + MC_ERR_STATUS);
+
+ type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
+ perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
+ MC_ERR_INVALID_SMMU_PAGE_SHIFT;
+ if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
+ sprintf(attr, "%c-%c-%c",
+ (perm & BIT(2)) ? 'R' : '-',
+ (perm & BIT(1)) ? 'W' : '-',
+ (perm & BIT(0)) ? 'S' : '-');
+ else
+ attr[0] = '\0';
+
+ cid = err & MC_CLIENT_ID_MASK;
+ if (cid < ARRAY_SIZE(tegra30_mc_client))
+ client = tegra30_mc_client[cid];
+
+ addr = readl(mc + MC_ERR_ADR);
+
+ dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
+ mc_int_err[idx], err, addr, client,
+ (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
+ (err & MC_ERR_RW) ? "write" : "read",
+ err_type[type], attr);
+}
+
+static const u32 tegra30_mc_ctx[] = {
+ MC_EMEM_ARB_CFG,
+ MC_EMEM_ARB_OUTSTANDING_REQ,
+ MC_EMEM_ARB_TIMING_RCD,
+ MC_EMEM_ARB_TIMING_RP,
+ MC_EMEM_ARB_TIMING_RC,
+ MC_EMEM_ARB_TIMING_RAS,
+ MC_EMEM_ARB_TIMING_FAW,
+ MC_EMEM_ARB_TIMING_RRD,
+ MC_EMEM_ARB_TIMING_RAP2PRE,
+ MC_EMEM_ARB_TIMING_WAP2PRE,
+ MC_EMEM_ARB_TIMING_R2R,
+ MC_EMEM_ARB_TIMING_W2W,
+ MC_EMEM_ARB_TIMING_R2W,
+ MC_EMEM_ARB_TIMING_W2R,
+ MC_EMEM_ARB_DA_TURNS,
+ MC_EMEM_ARB_DA_COVERS,
+ MC_EMEM_ARB_MISC0,
+ MC_EMEM_ARB_MISC1,
+ MC_EMEM_ARB_RING3_THROTTLE,
+ MC_EMEM_ARB_OVERRIDE,
+ MC_INTMASK,
+};
+
+static int tegra30_mc_suspend(struct device *dev)
+{
+ int i;
+ struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+ mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
+ return 0;
+}
+
+static int tegra30_mc_resume(struct device *dev)
+{
+ int i;
+ struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+ mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
+
+ mc_writel(mc, 1, MC_TIMING_CONTROL);
+ /* Read-back to ensure that write reached */
+ mc_readl(mc, MC_TIMING_CONTROL);
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
+ tegra30_mc_suspend,
+ tegra30_mc_resume, NULL);
+
+static const struct of_device_id tegra30_mc_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra30-mc", },
+ {},
+};
+
+static irqreturn_t tegra30_mc_isr(int irq, void *data)
+{
+ u32 stat, mask, bit;
+ struct tegra30_mc *mc = data;
+
+ stat = mc_readl(mc, MC_INTSTATUS);
+ mask = mc_readl(mc, MC_INTMASK);
+ mask &= stat;
+ if (!mask)
+ return IRQ_NONE;
+ while ((bit = ffs(mask)) != 0)
+ tegra30_mc_decode(mc, bit - 1);
+ mc_writel(mc, stat, MC_INTSTATUS);
+ return IRQ_HANDLED;
+}
+
+static int __devinit tegra30_mc_probe(struct platform_device *pdev)
+{
+ struct resource *irq;
+ struct tegra30_mc *mc;
+ size_t bytes;
+ int err, i;
+ u32 intmask;
+
+ bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
+ mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+ mc->dev = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ return -ENODEV;
+ mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mc->regs[i])
+ return -EBUSY;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq)
+ return -ENODEV;
+ err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), mc);
+ if (err)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, mc);
+
+ intmask = MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+ mc_writel(mc, intmask, MC_INTMASK);
+ return 0;
+}
+
+static struct platform_driver tegra30_mc_driver = {
+ .probe = tegra30_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_mc_of_match,
+ .pm = &tegra30_mc_pm,
+ },
+};
+module_platform_driver(tegra30_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 11e44386..f4b4dad 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -162,6 +162,7 @@ config MFD_TPS6586X
bool "TPS6586x Power Management chips"
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
select MFD_CORE
+ depends on REGULATOR
help
If you say yes here you get support for the TPS6586X series of
Power Management chips.
@@ -414,7 +415,7 @@ config MFD_MAX8925
select MFD_CORE
help
Say yes here to support for Maxim Semiconductor MAX8925. This is
- a Power Management IC. This driver provies common support for
+ a Power Management IC. This driver provides common support for
accessing the device, additional drivers must be enabled in order
to use the functionality of the device.
@@ -437,7 +438,7 @@ config MFD_MAX8998
help
Say yes here to support for Maxim Semiconductor MAX8998 and
National Semiconductor LP3974. This is a Power Management IC.
- This driver provies common support for accessing the device,
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device.
@@ -448,7 +449,7 @@ config MFD_S5M_CORE
select REGMAP_I2C
help
Support for the Samsung Electronics S5M MFD series.
- This driver provies common support for accessing the device,
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device
@@ -648,23 +649,6 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc..
-config AB5500_CORE
- bool "ST-Ericsson AB5500 Mixed Signal Power Management chip"
- depends on ABX500_CORE && MFD_DB5500_PRCMU
- select MFD_CORE
- help
- Select this option to enable access to AB5500 power management
- chip. This connects to the db5500 chip via the I2C bus via PRCMU.
- This chip embeds various other multimedia funtionalities as well.
-
-config AB5500_DEBUG
- bool "Enable debug info via debugfs"
- depends on AB5500_CORE && DEBUG_FS
- default y if DEBUG_FS
- help
- Select this option if you want debug information from the AB5500
- using the debug filesystem, debugfs.
-
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on GENERIC_HARDIRQS && ABX500_CORE
@@ -711,16 +695,6 @@ config MFD_DB8500_PRCMU
system controller running an XP70 microprocessor, which is accessed
through a register map.
-config MFD_DB5500_PRCMU
- bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
- depends on UX500_SOC_DB5500
- select MFD_CORE
- help
- Select this option to enable support for the DB5500 Power Reset
- and Control Management Unit. This is basically an autonomous
- system controller running an XP70 microprocessor, which is accessed
- through a register map.
-
config MFD_CS5535
tristate "Support for CS5535 and CS5536 southbridge core functions"
select MFD_CORE
@@ -888,6 +862,16 @@ config MFD_ANATOP
MFD controller. This controller embeds regulator and
thermal devices for Freescale i.MX platforms.
+config MFD_PALMAS
+ bool "Support for the TI Palmas series chips"
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ depends on I2C=y
+ help
+ If you say yes here you get support for the Palmas
+ series of PMIC chips from Texas Instruments.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 05fa538..43672b8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -87,15 +87,12 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
-obj-$(CONFIG_AB5500_CORE) += ab5500-core.o
-obj-$(CONFIG_AB5500_DEBUG) += ab5500-debugfs.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
-obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
@@ -113,6 +110,8 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
+obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
deleted file mode 100644
index 54d0fe4..0000000
--- a/drivers/mfd/ab5500-core.c
+++ /dev/null
@@ -1,1439 +0,0 @@
-/*
- * Copyright (C) 2007-2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Low-level core for exclusive access to the AB5500 IC on the I2C bus
- * and some basic chip-configuration.
- * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- * Author: Mattias Wallin <mattias.wallin@stericsson.com>
- * Author: Rickard Andersson <rickard.andersson@stericsson.com>
- * Author: Karl Komierowski <karl.komierowski@stericsson.com>
- * Author: Bibek Basu <bibek.basu@stericsson.com>
- *
- * TODO: Event handling with irq_chip. Waiting for PRCMU fw support.
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/random.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/db5500-prcmu.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-#define AB5500_NUM_EVENT_REG 23
-#define AB5500_IT_LATCH0_REG 0x40
-#define AB5500_IT_MASK0_REG 0x60
-
-/*
- * Permissible register ranges for reading and writing per device and bank.
- *
- * The ranges must be listed in increasing address order, and no overlaps are
- * allowed. It is assumed that write permission implies read permission
- * (i.e. only RO and RW permissions should be used). Ranges with write
- * permission must not be split up.
- */
-
-#define NO_RANGE {.count = 0, .range = NULL,}
-static struct ab5500_i2c_banks ab5500_bank_ranges[AB5500_NUM_DEVICES] = {
- [AB5500_DEVID_USB] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_USB,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x83,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8B,
- .last = 0x8B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x91,
- .last = 0x92,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x93,
- .last = 0x93,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x94,
- .last = 0x94,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xA8,
- .last = 0xB0,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB2,
- .last = 0xB2,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB4,
- .last = 0xBC,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xBF,
- .last = 0xBF,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xC1,
- .last = 0xC5,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- },
- },
- [AB5500_DEVID_ADC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_ADC,
- .nranges = 6,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x1F,
- .last = 0x22,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x23,
- .last = 0x24,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x26,
- .last = 0x2D,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x37,
- .last = 0x57,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x58,
- .last = 0x58,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- },
- },
- [AB5500_DEVID_LEDS] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_LED,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_VIDEO] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_VDENC,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x09,
- .last = 0x09,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0A,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x15,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1B,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x41,
- .last = 0x41,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x69,
- .last = 0x69,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x6C,
- .last = 0x6D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x81,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_REGULATORS] = {
- .nbanks = 2,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1F,
- .last = 0x1F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x2E,
- .last = 0x2E,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x51,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x61,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x66,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8C,
- .last = 0x96,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xAA,
- .last = 0xB4,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xB7,
- .last = 0xBF,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xC1,
- .last = 0xCA,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xD3,
- .last = 0xE0,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_SIM] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_RTC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_RTC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x04,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x06,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_CHARGER] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_CHG,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x11,
- .last = 0x11,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x12,
- .last = 0x1B,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_FUELGAUGE] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_FG_BATTCOM_ACC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0C,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_VIBRATOR] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_VIBRA,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x10,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xFE,
- .last = 0xFE,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_CODEC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x48,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xEB,
- .last = 0xFB,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_POWER] = {
- .nbanks = 2,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x30,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- {
- .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
-};
-
-#define AB5500_IRQ(bank, bit) ((bank) * 8 + (bit))
-
-/* I appologize for the resource names beeing a mix of upper case
- * and lower case but I want them to be exact as the documentation */
-static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = {
- [AB5500_DEVID_LEDS] = {
- .name = "ab5500-leds",
- .id = AB5500_DEVID_LEDS,
- },
- [AB5500_DEVID_POWER] = {
- .name = "ab5500-power",
- .id = AB5500_DEVID_POWER,
- },
- [AB5500_DEVID_REGULATORS] = {
- .name = "ab5500-regulator",
- .id = AB5500_DEVID_REGULATORS,
- },
- [AB5500_DEVID_SIM] = {
- .name = "ab5500-sim",
- .id = AB5500_DEVID_SIM,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "SIMOFF",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(2, 0), /*rising*/
- .end = AB5500_IRQ(2, 1), /*falling*/
- },
- },
- },
- [AB5500_DEVID_RTC] = {
- .name = "ab5500-rtc",
- .id = AB5500_DEVID_RTC,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "RTC_Alarm",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 7),
- .end = AB5500_IRQ(1, 7),
- }
- },
- },
- [AB5500_DEVID_CHARGER] = {
- .name = "ab5500-charger",
- .id = AB5500_DEVID_CHARGER,
- },
- [AB5500_DEVID_ADC] = {
- .name = "ab5500-adc",
- .id = AB5500_DEVID_ADC,
- .num_resources = 10,
- .resources = (struct resource[]) {
- {
- .name = "TRIGGER-0",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 0),
- .end = AB5500_IRQ(0, 0),
- },
- {
- .name = "TRIGGER-1",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 1),
- .end = AB5500_IRQ(0, 1),
- },
- {
- .name = "TRIGGER-2",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 2),
- .end = AB5500_IRQ(0, 2),
- },
- {
- .name = "TRIGGER-3",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 3),
- .end = AB5500_IRQ(0, 3),
- },
- {
- .name = "TRIGGER-4",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 4),
- .end = AB5500_IRQ(0, 4),
- },
- {
- .name = "TRIGGER-5",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 5),
- .end = AB5500_IRQ(0, 5),
- },
- {
- .name = "TRIGGER-6",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 6),
- .end = AB5500_IRQ(0, 6),
- },
- {
- .name = "TRIGGER-7",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 7),
- .end = AB5500_IRQ(0, 7),
- },
- {
- .name = "TRIGGER-VBAT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 8),
- .end = AB5500_IRQ(0, 8),
- },
- {
- .name = "TRIGGER-VBAT-TXON",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 9),
- .end = AB5500_IRQ(0, 9),
- },
- },
- },
- [AB5500_DEVID_FUELGAUGE] = {
- .name = "ab5500-fuelgauge",
- .id = AB5500_DEVID_FUELGAUGE,
- .num_resources = 6,
- .resources = (struct resource[]) {
- {
- .name = "Batt_attach",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 5),
- .end = AB5500_IRQ(7, 5),
- },
- {
- .name = "Batt_removal",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 6),
- .end = AB5500_IRQ(7, 6),
- },
- {
- .name = "UART_framing",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 7),
- .end = AB5500_IRQ(7, 7),
- },
- {
- .name = "UART_overrun",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 0),
- .end = AB5500_IRQ(8, 0),
- },
- {
- .name = "UART_Rdy_RX",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 1),
- .end = AB5500_IRQ(8, 1),
- },
- {
- .name = "UART_Rdy_TX",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 2),
- .end = AB5500_IRQ(8, 2),
- },
- },
- },
- [AB5500_DEVID_VIBRATOR] = {
- .name = "ab5500-vibrator",
- .id = AB5500_DEVID_VIBRATOR,
- },
- [AB5500_DEVID_CODEC] = {
- .name = "ab5500-codec",
- .id = AB5500_DEVID_CODEC,
- .num_resources = 3,
- .resources = (struct resource[]) {
- {
- .name = "audio_spkr1_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 5),
- .end = AB5500_IRQ(9, 5),
- },
- {
- .name = "audio_plllocked",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 6),
- .end = AB5500_IRQ(9, 6),
- },
- {
- .name = "audio_spkr2_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 4),
- .end = AB5500_IRQ(17, 4),
- },
- },
- },
- [AB5500_DEVID_USB] = {
- .name = "ab5500-usb",
- .id = AB5500_DEVID_USB,
- .num_resources = 36,
- .resources = (struct resource[]) {
- {
- .name = "Link_Update",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(22, 1),
- .end = AB5500_IRQ(22, 1),
- },
- {
- .name = "DCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 3),
- .end = AB5500_IRQ(8, 4),
- },
- {
- .name = "VBUS_R",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 5),
- .end = AB5500_IRQ(8, 5),
- },
- {
- .name = "VBUS_F",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 6),
- .end = AB5500_IRQ(8, 6),
- },
- {
- .name = "CHGstate_10_PCVBUSchg",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 7),
- .end = AB5500_IRQ(8, 7),
- },
- {
- .name = "DCIOreverse_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 0),
- .end = AB5500_IRQ(9, 0),
- },
- {
- .name = "USBCharDetDone",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 1),
- .end = AB5500_IRQ(9, 1),
- },
- {
- .name = "DCIO_no_limit",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 2),
- .end = AB5500_IRQ(9, 2),
- },
- {
- .name = "USB_suspend",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 3),
- .end = AB5500_IRQ(9, 3),
- },
- {
- .name = "DCIOreverse_fwdcurrent",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 4),
- .end = AB5500_IRQ(9, 4),
- },
- {
- .name = "Vbus_Imeasmax_change",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 5),
- .end = AB5500_IRQ(9, 6),
- },
- {
- .name = "OVV",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 5),
- .end = AB5500_IRQ(14, 5),
- },
- {
- .name = "USBcharging_NOTok",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 3),
- .end = AB5500_IRQ(15, 3),
- },
- {
- .name = "usb_adp_sensoroff",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 6),
- .end = AB5500_IRQ(15, 6),
- },
- {
- .name = "usb_adp_probeplug",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 7),
- .end = AB5500_IRQ(15, 7),
- },
- {
- .name = "usb_adp_sinkerror",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 0),
- .end = AB5500_IRQ(16, 6),
- },
- {
- .name = "usb_adp_sourceerror",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 1),
- .end = AB5500_IRQ(16, 1),
- },
- {
- .name = "usb_idgnd_r",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 2),
- .end = AB5500_IRQ(16, 2),
- },
- {
- .name = "usb_idgnd_f",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 3),
- .end = AB5500_IRQ(16, 3),
- },
- {
- .name = "usb_iddetR1",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 4),
- .end = AB5500_IRQ(16, 5),
- },
- {
- .name = "usb_iddetR2",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 6),
- .end = AB5500_IRQ(16, 7),
- },
- {
- .name = "usb_iddetR3",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 0),
- .end = AB5500_IRQ(17, 1),
- },
- {
- .name = "usb_iddetR4",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 2),
- .end = AB5500_IRQ(17, 3),
- },
- {
- .name = "CharTempWindowOk",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 7),
- .end = AB5500_IRQ(18, 0),
- },
- {
- .name = "USB_SprDetect",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 1),
- .end = AB5500_IRQ(18, 1),
- },
- {
- .name = "usb_adp_probe_unplug",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 2),
- .end = AB5500_IRQ(18, 2),
- },
- {
- .name = "VBUSChDrop",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 3),
- .end = AB5500_IRQ(18, 4),
- },
- {
- .name = "dcio_char_rec_done",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 5),
- .end = AB5500_IRQ(18, 5),
- },
- {
- .name = "Charging_stopped_by_temp",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 6),
- .end = AB5500_IRQ(18, 6),
- },
- {
- .name = "CHGstate_11_SafeModeVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 1),
- .end = AB5500_IRQ(21, 2),
- },
- {
- .name = "CHGstate_12_comletedVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 2),
- .end = AB5500_IRQ(21, 2),
- },
- {
- .name = "CHGstate_13_completedVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 3),
- .end = AB5500_IRQ(21, 3),
- },
- {
- .name = "CHGstate_14_FullChgDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 4),
- .end = AB5500_IRQ(21, 4),
- },
- {
- .name = "CHGstate_15_SafeModeDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 5),
- .end = AB5500_IRQ(21, 5),
- },
- {
- .name = "CHGstate_16_OFFsuspendDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 6),
- .end = AB5500_IRQ(21, 6),
- },
- {
- .name = "CHGstate_17_completedDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 7),
- .end = AB5500_IRQ(21, 7),
- },
- },
- },
- [AB5500_DEVID_OTP] = {
- .name = "ab5500-otp",
- .id = AB5500_DEVID_OTP,
- },
- [AB5500_DEVID_VIDEO] = {
- .name = "ab5500-video",
- .id = AB5500_DEVID_VIDEO,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "plugTVdet",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(22, 2),
- .end = AB5500_IRQ(22, 2),
- },
- },
- },
- [AB5500_DEVID_DBIECI] = {
- .name = "ab5500-dbieci",
- .id = AB5500_DEVID_DBIECI,
- .num_resources = 10,
- .resources = (struct resource[]) {
- {
- .name = "COLL",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 0),
- .end = AB5500_IRQ(14, 0),
- },
- {
- .name = "RESERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 1),
- .end = AB5500_IRQ(14, 1),
- },
- {
- .name = "FRAERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 2),
- .end = AB5500_IRQ(14, 2),
- },
- {
- .name = "COMERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 3),
- .end = AB5500_IRQ(14, 3),
- },
- {
- .name = "BSI_indicator",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 4),
- .end = AB5500_IRQ(14, 4),
- },
- {
- .name = "SPDSET",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 6),
- .end = AB5500_IRQ(14, 6),
- },
- {
- .name = "DSENT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 7),
- .end = AB5500_IRQ(14, 7),
- },
- {
- .name = "DREC",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 0),
- .end = AB5500_IRQ(15, 0),
- },
- {
- .name = "ACCINT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 1),
- .end = AB5500_IRQ(15, 1),
- },
- {
- .name = "NOPINT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 2),
- .end = AB5500_IRQ(15, 2),
- },
- },
- },
- [AB5500_DEVID_ONSWA] = {
- .name = "ab5500-onswa",
- .id = AB5500_DEVID_ONSWA,
- .num_resources = 2,
- .resources = (struct resource[]) {
- {
- .name = "ONSWAn_rising",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 3),
- .end = AB5500_IRQ(1, 3),
- },
- {
- .name = "ONSWAn_falling",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 4),
- .end = AB5500_IRQ(1, 4),
- },
- },
- },
-};
-
-/*
- * Functionality for getting/setting register values.
- */
-int ab5500_get_register_interruptible_raw(struct ab5500 *ab,
- u8 bank, u8 reg,
- u8 *value)
-{
- int err;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, reg, value, 1);
-
- mutex_unlock(&ab->access_mutex);
- return err;
-}
-
-static int get_register_page_interruptible(struct ab5500 *ab, u8 bank,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- int err;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
-
- while (numregs) {
- /* The hardware limit for get page is 4 */
- u8 curnum = min_t(u8, numregs, 4u);
-
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
- first_reg, regvals, curnum);
- if (err)
- goto out;
-
- numregs -= curnum;
- first_reg += curnum;
- regvals += curnum;
- }
-
-out:
- mutex_unlock(&ab->access_mutex);
- return err;
-}
-
-int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank,
- u8 reg, u8 bitmask, u8 bitvalues)
-{
- int err = 0;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- if (bitmask) {
- u8 buf;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
-
- if (bitmask == 0xFF) /* No need to read in this case. */
- buf = bitvalues;
- else { /* Read and modify the register value. */
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
- reg, &buf, 1);
- if (err)
- return err;
-
- buf = ((~bitmask & buf) | (bitmask & bitvalues));
- }
- /* Write the new value. */
- err = db5500_prcmu_abb_write(bankinfo[bank].slave_addr, reg,
- &buf, 1);
-
- mutex_unlock(&ab->access_mutex);
- }
- return err;
-}
-
-static int
-set_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg, u8 value)
-{
- return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
- 0xff, value);
-}
-
-/*
- * Read/write permission checking functions.
- */
-static const struct ab5500_i2c_ranges *get_bankref(u8 devid, u8 bank)
-{
- u8 i;
-
- if (devid < AB5500_NUM_DEVICES) {
- for (i = 0; i < ab5500_bank_ranges[devid].nbanks; i++) {
- if (ab5500_bank_ranges[devid].bank[i].bankid == bank)
- return &ab5500_bank_ranges[devid].bank[i];
- }
- }
- return NULL;
-}
-
-static bool page_write_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
- u8 i; /* range loop index */
- const struct ab5500_i2c_ranges *bankref;
-
- bankref = get_bankref(devid, bank);
- if (bankref == NULL || last_reg < first_reg)
- return false;
-
- for (i = 0; i < bankref->nranges; i++) {
- if (first_reg < bankref->range[i].first)
- break;
- if ((last_reg <= bankref->range[i].last) &&
- (bankref->range[i].perm & AB5500_PERM_WR))
- return true;
- }
- return false;
-}
-
-static bool reg_write_allowed(u8 devid, u8 bank, u8 reg)
-{
- return page_write_allowed(devid, bank, reg, reg);
-}
-
-static bool page_read_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
- u8 i;
- const struct ab5500_i2c_ranges *bankref;
-
- bankref = get_bankref(devid, bank);
- if (bankref == NULL || last_reg < first_reg)
- return false;
-
-
- /* Find the range (if it exists in the list) that includes first_reg. */
- for (i = 0; i < bankref->nranges; i++) {
- if (first_reg < bankref->range[i].first)
- return false;
- if (first_reg <= bankref->range[i].last)
- break;
- }
- /* Make sure that the entire range up to and including last_reg is
- * readable. This may span several of the ranges in the list.
- */
- while ((i < bankref->nranges) &&
- (bankref->range[i].perm & AB5500_PERM_RD)) {
- if (last_reg <= bankref->range[i].last)
- return true;
- if ((++i >= bankref->nranges) ||
- (bankref->range[i].first !=
- (bankref->range[i - 1].last + 1))) {
- break;
- }
- }
- return false;
-}
-
-static bool reg_read_allowed(u8 devid, u8 bank, u8 reg)
-{
- return page_read_allowed(devid, bank, reg, reg);
-}
-
-
-/*
- * The exported register access functionality.
- */
-static int ab5500_get_chip_id(struct device *dev)
-{
- struct ab5500 *ab = dev_get_drvdata(dev->parent);
-
- return (int)ab->chip_id;
-}
-
-static int ab5500_mask_and_set_register_interruptible(struct device *dev,
- u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !reg_write_allowed(pdev->id, bank, reg))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
- bitmask, bitvalues);
-}
-
-static int ab5500_set_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 value)
-{
- return ab5500_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
- value);
-}
-
-static int ab5500_get_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 *value)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !reg_read_allowed(pdev->id, bank, reg))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return ab5500_get_register_interruptible_raw(ab, bank, reg, value);
-}
-
-static int ab5500_get_register_page_interruptible(struct device *dev, u8 bank,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !page_read_allowed(pdev->id, bank,
- first_reg, (first_reg + numregs - 1)))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return get_register_page_interruptible(ab, bank, first_reg, regvals,
- numregs);
-}
-
-static int
-ab5500_event_registers_startup_state_get(struct device *dev, u8 *event)
-{
- struct ab5500 *ab;
-
- ab = dev_get_drvdata(dev->parent);
- if (!ab->startup_events_read)
- return -EAGAIN; /* Try again later */
-
- memcpy(event, ab->startup_events, AB5500_NUM_EVENT_REG);
- return 0;
-}
-
-static struct abx500_ops ab5500_ops = {
- .get_chip_id = ab5500_get_chip_id,
- .get_register = ab5500_get_register_interruptible,
- .set_register = ab5500_set_register_interruptible,
- .get_register_page = ab5500_get_register_page_interruptible,
- .set_register_page = NULL,
- .mask_and_set_register = ab5500_mask_and_set_register_interruptible,
- .event_registers_startup_state_get =
- ab5500_event_registers_startup_state_get,
- .startup_irq_enabled = NULL,
-};
-
-/*
- * ab5500_setup : Basic set-up, datastructure creation/destruction
- * and I2C interface.This sets up a default config
- * in the AB5500 chip so that it will work as expected.
- * @ab : Pointer to ab5500 structure
- * @settings : Pointer to struct abx500_init_settings
- * @size : Size of init data
- */
-static int __init ab5500_setup(struct ab5500 *ab,
- struct abx500_init_settings *settings, unsigned int size)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < size; i++) {
- err = ab5500_mask_and_set_register_interruptible_raw(ab,
- settings[i].bank,
- settings[i].reg,
- 0xFF, settings[i].setting);
- if (err)
- goto exit_no_setup;
-
- /* If event mask register update the event mask in ab5500 */
- if ((settings[i].bank == AB5500_BANK_IT) &&
- (AB5500_MASK_BASE <= settings[i].reg) &&
- (settings[i].reg <= AB5500_MASK_END)) {
- ab->mask[settings[i].reg - AB5500_MASK_BASE] =
- settings[i].setting;
- }
- }
-exit_no_setup:
- return err;
-}
-
-struct ab_family_id {
- u8 id;
- char *name;
-};
-
-static const struct ab_family_id ids[] __initdata = {
- /* AB5500 */
- {
- .id = AB5500_1_0,
- .name = "1.0"
- },
- {
- .id = AB5500_1_1,
- .name = "1.1"
- },
- /* Terminator */
- {
- .id = 0x00,
- }
-};
-
-static int __init ab5500_probe(struct platform_device *pdev)
-{
- struct ab5500 *ab;
- struct ab5500_platform_data *ab5500_plf_data =
- pdev->dev.platform_data;
- int err;
- int i;
-
- ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL);
- if (!ab) {
- dev_err(&pdev->dev,
- "could not allocate ab5500 device\n");
- return -ENOMEM;
- }
-
- /* Initialize data structure */
- mutex_init(&ab->access_mutex);
- mutex_init(&ab->irq_lock);
- ab->dev = &pdev->dev;
-
- platform_set_drvdata(pdev, ab);
-
- /* Read chip ID register */
- err = ab5500_get_register_interruptible_raw(ab,
- AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- AB5500_CHIP_ID, &ab->chip_id);
- if (err) {
- dev_err(&pdev->dev, "could not communicate with the analog "
- "baseband chip\n");
- goto exit_no_detect;
- }
-
- for (i = 0; ids[i].id != 0x0; i++) {
- if (ids[i].id == ab->chip_id) {
- snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1,
- "AB5500 %s", ids[i].name);
- break;
- }
- }
- if (ids[i].id == 0x0) {
- dev_err(&pdev->dev, "unknown analog baseband chip id: 0x%x\n",
- ab->chip_id);
- dev_err(&pdev->dev, "driver not started!\n");
- goto exit_no_detect;
- }
-
- /* Clear and mask all interrupts */
- for (i = 0; i < AB5500_NUM_IRQ_REGS; i++) {
- u8 latchreg = AB5500_IT_LATCH0_REG + i;
- u8 maskreg = AB5500_IT_MASK0_REG + i;
- u8 val;
-
- ab5500_get_register_interruptible_raw(ab, AB5500_BANK_IT,
- latchreg, &val);
- set_register_interruptible(ab, AB5500_BANK_IT, maskreg, 0xff);
- ab->mask[i] = ab->oldmask[i] = 0xff;
- }
-
- err = abx500_register_ops(&pdev->dev, &ab5500_ops);
- if (err) {
- dev_err(&pdev->dev, "ab5500_register ops error\n");
- goto exit_no_detect;
- }
-
- /* Set up and register the platform devices. */
- for (i = 0; i < AB5500_NUM_DEVICES; i++) {
- ab5500_devs[i].platform_data = ab5500_plf_data->dev_data[i];
- ab5500_devs[i].pdata_size =
- sizeof(ab5500_plf_data->dev_data[i]);
- }
-
- err = mfd_add_devices(&pdev->dev, 0, ab5500_devs,
- ARRAY_SIZE(ab5500_devs), NULL,
- ab5500_plf_data->irq.base);
- if (err) {
- dev_err(&pdev->dev, "ab5500_mfd_add_device error\n");
- goto exit_no_detect;
- }
-
- err = ab5500_setup(ab, ab5500_plf_data->init_settings,
- ab5500_plf_data->init_settings_sz);
- if (err) {
- dev_err(&pdev->dev, "ab5500_setup error\n");
- goto exit_no_detect;
- }
-
- ab5500_setup_debugfs(ab);
-
- dev_info(&pdev->dev, "detected AB chip: %s\n", &ab->chip_name[0]);
- return 0;
-
-exit_no_detect:
- kfree(ab);
- return err;
-}
-
-static int __exit ab5500_remove(struct platform_device *pdev)
-{
- struct ab5500 *ab = platform_get_drvdata(pdev);
-
- ab5500_remove_debugfs();
- mfd_remove_devices(&pdev->dev);
- kfree(ab);
- return 0;
-}
-
-static struct platform_driver ab5500_driver = {
- .driver = {
- .name = "ab5500-core",
- .owner = THIS_MODULE,
- },
- .remove = __exit_p(ab5500_remove),
-};
-
-static int __init ab5500_core_init(void)
-{
- return platform_driver_probe(&ab5500_driver, ab5500_probe);
-}
-
-static void __exit ab5500_core_exit(void)
-{
- platform_driver_unregister(&ab5500_driver);
-}
-
-subsys_initcall(ab5500_core_init);
-module_exit(ab5500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("AB5500 core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c
deleted file mode 100644
index 7200694..0000000
--- a/drivers/mfd/ab5500-debugfs.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs support for the AB5500 MFD driver
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/uaccess.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = {
- [AB5500_BANK_LED] = {
- .bankid = AB5500_BANK_LED,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_ADC] = {
- .bankid = AB5500_BANK_ADC,
- .nranges = 6,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x1F,
- .last = 0x22,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x23,
- .last = 0x24,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x26,
- .last = 0x2D,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x37,
- .last = 0x57,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x58,
- .last = 0x58,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_RTC] = {
- .bankid = AB5500_BANK_RTC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x04,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x06,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_STARTUP] = {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1F,
- .last = 0x1F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x2E,
- .last = 0x2E,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x51,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x61,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x66,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8C,
- .last = 0x96,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xAA,
- .last = 0xB4,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xB7,
- .last = 0xBF,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xC1,
- .last = 0xCA,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xD3,
- .last = 0xE0,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_DBI_ECI] = {
- .bankid = AB5500_BANK_DBI_ECI,
- .nranges = 3,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x07,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x10,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x13,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_CHG] = {
- .bankid = AB5500_BANK_CHG,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x11,
- .last = 0x11,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x12,
- .last = 0x1B,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_FG_BATTCOM_ACC] = {
- .bankid = AB5500_BANK_FG_BATTCOM_ACC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0C,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_USB] = {
- .bankid = AB5500_BANK_USB,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x83,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8B,
- .last = 0x8B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x91,
- .last = 0x92,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x93,
- .last = 0x93,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x94,
- .last = 0x94,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xA8,
- .last = 0xB0,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB2,
- .last = 0xB2,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB4,
- .last = 0xBC,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xBF,
- .last = 0xBF,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xC1,
- .last = 0xC5,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_IT] = {
- .bankid = AB5500_BANK_IT,
- .nranges = 4,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x02,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x20,
- .last = 0x36,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x40,
- .last = 0x56,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x60,
- .last = 0x76,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
- .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST,
- .nranges = 7,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x02,
- .last = 0x02,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x12,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x30,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x40,
- .last = 0x44,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x54,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x64,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x70,
- .last = 0x74,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
- .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- .nranges = 13,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x02,
- .last = 0x02,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0D,
- .last = 0x0F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1C,
- .last = 0x1C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1E,
- .last = 0x1E,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x20,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x25,
- .last = 0x25,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x28,
- .last = 0x2A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x30,
- .last = 0x33,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x40,
- .last = 0x43,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x53,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x63,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x70,
- .last = 0x73,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VIBRA] = {
- .bankid = AB5500_BANK_VIBRA,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x10,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xFE,
- .last = 0xFE,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_AUDIO_HEADSETUSB] = {
- .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x48,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xEB,
- .last = 0xFB,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_SIM_USBSIM] = {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VDENC] = {
- .bankid = AB5500_BANK_VDENC,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x09,
- .last = 0x09,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0A,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x15,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1B,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x41,
- .last = 0x41,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x69,
- .last = 0x69,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x6C,
- .last = 0x6D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x81,
- .perm = AB5500_PERM_RW,
- },
- },
- },
-};
-
-static int ab5500_registers_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
- unsigned int i;
- u8 bank = (u8)ab->debug_bank;
-
- seq_printf(s, "ab5500 register values:\n");
- for (bank = 0; bank < AB5500_NUM_BANKS; bank++) {
- seq_printf(s, " bank %u, %s (0x%x):\n", bank,
- bankinfo[bank].name,
- bankinfo[bank].slave_addr);
- for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) {
- u8 reg;
- int err;
-
- for (reg = ab5500_reg_ranges[bank].range[i].first;
- reg <= ab5500_reg_ranges[bank].range[i].last;
- reg++) {
- u8 value;
-
- err = ab5500_get_register_interruptible_raw(ab,
- bank, reg,
- &value);
- if (err < 0) {
- dev_err(ab->dev, "get_reg failed %d"
- "bank 0x%x reg 0x%x\n",
- err, bank, reg);
- return err;
- }
-
- err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n",
- bank, reg, value);
- if (err < 0) {
- dev_err(ab->dev,
- "seq_printf overflow\n");
- /*
- * Error is not returned here since
- * the output is wanted in any case
- */
- return 0;
- }
- }
- }
- }
- return 0;
-}
-
-static int ab5500_registers_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_registers_print, inode->i_private);
-}
-
-static const struct file_operations ab5500_registers_fops = {
- .open = ab5500_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int ab5500_bank_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
-
- seq_printf(s, "%d\n", ab->debug_bank);
- return 0;
-}
-
-static int ab5500_bank_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_bank_print, inode->i_private);
-}
-
-static ssize_t ab5500_bank_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_bank;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_bank);
- if (err)
- return -EINVAL;
-
- if (user_bank >= AB5500_NUM_BANKS) {
- dev_err(ab->dev,
- "debugfs error input > number of banks\n");
- return -EINVAL;
- }
-
- ab->debug_bank = user_bank;
-
- return buf_size;
-}
-
-static int ab5500_address_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
-
- seq_printf(s, "0x%02X\n", ab->debug_address);
- return 0;
-}
-
-static int ab5500_address_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_address_print, inode->i_private);
-}
-
-static ssize_t ab5500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_address;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_address);
- if (err)
- return -EINVAL;
- if (user_address > 0xff) {
- dev_err(ab->dev,
- "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- ab->debug_address = user_address;
- return buf_size;
-}
-
-static int ab5500_val_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
- int err;
- u8 regvalue;
-
- err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, &regvalue);
- if (err) {
- dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
- ", reg 0x%x\n", err, ab->debug_bank,
- ab->debug_address);
- return -EINVAL;
- }
- seq_printf(s, "0x%02X\n", regvalue);
-
- return 0;
-}
-
-static int ab5500_val_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_val_print, inode->i_private);
-}
-
-static ssize_t ab5500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_val;
- int err;
- u8 regvalue;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
- if (err)
- return -EINVAL;
- if (user_val > 0xff) {
- dev_err(ab->dev,
- "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- err = ab5500_mask_and_set_register_interruptible_raw(
- ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, 0xFF, (u8)user_val);
- if (err)
- return -EINVAL;
-
- ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, &regvalue);
- if (err)
- return -EINVAL;
-
- return buf_size;
-}
-
-static const struct file_operations ab5500_bank_fops = {
- .open = ab5500_bank_open,
- .write = ab5500_bank_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_address_fops = {
- .open = ab5500_address_open,
- .write = ab5500_address_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_val_fops = {
- .open = ab5500_val_open,
- .write = ab5500_val_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static struct dentry *ab5500_dir;
-static struct dentry *ab5500_reg_file;
-static struct dentry *ab5500_bank_file;
-static struct dentry *ab5500_address_file;
-static struct dentry *ab5500_val_file;
-
-void __init ab5500_setup_debugfs(struct ab5500 *ab)
-{
- ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
- ab->debug_address = AB5500_CHIP_ID;
-
- ab5500_dir = debugfs_create_dir("ab5500", NULL);
- if (!ab5500_dir)
- goto exit_no_debugfs;
-
- ab5500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
- if (!ab5500_reg_file)
- goto exit_destroy_dir;
-
- ab5500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
- if (!ab5500_bank_file)
- goto exit_destroy_reg;
-
- ab5500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
- if (!ab5500_address_file)
- goto exit_destroy_bank;
-
- ab5500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
- if (!ab5500_val_file)
- goto exit_destroy_address;
-
- return;
-
-exit_destroy_address:
- debugfs_remove(ab5500_address_file);
-exit_destroy_bank:
- debugfs_remove(ab5500_bank_file);
-exit_destroy_reg:
- debugfs_remove(ab5500_reg_file);
-exit_destroy_dir:
- debugfs_remove(ab5500_dir);
-exit_no_debugfs:
- dev_err(ab->dev, "failed to create debugfs entries.\n");
- return;
-}
-
-void __exit ab5500_remove_debugfs(void)
-{
- debugfs_remove(ab5500_val_file);
- debugfs_remove(ab5500_address_file);
- debugfs_remove(ab5500_bank_file);
- debugfs_remove(ab5500_reg_file);
- debugfs_remove(ab5500_dir);
-}
diff --git a/drivers/mfd/ab5500-debugfs.h b/drivers/mfd/ab5500-debugfs.h
deleted file mode 100644
index 7330a9b..0000000
--- a/drivers/mfd/ab5500-debugfs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs interface to the AB5500 core driver
- */
-
-#ifdef CONFIG_DEBUG_FS
-
-void ab5500_setup_debugfs(struct ab5500 *ab);
-void ab5500_remove_debugfs(void);
-
-#else /* !CONFIG_DEBUG_FS */
-
-static inline void ab5500_setup_debugfs(struct ab5500 *ab)
-{
-}
-
-static inline void ab5500_remove_debugfs(void)
-{
-}
-
-#endif
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index 7ff313f..7776aff 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -659,12 +659,11 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
da9052->irq_base, &da9052_regmap_irq_chip,
- NULL);
+ &da9052->irq_data);
if (ret < 0)
goto regmap_err;
- desc = irq_to_desc(da9052->chip_irq);
- da9052->irq_base = regmap_irq_chip_get_base(desc->action->dev_id);
+ da9052->irq_base = regmap_irq_chip_get_base(da9052->irq_data);
ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
ARRAY_SIZE(da9052_subdev_info), NULL, 0);
@@ -681,8 +680,7 @@ regmap_err:
void da9052_device_exit(struct da9052 *da9052)
{
- regmap_del_irq_chip(da9052->chip_irq,
- irq_get_irq_data(da9052->irq_base)->chip_data);
+ regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);
mfd_remove_devices(da9052->dev);
}
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
deleted file mode 100644
index bb115b2..0000000
--- a/drivers/mfd/db5500-prcmu.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U5500 PRCM Unit interface driver
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/db5500-regs.h>
-#include "dbx500-prcmu-regs.h"
-
-#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
-#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
-#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
-#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
-#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
-#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
-#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
-#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
-#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
-#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
-#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
-#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
-#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
-#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
-#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
-#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
-#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
-
-/* Req Mailboxes */
-#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
-#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
-#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
-#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
-#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
-#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
-#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
-#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
-
-/* Ack Mailboxes */
-#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
-#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
-#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
-#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
-#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
-#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
-#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
-#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
-
-enum mb_return_code {
- RC_SUCCESS,
- RC_FAIL,
-};
-
-/* Mailbox 0 headers. */
-enum mb0_header {
- /* request */
- RMB0H_PWR_STATE_TRANS = 1,
- RMB0H_WAKE_UP_CFG,
- RMB0H_RD_WAKE_UP_ACK,
- /* acknowledge */
- AMB0H_WAKE_UP = 1,
-};
-
-/* Mailbox 5 headers. */
-enum mb5_header {
- MB5H_I2C_WRITE = 1,
- MB5H_I2C_READ,
-};
-
-/* Request mailbox 5 fields. */
-#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
-#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
-#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
-#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
-
-/* Acknowledge mailbox 5 fields. */
-#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
-#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
-
-#define NUM_MB 8
-#define MBOX_BIT BIT
-#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
-
-/*
-* Used by MCDE to setup all necessary PRCMU registers
-*/
-#define PRCMU_RESET_DSIPLL 0x00004000
-#define PRCMU_UNCLAMP_DSIPLL 0x00400800
-
-/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
-#define PRCMU_DSI_CLOCK_SETTING 0x00000128
-/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
-#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135
-#define PRCMU_PLLDSI_FREQ_SETTING 0x00020121
-#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002
-#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000201
-#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101
-
-#define PRCMU_ENABLE_PLLDSI 0x00000001
-#define PRCMU_DISABLE_PLLDSI 0x00000000
-
-#define PRCMU_DSI_RESET_SW 0x00000003
-#define PRCMU_RESOUTN0_PIN 0x00000001
-#define PRCMU_RESOUTN1_PIN 0x00000002
-#define PRCMU_RESOUTN2_PIN 0x00000004
-
-#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
-
-/*
- * mb0_transfer - state needed for mailbox 0 communication.
- * @lock: The transaction lock.
- */
-static struct {
- spinlock_t lock;
-} mb0_transfer;
-
-/*
- * mb5_transfer - state needed for mailbox 5 communication.
- * @lock: The transaction lock.
- * @work: The transaction completion structure.
- * @ack: Reply ("acknowledge") data.
- */
-static struct {
- struct mutex lock;
- struct completion work;
- struct {
- u8 header;
- u8 status;
- u8 value[4];
- } ack;
-} mb5_transfer;
-
-/* PRCMU TCDM base IO address. */
-static __iomem void *tcdm_base;
-
-/**
- * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The read out value(s).
- * @size: The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if ((size < 1) || (4 < size))
- return -EINVAL;
-
- mutex_lock(&mb5_transfer.lock);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
- writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
- writeb(reg, PRCM_REQ_MB5_I2C_REG);
- writeb(size, PRCM_REQ_MB5_I2C_SIZE);
- writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb5_transfer.work);
-
- r = 0;
- if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
- (mb5_transfer.ack.status == RC_SUCCESS))
- memcpy(value, mb5_transfer.ack.value, (size_t)size);
- else
- r = -EIO;
-
- mutex_unlock(&mb5_transfer.lock);
-
- return r;
-}
-
-/**
- * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The value(s) to write.
- * @size: The number of registers to write.
- *
- * Writes register value(s) to the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if ((size < 1) || (4 < size))
- return -EINVAL;
-
- mutex_lock(&mb5_transfer.lock);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
- writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
- writeb(reg, PRCM_REQ_MB5_I2C_REG);
- writeb(size, PRCM_REQ_MB5_I2C_SIZE);
- memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
- writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb5_transfer.work);
-
- if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
- (mb5_transfer.ack.status == RC_SUCCESS))
- r = 0;
- else
- r = -EIO;
-
- mutex_unlock(&mb5_transfer.lock);
-
- return r;
-}
-
-int db5500_prcmu_enable_dsipll(void)
-{
- int i;
-
- /* Enable DSIPLL_RESETN resets */
- writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
- /* Unclamp DSIPLL in/out */
- writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
- /* Set DSI PLL FREQ */
- writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
- writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
- PRCM_DSI_PLLOUT_SEL);
- /* Enable Escape clocks */
- writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
-
- /* Start DSI PLL */
- writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
- /* Reset DSI PLL */
- writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
- for (i = 0; i < 10; i++) {
- if ((readl(PRCM_PLLDSI_LOCKP) &
- PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
- break;
- udelay(100);
- }
- /* Release DSIPLL_RESETN */
- writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
- return 0;
-}
-
-int db5500_prcmu_disable_dsipll(void)
-{
- /* Disable dsi pll */
- writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
- /* Disable escapeclock */
- writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
- return 0;
-}
-
-int db5500_prcmu_set_display_clocks(void)
-{
- /* HDMI and TVCLK Should be handled somewhere else */
- /* PLLDIV=8, PLLSW=2, CLKEN=1 */
- writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
- /* PLLDIV=14, PLLSW=2, CLKEN=1 */
- writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
- return 0;
-}
-
-static void ack_dbb_wakeup(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mb0_transfer.lock, flags);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
- cpu_relax();
-
- writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
- writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
-
- spin_unlock_irqrestore(&mb0_transfer.lock, flags);
-}
-
-static inline void print_unknown_header_warning(u8 n, u8 header)
-{
- pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
- header, n);
-}
-
-static bool read_mailbox_0(void)
-{
- bool r;
- u8 header;
-
- header = readb(PRCM_ACK_MB0_HEADER);
- switch (header) {
- case AMB0H_WAKE_UP:
- r = true;
- break;
- default:
- print_unknown_header_warning(0, header);
- r = false;
- break;
- }
- writel(MBOX_BIT(0), PRCM_ARM_IT1_CLR);
- return r;
-}
-
-static bool read_mailbox_1(void)
-{
- writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_2(void)
-{
- writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_3(void)
-{
- writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_4(void)
-{
- writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_5(void)
-{
- u8 header;
-
- header = readb(PRCM_ACK_MB5_HEADER);
- switch (header) {
- case MB5H_I2C_READ:
- memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
- case MB5H_I2C_WRITE:
- mb5_transfer.ack.header = header;
- mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
- complete(&mb5_transfer.work);
- break;
- default:
- print_unknown_header_warning(5, header);
- break;
- }
- writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_6(void)
-{
- writel(MBOX_BIT(6), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_7(void)
-{
- writel(MBOX_BIT(7), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool (* const read_mailbox[NUM_MB])(void) = {
- read_mailbox_0,
- read_mailbox_1,
- read_mailbox_2,
- read_mailbox_3,
- read_mailbox_4,
- read_mailbox_5,
- read_mailbox_6,
- read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
- u32 bits;
- u8 n;
- irqreturn_t r;
-
- bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
- if (unlikely(!bits))
- return IRQ_NONE;
-
- r = IRQ_HANDLED;
- for (n = 0; bits; n++) {
- if (bits & MBOX_BIT(n)) {
- bits -= MBOX_BIT(n);
- if (read_mailbox[n]())
- r = IRQ_WAKE_THREAD;
- }
- }
- return r;
-}
-
-static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
-{
- ack_dbb_wakeup();
- return IRQ_HANDLED;
-}
-
-void __init db5500_prcmu_early_init(void)
-{
- tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
- spin_lock_init(&mb0_transfer.lock);
- mutex_init(&mb5_transfer.lock);
- init_completion(&mb5_transfer.work);
-}
-
-/**
- * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
- *
- */
-int __init db5500_prcmu_init(void)
-{
- int r = 0;
-
- if (ux500_is_svp() || !cpu_is_u5500())
- return -ENODEV;
-
- /* Clean up the mailbox interrupts after pre-kernel code. */
- writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
-
- r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
- prcmu_irq_thread_fn, 0, "prcmu", NULL);
- if (r < 0) {
- pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
- return -EBUSY;
- }
- return 0;
-}
-
-arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 9fd4f63..738722c 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -813,7 +813,8 @@ err_revision:
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (mc13xxx->flags & MC13XXX_USE_CODEC)
- mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+ pdata->codec, sizeof(*pdata->codec));
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
new file mode 100644
index 0000000..00c0aba
--- /dev/null
+++ b/drivers/mfd/palmas.c
@@ -0,0 +1,509 @@
+/*
+ * TI Palmas MFD Driver
+ *
+ * Copyright 2011-2012 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/palmas.h>
+
+static const struct resource gpadc_resource[] = {
+ {
+ .name = "EOC_SW",
+ .start = PALMAS_GPADC_EOC_SW_IRQ,
+ .end = PALMAS_GPADC_EOC_SW_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static const struct resource usb_resource[] = {
+ {
+ .name = "ID",
+ .start = PALMAS_ID_OTG_IRQ,
+ .end = PALMAS_ID_OTG_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP",
+ .start = PALMAS_ID_IRQ,
+ .end = PALMAS_ID_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS",
+ .start = PALMAS_VBUS_OTG_IRQ,
+ .end = PALMAS_VBUS_OTG_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_WAKEUP",
+ .start = PALMAS_VBUS_IRQ,
+ .end = PALMAS_VBUS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct resource rtc_resource[] = {
+ {
+ .name = "RTC_ALARM",
+ .start = PALMAS_RTC_ALARM_IRQ,
+ .end = PALMAS_RTC_ALARM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct resource pwron_resource[] = {
+ {
+ .name = "PWRON_BUTTON",
+ .start = PALMAS_PWRON_IRQ,
+ .end = PALMAS_PWRON_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+enum palmas_ids {
+ PALMAS_PMIC_ID,
+ PALMAS_GPIO_ID,
+ PALMAS_LEDS_ID,
+ PALMAS_WDT_ID,
+ PALMAS_RTC_ID,
+ PALMAS_PWRBUTTON_ID,
+ PALMAS_GPADC_ID,
+ PALMAS_RESOURCE_ID,
+ PALMAS_CLK_ID,
+ PALMAS_PWM_ID,
+ PALMAS_USB_ID,
+};
+
+static const struct mfd_cell palmas_children[] = {
+ {
+ .name = "palmas-pmic",
+ .id = PALMAS_PMIC_ID,
+ },
+ {
+ .name = "palmas-gpio",
+ .id = PALMAS_GPIO_ID,
+ },
+ {
+ .name = "palmas-leds",
+ .id = PALMAS_LEDS_ID,
+ },
+ {
+ .name = "palmas-wdt",
+ .id = PALMAS_WDT_ID,
+ },
+ {
+ .name = "palmas-rtc",
+ .num_resources = ARRAY_SIZE(rtc_resource),
+ .resources = rtc_resource,
+ .id = PALMAS_RTC_ID,
+ },
+ {
+ .name = "palmas-pwrbutton",
+ .num_resources = ARRAY_SIZE(pwron_resource),
+ .resources = pwron_resource,
+ .id = PALMAS_PWRBUTTON_ID,
+ },
+ {
+ .name = "palmas-gpadc",
+ .num_resources = ARRAY_SIZE(gpadc_resource),
+ .resources = gpadc_resource,
+ .id = PALMAS_GPADC_ID,
+ },
+ {
+ .name = "palmas-resource",
+ .id = PALMAS_RESOURCE_ID,
+ },
+ {
+ .name = "palmas-clk",
+ .id = PALMAS_CLK_ID,
+ },
+ {
+ .name = "palmas-pwm",
+ .id = PALMAS_PWM_ID,
+ },
+ {
+ .name = "palmas-usb",
+ .num_resources = ARRAY_SIZE(usb_resource),
+ .resources = usb_resource,
+ .id = PALMAS_USB_ID,
+ }
+};
+
+static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD3),
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SMPS_VSEL_MONITORING),
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE,
+ PALMAS_GPADC_TRIM16),
+ },
+};
+
+static const struct regmap_irq palmas_irqs[] = {
+ /* INT1 IRQs */
+ [PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV,
+ },
+ [PALMAS_PWRON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_PWRON,
+ },
+ [PALMAS_LONG_PRESS_KEY_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY,
+ },
+ [PALMAS_RPWRON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_RPWRON,
+ },
+ [PALMAS_PWRDOWN_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_PWRDOWN,
+ },
+ [PALMAS_HOTDIE_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_HOTDIE,
+ },
+ [PALMAS_VSYS_MON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_VSYS_MON,
+ },
+ [PALMAS_VBAT_MON_IRQ] = {
+ .mask = PALMAS_INT1_STATUS_VBAT_MON,
+ },
+ /* INT2 IRQs*/
+ [PALMAS_RTC_ALARM_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RTC_ALARM,
+ .reg_offset = 1,
+ },
+ [PALMAS_RTC_TIMER_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RTC_TIMER,
+ .reg_offset = 1,
+ },
+ [PALMAS_WDT_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_WDT,
+ .reg_offset = 1,
+ },
+ [PALMAS_BATREMOVAL_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_BATREMOVAL,
+ .reg_offset = 1,
+ },
+ [PALMAS_RESET_IN_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_RESET_IN,
+ .reg_offset = 1,
+ },
+ [PALMAS_FBI_BB_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_FBI_BB,
+ .reg_offset = 1,
+ },
+ [PALMAS_SHORT_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_SHORT,
+ .reg_offset = 1,
+ },
+ [PALMAS_VAC_ACOK_IRQ] = {
+ .mask = PALMAS_INT2_STATUS_VAC_ACOK,
+ .reg_offset = 1,
+ },
+ /* INT3 IRQs */
+ [PALMAS_GPADC_AUTO_0_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_AUTO_0,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_AUTO_1_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_AUTO_1,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_EOC_SW_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_EOC_SW,
+ .reg_offset = 2,
+ },
+ [PALMAS_GPADC_EOC_RT_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_GPADC_EOC_RT,
+ .reg_offset = 2,
+ },
+ [PALMAS_ID_OTG_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_ID_OTG,
+ .reg_offset = 2,
+ },
+ [PALMAS_ID_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_ID,
+ .reg_offset = 2,
+ },
+ [PALMAS_VBUS_OTG_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_VBUS_OTG,
+ .reg_offset = 2,
+ },
+ [PALMAS_VBUS_IRQ] = {
+ .mask = PALMAS_INT3_STATUS_VBUS,
+ .reg_offset = 2,
+ },
+ /* INT4 IRQs */
+ [PALMAS_GPIO_0_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_0,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_1_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_1,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_2_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_2,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_3_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_3,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_4_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_4,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_5_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_5,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_6_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_6,
+ .reg_offset = 3,
+ },
+ [PALMAS_GPIO_7_IRQ] = {
+ .mask = PALMAS_INT4_STATUS_GPIO_7,
+ .reg_offset = 3,
+ },
+};
+
+static struct regmap_irq_chip palmas_irq_chip = {
+ .name = "palmas",
+ .irqs = palmas_irqs,
+ .num_irqs = ARRAY_SIZE(palmas_irqs),
+
+ .num_regs = 4,
+ .irq_reg_stride = 5,
+ .status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+ PALMAS_INT1_STATUS),
+ .mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+ PALMAS_INT1_MASK),
+};
+
+static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct palmas *palmas;
+ struct palmas_platform_data *pdata;
+ int ret = 0, i;
+ unsigned int reg, addr;
+ int slave;
+ struct mfd_cell *children;
+
+ pdata = dev_get_platdata(&i2c->dev);
+ if (!pdata)
+ return -EINVAL;
+
+ palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL);
+ if (palmas == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, palmas);
+ palmas->dev = &i2c->dev;
+ palmas->id = id->driver_data;
+ palmas->irq = i2c->irq;
+
+ for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
+ if (i == 0)
+ palmas->i2c_clients[i] = i2c;
+ else {
+ palmas->i2c_clients[i] =
+ i2c_new_dummy(i2c->adapter,
+ i2c->addr + i);
+ if (!palmas->i2c_clients[i]) {
+ dev_err(palmas->dev,
+ "can't attach client %d\n", i);
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+ palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
+ &palmas_regmap_config[i]);
+ if (IS_ERR(palmas->regmap[i])) {
+ ret = PTR_ERR(palmas->regmap[i]);
+ dev_err(palmas->dev,
+ "Failed to allocate regmap %d, err: %d\n",
+ i, ret);
+ goto err;
+ }
+ }
+
+ ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
+ &palmas->irq_data);
+ if (ret < 0)
+ goto err;
+
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
+ addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD1);
+
+ if (pdata->mux_from_pdata) {
+ reg = pdata->pad1;
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+ } else {
+ ret = regmap_read(palmas->regmap[slave], addr, &reg);
+ if (ret)
+ goto err;
+ }
+
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
+ palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+ (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+ palmas->led_muxed |= PALMAS_LED1_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+ (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+ palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+ (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+ palmas->led_muxed |= PALMAS_LED2_MUXED;
+ else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+ (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+ palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
+ palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD2);
+
+ if (pdata->mux_from_pdata) {
+ reg = pdata->pad2;
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+ } else {
+ ret = regmap_read(palmas->regmap[slave], addr, &reg);
+ if (ret)
+ goto err;
+ }
+
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
+ palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
+ palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
+ if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
+ palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;
+
+ dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
+ palmas->gpio_muxed, palmas->pwm_muxed,
+ palmas->led_muxed);
+
+ reg = pdata->power_ctrl;
+
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
+ addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL);
+
+ ret = regmap_write(palmas->regmap[slave], addr, reg);
+ if (ret)
+ goto err;
+
+ children = kmemdup(palmas_children, sizeof(palmas_children),
+ GFP_KERNEL);
+ if (!children) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = mfd_add_devices(palmas->dev, -1,
+ children, ARRAY_SIZE(palmas_children),
+ NULL, regmap_irq_chip_get_base(palmas->irq_data));
+ kfree(children);
+
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(palmas->dev);
+ kfree(palmas);
+ return ret;
+}
+
+static int palmas_i2c_remove(struct i2c_client *i2c)
+{
+ struct palmas *palmas = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(palmas->dev);
+ regmap_del_irq_chip(palmas->irq, palmas->irq_data);
+
+ return 0;
+}
+
+static const struct i2c_device_id palmas_i2c_id[] = {
+ { "palmas", },
+ { "twl6035", },
+ { "twl6037", },
+ { "tps65913", },
+};
+MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
+
+static struct of_device_id __devinitdata of_palmas_match_tbl[] = {
+ { .compatible = "ti,palmas", },
+ { /* end */ }
+};
+
+static struct i2c_driver palmas_i2c_driver = {
+ .driver = {
+ .name = "palmas",
+ .of_match_table = of_palmas_match_tbl,
+ .owner = THIS_MODULE,
+ },
+ .probe = palmas_i2c_probe,
+ .remove = palmas_i2c_remove,
+ .id_table = palmas_i2c_id,
+};
+
+static int __init palmas_i2c_init(void)
+{
+ return i2c_add_driver(&palmas_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(palmas_i2c_init);
+
+static void __exit palmas_i2c_exit(void)
+{
+ i2c_del_driver(&palmas_i2c_driver);
+}
+module_exit(palmas_i2c_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("Palmas chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index a66d4df..47f802b 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -78,17 +78,6 @@ static struct mfd_cell tps65090s[] = {
},
};
-struct tps65090 {
- struct mutex lock;
- struct device *dev;
- struct i2c_client *client;
- struct regmap *rmap;
- struct irq_chip irq_chip;
- struct mutex irq_lock;
- int irq_base;
- unsigned int id;
-};
-
int tps65090_write(struct device *dev, int reg, uint8_t val)
{
struct tps65090 *tps = dev_get_drvdata(dev);
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index a5ddf31..c84b550 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6586x.h>
@@ -460,6 +461,7 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
pdev->dev.parent = tps6586x->dev;
pdev->dev.platform_data = subdev->platform_data;
+ pdev->dev.of_node = subdev->of_node;
ret = platform_device_add(pdev);
if (ret) {
@@ -474,6 +476,86 @@ failed:
return ret;
}
+#ifdef CONFIG_OF
+static struct of_regulator_match tps6586x_matches[] = {
+ { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 },
+ { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 },
+ { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 },
+ { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 },
+ { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 },
+ { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 },
+ { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 },
+ { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 },
+ { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 },
+ { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 },
+ { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 },
+ { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 },
+ { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 },
+ { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC },
+};
+
+static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client)
+{
+ const unsigned int num = ARRAY_SIZE(tps6586x_matches);
+ struct device_node *np = client->dev.of_node;
+ struct tps6586x_platform_data *pdata;
+ struct tps6586x_subdev_info *devs;
+ struct device_node *regs;
+ unsigned int count;
+ unsigned int i, j;
+ int err;
+
+ regs = of_find_node_by_name(np, "regulators");
+ if (!regs)
+ return NULL;
+
+ err = of_regulator_match(&client->dev, regs, tps6586x_matches, num);
+ if (err < 0) {
+ of_node_put(regs);
+ return NULL;
+ }
+
+ of_node_put(regs);
+ count = err;
+
+ devs = devm_kzalloc(&client->dev, count * sizeof(*devs), GFP_KERNEL);
+ if (!devs)
+ return NULL;
+
+ for (i = 0, j = 0; i < num && j < count; i++) {
+ if (!tps6586x_matches[i].init_data)
+ continue;
+
+ devs[j].name = "tps6586x-regulator";
+ devs[j].platform_data = tps6586x_matches[i].init_data;
+ devs[j].id = (int)tps6586x_matches[i].driver_data;
+ devs[j].of_node = tps6586x_matches[i].of_node;
+ j++;
+ }
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->num_subdevs = count;
+ pdata->subdevs = devs;
+ pdata->gpio_base = -1;
+ pdata->irq_base = -1;
+
+ return pdata;
+}
+
+static struct of_device_id tps6586x_of_match[] = {
+ { .compatible = "ti,tps6586x", },
+ { },
+};
+#else
+static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client)
+{
+ return NULL;
+}
+#endif
+
static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -481,6 +563,9 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
struct tps6586x *tps6586x;
int ret;
+ if (!pdata && client->dev.of_node)
+ pdata = tps6586x_parse_dt(client);
+
if (!pdata) {
dev_err(&client->dev, "tps6586x requires platform data\n");
return -ENOTSUPP;
@@ -573,6 +658,7 @@ static struct i2c_driver tps6586x_driver = {
.driver = {
.name = "tps6586x",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps6586x_of_match),
},
.probe = tps6586x_i2c_probe,
.remove = __devexit_p(tps6586x_i2c_remove),
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index e7ff783..5a62e6bf 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -26,7 +26,7 @@
#define COMP1 1
#define COMP2 2
-/* Comparator 1 voltage selection table in milivolts */
+/* Comparator 1 voltage selection table in millivolts */
static const u16 COMP_VSEL_TABLE[] = {
0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 7c2267e..6fc90be 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -224,13 +224,6 @@
#define HIGH_PERF_SQ (1 << 3)
#define CK32K_LOWPWR_EN (1 << 7)
-
-/* chip-specific feature flags, for i2c_device_id.driver_data */
-#define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */
-#define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */
-#define TWL5031 BIT(2) /* twl5031 has different registers */
-#define TWL6030_CLASS BIT(3) /* TWL6030 class */
-
/*----------------------------------------------------------------------*/
/* is driver active, bound to a chip? */
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index 46b20c4..f1837f6 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -147,12 +147,6 @@ int wm8994_irq_init(struct wm8994 *wm8994)
return 0;
}
- if (!wm8994->irq_base) {
- dev_err(wm8994->dev,
- "No interrupt base specified, no interrupts\n");
- return 0;
- }
-
ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
wm8994->irq_base, &wm8994_irq_chip,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c779509..2661f6e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -452,14 +452,32 @@ config ARM_CHARLCD
still useful.
config BMP085
- tristate "BMP085 digital pressure sensor"
+ bool
+ depends on SYSFS
+
+config BMP085_I2C
+ tristate "BMP085 digital pressure sensor on I2C"
+ select BMP085
+ select REGMAP_I2C
depends on I2C && SYSFS
help
- If you say yes here you get support for the Bosch Sensortec
- BMP085 digital pressure sensor.
+ Say Y here if you want to support Bosch Sensortec's digital pressure
+ sensor hooked to an I2C bus.
To compile this driver as a module, choose M here: the
- module will be called bmp085.
+ module will be called bmp085-i2c.
+
+config BMP085_SPI
+ tristate "BMP085 digital pressure sensor on SPI"
+ select BMP085
+ select REGMAP_SPI
+ depends on SPI_MASTER && SYSFS
+ help
+ Say Y here if you want to support Bosch Sensortec's digital pressure
+ sensor hooked to an SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bmp085-spi.
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
@@ -490,14 +508,6 @@ config USB_SWITCH_FSA9480
stereo and mono audio, video, microphone and UART data to use
a common connector port.
-config MAX8997_MUIC
- tristate "MAX8997 MUIC Support"
- depends on MFD_MAX8997
- help
- If you say yes here you get support for the MUIC device of
- Maxim MAX8997 PMIC.
- The MAX8997 MUIC is a USB port accessory detector and switch.
-
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -506,4 +516,5 @@ source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/altera-stapl/Kconfig"
+source "drivers/misc/mei/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3e1d801..456972f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
+obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
+obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -48,4 +50,4 @@ obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
-obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
+obj-$(CONFIG_INTEL_MEI) += mei/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index 1d1d426..6938f1b 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -749,7 +749,7 @@ exit:
}
EXPORT_SYMBOL(ad_dpot_probe);
-__devexit int ad_dpot_remove(struct device *dev)
+int ad_dpot_remove(struct device *dev)
{
struct dpot_data *data = dev_get_drvdata(dev);
int i;
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index 54f6f39..f1f9877 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = {
static struct i2c_driver bh1780_driver = {
.probe = bh1780_probe,
- .remove = bh1780_remove,
+ .remove = __devexit_p(bh1780_remove),
.id_table = bh1780_id,
.driver = {
.name = "bh1780",
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c
new file mode 100644
index 0000000..9943971
--- /dev/null
+++ b/drivers/misc/bmp085-i2c.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+#define BMP085_I2C_ADDRESS 0x77
+
+static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
+ I2C_CLIENT_END };
+
+static int bmp085_i2c_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ if (client->addr != BMP085_I2C_ADDRESS)
+ return -ENODEV;
+
+ return bmp085_detect(&client->dev);
+}
+
+static int __devinit bmp085_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct regmap *regmap = devm_regmap_init_i2c(client,
+ &bmp085_regmap_config);
+
+ if (IS_ERR(regmap)) {
+ err = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+ return err;
+ }
+
+ return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_i2c_remove(struct i2c_client *client)
+{
+ return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+ { .compatible = "bosch,bmp085", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct i2c_device_id bmp085_id[] = {
+ { BMP085_NAME, 0 },
+ { "bmp180", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
+
+static struct i2c_driver bmp085_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = BMP085_NAME,
+ .of_match_table = bmp085_of_match
+ },
+ .id_table = bmp085_id,
+ .probe = bmp085_i2c_probe,
+ .remove = __devexit_p(bmp085_i2c_remove),
+
+ .detect = bmp085_i2c_detect,
+ .address_list = normal_i2c
+};
+
+module_i2c_driver(bmp085_i2c_driver);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c
new file mode 100644
index 0000000..78aaff9
--- /dev/null
+++ b/drivers/misc/bmp085-spi.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+static int __devinit bmp085_spi_probe(struct spi_device *client)
+{
+ int err;
+ struct regmap *regmap;
+
+ client->bits_per_word = 8;
+ err = spi_setup(client);
+ if (err < 0) {
+ dev_err(&client->dev, "spi_setup failed!\n");
+ return err;
+ }
+
+ regmap = devm_regmap_init_spi(client, &bmp085_regmap_config);
+ if (IS_ERR(regmap)) {
+ err = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+ return err;
+ }
+
+ return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_spi_remove(struct spi_device *client)
+{
+ return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+ { .compatible = "bosch,bmp085", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct spi_device_id bmp085_id[] = {
+ { "bmp180", 0 },
+ { "bmp181", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, bmp085_id);
+
+static struct spi_driver bmp085_spi_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = BMP085_NAME,
+ .of_match_table = bmp085_of_match
+ },
+ .id_table = bmp085_id,
+ .probe = bmp085_spi_probe,
+ .remove = __devexit_p(bmp085_spi_remove)
+};
+
+static int __init bmp085_spi_init(void)
+{
+ return spi_register_driver(&bmp085_spi_driver);
+}
+
+static void __exit bmp085_spi_exit(void)
+{
+ spi_unregister_driver(&bmp085_spi_driver);
+}
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 SPI bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(bmp085_spi_init);
+module_exit(bmp085_spi_exit);
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index 76c3064..62e4182 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -1,62 +1,62 @@
/* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
-
- This driver supports the bmp085 digital barometric pressure
- and temperature sensor from Bosch Sensortec. The datasheet
- is available from their website:
- http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
-
- A pressure measurement is issued by reading from pressure0_input.
- The return value ranges from 30000 to 110000 pascal with a resulution
- of 1 pascal (0.01 millibar) which enables measurements from 9000m above
- to 500m below sea level.
-
- The temperature can be read from temp0_input. Values range from
- -400 to 850 representing the ambient temperature in degree celsius
- multiplied by 10.The resolution is 0.1 celsius.
-
- Because ambient pressure is temperature dependent, a temperature
- measurement will be executed automatically even if the user is reading
- from pressure0_input. This happens if the last temperature measurement
- has been executed more then one second ago.
-
- To decrease RMS noise from pressure measurements, the bmp085 can
- autonomously calculate the average of up to eight samples. This is
- set up by writing to the oversampling sysfs file. Accepted values
- are 0, 1, 2 and 3. 2^x when x is the value written to this file
- specifies the number of samples used to calculate the ambient pressure.
- RMS noise is specified with six pascal (without averaging) and decreases
- down to 3 pascal when using an oversampling setting of 3.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This driver supports the bmp085 and bmp18x digital barometric pressure
+ * and temperature sensors from Bosch Sensortec. The datasheets
+ * are available from their website:
+ * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
+ * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf
+ *
+ * A pressure measurement is issued by reading from pressure0_input.
+ * The return value ranges from 30000 to 110000 pascal with a resulution
+ * of 1 pascal (0.01 millibar) which enables measurements from 9000m above
+ * to 500m below sea level.
+ *
+ * The temperature can be read from temp0_input. Values range from
+ * -400 to 850 representing the ambient temperature in degree celsius
+ * multiplied by 10.The resolution is 0.1 celsius.
+ *
+ * Because ambient pressure is temperature dependent, a temperature
+ * measurement will be executed automatically even if the user is reading
+ * from pressure0_input. This happens if the last temperature measurement
+ * has been executed more then one second ago.
+ *
+ * To decrease RMS noise from pressure measurements, the bmp085 can
+ * autonomously calculate the average of up to eight samples. This is
+ * set up by writing to the oversampling sysfs file. Accepted values
+ * are 0, 1, 2 and 3. 2^x when x is the value written to this file
+ * specifies the number of samples used to calculate the ambient pressure.
+ * RMS noise is specified with six pascal (without averaging) and decreases
+ * down to 3 pascal when using an oversampling setting of 3.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <linux/module.h>
+#include <linux/device.h>
#include <linux/init.h>
-#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include "bmp085.h"
-
-#define BMP085_I2C_ADDRESS 0x77
#define BMP085_CHIP_ID 0x55
-
#define BMP085_CALIBRATION_DATA_START 0xAA
#define BMP085_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */
#define BMP085_CHIP_ID_REG 0xD0
-#define BMP085_VERSION_REG 0xD1
#define BMP085_CTRL_REG 0xF4
#define BMP085_TEMP_MEASUREMENT 0x2E
#define BMP085_PRESSURE_MEASUREMENT 0x34
@@ -65,12 +65,6 @@
#define BMP085_CONVERSION_REGISTER_XLSB 0xF8
#define BMP085_TEMP_CONVERSION_TIME 5
-#define BMP085_CLIENT_NAME "bmp085"
-
-
-static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
- I2C_CLIENT_END };
-
struct bmp085_calibration_data {
s16 AC1, AC2, AC3;
u16 AC4, AC5, AC6;
@@ -78,35 +72,30 @@ struct bmp085_calibration_data {
s16 MB, MC, MD;
};
-
-/* Each client has this additional data */
struct bmp085_data {
- struct i2c_client *client;
- struct mutex lock;
- struct bmp085_calibration_data calibration;
- u32 raw_temperature;
- u32 raw_pressure;
- unsigned char oversampling_setting;
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex lock;
+ struct bmp085_calibration_data calibration;
+ u8 oversampling_setting;
+ u32 raw_temperature;
+ u32 raw_pressure;
+ u32 temp_measurement_period;
unsigned long last_temp_measurement;
- s32 b6; /* calculated temperature correction coefficient */
+ u8 chip_id;
+ s32 b6; /* calculated temperature correction coefficient */
};
-
-static s32 bmp085_read_calibration_data(struct i2c_client *client)
+static s32 bmp085_read_calibration_data(struct bmp085_data *data)
{
u16 tmp[BMP085_CALIBRATION_DATA_LENGTH];
- struct bmp085_data *data = i2c_get_clientdata(client);
struct bmp085_calibration_data *cali = &(data->calibration);
- s32 status = i2c_smbus_read_i2c_block_data(client,
- BMP085_CALIBRATION_DATA_START,
- BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16),
- (u8 *)tmp);
+ s32 status = regmap_bulk_read(data->regmap,
+ BMP085_CALIBRATION_DATA_START, (u8 *)tmp,
+ (BMP085_CALIBRATION_DATA_LENGTH << 1));
if (status < 0)
return status;
- if (status != BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16))
- return -EIO;
-
cali->AC1 = be16_to_cpu(tmp[0]);
cali->AC2 = be16_to_cpu(tmp[1]);
cali->AC3 = be16_to_cpu(tmp[2]);
@@ -121,30 +110,26 @@ static s32 bmp085_read_calibration_data(struct i2c_client *client)
return 0;
}
-
static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
{
u16 tmp;
s32 status;
mutex_lock(&data->lock);
- status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
- BMP085_TEMP_MEASUREMENT);
- if (status != 0) {
- dev_err(&data->client->dev,
+ status = regmap_write(data->regmap, BMP085_CTRL_REG,
+ BMP085_TEMP_MEASUREMENT);
+ if (status < 0) {
+ dev_err(data->dev,
"Error while requesting temperature measurement.\n");
goto exit;
}
msleep(BMP085_TEMP_CONVERSION_TIME);
- status = i2c_smbus_read_i2c_block_data(data->client,
- BMP085_CONVERSION_REGISTER_MSB, sizeof(tmp), (u8 *)&tmp);
- if (status < 0)
- goto exit;
- if (status != sizeof(tmp)) {
- dev_err(&data->client->dev,
+ status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+ &tmp, sizeof(tmp));
+ if (status < 0) {
+ dev_err(data->dev,
"Error while reading temperature measurement result\n");
- status = -EIO;
goto exit;
}
data->raw_temperature = be16_to_cpu(tmp);
@@ -162,10 +147,11 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
s32 status;
mutex_lock(&data->lock);
- status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
- BMP085_PRESSURE_MEASUREMENT + (data->oversampling_setting<<6));
- if (status != 0) {
- dev_err(&data->client->dev,
+ status = regmap_write(data->regmap, BMP085_CTRL_REG,
+ BMP085_PRESSURE_MEASUREMENT +
+ (data->oversampling_setting << 6));
+ if (status < 0) {
+ dev_err(data->dev,
"Error while requesting pressure measurement.\n");
goto exit;
}
@@ -174,14 +160,11 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
msleep(2+(3 << data->oversampling_setting));
/* copy data into a u32 (4 bytes), but skip the first byte. */
- status = i2c_smbus_read_i2c_block_data(data->client,
- BMP085_CONVERSION_REGISTER_MSB, 3, ((u8 *)&tmp)+1);
- if (status < 0)
- goto exit;
- if (status != 3) {
- dev_err(&data->client->dev,
+ status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+ ((u8 *)&tmp)+1, 3);
+ if (status < 0) {
+ dev_err(data->dev,
"Error while reading pressure measurement results\n");
- status = -EIO;
goto exit;
}
data->raw_pressure = be32_to_cpu((tmp));
@@ -193,7 +176,6 @@ exit:
return status;
}
-
/*
* This function starts the temperature measurement and returns the value
* in tenth of a degree celsius.
@@ -205,7 +187,7 @@ static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature)
int status;
status = bmp085_update_raw_temperature(data);
- if (status != 0)
+ if (status < 0)
goto exit;
x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15;
@@ -222,8 +204,10 @@ exit:
/*
* This function starts the pressure measurement and returns the value
* in millibar. Since the pressure depends on the ambient temperature,
- * a temperature measurement is executed if the last known value is older
- * than one second.
+ * a temperature measurement is executed according to the given temperature
+ * measurement period (default is 1 sec boundary). This period could vary
+ * and needs to be adjusted according to the sensor environment, i.e. if big
+ * temperature variations then the temperature needs to be read out often.
*/
static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
{
@@ -234,16 +218,16 @@ static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
int status;
/* alt least every second force an update of the ambient temperature */
- if (data->last_temp_measurement == 0 ||
- time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
+ if ((data->last_temp_measurement == 0) ||
+ time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
status = bmp085_get_temperature(data, NULL);
- if (status != 0)
- goto exit;
+ if (status < 0)
+ return status;
}
status = bmp085_update_raw_pressure(data);
- if (status != 0)
- goto exit;
+ if (status < 0)
+ return status;
x1 = (data->b6 * data->b6) >> 12;
x1 *= cali->B2;
@@ -274,15 +258,14 @@ static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
*pressure = p;
-exit:
- return status;
+ return 0;
}
/*
* This function sets the chip-internal oversampling. Valid values are 0..3.
* The chip will use 2^oversampling samples for internal averaging.
* This influences the measurement time and the accuracy; larger values
- * increase both. The datasheet gives on overview on how measurement time,
+ * increase both. The datasheet gives an overview on how measurement time,
* accuracy and noise correlate.
*/
static void bmp085_set_oversampling(struct bmp085_data *data,
@@ -306,22 +289,25 @@ static ssize_t set_oversampling(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
unsigned long oversampling;
- int success = strict_strtoul(buf, 10, &oversampling);
- if (success == 0) {
+ int err = kstrtoul(buf, 10, &oversampling);
+
+ if (err == 0) {
+ mutex_lock(&data->lock);
bmp085_set_oversampling(data, oversampling);
+ mutex_unlock(&data->lock);
return count;
}
- return success;
+
+ return err;
}
static ssize_t show_oversampling(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
+
return sprintf(buf, "%u\n", bmp085_get_oversampling(data));
}
static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
@@ -333,11 +319,10 @@ static ssize_t show_temperature(struct device *dev,
{
int temperature;
int status;
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
status = bmp085_get_temperature(data, &temperature);
- if (status != 0)
+ if (status < 0)
return status;
else
return sprintf(buf, "%d\n", temperature);
@@ -350,11 +335,10 @@ static ssize_t show_pressure(struct device *dev,
{
int pressure;
int status;
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
status = bmp085_get_pressure(data, &pressure);
- if (status != 0)
+ if (status < 0)
return status;
else
return sprintf(buf, "%d\n", pressure);
@@ -373,38 +357,70 @@ static const struct attribute_group bmp085_attr_group = {
.attrs = bmp085_attributes,
};
-static int bmp085_detect(struct i2c_client *client, struct i2c_board_info *info)
+int bmp085_detect(struct device *dev)
{
- if (client->addr != BMP085_I2C_ADDRESS)
- return -ENODEV;
+ struct bmp085_data *data = dev_get_drvdata(dev);
+ unsigned int id;
+ int ret;
- if (i2c_smbus_read_byte_data(client, BMP085_CHIP_ID_REG) != BMP085_CHIP_ID)
+ ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id);
+ if (ret < 0)
+ return ret;
+
+ if (id != data->chip_id)
return -ENODEV;
return 0;
}
+EXPORT_SYMBOL_GPL(bmp085_detect);
-static int bmp085_init_client(struct i2c_client *client)
+static void __init bmp085_get_of_properties(struct bmp085_data *data)
{
- unsigned char version;
- int status;
- struct bmp085_data *data = i2c_get_clientdata(client);
- data->client = client;
- status = bmp085_read_calibration_data(client);
- if (status != 0)
- goto exit;
- version = i2c_smbus_read_byte_data(client, BMP085_VERSION_REG);
+#ifdef CONFIG_OF
+ struct device_node *np = data->dev->of_node;
+ u32 prop;
+
+ if (!np)
+ return;
+
+ if (!of_property_read_u32(np, "chip-id", &prop))
+ data->chip_id = prop & 0xff;
+
+ if (!of_property_read_u32(np, "temp-measurement-period", &prop))
+ data->temp_measurement_period = (prop/100)*HZ;
+
+ if (!of_property_read_u32(np, "default-oversampling", &prop))
+ data->oversampling_setting = prop & 0xff;
+#endif
+}
+
+static int bmp085_init_client(struct bmp085_data *data)
+{
+ int status = bmp085_read_calibration_data(data);
+
+ if (status < 0)
+ return status;
+
+ /* default settings */
+ data->chip_id = BMP085_CHIP_ID;
data->last_temp_measurement = 0;
+ data->temp_measurement_period = 1*HZ;
data->oversampling_setting = 3;
+
+ bmp085_get_of_properties(data);
+
mutex_init(&data->lock);
- dev_info(&data->client->dev, "BMP085 ver. %d.%d found.\n",
- (version & 0x0F), (version & 0xF0) >> 4);
-exit:
- return status;
+
+ return 0;
}
-static int __devinit bmp085_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+struct regmap_config bmp085_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8
+};
+EXPORT_SYMBOL_GPL(bmp085_regmap_config);
+
+__devinit int bmp085_probe(struct device *dev, struct regmap *regmap)
{
struct bmp085_data *data;
int err = 0;
@@ -415,58 +431,48 @@ static int __devinit bmp085_probe(struct i2c_client *client,
goto exit;
}
- /* default settings after POR */
- data->oversampling_setting = 0x00;
-
- i2c_set_clientdata(client, data);
+ dev_set_drvdata(dev, data);
+ data->dev = dev;
+ data->regmap = regmap;
/* Initialize the BMP085 chip */
- err = bmp085_init_client(client);
- if (err != 0)
+ err = bmp085_init_client(data);
+ if (err < 0)
goto exit_free;
+ err = bmp085_detect(dev);
+ if (err < 0) {
+ dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME);
+ goto exit_free;
+ }
+
/* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &bmp085_attr_group);
+ err = sysfs_create_group(&dev->kobj, &bmp085_attr_group);
if (err)
goto exit_free;
- dev_info(&data->client->dev, "Successfully initialized bmp085!\n");
- goto exit;
+ dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME);
+
+ return 0;
exit_free:
kfree(data);
exit:
return err;
}
+EXPORT_SYMBOL_GPL(bmp085_probe);
-static int __devexit bmp085_remove(struct i2c_client *client)
+int bmp085_remove(struct device *dev)
{
- sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group);
- kfree(i2c_get_clientdata(client));
- return 0;
-}
+ struct bmp085_data *data = dev_get_drvdata(dev);
-static const struct i2c_device_id bmp085_id[] = {
- { "bmp085", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, bmp085_id);
-
-static struct i2c_driver bmp085_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "bmp085"
- },
- .id_table = bmp085_id,
- .probe = bmp085_probe,
- .remove = __devexit_p(bmp085_remove),
-
- .detect = bmp085_detect,
- .address_list = normal_i2c
-};
+ sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group);
+ kfree(data);
-module_i2c_driver(bmp085_driver);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bmp085_remove);
-MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com");
+MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>");
MODULE_DESCRIPTION("BMP085 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.h b/drivers/misc/bmp085.h
new file mode 100644
index 0000000..2b8f615
--- /dev/null
+++ b/drivers/misc/bmp085.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BMP085_H
+#define _BMP085_H
+
+#include <linux/regmap.h>
+
+#define BMP085_NAME "bmp085"
+
+extern struct regmap_config bmp085_regmap_config;
+
+int bmp085_probe(struct device *dev, struct regmap *regmap);
+int bmp085_remove(struct device *dev);
+int bmp085_detect(struct device *dev);
+
+#endif
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
index e46af9a..33ee834 100644
--- a/drivers/misc/c2port/Kconfig
+++ b/drivers/misc/c2port/Kconfig
@@ -5,7 +5,7 @@
menuconfig C2PORT
tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
depends on EXPERIMENTAL
- default no
+ default n
help
This option enables support for Silicon Labs C2 port used to
program Silicon micro controller chips (and other 8051 compatible).
@@ -23,8 +23,8 @@ if C2PORT
config C2PORT_DURAMAR_2150
tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
- depends on X86 && C2PORT
- default no
+ depends on X86
+ default n
help
This option enables C2 support for the Eurotech's Duramar 2150
on board micro controller.
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 01ab3c9..0842c29 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -50,6 +50,7 @@ struct at25_data {
#define AT25_SR_BP1 0x08
#define AT25_SR_WPEN 0x80 /* writeprotect enable */
+#define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */
#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
@@ -75,6 +76,7 @@ at25_ee_read(
ssize_t status;
struct spi_transfer t[2];
struct spi_message m;
+ u8 instr;
if (unlikely(offset >= at25->bin.size))
return 0;
@@ -84,7 +86,12 @@ at25_ee_read(
return count;
cp = command;
- *cp++ = AT25_READ;
+
+ instr = AT25_READ;
+ if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+ if (offset >= (1U << (at25->addrlen * 8)))
+ instr |= AT25_INSTR_BIT3;
+ *cp++ = instr;
/* 8/16/24-bit address is written MSB first */
switch (at25->addrlen) {
@@ -167,14 +174,14 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
/* For write, rollover is within the page ... so we write at
* most one page, then manually roll over to the next page.
*/
- bounce[0] = AT25_WRITE;
mutex_lock(&at25->lock);
do {
unsigned long timeout, retries;
unsigned segment;
unsigned offset = (unsigned) off;
- u8 *cp = bounce + 1;
+ u8 *cp = bounce;
int sr;
+ u8 instr;
*cp = AT25_WREN;
status = spi_write(at25->spi, cp, 1);
@@ -184,6 +191,12 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
break;
}
+ instr = AT25_WRITE;
+ if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+ if (offset >= (1U << (at25->addrlen * 8)))
+ instr |= AT25_INSTR_BIT3;
+ *cp++ = instr;
+
/* 8/16/24-bit address is written MSB first */
switch (at25->addrlen) {
default: /* case 3 */
diff --git a/drivers/staging/mei/Kconfig b/drivers/misc/mei/Kconfig
index 47d78a7..47d78a7 100644
--- a/drivers/staging/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
diff --git a/drivers/staging/mei/Makefile b/drivers/misc/mei/Makefile
index 57168db..57168db 100644
--- a/drivers/staging/mei/Makefile
+++ b/drivers/misc/mei/Makefile
diff --git a/drivers/staging/mei/hw.h b/drivers/misc/mei/hw.h
index 24c4c96..24c4c96 100644
--- a/drivers/staging/mei/hw.h
+++ b/drivers/misc/mei/hw.h
diff --git a/drivers/staging/mei/init.c b/drivers/misc/mei/init.c
index eab711f..a7d0bb0 100644
--- a/drivers/staging/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -22,7 +22,7 @@
#include "mei_dev.h"
#include "hw.h"
#include "interface.h"
-#include "mei.h"
+#include <linux/mei.h>
const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
0xa8, 0x46, 0xe0, 0xff, 0x65,
@@ -200,7 +200,7 @@ int mei_hw_init(struct mei_device *dev)
if (!(dev->me_hw_state & ME_RDY_HRA))
dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
- printk(KERN_ERR "mei: link layer initialization failed.\n");
+ dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
ret = -ENODEV;
goto out;
}
diff --git a/drivers/staging/mei/interface.c b/drivers/misc/mei/interface.c
index 9a2cfaf..428d21e 100644
--- a/drivers/staging/mei/interface.c
+++ b/drivers/misc/mei/interface.c
@@ -16,7 +16,7 @@
#include <linux/pci.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
diff --git a/drivers/staging/mei/interface.h b/drivers/misc/mei/interface.h
index fb90c6f..ddff5d1 100644
--- a/drivers/staging/mei/interface.h
+++ b/drivers/misc/mei/interface.h
@@ -19,7 +19,7 @@
#ifndef _MEI_INTERFACE_H_
#define _MEI_INTERFACE_H_
-#include "mei.h"
+#include <linux/mei.h>
#include "mei_dev.h"
@@ -51,8 +51,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
int mei_wd_send(struct mei_device *dev);
int mei_wd_stop(struct mei_device *dev, bool preserve);
-bool mei_wd_host_init(struct mei_device *dev);
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout);
+int mei_wd_host_init(struct mei_device *dev);
/*
* mei_watchdog_register - Registering watchdog interface
* once we got connection to the WD Client
diff --git a/drivers/staging/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 2007d24..93936f1 100644
--- a/drivers/staging/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -22,7 +22,7 @@
#include <linux/jiffies.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "hw.h"
#include "interface.h"
diff --git a/drivers/staging/mei/iorw.c b/drivers/misc/mei/iorw.c
index 0a80dc4..f9cced6 100644
--- a/drivers/staging/mei/iorw.c
+++ b/drivers/misc/mei/iorw.c
@@ -35,7 +35,7 @@
#include "mei_dev.h"
#include "hw.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
diff --git a/drivers/staging/mei/main.c b/drivers/misc/mei/main.c
index 7c9321f..c703332 100644
--- a/drivers/staging/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -14,6 +14,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -36,19 +38,10 @@
#include <linux/miscdevice.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
-
-#define MEI_READ_TIMEOUT 45
-#define MEI_DRIVER_NAME "mei"
-#define MEI_DEV_NAME "mei"
-
-/*
- * mei driver strings
- */
-static char mei_driver_name[] = MEI_DRIVER_NAME;
-static const char mei_driver_string[] = "Intel(R) Management Engine Interface";
+static const char mei_driver_name[] = "mei";
/* The device pointer */
/* Currently this driver works as long as there is only a single AMT device. */
@@ -931,7 +924,7 @@ static const struct file_operations mei_fops = {
* Misc Device Struct
*/
static struct miscdevice mei_misc_device = {
- .name = MEI_DRIVER_NAME,
+ .name = "mei",
.fops = &mei_fops,
.minor = MISC_DYNAMIC_MINOR,
};
@@ -958,7 +951,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* enable pci dev */
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR "mei: Failed to enable pci device.\n");
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
goto end;
}
/* set PCI host mastering */
@@ -966,7 +959,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* pci request regions for mei driver */
err = pci_request_regions(pdev, mei_driver_name);
if (err) {
- printk(KERN_ERR "mei: Failed to get pci regions.\n");
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
goto disable_device;
}
/* allocates and initializes the mei dev structure */
@@ -978,7 +971,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* mapping IO device memory */
dev->mem_addr = pci_iomap(pdev, 0, 0);
if (!dev->mem_addr) {
- printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
err = -ENOMEM;
goto free_device;
}
@@ -997,13 +990,13 @@ static int __devinit mei_probe(struct pci_dev *pdev,
IRQF_SHARED, mei_driver_name, dev);
if (err) {
- printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
+ dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
pdev->irq);
goto unmap_memory;
}
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
if (mei_hw_init(dev)) {
- printk(KERN_ERR "mei: Init hw failure.\n");
+ dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV;
goto release_irq;
}
@@ -1020,7 +1013,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
mutex_unlock(&mei_mutex);
- pr_debug("mei: Driver initialization successful.\n");
+ pr_debug("initialization successful.\n");
return 0;
@@ -1041,7 +1034,7 @@ disable_device:
pci_disable_device(pdev);
end:
mutex_unlock(&mei_mutex);
- printk(KERN_ERR "mei: Driver initialization failed.\n");
+ dev_err(&pdev->dev, "initialization failed.\n");
return err;
}
@@ -1160,8 +1153,8 @@ static int mei_pci_resume(struct device *device)
IRQF_SHARED, mei_driver_name, dev);
if (err) {
- printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
- pdev->irq);
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
return err;
}
@@ -1204,11 +1197,11 @@ static int __init mei_init_module(void)
{
int ret;
- pr_debug("mei: %s\n", mei_driver_string);
+ pr_debug("loading.\n");
/* init pci module */
ret = pci_register_driver(&mei_driver);
if (ret < 0)
- printk(KERN_ERR "mei: Error registering driver.\n");
+ pr_err("error registering driver.\n");
return ret;
}
@@ -1226,7 +1219,7 @@ static void __exit mei_exit_module(void)
misc_deregister(&mei_misc_device);
pci_unregister_driver(&mei_driver);
- pr_debug("mei: Driver unloaded successfully.\n");
+ pr_debug("unloaded successfully.\n");
}
module_exit(mei_exit_module);
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 10b1b4e..63d7ee9 100644
--- a/drivers/staging/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -19,7 +19,7 @@
#include <linux/types.h>
#include <linux/watchdog.h>
-#include "mei.h"
+#include <linux/mei.h>
#include "hw.h"
/*
diff --git a/drivers/staging/mei/wd.c b/drivers/misc/mei/wd.c
index cf4c29d..6be5605 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -24,7 +24,7 @@
#include "mei_dev.h"
#include "hw.h"
#include "interface.h"
-#include "mei.h"
+#include <linux/mei.h>
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
@@ -45,23 +45,22 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
0x9D, 0xA9, 0x15, 0x14, 0xCB,
0x32, 0xAB);
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
+static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
{
- dev_dbg(&dev->pdev->dev, "timeout=%d.\n", timeout);
+ dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
- memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE,
- &timeout, sizeof(u16));
+ memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
}
/**
* host_init_wd - mei initialization wd.
*
* @dev: the device structure
+ * returns -ENENT if wd client cannot be found
+ * -EIO if write has failed
*/
-bool mei_wd_host_init(struct mei_device *dev)
+int mei_wd_host_init(struct mei_device *dev)
{
- bool ret = false;
-
mei_cl_init(&dev->wd_cl, dev);
/* look for WD client and connect to it */
@@ -72,25 +71,21 @@ bool mei_wd_host_init(struct mei_device *dev)
mei_find_me_client_update_filext(dev, &dev->wd_cl,
&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
- dev_dbg(&dev->pdev->dev, "check wd_cl\n");
- if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
- if (mei_connect(dev, &dev->wd_cl)) {
- dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
- dev->wd_cl.state = MEI_FILE_DISCONNECTED;
- dev->wd_cl.host_client_id = 0;
- ret = false;
- goto end;
- } else {
- dev->wd_cl.timer_count = CONNECT_TIMEOUT;
- }
- } else {
- dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
- ret = false;
- goto end;
+ dev_dbg(&dev->pdev->dev, "wd: check client\n");
+ if (MEI_FILE_CONNECTING != dev->wd_cl.state) {
+ dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
+ return -ENOENT;
}
-end:
- return ret;
+ if (mei_connect(dev, &dev->wd_cl)) {
+ dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
+ dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+ dev->wd_cl.host_client_id = 0;
+ return -EIO;
+ }
+ dev->wd_cl.timer_count = CONNECT_TIMEOUT;
+
+ return 0;
}
/**
@@ -159,7 +154,7 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
if (ret)
goto out;
} else {
- dev_dbg(&dev->pdev->dev, "send stop WD failed\n");
+ dev_err(&dev->pdev->dev, "wd: send stop failed\n");
}
dev->wd_pending = false;
@@ -173,13 +168,13 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
dev->wd_stopped, 10 * HZ);
mutex_lock(&dev->device_lock);
if (dev->wd_stopped) {
- dev_dbg(&dev->pdev->dev, "stop wd complete ret=%d.\n", ret);
+ dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
ret = 0;
} else {
if (!ret)
ret = -ETIMEDOUT;
dev_warn(&dev->pdev->dev,
- "stop wd failed to complete ret=%d.\n", ret);
+ "wd: stop failed to complete ret=%d.\n", ret);
}
if (preserve)
@@ -208,13 +203,15 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
- dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
- dev->mei_state);
+ dev_dbg(&dev->pdev->dev,
+ "wd: mei_state != MEI_ENABLED mei_state = %d\n",
+ dev->mei_state);
goto end_unlock;
}
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
- dev_dbg(&dev->pdev->dev, "MEI Driver is not connected to Watchdog Client\n");
+ dev_dbg(&dev->pdev->dev,
+ "MEI Driver is not connected to Watchdog Client\n");
goto end_unlock;
}
@@ -267,7 +264,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
- dev_dbg(&dev->pdev->dev, "wd is not connected.\n");
+ dev_err(&dev->pdev->dev, "wd: not connected.\n");
ret = -ENODEV;
goto end;
}
@@ -277,16 +274,17 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
dev->mei_host_buffer_is_empty = false;
- dev_dbg(&dev->pdev->dev, "sending watchdog ping\n");
+ dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
if (mei_wd_send(dev)) {
- dev_dbg(&dev->pdev->dev, "wd send failed.\n");
+ dev_err(&dev->pdev->dev, "wd: send failed.\n");
ret = -EIO;
goto end;
}
if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
- dev_dbg(&dev->pdev->dev, "mei_flow_ctrl_reduce() failed.\n");
+ dev_err(&dev->pdev->dev,
+ "wd: mei_flow_ctrl_reduce() failed.\n");
ret = -EIO;
goto end;
}
@@ -346,7 +344,7 @@ static const struct watchdog_info wd_info = {
.options = WDIOF_KEEPALIVEPING,
};
-struct watchdog_device amt_wd_dev = {
+static struct watchdog_device amt_wd_dev = {
.info = &wd_info,
.ops = &wd_ops,
.timeout = AMT_WD_DEFAULT_TIMEOUT,
@@ -362,10 +360,12 @@ void mei_watchdog_register(struct mei_device *dev)
dev->wd_due_counter = !!dev->wd_timeout;
if (watchdog_register_device(&amt_wd_dev)) {
- dev_err(&dev->pdev->dev, "unable to register watchdog device.\n");
+ dev_err(&dev->pdev->dev,
+ "wd: unable to register watchdog device.\n");
dev->wd_interface_reg = false;
} else {
- dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n");
+ dev_dbg(&dev->pdev->dev,
+ "wd: successfully register watchdog interface.\n");
dev->wd_interface_reg = true;
}
}
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 10fc478..9fbcacd 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -65,10 +65,6 @@
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
-/* Macros for ML7213 */
-#define PCI_VENDOR_ID_ROHM 0x10db
-#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
-
/* Macros for ML7223 */
#define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */
#define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 383133b..b7eb545 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -888,7 +888,7 @@ static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
.probe = pti_pci_probe,
- .remove = pti_pci_remove,
+ .remove = __devexit_p(pti_pci_remove),
};
/**
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 032b847..b6f3842 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -94,6 +94,17 @@ static struct variant_data variant_u300 = {
.signal_direction = true,
};
+static struct variant_data variant_nomadik = {
+ .fifosize = 16 * 4,
+ .fifohalfsize = 8 * 4,
+ .clkreg = MCI_CLK_ENABLE,
+ .datalength_bits = 24,
+ .sdio = true,
+ .st_clkdiv = true,
+ .pwrreg_powerup = MCI_PWR_ON,
+ .signal_direction = true,
+};
+
static struct variant_data variant_ux500 = {
.fifosize = 30 * 4,
.fifohalfsize = 8 * 4,
@@ -1397,7 +1408,7 @@ static int __devinit mmci_probe(struct amba_device *dev,
if (ret)
goto unmap;
- if (dev->irq[1] == NO_IRQ || !dev->irq[1])
+ if (!dev->irq[1])
host->singleirq = true;
else {
ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
@@ -1569,6 +1580,11 @@ static struct amba_id mmci_ids[] = {
.data = &variant_u300,
},
{
+ .id = 0x10180180,
+ .mask = 0xf0ffffff,
+ .data = &variant_nomadik,
+ },
+ {
.id = 0x00280180,
.mask = 0x00ffffff,
.data = &variant_u300,
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index e3f5af9..bb03ddd 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -39,6 +39,7 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/fsl/mxs-dma.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/mxs.h>
#include <mach/common.h>
@@ -682,6 +683,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mmc_host *mmc;
struct resource *iores, *dmares, *r;
struct mxs_mmc_platform_data *pdata;
+ struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
@@ -719,6 +721,12 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host->irq = irq_err;
host->sdio_irq_en = 0;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_iounmap;
+ }
+
host->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8abdaf6..d190d04 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/esdhc.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -68,6 +69,7 @@ struct pltfm_imx_data {
int flags;
u32 scratchpad;
enum imx_esdhc_type devtype;
+ struct pinctrl *pinctrl;
struct esdhc_platform_data boarddata;
};
@@ -467,6 +469,12 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_prepare_enable(clk);
pltfm_host->clk = clk;
+ imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(imx_data->pinctrl)) {
+ err = PTR_ERR(imx_data->pinctrl);
+ goto pin_err;
+ }
+
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
@@ -558,6 +566,7 @@ no_card_detect_irq:
gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
+pin_err:
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 53b2650..ff5a169 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -269,7 +269,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate power gpio\n");
goto err_power_req;
}
- tegra_gpio_enable(plat->power_gpio);
gpio_direction_output(plat->power_gpio, 1);
}
@@ -280,7 +279,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate cd gpio\n");
goto err_cd_req;
}
- tegra_gpio_enable(plat->cd_gpio);
gpio_direction_input(plat->cd_gpio);
rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
@@ -301,7 +299,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate wp gpio\n");
goto err_wp_req;
}
- tegra_gpio_enable(plat->wp_gpio);
gpio_direction_input(plat->wp_gpio);
}
@@ -329,23 +326,17 @@ err_add_host:
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
err_wp_req:
if (gpio_is_valid(plat->cd_gpio))
free_irq(gpio_to_irq(plat->cd_gpio), host);
err_cd_irq_req:
- if (gpio_is_valid(plat->cd_gpio)) {
- tegra_gpio_disable(plat->cd_gpio);
+ if (gpio_is_valid(plat->cd_gpio))
gpio_free(plat->cd_gpio);
- }
err_cd_req:
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
err_power_req:
err_no_plat:
sdhci_pltfm_free(pdev);
@@ -362,21 +353,16 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead);
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
if (gpio_is_valid(plat->cd_gpio)) {
free_irq(gpio_to_irq(plat->cd_gpio), host);
- tegra_gpio_disable(plat->cd_gpio);
gpio_free(plat->cd_gpio);
}
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 8272c02..50aa90a 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -383,7 +383,7 @@ static void doc_set_device_id(struct docg3 *docg3, int id)
* leveling counters are stored. To access this last area of 4 bytes, a special
* mode must be input to the flash ASIC.
*
- * Returns 0 if no error occured, -EIO else.
+ * Returns 0 if no error occurred, -EIO else.
*/
static int doc_set_extra_page_mode(struct docg3 *docg3)
{
@@ -681,7 +681,7 @@ out:
* - one read of 512 bytes at offset 0
* - one read of 512 bytes at offset 512 + 16
*
- * Returns 0 if successful, -EIO if a read error occured.
+ * Returns 0 if successful, -EIO if a read error occurred.
*/
static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1,
int page, int offset)
@@ -839,7 +839,7 @@ static void calc_block_sector(loff_t from, int *block0, int *block1, int *page,
*
* Reads flash memory OOB area of pages.
*
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
*/
static int doc_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
@@ -971,7 +971,7 @@ err_in_read:
* Reads flash memory pages. This function does not read the OOB chunk, but only
* the page data.
*
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
*/
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
@@ -1109,7 +1109,7 @@ static int doc_get_op_status(struct docg3 *docg3)
* Wait for the chip to be ready again after erase or write operation, and check
* erase/write status.
*
- * Returns 0 if erase successfull, -EIO if erase/write issue, -ETIMEOUT if
+ * Returns 0 if erase successful, -EIO if erase/write issue, -ETIMEOUT if
* timeout
*/
static int doc_write_erase_wait_status(struct docg3 *docg3)
@@ -1186,7 +1186,7 @@ static int doc_erase_block(struct docg3 *docg3, int block0, int block1)
* Erase a bunch of contiguous blocks, by pairs, as a "mtd" page of 1024 is
* split into 2 pages of 512 bytes on 2 contiguous blocks.
*
- * Returns 0 if erase successful, -EINVAL if adressing error, -EIO if erase
+ * Returns 0 if erase successful, -EINVAL if addressing error, -EIO if erase
* issue
*/
static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
@@ -1397,7 +1397,7 @@ static int doc_backup_oob(struct docg3 *docg3, loff_t to,
* Or provide data without OOB, and then a all zeroed OOB will be used (ECC will
* still be filled in if asked for).
*
- * Returns 0 is successfull, EINVAL if length is not 14 bytes
+ * Returns 0 is successful, EINVAL if length is not 14 bytes
*/
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
@@ -1945,7 +1945,7 @@ static void doc_release_device(struct mtd_info *mtd)
* docg3_resume - Awakens docg3 floor
* @pdev: platfrom device
*
- * Returns 0 (always successfull)
+ * Returns 0 (always successful)
*/
static int docg3_resume(struct platform_device *pdev)
{
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index 2e42ec2..04769a4 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -102,10 +102,10 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
void __iomem *addr;
unsigned char bits;
- addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
- bits = (ctrl & NAND_CLE) << 4;
+ bits = clps_readb(AUTCPU12_SMC_PORT_OFFSET) & ~0x30;
+ bits |= (ctrl & NAND_CLE) << 4;
bits |= (ctrl & NAND_ALE) << 2;
- writeb((readb(addr) & ~0x30) | bits, addr);
+ clps_writeb(bits, AUTCPU12_SMC_PORT_OFFSET);
addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
@@ -120,9 +120,7 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
*/
int autcpu12_device_ready(struct mtd_info *mtd)
{
- void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
-
- return readb(addr) & AUTCPU12_SMC_RDY;
+ return clps_readb(AUTCPU12_SMC_PORT_OFFSET) & AUTCPU12_SMC_RDY;
}
/*
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 9ec51ce..b68e043 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/mtd/gpmi-nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/pinctrl/consumer.h>
#include "gpmi-nand.h"
/* add our owner bbt descriptor */
@@ -476,6 +477,7 @@ acquire_err:
static int __devinit acquire_resources(struct gpmi_nand_data *this)
{
struct resources *res = &this->resources;
+ struct pinctrl *pinctrl;
int ret;
ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
@@ -494,6 +496,12 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
if (ret)
goto exit_dma_channels;
+ pinctrl = devm_pinctrl_get_select_default(&this->pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto exit_pin;
+ }
+
res->clock = clk_get(&this->pdev->dev, NULL);
if (IS_ERR(res->clock)) {
pr_err("can not get the clock\n");
@@ -503,6 +511,7 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
return 0;
exit_clock:
+exit_pin:
release_dma_channels(this);
exit_dma_channels:
release_bch_irq(this);
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
index 11e4878..9bf5ce5 100644
--- a/drivers/mtd/nand/h1910.c
+++ b/drivers/mtd/nand/h1910.c
@@ -24,7 +24,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
-#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <mach/hardware.h>
#include <asm/sizes.h>
#include <mach/h1900-gpio.h>
#include <mach/ipaq.h>
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 1d3bfb2..0f50ef3 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -74,11 +75,13 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static int __init orion_nand_probe(struct platform_device *pdev)
{
struct mtd_info *mtd;
+ struct mtd_part_parser_data ppdata = {};
struct nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
void __iomem *io_base;
int ret = 0;
+ u32 val = 0;
nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
if (!nc) {
@@ -101,7 +104,32 @@ static int __init orion_nand_probe(struct platform_device *pdev)
goto no_res;
}
- board = pdev->dev.platform_data;
+ if (pdev->dev.of_node) {
+ board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
+ GFP_KERNEL);
+ if (!board) {
+ printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
+ ret = -ENOMEM;
+ goto no_res;
+ }
+ if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
+ board->cle = (u8)val;
+ else
+ board->cle = 0;
+ if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
+ board->ale = (u8)val;
+ else
+ board->ale = 1;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "bank-width", &val))
+ board->width = (u8)val * 8;
+ else
+ board->width = 8;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "chip-delay", &val))
+ board->chip_delay = (u8)val;
+ } else
+ board = pdev->dev.platform_data;
mtd->priv = nc;
mtd->owner = THIS_MODULE;
@@ -115,6 +143,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (board->chip_delay)
nc->chip_delay = board->chip_delay;
+ WARN(board->width > 16,
+ "%d bit bus width out of range",
+ board->width);
+
if (board->width == 16)
nc->options |= NAND_BUSWIDTH_16;
@@ -129,8 +161,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
}
mtd->name = "orion_nand";
- ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts,
- board->nr_parts);
+ ppdata.of_node = pdev->dev.of_node;
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata,
+ board->parts, board->nr_parts);
if (ret) {
nand_release(mtd);
goto no_dev;
@@ -161,11 +194,19 @@ static int __devexit orion_nand_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static struct of_device_id orion_nand_of_match_table[] = {
+ { .compatible = "mrvl,orion-nand", },
+ {},
+};
+#endif
+
static struct platform_driver orion_nand_driver = {
.remove = __devexit_p(orion_nand_remove),
.driver = {
.name = "orion_nand",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(orion_nand_of_match_table),
},
};
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 4dcc752..738ee8d 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -52,12 +52,4 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy
software.
-config MTD_UBI_DEBUG
- bool "UBI debugging"
- depends on SYSFS
- select DEBUG_FS
- select KALLSYMS
- help
- This option enables UBI debugging.
-
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index c9302a5..a0803ac 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -1,7 +1,6 @@
obj-$(CONFIG_MTD_UBI) += ubi.o
-ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
-ubi-y += misc.o
+ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
+ubi-y += misc.o debug.o
-ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/attach.c
index 12c43b4..bd27cbb 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/attach.c
@@ -19,21 +19,21 @@
*/
/*
- * UBI scanning sub-system.
+ * UBI attaching sub-system.
*
- * This sub-system is responsible for scanning the flash media, checking UBI
- * headers and providing complete information about the UBI flash image.
+ * This sub-system is responsible for attaching MTD devices and it also
+ * implements flash media scanning.
*
- * The scanning information is represented by a &struct ubi_scan_info' object.
- * Information about found volumes is represented by &struct ubi_scan_volume
+ * The attaching information is represented by a &struct ubi_attach_info'
+ * object. Information about volumes is represented by &struct ubi_ainf_volume
* objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID.
*
- * Scanned logical eraseblocks are represented by &struct ubi_scan_leb objects.
- * These objects are kept in per-volume RB-trees with the root at the
- * corresponding &struct ubi_scan_volume object. To put it differently, we keep
- * an RB-tree of per-volume objects and each of these objects is the root of
- * RB-tree of per-eraseblock objects.
+ * Logical eraseblocks are represented by &struct ubi_ainf_peb objects. These
+ * objects are kept in per-volume RB-trees with the root at the corresponding
+ * &struct ubi_ainf_volume object. To put it differently, we keep an RB-tree of
+ * per-volume objects and each of these objects is the root of RB-tree of
+ * per-LEB objects.
*
* Corrupted physical eraseblocks are put to the @corr list, free physical
* eraseblocks are put to the @free list and the physical eraseblock to be
@@ -51,28 +51,29 @@
*
* 1. Corruptions caused by power cuts. These are expected corruptions and UBI
* tries to handle them gracefully, without printing too many warnings and
- * error messages. The idea is that we do not lose important data in these case
- * - we may lose only the data which was being written to the media just before
- * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
- * handle such data losses (e.g., by using the FS journal).
+ * error messages. The idea is that we do not lose important data in these
+ * cases - we may lose only the data which were being written to the media just
+ * before the power cut happened, and the upper layers (e.g., UBIFS) are
+ * supposed to handle such data losses (e.g., by using the FS journal).
*
* When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
* the reason is a power cut, UBI puts this PEB to the @erase list, and all
* PEBs in the @erase list are scheduled for erasure later.
*
* 2. Unexpected corruptions which are not caused by power cuts. During
- * scanning, such PEBs are put to the @corr list and UBI preserves them.
+ * attaching, such PEBs are put to the @corr list and UBI preserves them.
* Obviously, this lessens the amount of available PEBs, and if at some point
* UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
* about such PEBs every time the MTD device is attached.
*
* However, it is difficult to reliably distinguish between these types of
- * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
- * if the VID header is corrupted and the data area does not contain all 0xFFs,
- * and there were no bit-flips or integrity errors while reading the data area.
- * Otherwise UBI assumes corruption type 1. So the decision criteria are as
- * follows.
- * o If the data area contains only 0xFFs, there is no data, and it is safe
+ * corruptions and UBI's strategy is as follows (in case of attaching by
+ * scanning). UBI assumes corruption type 2 if the VID header is corrupted and
+ * the data area does not contain all 0xFFs, and there were no bit-flips or
+ * integrity errors (e.g., ECC errors in case of NAND) while reading the data
+ * area. Otherwise UBI assumes corruption type 1. So the decision criteria
+ * are as follows.
+ * o If the data area contains only 0xFFs, there are no data, and it is safe
* to just erase this PEB - this is corruption type 1.
* o If the data area has bit-flips or data integrity errors (ECC errors on
* NAND), it is probably a PEB which was being erased when power cut
@@ -88,11 +89,7 @@
#include <linux/random.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
-#else
-#define paranoid_check_si(ubi, si) 0
-#endif
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* Temporary variables used during scanning */
static struct ubi_ec_hdr *ech;
@@ -100,13 +97,18 @@ static struct ubi_vid_hdr *vidh;
/**
* add_to_list - add physical eraseblock to a list.
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to add
+ * @vol_id: the last used volume id for the PEB
+ * @lnum: the last used LEB number for the PEB
* @ec: erase counter of the physical eraseblock
* @to_head: if not zero, add to the head of the list
* @list: the list to add to
*
- * This function adds physical eraseblock @pnum to free, erase, or alien lists.
+ * This function allocates a 'struct ubi_ainf_peb' object for physical
+ * eraseblock @pnum and adds it to the "free", "erase", or "alien" lists.
+ * It stores the @lnum and @vol_id alongside, which can both be
+ * %UBI_UNKNOWN if they are not available, not readable, or not assigned.
* If @to_head is not zero, PEB will be added to the head of the list, which
* basically means it will be processed first later. E.g., we add corrupted
* PEBs (corrupted due to power cuts) to the head of the erase list to make
@@ -114,65 +116,68 @@ static struct ubi_vid_hdr *vidh;
* returns zero in case of success and a negative error code in case of
* failure.
*/
-static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
- struct list_head *list)
+static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
+ int lnum, int ec, int to_head, struct list_head *list)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
- if (list == &si->free) {
+ if (list == &ai->free) {
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
- } else if (list == &si->erase) {
+ } else if (list == &ai->erase) {
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- } else if (list == &si->alien) {
+ } else if (list == &ai->alien) {
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
- si->alien_peb_count += 1;
+ ai->alien_peb_count += 1;
} else
BUG();
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- seb->pnum = pnum;
- seb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->ec = ec;
if (to_head)
- list_add(&seb->u.list, list);
+ list_add(&aeb->u.list, list);
else
- list_add_tail(&seb->u.list, list);
+ list_add_tail(&aeb->u.list, list);
return 0;
}
/**
* add_corrupted - add a corrupted physical eraseblock.
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to add
* @ec: erase counter of the physical eraseblock
*
- * This function adds corrupted physical eraseblock @pnum to the 'corr' list.
- * The corruption was presumably not caused by a power cut. Returns zero in
- * case of success and a negative error code in case of failure.
+ * This function allocates a 'struct ubi_ainf_peb' object for a corrupted
+ * physical eraseblock @pnum and adds it to the 'corr' list. The corruption
+ * was presumably not caused by a power cut. Returns zero in case of success
+ * and a negative error code in case of failure.
*/
-static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
+static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- si->corr_peb_count += 1;
- seb->pnum = pnum;
- seb->ec = ec;
- list_add(&seb->u.list, &si->corr);
+ ai->corr_peb_count += 1;
+ aeb->pnum = pnum;
+ aeb->ec = ec;
+ list_add(&aeb->u.list, &ai->corr);
return 0;
}
/**
* validate_vid_hdr - check volume identifier header.
* @vid_hdr: the volume identifier header to check
- * @sv: information about the volume this logical eraseblock belongs to
+ * @av: information about the volume this logical eraseblock belongs to
* @pnum: physical eraseblock number the VID header came from
*
* This function checks that data stored in @vid_hdr is consistent. Returns
@@ -184,15 +189,15 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
* headers of the same volume.
*/
static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
- const struct ubi_scan_volume *sv, int pnum)
+ const struct ubi_ainf_volume *av, int pnum)
{
int vol_type = vid_hdr->vol_type;
int vol_id = be32_to_cpu(vid_hdr->vol_id);
int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
int data_pad = be32_to_cpu(vid_hdr->data_pad);
- if (sv->leb_count != 0) {
- int sv_vol_type;
+ if (av->leb_count != 0) {
+ int av_vol_type;
/*
* This is not the first logical eraseblock belonging to this
@@ -200,28 +205,28 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
* to the data in previous logical eraseblock headers.
*/
- if (vol_id != sv->vol_id) {
- dbg_err("inconsistent vol_id");
+ if (vol_id != av->vol_id) {
+ ubi_err("inconsistent vol_id");
goto bad;
}
- if (sv->vol_type == UBI_STATIC_VOLUME)
- sv_vol_type = UBI_VID_STATIC;
+ if (av->vol_type == UBI_STATIC_VOLUME)
+ av_vol_type = UBI_VID_STATIC;
else
- sv_vol_type = UBI_VID_DYNAMIC;
+ av_vol_type = UBI_VID_DYNAMIC;
- if (vol_type != sv_vol_type) {
- dbg_err("inconsistent vol_type");
+ if (vol_type != av_vol_type) {
+ ubi_err("inconsistent vol_type");
goto bad;
}
- if (used_ebs != sv->used_ebs) {
- dbg_err("inconsistent used_ebs");
+ if (used_ebs != av->used_ebs) {
+ ubi_err("inconsistent used_ebs");
goto bad;
}
- if (data_pad != sv->data_pad) {
- dbg_err("inconsistent data_pad");
+ if (data_pad != av->data_pad) {
+ ubi_err("inconsistent data_pad");
goto bad;
}
}
@@ -230,74 +235,74 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
bad:
ubi_err("inconsistent VID header at PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_sv(sv);
+ ubi_dump_vid_hdr(vid_hdr);
+ ubi_dump_av(av);
return -EINVAL;
}
/**
- * add_volume - add volume to the scanning information.
- * @si: scanning information
+ * add_volume - add volume to the attaching information.
+ * @ai: attaching information
* @vol_id: ID of the volume to add
* @pnum: physical eraseblock number
* @vid_hdr: volume identifier header
*
* If the volume corresponding to the @vid_hdr logical eraseblock is already
- * present in the scanning information, this function does nothing. Otherwise
- * it adds corresponding volume to the scanning information. Returns a pointer
- * to the scanning volume object in case of success and a negative error code
- * in case of failure.
+ * present in the attaching information, this function does nothing. Otherwise
+ * it adds corresponding volume to the attaching information. Returns a pointer
+ * to the allocated "av" object in case of success and a negative error code in
+ * case of failure.
*/
-static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
- int pnum,
+static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
+ int vol_id, int pnum,
const struct ubi_vid_hdr *vid_hdr)
{
- struct ubi_scan_volume *sv;
- struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
+ struct ubi_ainf_volume *av;
+ struct rb_node **p = &ai->volumes.rb_node, *parent = NULL;
ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */
while (*p) {
parent = *p;
- sv = rb_entry(parent, struct ubi_scan_volume, rb);
+ av = rb_entry(parent, struct ubi_ainf_volume, rb);
- if (vol_id == sv->vol_id)
- return sv;
+ if (vol_id == av->vol_id)
+ return av;
- if (vol_id > sv->vol_id)
+ if (vol_id > av->vol_id)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
/* The volume is absent - add it */
- sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);
- if (!sv)
+ av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
+ if (!av)
return ERR_PTR(-ENOMEM);
- sv->highest_lnum = sv->leb_count = 0;
- sv->vol_id = vol_id;
- sv->root = RB_ROOT;
- sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
- sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
- sv->compat = vid_hdr->compat;
- sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
+ av->highest_lnum = av->leb_count = 0;
+ av->vol_id = vol_id;
+ av->root = RB_ROOT;
+ av->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ av->data_pad = be32_to_cpu(vid_hdr->data_pad);
+ av->compat = vid_hdr->compat;
+ av->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME;
- if (vol_id > si->highest_vol_id)
- si->highest_vol_id = vol_id;
+ if (vol_id > ai->highest_vol_id)
+ ai->highest_vol_id = vol_id;
- rb_link_node(&sv->rb, parent, p);
- rb_insert_color(&sv->rb, &si->volumes);
- si->vols_found += 1;
+ rb_link_node(&av->rb, parent, p);
+ rb_insert_color(&av->rb, &ai->volumes);
+ ai->vols_found += 1;
dbg_bld("added volume %d", vol_id);
- return sv;
+ return av;
}
/**
* compare_lebs - find out which logical eraseblock is newer.
* @ubi: UBI device description object
- * @seb: first logical eraseblock to compare
+ * @aeb: first logical eraseblock to compare
* @pnum: physical eraseblock number of the second logical eraseblock to
* compare
* @vid_hdr: volume identifier header of the second logical eraseblock
@@ -306,7 +311,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* case of success this function returns a positive value, in case of failure, a
* negative error code is returned. The success return codes use the following
* bits:
- * o bit 0 is cleared: the first PEB (described by @seb) is newer than the
+ * o bit 0 is cleared: the first PEB (described by @aeb) is newer than the
* second PEB (described by @pnum and @vid_hdr);
* o bit 0 is set: the second PEB is newer;
* o bit 1 is cleared: no bit-flips were detected in the newer LEB;
@@ -314,7 +319,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* o bit 2 is cleared: the older LEB is not corrupted;
* o bit 2 is set: the older LEB is corrupted.
*/
-static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
int pnum, const struct ubi_vid_hdr *vid_hdr)
{
void *buf;
@@ -323,7 +328,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
struct ubi_vid_hdr *vh = NULL;
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
- if (sqnum2 == seb->sqnum) {
+ if (sqnum2 == aeb->sqnum) {
/*
* This must be a really ancient UBI image which has been
* created before sequence numbers support has been added. At
@@ -337,7 +342,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
}
/* Obviously the LEB with lower sequence counter is older */
- second_is_newer = !!(sqnum2 > seb->sqnum);
+ second_is_newer = (sqnum2 > aeb->sqnum);
/*
* Now we know which copy is newer. If the copy flag of the PEB with
@@ -356,7 +361,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
return 1;
}
} else {
- if (!seb->copy_flag) {
+ if (!aeb->copy_flag) {
/* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset",
pnum);
@@ -367,13 +372,13 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
if (!vh)
return -ENOMEM;
- pnum = seb->pnum;
+ pnum = aeb->pnum;
err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) {
if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else {
- dbg_err("VID of PEB %d header is bad, but it "
+ ubi_err("VID of PEB %d header is bad, but it "
"was OK earlier, err %d", pnum, err);
if (err > 0)
err = -EIO;
@@ -429,9 +434,9 @@ out_free_vidh:
}
/**
- * ubi_scan_add_used - add physical eraseblock to the scanning information.
+ * ubi_add_to_av - add used physical eraseblock to the attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: the physical eraseblock number
* @ec: erase counter
* @vid_hdr: the volume identifier header
@@ -444,14 +449,13 @@ out_free_vidh:
* to be picked, while the older one has to be dropped. This function returns
* zero in case of success and a negative error code in case of failure.
*/
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
- int bitflips)
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+ int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips)
{
int err, vol_id, lnum;
unsigned long long sqnum;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb;
struct rb_node **p, *parent = NULL;
vol_id = be32_to_cpu(vid_hdr->vol_id);
@@ -461,25 +465,25 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, bitflips);
- sv = add_volume(si, vol_id, pnum, vid_hdr);
- if (IS_ERR(sv))
- return PTR_ERR(sv);
+ av = add_volume(ai, vol_id, pnum, vid_hdr);
+ if (IS_ERR(av))
+ return PTR_ERR(av);
- if (si->max_sqnum < sqnum)
- si->max_sqnum = sqnum;
+ if (ai->max_sqnum < sqnum)
+ ai->max_sqnum = sqnum;
/*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not.
*/
- p = &sv->root.rb_node;
+ p = &av->root.rb_node;
while (*p) {
int cmp_res;
parent = *p;
- seb = rb_entry(parent, struct ubi_scan_leb, u.rb);
- if (lnum != seb->lnum) {
- if (lnum < seb->lnum)
+ aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb);
+ if (lnum != aeb->lnum) {
+ if (lnum < aeb->lnum)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -491,8 +495,8 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* logical eraseblock present.
*/
- dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
- "EC %d", seb->pnum, seb->sqnum, seb->ec);
+ dbg_bld("this LEB already exists: PEB %d, sqnum %llu, EC %d",
+ aeb->pnum, aeb->sqnum, aeb->ec);
/*
* Make sure that the logical eraseblocks have different
@@ -507,11 +511,11 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* images, but refuse attaching old images with duplicated
* logical eraseblocks because there was an unclean reboot.
*/
- if (seb->sqnum == sqnum && sqnum != 0) {
+ if (aeb->sqnum == sqnum && sqnum != 0) {
ubi_err("two LEBs with same sequence number %llu",
sqnum);
- ubi_dbg_dump_seb(seb, 0);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_aeb(aeb, 0);
+ ubi_dump_vid_hdr(vid_hdr);
return -EINVAL;
}
@@ -519,7 +523,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* Now we have to drop the older one and preserve the newer
* one.
*/
- cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);
+ cmp_res = compare_lebs(ubi, aeb, pnum, vid_hdr);
if (cmp_res < 0)
return cmp_res;
@@ -528,23 +532,26 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* This logical eraseblock is newer than the one
* found earlier.
*/
- err = validate_vid_hdr(vid_hdr, sv, pnum);
+ err = validate_vid_hdr(vid_hdr, av, pnum);
if (err)
return err;
- err = add_to_list(si, seb->pnum, seb->ec, cmp_res & 4,
- &si->erase);
+ err = add_to_list(ai, aeb->pnum, aeb->vol_id,
+ aeb->lnum, aeb->ec, cmp_res & 4,
+ &ai->erase);
if (err)
return err;
- seb->ec = ec;
- seb->pnum = pnum;
- seb->scrub = ((cmp_res & 2) || bitflips);
- seb->copy_flag = vid_hdr->copy_flag;
- seb->sqnum = sqnum;
+ aeb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->scrub = ((cmp_res & 2) || bitflips);
+ aeb->copy_flag = vid_hdr->copy_flag;
+ aeb->sqnum = sqnum;
- if (sv->highest_lnum == lnum)
- sv->last_data_size =
+ if (av->highest_lnum == lnum)
+ av->last_data_size =
be32_to_cpu(vid_hdr->data_size);
return 0;
@@ -553,92 +560,64 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* This logical eraseblock is older than the one found
* previously.
*/
- return add_to_list(si, pnum, ec, cmp_res & 4,
- &si->erase);
+ return add_to_list(ai, pnum, vol_id, lnum, ec,
+ cmp_res & 4, &ai->erase);
}
}
/*
* We've met this logical eraseblock for the first time, add it to the
- * scanning information.
+ * attaching information.
*/
- err = validate_vid_hdr(vid_hdr, sv, pnum);
+ err = validate_vid_hdr(vid_hdr, av, pnum);
if (err)
return err;
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- seb->ec = ec;
- seb->pnum = pnum;
- seb->lnum = lnum;
- seb->scrub = bitflips;
- seb->copy_flag = vid_hdr->copy_flag;
- seb->sqnum = sqnum;
-
- if (sv->highest_lnum <= lnum) {
- sv->highest_lnum = lnum;
- sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
+ aeb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->scrub = bitflips;
+ aeb->copy_flag = vid_hdr->copy_flag;
+ aeb->sqnum = sqnum;
+
+ if (av->highest_lnum <= lnum) {
+ av->highest_lnum = lnum;
+ av->last_data_size = be32_to_cpu(vid_hdr->data_size);
}
- sv->leb_count += 1;
- rb_link_node(&seb->u.rb, parent, p);
- rb_insert_color(&seb->u.rb, &sv->root);
+ av->leb_count += 1;
+ rb_link_node(&aeb->u.rb, parent, p);
+ rb_insert_color(&aeb->u.rb, &av->root);
return 0;
}
/**
- * ubi_scan_find_sv - find volume in the scanning information.
- * @si: scanning information
+ * ubi_find_av - find volume in the attaching information.
+ * @ai: attaching information
* @vol_id: the requested volume ID
*
* This function returns a pointer to the volume description or %NULL if there
- * are no data about this volume in the scanning information.
- */
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
- int vol_id)
-{
- struct ubi_scan_volume *sv;
- struct rb_node *p = si->volumes.rb_node;
-
- while (p) {
- sv = rb_entry(p, struct ubi_scan_volume, rb);
-
- if (vol_id == sv->vol_id)
- return sv;
-
- if (vol_id > sv->vol_id)
- p = p->rb_left;
- else
- p = p->rb_right;
- }
-
- return NULL;
-}
-
-/**
- * ubi_scan_find_seb - find LEB in the volume scanning information.
- * @sv: a pointer to the volume scanning information
- * @lnum: the requested logical eraseblock
- *
- * This function returns a pointer to the scanning logical eraseblock or %NULL
- * if there are no data about it in the scanning volume information.
+ * are no data about this volume in the attaching information.
*/
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
- int lnum)
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+ int vol_id)
{
- struct ubi_scan_leb *seb;
- struct rb_node *p = sv->root.rb_node;
+ struct ubi_ainf_volume *av;
+ struct rb_node *p = ai->volumes.rb_node;
while (p) {
- seb = rb_entry(p, struct ubi_scan_leb, u.rb);
+ av = rb_entry(p, struct ubi_ainf_volume, rb);
- if (lnum == seb->lnum)
- return seb;
+ if (vol_id == av->vol_id)
+ return av;
- if (lnum > seb->lnum)
+ if (vol_id > av->vol_id)
p = p->rb_left;
else
p = p->rb_right;
@@ -648,34 +627,34 @@ struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
}
/**
- * ubi_scan_rm_volume - delete scanning information about a volume.
- * @si: scanning information
- * @sv: the volume scanning information to delete
+ * ubi_remove_av - delete attaching information about a volume.
+ * @ai: attaching information
+ * @av: the volume attaching information to delete
*/
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
{
struct rb_node *rb;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
- dbg_bld("remove scanning information about volume %d", sv->vol_id);
+ dbg_bld("remove attaching information about volume %d", av->vol_id);
- while ((rb = rb_first(&sv->root))) {
- seb = rb_entry(rb, struct ubi_scan_leb, u.rb);
- rb_erase(&seb->u.rb, &sv->root);
- list_add_tail(&seb->u.list, &si->erase);
+ while ((rb = rb_first(&av->root))) {
+ aeb = rb_entry(rb, struct ubi_ainf_peb, u.rb);
+ rb_erase(&aeb->u.rb, &av->root);
+ list_add_tail(&aeb->u.list, &ai->erase);
}
- rb_erase(&sv->rb, &si->volumes);
- kfree(sv);
- si->vols_found -= 1;
+ rb_erase(&av->rb, &ai->volumes);
+ kfree(av);
+ ai->vols_found -= 1;
}
/**
- * ubi_scan_erase_peb - erase a physical eraseblock.
+ * early_erase_peb - erase a physical eraseblock.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to erase;
- * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ * @ec: erase counter value to write (%UBI_UNKNOWN if it is unknown)
*
* This function erases physical eraseblock 'pnum', and writes the erase
* counter header to it. This function should only be used on UBI device
@@ -683,8 +662,8 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
- int pnum, int ec)
+static int early_erase_peb(struct ubi_device *ubi,
+ const struct ubi_attach_info *ai, int pnum, int ec)
{
int err;
struct ubi_ec_hdr *ec_hdr;
@@ -716,9 +695,9 @@ out_free:
}
/**
- * ubi_scan_get_free_peb - get a free physical eraseblock.
+ * ubi_early_get_peb - get a free physical eraseblock.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns a free physical eraseblock. It is supposed to be
* called on the UBI initialization stages when the wear-leveling sub-system is
@@ -726,20 +705,20 @@ out_free:
* the lists, writes the EC header if it is needed, and removes it from the
* list.
*
- * This function returns scanning physical eraseblock information in case of
- * success and an error code in case of failure.
+ * This function returns a pointer to the "aeb" of the found free PEB in case
+ * of success and an error code in case of failure.
*/
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+ struct ubi_attach_info *ai)
{
int err = 0;
- struct ubi_scan_leb *seb, *tmp_seb;
+ struct ubi_ainf_peb *aeb, *tmp_aeb;
- if (!list_empty(&si->free)) {
- seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);
- list_del(&seb->u.list);
- dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);
- return seb;
+ if (!list_empty(&ai->free)) {
+ aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list);
+ list_del(&aeb->u.list);
+ dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec);
+ return aeb;
}
/*
@@ -748,18 +727,18 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
* so forth. We don't want to take care about bad eraseblocks here -
* they'll be handled later.
*/
- list_for_each_entry_safe(seb, tmp_seb, &si->erase, u.list) {
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry_safe(aeb, tmp_aeb, &ai->erase, u.list) {
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);
+ err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1);
if (err)
continue;
- seb->ec += 1;
- list_del(&seb->u.list);
- dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);
- return seb;
+ aeb->ec += 1;
+ list_del(&aeb->u.list);
+ dbg_bld("return PEB %d, EC %d", aeb->pnum, aeb->ec);
+ return aeb;
}
ubi_err("no free eraseblocks");
@@ -814,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
ubi_err("PEB %d contains corrupted VID header, and the data does not "
"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
"header corruption which requires manual inspection", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
dbg_msg("hexdump of PEB %d offset %d, length %d",
pnum, ubi->leb_start, ubi->leb_size);
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
@@ -827,16 +806,18 @@ out_unlock:
}
/**
- * process_eb - read, check UBI headers, and add them to scanning information.
+ * scan_peb - scan and process UBI headers of a PEB.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: the physical eraseblock number
*
- * This function returns a zero if the physical eraseblock was successfully
- * handled and a negative error code in case of failure.
+ * This function reads UBI headers of PEB @pnum, checks them, and adds
+ * information about this PEB to the corresponding list or RB-tree in the
+ * "attaching info" structure. Returns zero if the physical eraseblock was
+ * successfully handled and a negative error code in case of failure.
*/
-static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum)
+static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
+ int pnum)
{
long long uninitialized_var(ec);
int err, bitflips = 0, vol_id, ec_err = 0;
@@ -848,12 +829,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
if (err < 0)
return err;
else if (err) {
- /*
- * FIXME: this is actually duty of the I/O sub-system to
- * initialize this, but MTD does not provide enough
- * information.
- */
- si->bad_peb_count += 1;
+ ai->bad_peb_count += 1;
return 0;
}
@@ -867,13 +843,13 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
bitflips = 1;
break;
case UBI_IO_FF:
- si->empty_peb_count += 1;
- return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 0,
- &si->erase);
+ ai->empty_peb_count += 1;
+ return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ UBI_UNKNOWN, 0, &ai->erase);
case UBI_IO_FF_BITFLIPS:
- si->empty_peb_count += 1;
- return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 1,
- &si->erase);
+ ai->empty_peb_count += 1;
+ return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ UBI_UNKNOWN, 1, &ai->erase);
case UBI_IO_BAD_HDR_EBADMSG:
case UBI_IO_BAD_HDR:
/*
@@ -882,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* moved and EC be re-created.
*/
ec_err = err;
- ec = UBI_SCAN_UNKNOWN_EC;
+ ec = UBI_UNKNOWN;
bitflips = 1;
break;
default:
@@ -911,7 +887,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
*/
ubi_err("erase counter overflow, max is %d",
UBI_MAX_ERASECOUNTER);
- ubi_dbg_dump_ec_hdr(ech);
+ ubi_dump_ec_hdr(ech);
return -EINVAL;
}
@@ -933,7 +909,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
ubi->image_seq != image_seq) {
ubi_err("bad image sequence number %d in PEB %d, "
"expected %d", image_seq, pnum, ubi->image_seq);
- ubi_dbg_dump_ec_hdr(ech);
+ ubi_dump_ec_hdr(ech);
return -EINVAL;
}
}
@@ -957,7 +933,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* PEB, bit it is not marked as bad yet. This may also
* be a result of power cut during erasure.
*/
- si->maybe_bad_peb_count += 1;
+ ai->maybe_bad_peb_count += 1;
case UBI_IO_BAD_HDR:
if (ec_err)
/*
@@ -984,23 +960,27 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
else if (!err)
/* This corruption is caused by a power cut */
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 1, &ai->erase);
else
/* This is an unexpected corruption */
- err = add_corrupted(si, pnum, ec);
+ err = add_corrupted(ai, pnum, ec);
if (err)
return err;
goto adjust_mean_ec;
case UBI_IO_FF_BITFLIPS:
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ ec, 1, &ai->erase);
if (err)
return err;
goto adjust_mean_ec;
case UBI_IO_FF:
if (ec_err)
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 1, &ai->erase);
else
- err = add_to_list(si, pnum, ec, 0, &si->free);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 0, &ai->free);
if (err)
return err;
goto adjust_mean_ec;
@@ -1019,7 +999,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, will remove it", vol_id, lnum);
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, vol_id, lnum,
+ ec, 1, &ai->erase);
if (err)
return err;
return 0;
@@ -1034,7 +1015,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum);
- err = add_to_list(si, pnum, ec, 0, &si->alien);
+ err = add_to_list(ai, pnum, vol_id, lnum,
+ ec, 0, &ai->alien);
if (err)
return err;
return 0;
@@ -1049,40 +1031,40 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
if (ec_err)
ubi_warn("valid VID header but corrupted EC header at PEB %d",
pnum);
- err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
+ err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
if (err)
return err;
adjust_mean_ec:
if (!ec_err) {
- si->ec_sum += ec;
- si->ec_count += 1;
- if (ec > si->max_ec)
- si->max_ec = ec;
- if (ec < si->min_ec)
- si->min_ec = ec;
+ ai->ec_sum += ec;
+ ai->ec_count += 1;
+ if (ec > ai->max_ec)
+ ai->max_ec = ec;
+ if (ec < ai->min_ec)
+ ai->min_ec = ec;
}
return 0;
}
/**
- * check_what_we_have - check what PEB were found by scanning.
+ * late_analysis - analyze the overall situation with PEB.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
- * This is a helper function which takes a look what PEBs were found by
- * scanning, and decides whether the flash is empty and should be formatted and
- * whether there are too many corrupted PEBs and we should not attach this
- * MTD device. Returns zero if we should proceed with attaching the MTD device,
- * and %-EINVAL if we should not.
+ * This is a helper function which takes a look what PEBs we have after we
+ * gather information about all of them ("ai" is compete). It decides whether
+ * the flash is empty and should be formatted of whether there are too many
+ * corrupted PEBs and we should not attach this MTD device. Returns zero if we
+ * should proceed with attaching the MTD device, and %-EINVAL if we should not.
*/
-static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
+static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
int max_corr, peb_count;
- peb_count = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
+ peb_count = ubi->peb_count - ai->bad_peb_count - ai->alien_peb_count;
max_corr = peb_count / 20 ?: 8;
/*
@@ -1090,25 +1072,25 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
* unclean reboots. However, many of them may indicate some problems
* with the flash HW or driver.
*/
- if (si->corr_peb_count) {
+ if (ai->corr_peb_count) {
ubi_err("%d PEBs are corrupted and preserved",
- si->corr_peb_count);
+ ai->corr_peb_count);
printk(KERN_ERR "Corrupted PEBs are:");
- list_for_each_entry(seb, &si->corr, u.list)
- printk(KERN_CONT " %d", seb->pnum);
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ printk(KERN_CONT " %d", aeb->pnum);
printk(KERN_CONT "\n");
/*
* If too many PEBs are corrupted, we refuse attaching,
* otherwise, only print a warning.
*/
- if (si->corr_peb_count >= max_corr) {
+ if (ai->corr_peb_count >= max_corr) {
ubi_err("too many corrupted PEBs, refusing");
return -EINVAL;
}
}
- if (si->empty_peb_count + si->maybe_bad_peb_count == peb_count) {
+ if (ai->empty_peb_count + ai->maybe_bad_peb_count == peb_count) {
/*
* All PEBs are empty, or almost all - a couple PEBs look like
* they may be bad PEBs which were not marked as bad yet.
@@ -1124,8 +1106,8 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
* 2. Flash contains non-UBI data and we do not want to format
* it and destroy possibly important information.
*/
- if (si->maybe_bad_peb_count <= 2) {
- si->is_empty = 1;
+ if (ai->maybe_bad_peb_count <= 2) {
+ ai->is_empty = 1;
ubi_msg("empty MTD device detected");
get_random_bytes(&ubi->image_seq,
sizeof(ubi->image_seq));
@@ -1141,40 +1123,41 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
}
/**
- * ubi_scan - scan an MTD device.
+ * scan_all - scan entire MTD device.
* @ubi: UBI device description object
*
* This function does full scanning of an MTD device and returns complete
- * information about it. In case of failure, an error code is returned.
+ * information about it in form of a "struct ubi_attach_info" object. In case
+ * of failure, an error code is returned.
*/
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
+static struct ubi_attach_info *scan_all(struct ubi_device *ubi)
{
int err, pnum;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb;
- struct ubi_scan_info *si;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb;
+ struct ubi_attach_info *ai;
- si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
- if (!si)
+ ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
+ if (!ai)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&si->corr);
- INIT_LIST_HEAD(&si->free);
- INIT_LIST_HEAD(&si->erase);
- INIT_LIST_HEAD(&si->alien);
- si->volumes = RB_ROOT;
+ INIT_LIST_HEAD(&ai->corr);
+ INIT_LIST_HEAD(&ai->free);
+ INIT_LIST_HEAD(&ai->erase);
+ INIT_LIST_HEAD(&ai->alien);
+ ai->volumes = RB_ROOT;
err = -ENOMEM;
- si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
- sizeof(struct ubi_scan_leb),
- 0, 0, NULL);
- if (!si->scan_leb_slab)
- goto out_si;
+ ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
+ sizeof(struct ubi_ainf_peb),
+ 0, 0, NULL);
+ if (!ai->aeb_slab_cache)
+ goto out_ai;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech)
- goto out_si;
+ goto out_ai;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
@@ -1184,7 +1167,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
cond_resched();
dbg_gen("process PEB %d", pnum);
- err = process_eb(ubi, si, pnum);
+ err = scan_peb(ubi, ai, pnum);
if (err < 0)
goto out_vidh;
}
@@ -1192,10 +1175,10 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
dbg_msg("scanning is finished");
/* Calculate mean erase counter */
- if (si->ec_count)
- si->mean_ec = div_u64(si->ec_sum, si->ec_count);
+ if (ai->ec_count)
+ ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
- err = check_what_we_have(ubi, si);
+ err = late_analysis(ubi, ai);
if (err)
goto out_vidh;
@@ -1203,55 +1186,102 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
* In case of unknown erase counter we use the mean erase counter
* value.
*/
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
}
- list_for_each_entry(seb, &si->free, u.list) {
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->free, u.list) {
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
}
- list_for_each_entry(seb, &si->corr, u.list)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- list_for_each_entry(seb, &si->erase, u.list)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->erase, u.list)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- err = paranoid_check_si(ubi, si);
+ err = self_check_ai(ubi, ai);
if (err)
goto out_vidh;
ubi_free_vid_hdr(ubi, vidh);
kfree(ech);
- return si;
+ return ai;
out_vidh:
ubi_free_vid_hdr(ubi, vidh);
out_ech:
kfree(ech);
-out_si:
- ubi_scan_destroy_si(si);
+out_ai:
+ ubi_destroy_ai(ai);
return ERR_PTR(err);
}
/**
- * destroy_sv - free the scanning volume information
- * @sv: scanning volume information
- * @si: scanning information
+ * ubi_attach - attach an MTD device.
+ * @ubi: UBI device descriptor
*
- * This function destroys the volume RB-tree (@sv->root) and the scanning
- * volume information.
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
*/
-static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+int ubi_attach(struct ubi_device *ubi)
{
- struct ubi_scan_leb *seb;
- struct rb_node *this = sv->root.rb_node;
+ int err;
+ struct ubi_attach_info *ai;
+
+ ai = scan_all(ubi);
+ if (IS_ERR(ai))
+ return PTR_ERR(ai);
+
+ ubi->bad_peb_count = ai->bad_peb_count;
+ ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
+ ubi->corr_peb_count = ai->corr_peb_count;
+ ubi->max_ec = ai->max_ec;
+ ubi->mean_ec = ai->mean_ec;
+ ubi_msg("max. sequence number: %llu", ai->max_sqnum);
+
+ err = ubi_read_volume_table(ubi, ai);
+ if (err)
+ goto out_ai;
+
+ err = ubi_wl_init(ubi, ai);
+ if (err)
+ goto out_vtbl;
+
+ err = ubi_eba_init(ubi, ai);
+ if (err)
+ goto out_wl;
+
+ ubi_destroy_ai(ai);
+ return 0;
+
+out_wl:
+ ubi_wl_close(ubi);
+out_vtbl:
+ ubi_free_internal_volumes(ubi);
+ vfree(ubi->vtbl);
+out_ai:
+ ubi_destroy_ai(ai);
+ return err;
+}
+
+/**
+ * destroy_av - free volume attaching information.
+ * @av: volume attaching information
+ * @ai: attaching information
+ *
+ * This function destroys the volume attaching information.
+ */
+static void destroy_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
+{
+ struct ubi_ainf_peb *aeb;
+ struct rb_node *this = av->root.rb_node;
while (this) {
if (this->rb_left)
@@ -1259,224 +1289,222 @@ static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
else if (this->rb_right)
this = this->rb_right;
else {
- seb = rb_entry(this, struct ubi_scan_leb, u.rb);
+ aeb = rb_entry(this, struct ubi_ainf_peb, u.rb);
this = rb_parent(this);
if (this) {
- if (this->rb_left == &seb->u.rb)
+ if (this->rb_left == &aeb->u.rb)
this->rb_left = NULL;
else
this->rb_right = NULL;
}
- kmem_cache_free(si->scan_leb_slab, seb);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
}
- kfree(sv);
+ kfree(av);
}
/**
- * ubi_scan_destroy_si - destroy scanning information.
- * @si: scanning information
+ * ubi_destroy_ai - destroy attaching information.
+ * @ai: attaching information
*/
-void ubi_scan_destroy_si(struct ubi_scan_info *si)
+void ubi_destroy_ai(struct ubi_attach_info *ai)
{
- struct ubi_scan_leb *seb, *seb_tmp;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_peb *aeb, *aeb_tmp;
+ struct ubi_ainf_volume *av;
struct rb_node *rb;
- list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->alien, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->erase, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->corr, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->free, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
/* Destroy the volume RB-tree */
- rb = si->volumes.rb_node;
+ rb = ai->volumes.rb_node;
while (rb) {
if (rb->rb_left)
rb = rb->rb_left;
else if (rb->rb_right)
rb = rb->rb_right;
else {
- sv = rb_entry(rb, struct ubi_scan_volume, rb);
+ av = rb_entry(rb, struct ubi_ainf_volume, rb);
rb = rb_parent(rb);
if (rb) {
- if (rb->rb_left == &sv->rb)
+ if (rb->rb_left == &av->rb)
rb->rb_left = NULL;
else
rb->rb_right = NULL;
}
- destroy_sv(si, sv);
+ destroy_av(ai, av);
}
}
- if (si->scan_leb_slab)
- kmem_cache_destroy(si->scan_leb_slab);
+ if (ai->aeb_slab_cache)
+ kmem_cache_destroy(ai->aeb_slab_cache);
- kfree(si);
+ kfree(ai);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_si - check the scanning information.
+ * self_check_ai - check the attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
- * This function returns zero if the scanning information is all right, and a
+ * This function returns zero if the attaching information is all right, and a
* negative error code if not or if an error occurred.
*/
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb, *last_seb;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb, *last_aeb;
uint8_t *buf;
if (!ubi->dbg->chk_gen)
return 0;
/*
- * At first, check that scanning information is OK.
+ * At first, check that attaching information is OK.
*/
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
int leb_count = 0;
cond_resched();
vols_found += 1;
- if (si->is_empty) {
+ if (ai->is_empty) {
ubi_err("bad is_empty flag");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id < 0 || sv->highest_lnum < 0 ||
- sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 ||
- sv->data_pad < 0 || sv->last_data_size < 0) {
+ if (av->vol_id < 0 || av->highest_lnum < 0 ||
+ av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
+ av->data_pad < 0 || av->last_data_size < 0) {
ubi_err("negative values");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id >= UBI_MAX_VOLUMES &&
- sv->vol_id < UBI_INTERNAL_VOL_START) {
+ if (av->vol_id >= UBI_MAX_VOLUMES &&
+ av->vol_id < UBI_INTERNAL_VOL_START) {
ubi_err("bad vol_id");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id > si->highest_vol_id) {
+ if (av->vol_id > ai->highest_vol_id) {
ubi_err("highest_vol_id is %d, but vol_id %d is there",
- si->highest_vol_id, sv->vol_id);
+ ai->highest_vol_id, av->vol_id);
goto out;
}
- if (sv->vol_type != UBI_DYNAMIC_VOLUME &&
- sv->vol_type != UBI_STATIC_VOLUME) {
+ if (av->vol_type != UBI_DYNAMIC_VOLUME &&
+ av->vol_type != UBI_STATIC_VOLUME) {
ubi_err("bad vol_type");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->data_pad > ubi->leb_size / 2) {
+ if (av->data_pad > ubi->leb_size / 2) {
ubi_err("bad data_pad");
- goto bad_sv;
+ goto bad_av;
}
- last_seb = NULL;
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ last_aeb = NULL;
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
cond_resched();
- last_seb = seb;
+ last_aeb = aeb;
leb_count += 1;
- if (seb->pnum < 0 || seb->ec < 0) {
+ if (aeb->pnum < 0 || aeb->ec < 0) {
ubi_err("negative values");
- goto bad_seb;
+ goto bad_aeb;
}
- if (seb->ec < si->min_ec) {
- ubi_err("bad si->min_ec (%d), %d found",
- si->min_ec, seb->ec);
- goto bad_seb;
+ if (aeb->ec < ai->min_ec) {
+ ubi_err("bad ai->min_ec (%d), %d found",
+ ai->min_ec, aeb->ec);
+ goto bad_aeb;
}
- if (seb->ec > si->max_ec) {
- ubi_err("bad si->max_ec (%d), %d found",
- si->max_ec, seb->ec);
- goto bad_seb;
+ if (aeb->ec > ai->max_ec) {
+ ubi_err("bad ai->max_ec (%d), %d found",
+ ai->max_ec, aeb->ec);
+ goto bad_aeb;
}
- if (seb->pnum >= ubi->peb_count) {
+ if (aeb->pnum >= ubi->peb_count) {
ubi_err("too high PEB number %d, total PEBs %d",
- seb->pnum, ubi->peb_count);
- goto bad_seb;
+ aeb->pnum, ubi->peb_count);
+ goto bad_aeb;
}
- if (sv->vol_type == UBI_STATIC_VOLUME) {
- if (seb->lnum >= sv->used_ebs) {
+ if (av->vol_type == UBI_STATIC_VOLUME) {
+ if (aeb->lnum >= av->used_ebs) {
ubi_err("bad lnum or used_ebs");
- goto bad_seb;
+ goto bad_aeb;
}
} else {
- if (sv->used_ebs != 0) {
+ if (av->used_ebs != 0) {
ubi_err("non-zero used_ebs");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (seb->lnum > sv->highest_lnum) {
+ if (aeb->lnum > av->highest_lnum) {
ubi_err("incorrect highest_lnum or lnum");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (sv->leb_count != leb_count) {
+ if (av->leb_count != leb_count) {
ubi_err("bad leb_count, %d objects in the tree",
leb_count);
- goto bad_sv;
+ goto bad_av;
}
- if (!last_seb)
+ if (!last_aeb)
continue;
- seb = last_seb;
+ aeb = last_aeb;
- if (seb->lnum != sv->highest_lnum) {
+ if (aeb->lnum != av->highest_lnum) {
ubi_err("bad highest_lnum");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (vols_found != si->vols_found) {
- ubi_err("bad si->vols_found %d, should be %d",
- si->vols_found, vols_found);
+ if (vols_found != ai->vols_found) {
+ ubi_err("bad ai->vols_found %d, should be %d",
+ ai->vols_found, vols_found);
goto out;
}
- /* Check that scanning information is correct */
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- last_seb = NULL;
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ /* Check that attaching information is correct */
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ last_aeb = NULL;
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
int vol_type;
cond_resched();
- last_seb = seb;
+ last_aeb = aeb;
- err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1);
+ err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1);
if (err && err != UBI_IO_BITFLIPS) {
ubi_err("VID header is not OK (%d)", err);
if (err > 0)
@@ -1486,52 +1514,52 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
- if (sv->vol_type != vol_type) {
+ if (av->vol_type != vol_type) {
ubi_err("bad vol_type");
goto bad_vid_hdr;
}
- if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
- ubi_err("bad sqnum %llu", seb->sqnum);
+ if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
+ ubi_err("bad sqnum %llu", aeb->sqnum);
goto bad_vid_hdr;
}
- if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
- ubi_err("bad vol_id %d", sv->vol_id);
+ if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
+ ubi_err("bad vol_id %d", av->vol_id);
goto bad_vid_hdr;
}
- if (sv->compat != vidh->compat) {
+ if (av->compat != vidh->compat) {
ubi_err("bad compat %d", vidh->compat);
goto bad_vid_hdr;
}
- if (seb->lnum != be32_to_cpu(vidh->lnum)) {
- ubi_err("bad lnum %d", seb->lnum);
+ if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad lnum %d", aeb->lnum);
goto bad_vid_hdr;
}
- if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
- ubi_err("bad used_ebs %d", sv->used_ebs);
+ if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
+ ubi_err("bad used_ebs %d", av->used_ebs);
goto bad_vid_hdr;
}
- if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
- ubi_err("bad data_pad %d", sv->data_pad);
+ if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
+ ubi_err("bad data_pad %d", av->data_pad);
goto bad_vid_hdr;
}
}
- if (!last_seb)
+ if (!last_aeb)
continue;
- if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
- ubi_err("bad highest_lnum %d", sv->highest_lnum);
+ if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad highest_lnum %d", av->highest_lnum);
goto bad_vid_hdr;
}
- if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
- ubi_err("bad last_data_size %d", sv->last_data_size);
+ if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
+ ubi_err("bad last_data_size %d", av->last_data_size);
goto bad_vid_hdr;
}
}
@@ -1553,21 +1581,21 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
buf[pnum] = 1;
}
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- buf[seb->pnum] = 1;
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->free, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->free, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->corr, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->erase, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->erase, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->alien, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->alien, u.list)
+ buf[aeb->pnum] = 1;
err = 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++)
@@ -1581,25 +1609,23 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
goto out;
return 0;
-bad_seb:
- ubi_err("bad scanning information about LEB %d", seb->lnum);
- ubi_dbg_dump_seb(seb, 0);
- ubi_dbg_dump_sv(sv);
+bad_aeb:
+ ubi_err("bad attaching information about LEB %d", aeb->lnum);
+ ubi_dump_aeb(aeb, 0);
+ ubi_dump_av(av);
goto out;
-bad_sv:
- ubi_err("bad scanning information about volume %d", sv->vol_id);
- ubi_dbg_dump_sv(sv);
+bad_av:
+ ubi_err("bad attaching information about volume %d", av->vol_id);
+ ubi_dump_av(av);
goto out;
bad_vid_hdr:
- ubi_err("bad scanning information about volume %d", sv->vol_id);
- ubi_dbg_dump_sv(sv);
- ubi_dbg_dump_vid_hdr(vidh);
+ ubi_err("bad attaching information about volume %d", av->vol_id);
+ ubi_dump_av(av);
+ ubi_dump_vid_hdr(vidh);
out:
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc..2c5ed5c 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -27,10 +27,6 @@
* module load parameters or the kernel boot parameters. If MTD devices were
* specified, UBI does not attach any MTD device, but it is possible to do
* later using the "UBI control device".
- *
- * At the moment we only attach UBI devices by scanning, which will become a
- * bottleneck when flashes reach certain large size. Then one may improve UBI
- * and add other methods, although it does not seem to be easy to do.
*/
#include <linux/err.h>
@@ -554,10 +550,10 @@ static void uif_close(struct ubi_device *ubi)
}
/**
- * free_internal_volumes - free internal volumes.
+ * ubi_free_internal_volumes - free internal volumes.
* @ubi: UBI device description object
*/
-static void free_internal_volumes(struct ubi_device *ubi)
+void ubi_free_internal_volumes(struct ubi_device *ubi)
{
int i;
@@ -569,59 +565,6 @@ static void free_internal_volumes(struct ubi_device *ubi)
}
/**
- * attach_by_scanning - attach an MTD device using scanning method.
- * @ubi: UBI device descriptor
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- *
- * Note, currently this is the only method to attach UBI devices. Hopefully in
- * the future we'll have more scalable attaching methods and avoid full media
- * scanning. But even in this case scanning will be needed as a fall-back
- * attaching method if there are some on-flash table corruptions.
- */
-static int attach_by_scanning(struct ubi_device *ubi)
-{
- int err;
- struct ubi_scan_info *si;
-
- si = ubi_scan(ubi);
- if (IS_ERR(si))
- return PTR_ERR(si);
-
- ubi->bad_peb_count = si->bad_peb_count;
- ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
- ubi->corr_peb_count = si->corr_peb_count;
- ubi->max_ec = si->max_ec;
- ubi->mean_ec = si->mean_ec;
- ubi_msg("max. sequence number: %llu", si->max_sqnum);
-
- err = ubi_read_volume_table(ubi, si);
- if (err)
- goto out_si;
-
- err = ubi_wl_init_scan(ubi, si);
- if (err)
- goto out_vtbl;
-
- err = ubi_eba_init_scan(ubi, si);
- if (err)
- goto out_wl;
-
- ubi_scan_destroy_si(si);
- return 0;
-
-out_wl:
- ubi_wl_close(ubi);
-out_vtbl:
- free_internal_volumes(ubi);
- vfree(ubi->vtbl);
-out_si:
- ubi_scan_destroy_si(si);
- return err;
-}
-
-/**
* io_init - initialize I/O sub-system for a given UBI device.
* @ubi: UBI device description object
*
@@ -790,11 +733,11 @@ static int io_init(struct ubi_device *ubi)
ubi_msg("data offset: %d", ubi->leb_start);
/*
- * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+ * Note, ideally, we have to initialize @ubi->bad_peb_count here. But
* unfortunately, MTD does not provide this information. We should loop
* over all physical eraseblocks and invoke mtd->block_is_bad() for
- * each physical eraseblock. So, we skip ubi->bad_peb_count
- * uninitialized and initialize it after scanning.
+ * each physical eraseblock. So, we leave @ubi->bad_peb_count
+ * uninitialized so far.
*/
return 0;
@@ -805,7 +748,7 @@ static int io_init(struct ubi_device *ubi)
* @ubi: UBI device description object
* @vol_id: ID of the volume to re-size
*
- * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * This function re-sizes the volume marked by the %UBI_VTBL_AUTORESIZE_FLG in
* the volume table to the largest possible size. See comments in ubi-header.h
* for more description of the flag. Returns zero in case of success and a
* negative error code in case of failure.
@@ -881,7 +824,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
for (i = 0; i < UBI_MAX_DEVICES; i++) {
ubi = ubi_devices[i];
if (ubi && mtd->index == ubi->mtd->index) {
- dbg_err("mtd%d is already attached to ubi%d",
+ ubi_err("mtd%d is already attached to ubi%d",
mtd->index, i);
return -EEXIST;
}
@@ -907,7 +850,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (!ubi_devices[ubi_num])
break;
if (ubi_num == UBI_MAX_DEVICES) {
- dbg_err("only %d UBI devices may be created",
+ ubi_err("only %d UBI devices may be created",
UBI_MAX_DEVICES);
return -ENFILE;
}
@@ -917,7 +860,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
/* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) {
- dbg_err("ubi%d already exists", ubi_num);
+ ubi_err("ubi%d already exists", ubi_num);
return -EEXIST;
}
}
@@ -937,7 +880,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
spin_lock_init(&ubi->volumes_lock);
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
- dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
+ dbg_msg("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
err = io_init(ubi);
@@ -953,9 +896,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (err)
goto out_free;
- err = attach_by_scanning(ubi);
+ err = ubi_attach(ubi);
if (err) {
- dbg_err("failed to attach by scanning, error %d", err);
+ ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
goto out_debugging;
}
@@ -1020,7 +963,7 @@ out_uif:
uif_close(ubi);
out_detach:
ubi_wl_close(ubi);
- free_internal_volumes(ubi);
+ ubi_free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_debugging:
ubi_debugging_exit_dev(ubi);
@@ -1092,7 +1035,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
ubi_debugfs_exit_dev(ubi);
uif_close(ubi);
ubi_wl_close(ubi);
- free_internal_volumes(ubi);
+ ubi_free_internal_volumes(ubi);
vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
ubi_debugging_exit_dev(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index ad76592..acec85d 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -63,7 +63,7 @@ static int get_exclusive(struct ubi_volume_desc *desc)
users = vol->readers + vol->writers + vol->exclusive;
ubi_assert(users > 0);
if (users > 1) {
- dbg_err("%d users for volume %d", users, vol->vol_id);
+ ubi_err("%d users for volume %d", users, vol->vol_id);
err = -EBUSY;
} else {
vol->readers = vol->writers = 0;
@@ -159,7 +159,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
if (vol->updating) {
/* Update is in progress, seeking is prohibited */
- dbg_err("updating");
+ ubi_err("updating");
return -EBUSY;
}
@@ -178,7 +178,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
}
if (new_offset < 0 || new_offset > vol->used_bytes) {
- dbg_err("bad seek %lld", new_offset);
+ ubi_err("bad seek %lld", new_offset);
return -EINVAL;
}
@@ -216,11 +216,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
count, *offp, vol->vol_id);
if (vol->updating) {
- dbg_err("updating");
+ ubi_err("updating");
return -EBUSY;
}
if (vol->upd_marker) {
- dbg_err("damaged volume, update marker is set");
+ ubi_err("damaged volume, update marker is set");
return -EBADF;
}
if (*offp == vol->used_bytes || count == 0)
@@ -300,7 +300,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
if (off & (ubi->min_io_size - 1)) {
- dbg_err("unaligned position");
+ ubi_err("unaligned position");
return -EINVAL;
}
@@ -309,7 +309,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
/* We can write only in fractions of the minimum I/O unit */
if (count & (ubi->min_io_size - 1)) {
- dbg_err("unaligned write length");
+ ubi_err("unaligned write length");
return -EINVAL;
}
@@ -334,8 +334,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
break;
}
- err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len,
- UBI_UNKNOWN);
+ err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len);
if (err)
break;
@@ -477,9 +476,6 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
req.bytes < 0 || req.lnum >= vol->usable_leb_size)
break;
- if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
- req.dtype != UBI_UNKNOWN)
- break;
err = get_exclusive(desc);
if (err < 0)
@@ -518,7 +514,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
if (err)
break;
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
break;
}
@@ -532,7 +528,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
err = -EFAULT;
break;
}
- err = ubi_leb_map(desc, req.lnum, req.dtype);
+ err = ubi_leb_map(desc, req.lnum);
break;
}
@@ -647,8 +643,8 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
return 0;
bad:
- dbg_err("bad volume creation request");
- ubi_dbg_dump_mkvol_req(req);
+ ubi_err("bad volume creation request");
+ ubi_dump_mkvol_req(req);
return err;
}
@@ -713,12 +709,12 @@ static int rename_volumes(struct ubi_device *ubi,
for (i = 0; i < req->count - 1; i++) {
for (n = i + 1; n < req->count; n++) {
if (req->ents[i].vol_id == req->ents[n].vol_id) {
- dbg_err("duplicated volume id %d",
+ ubi_err("duplicated volume id %d",
req->ents[i].vol_id);
return -EINVAL;
}
if (!strcmp(req->ents[i].name, req->ents[n].name)) {
- dbg_err("duplicated volume name \"%s\"",
+ ubi_err("duplicated volume name \"%s\"",
req->ents[i].name);
return -EINVAL;
}
@@ -741,7 +737,7 @@ static int rename_volumes(struct ubi_device *ubi,
re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc);
- dbg_err("cannot open volume %d, error %d", vol_id, err);
+ ubi_err("cannot open volume %d, error %d", vol_id, err);
kfree(re);
goto out_free;
}
@@ -800,7 +796,7 @@ static int rename_volumes(struct ubi_device *ubi,
continue;
/* The volume exists but busy, or an error occurred */
- dbg_err("cannot open volume \"%s\", error %d",
+ ubi_err("cannot open volume \"%s\", error %d",
re->new_name, err);
goto out_free;
}
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 61af9bb..9f957c2 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -18,24 +18,49 @@
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
-/*
- * Here we keep all the UBI debugging stuff which should normally be disabled
- * and compiled-out, but it is extremely helpful when hunting bugs or doing big
- * changes.
- */
-
-#ifdef CONFIG_MTD_UBI_DEBUG
-
#include "ubi.h"
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/module.h>
+
+/**
+ * ubi_dump_flash - dump a region of flash.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to dump
+ * @offset: the starting offset within the physical eraseblock to dump
+ * @len: the length of the region to dump
+ */
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
+{
+ int err;
+ size_t read;
+ void *buf;
+ loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+ buf = vmalloc(len);
+ if (!buf)
+ return;
+ err = mtd_read(ubi->mtd, addr, len, &read, buf);
+ if (err && err != -EUCLEAN) {
+ ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, len, pnum, offset, read);
+ goto out;
+ }
+
+ ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
+ len, pnum, offset);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
+out:
+ vfree(buf);
+ return;
+}
+
/**
- * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+ * ubi_dump_ec_hdr - dump an erase counter header.
* @ec_hdr: the erase counter header to dump
*/
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
printk(KERN_DEBUG "Erase counter header dump:\n");
printk(KERN_DEBUG "\tmagic %#08x\n",
@@ -57,10 +82,10 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
}
/**
- * ubi_dbg_dump_vid_hdr - dump a volume identifier header.
+ * ubi_dump_vid_hdr - dump a volume identifier header.
* @vid_hdr: the volume identifier header to dump
*/
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
printk(KERN_DEBUG "Volume identifier header dump:\n");
printk(KERN_DEBUG "\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
@@ -82,10 +107,10 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
}
/**
- * ubi_dbg_dump_vol_info- dump volume information.
+ * ubi_dump_vol_info - dump volume information.
* @vol: UBI volume description object
*/
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
+void ubi_dump_vol_info(const struct ubi_volume *vol)
{
printk(KERN_DEBUG "Volume information dump:\n");
printk(KERN_DEBUG "\tvol_id %d\n", vol->vol_id);
@@ -112,11 +137,11 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
}
/**
- * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
* @r: the object to dump
* @idx: volume table index
*/
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
int name_len = be16_to_cpu(r->name_len);
@@ -146,44 +171,44 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
}
/**
- * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
- * @sv: the object to dump
+ * ubi_dump_av - dump a &struct ubi_ainf_volume object.
+ * @av: the object to dump
*/
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
+void ubi_dump_av(const struct ubi_ainf_volume *av)
{
- printk(KERN_DEBUG "Volume scanning information dump:\n");
- printk(KERN_DEBUG "\tvol_id %d\n", sv->vol_id);
- printk(KERN_DEBUG "\thighest_lnum %d\n", sv->highest_lnum);
- printk(KERN_DEBUG "\tleb_count %d\n", sv->leb_count);
- printk(KERN_DEBUG "\tcompat %d\n", sv->compat);
- printk(KERN_DEBUG "\tvol_type %d\n", sv->vol_type);
- printk(KERN_DEBUG "\tused_ebs %d\n", sv->used_ebs);
- printk(KERN_DEBUG "\tlast_data_size %d\n", sv->last_data_size);
- printk(KERN_DEBUG "\tdata_pad %d\n", sv->data_pad);
+ printk(KERN_DEBUG "Volume attaching information dump:\n");
+ printk(KERN_DEBUG "\tvol_id %d\n", av->vol_id);
+ printk(KERN_DEBUG "\thighest_lnum %d\n", av->highest_lnum);
+ printk(KERN_DEBUG "\tleb_count %d\n", av->leb_count);
+ printk(KERN_DEBUG "\tcompat %d\n", av->compat);
+ printk(KERN_DEBUG "\tvol_type %d\n", av->vol_type);
+ printk(KERN_DEBUG "\tused_ebs %d\n", av->used_ebs);
+ printk(KERN_DEBUG "\tlast_data_size %d\n", av->last_data_size);
+ printk(KERN_DEBUG "\tdata_pad %d\n", av->data_pad);
}
/**
- * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
- * @seb: the object to dump
+ * ubi_dump_aeb - dump a &struct ubi_ainf_peb object.
+ * @aeb: the object to dump
* @type: object type: 0 - not corrupted, 1 - corrupted
*/
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type)
{
- printk(KERN_DEBUG "eraseblock scanning information dump:\n");
- printk(KERN_DEBUG "\tec %d\n", seb->ec);
- printk(KERN_DEBUG "\tpnum %d\n", seb->pnum);
+ printk(KERN_DEBUG "eraseblock attaching information dump:\n");
+ printk(KERN_DEBUG "\tec %d\n", aeb->ec);
+ printk(KERN_DEBUG "\tpnum %d\n", aeb->pnum);
if (type == 0) {
- printk(KERN_DEBUG "\tlnum %d\n", seb->lnum);
- printk(KERN_DEBUG "\tscrub %d\n", seb->scrub);
- printk(KERN_DEBUG "\tsqnum %llu\n", seb->sqnum);
+ printk(KERN_DEBUG "\tlnum %d\n", aeb->lnum);
+ printk(KERN_DEBUG "\tscrub %d\n", aeb->scrub);
+ printk(KERN_DEBUG "\tsqnum %llu\n", aeb->sqnum);
}
}
/**
- * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
+ * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
* @req: the object to dump
*/
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
{
char nm[17];
@@ -200,38 +225,6 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
}
/**
- * ubi_dbg_dump_flash - dump a region of flash.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to dump
- * @offset: the starting offset within the physical eraseblock to dump
- * @len: the length of the region to dump
- */
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
-{
- int err;
- size_t read;
- void *buf;
- loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
-
- buf = vmalloc(len);
- if (!buf)
- return;
- err = mtd_read(ubi->mtd, addr, len, &read, buf);
- if (err && err != -EUCLEAN) {
- ubi_err("error %d while reading %d bytes from PEB %d:%d, "
- "read %zd bytes", err, len, pnum, offset, read);
- goto out;
- }
-
- dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
- len, pnum, offset);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
-out:
- vfree(buf);
- return;
-}
-
-/**
* ubi_debugging_init_dev - initialize debugging for an UBI device.
* @ubi: UBI device description object
*
@@ -479,5 +472,3 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
{
debugfs_remove_recursive(ubi->dbg->dfs_dir);
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ead2cd1..d5d2645 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -21,21 +21,20 @@
#ifndef __UBI_DEBUG_H__
#define __UBI_DEBUG_H__
-#ifdef CONFIG_MTD_UBI_DEBUG
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+
#include <linux/random.h>
#define ubi_assert(expr) do { \
if (unlikely(!(expr))) { \
printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \
- ubi_dbg_dump_stack(); \
+ dump_stack(); \
} \
} while (0)
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
-#define ubi_dbg_dump_stack() dump_stack()
-
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
print_hex_dump(l, ps, pt, r, g, b, len, a)
@@ -58,17 +57,13 @@
/* Initialization and build messages */
#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len);
+void ubi_dump_vol_info(const struct ubi_volume *vol);
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
+void ubi_dump_av(const struct ubi_ainf_volume *av);
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type);
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req);
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len);
int ubi_debugging_init_dev(struct ubi_device *ubi);
void ubi_debugging_exit_dev(struct ubi_device *ubi);
int ubi_debugfs_init(void);
@@ -167,73 +162,4 @@ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
return 0;
}
-#else
-
-/* Use "if (0)" to make compiler check arguments even if debugging is off */
-#define ubi_assert(expr) do { \
- if (0) { \
- printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
- __func__, __LINE__, current->pid); \
- } \
-} while (0)
-
-#define dbg_err(fmt, ...) do { \
- if (0) \
- ubi_err(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define ubi_dbg_msg(fmt, ...) do { \
- if (0) \
- printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
-} while (0)
-
-#define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_eba(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_wl(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_bld(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-
-static inline void ubi_dbg_dump_stack(void) { return; }
-static inline void
-ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) { return; }
-static inline void
-ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) { return; }
-static inline void
-ubi_dbg_dump_vol_info(const struct ubi_volume *vol) { return; }
-static inline void
-ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) { return; }
-static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
-static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
- int type) { return; }
-static inline void
-ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) { return; }
-static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
- int pnum, int offset, int len) { return; }
-static inline void
-ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
- int g, const void *b, size_t len, bool a) { return; }
-static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
- int pnum, int offset,
- int len) { return 0; }
-static inline int ubi_dbg_check_write(struct ubi_device *ubi,
- const void *buf, int pnum,
- int offset, int len) { return 0; }
-
-static inline int ubi_debugging_init_dev(struct ubi_device *ubi) { return 0; }
-static inline void ubi_debugging_exit_dev(struct ubi_device *ubi) { return; }
-static inline int ubi_debugfs_init(void) { return 0; }
-static inline void ubi_debugfs_exit(void) { return; }
-static inline int ubi_debugfs_init_dev(struct ubi_device *ubi) { return 0; }
-static inline void ubi_debugfs_exit_dev(struct ubi_device *ubi) { return; }
-
-static inline int
-ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) { return 0; }
-static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { return 0; }
-static inline int
-ubi_dbg_is_write_failure(const struct ubi_device *ubi) { return 0; }
-static inline int
-ubi_dbg_is_erase_failure(const struct ubi_device *ubi) { return 0; }
-
-#endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 2455d62..b703ac7 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -341,7 +341,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
- err = ubi_wl_put_peb(ubi, pnum, 0);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
out_unlock:
leb_write_unlock(ubi, vol_id, lnum);
@@ -507,7 +507,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
return -ENOMEM;
retry:
- new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
+ new_pnum = ubi_wl_get_peb(ubi);
if (new_pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
return new_pnum;
@@ -550,7 +550,7 @@ retry:
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
- ubi_wl_put_peb(ubi, pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
ubi_msg("data was successfully recovered");
return 0;
@@ -558,7 +558,7 @@ retry:
out_unlock:
mutex_unlock(&ubi->buf_mutex);
out_put:
- ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -568,7 +568,7 @@ write_error:
* get another one.
*/
ubi_warn("failed to write to PEB %d", new_pnum);
- ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) {
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -585,7 +585,6 @@ write_error:
* @buf: the data to write
* @offset: offset within the logical eraseblock where to write
* @len: how many bytes to write
- * @dtype: data type
*
* This function writes data to logical eraseblock @lnum of a dynamic volume
* @vol. Returns zero in case of success and a negative error code in case
@@ -593,7 +592,7 @@ write_error:
* written to the flash media, but may be some garbage.
*/
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
- const void *buf, int offset, int len, int dtype)
+ const void *buf, int offset, int len)
{
int err, pnum, tries = 0, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -641,7 +640,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
leb_write_unlock(ubi, vol_id, lnum);
@@ -687,7 +686,7 @@ write_error:
* eraseblock, so just put it and request a new one. We assume that if
* this physical eraseblock went bad, the erase code will handle that.
*/
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum);
@@ -707,7 +706,6 @@ write_error:
* @lnum: logical eraseblock number
* @buf: data to write
* @len: how many bytes to write
- * @dtype: data type
* @used_ebs: how many logical eraseblocks will this volume contain
*
* This function writes data to logical eraseblock @lnum of static volume
@@ -724,8 +722,7 @@ write_error:
* code in case of failure.
*/
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype,
- int used_ebs)
+ int lnum, const void *buf, int len, int used_ebs)
{
int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -763,7 +760,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
vid_hdr->data_crc = cpu_to_be32(crc);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
leb_write_unlock(ubi, vol_id, lnum);
@@ -807,7 +804,7 @@ write_error:
return err;
}
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum);
@@ -827,7 +824,6 @@ write_error:
* @lnum: logical eraseblock number
* @buf: data to write
* @len: how many bytes to write
- * @dtype: data type
*
* This function changes the contents of a logical eraseblock atomically. @buf
* has to contain new logical eraseblock data, and @len - the length of the
@@ -839,7 +835,7 @@ write_error:
* LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
*/
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype)
+ int lnum, const void *buf, int len)
{
int err, pnum, tries = 0, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -856,7 +852,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
err = ubi_eba_unmap_leb(ubi, vol, lnum);
if (err)
return err;
- return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
}
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -881,7 +877,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
vid_hdr->data_crc = cpu_to_be32(crc);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
err = pnum;
goto out_leb_unlock;
@@ -905,7 +901,7 @@ retry:
}
if (vol->eba_tbl[lnum] >= 0) {
- err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
if (err)
goto out_leb_unlock;
}
@@ -930,7 +926,7 @@ write_error:
goto out_leb_unlock;
}
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
goto out_leb_unlock;
@@ -1171,7 +1167,7 @@ out_unlock_leb:
* print_rsvd_warning - warn about not having enough reserved PEBs.
* @ubi: UBI device description object
*
- * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI
+ * This is a helper function for 'ubi_eba_init()' which is called when UBI
* cannot reserve enough PEBs for bad block handling. This function makes a
* decision whether we have to print a warning or not. The algorithm is as
* follows:
@@ -1186,13 +1182,13 @@ out_unlock_leb:
* reported by real users.
*/
static void print_rsvd_warning(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+ struct ubi_attach_info *ai)
{
/*
* The 1 << 18 (256KiB) number is picked randomly, just a reasonably
* large number to distinguish between newly flashed and used images.
*/
- if (si->max_sqnum > (1 << 18)) {
+ if (ai->max_sqnum > (1 << 18)) {
int min = ubi->beb_rsvd_level / 10;
if (!min)
@@ -1209,19 +1205,19 @@ static void print_rsvd_warning(struct ubi_device *ubi,
}
/**
- * ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
+ * ubi_eba_init - initialize the EBA sub-system using attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int i, j, err, num_volumes;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
struct rb_node *rb;
dbg_eba("initialize EBA sub-system");
@@ -1230,7 +1226,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
mutex_init(&ubi->alc_mutex);
ubi->ltree = RB_ROOT;
- ubi->global_sqnum = si->max_sqnum + 1;
+ ubi->global_sqnum = ai->max_sqnum + 1;
num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
for (i = 0; i < num_volumes; i++) {
@@ -1250,18 +1246,18 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
for (j = 0; j < vol->reserved_pebs; j++)
vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
- sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i));
- if (!sv)
+ av = ubi_find_av(ai, idx2vol_id(ubi, i));
+ if (!av)
continue;
- ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- if (seb->lnum >= vol->reserved_pebs)
+ ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+ if (aeb->lnum >= vol->reserved_pebs)
/*
* This may happen in case of an unclean reboot
* during re-size.
*/
- ubi_scan_move_to_list(sv, seb, &si->erase);
- vol->eba_tbl[seb->lnum] = seb->pnum;
+ ubi_move_aeb_to_list(av, aeb, &ai->erase);
+ vol->eba_tbl[aeb->lnum] = aeb->pnum;
}
}
@@ -1283,7 +1279,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi->avail_pebs < ubi->beb_rsvd_level) {
/* No enough free physical eraseblocks */
ubi->beb_rsvd_pebs = ubi->avail_pebs;
- print_rsvd_warning(ubi, si);
+ print_rsvd_warning(ubi, ai);
} else
ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 90b9882..4e44bee 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -227,7 +227,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
if (to_write > total_written)
to_write = total_written;
- err = ubi_write(gluebi->desc, lnum, buf, offs, to_write);
+ err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
if (err)
break;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 43f1a00..a8d5237 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -91,21 +91,15 @@
#include <linux/slab.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_ec_hdr *ec_hdr);
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_vid_hdr *vid_hdr);
-#else
-#define paranoid_check_not_bad(ubi, pnum) 0
-#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
-#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0
-#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
-#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
-#endif
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum);
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr);
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr);
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len);
/**
* ubi_io_read - read data from a physical eraseblock.
@@ -142,7 +136,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
ubi_assert(len > 0);
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err)
return err;
@@ -189,16 +183,16 @@ retry:
}
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d%s while reading %d bytes from PEB "
- "%d:%d, read only %zd bytes, retry",
- err, errstr, len, pnum, offset, read);
+ ubi_warn("error %d%s while reading %d bytes from PEB "
+ "%d:%d, read only %zd bytes, retry",
+ err, errstr, len, pnum, offset, read);
yield();
goto retry;
}
ubi_err("error %d%s while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, errstr, len, pnum, offset, read);
- ubi_dbg_dump_stack();
+ dump_stack();
/*
* The driver should never return -EBADMSG if it failed to read
@@ -257,14 +251,12 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
return -EROFS;
}
- /* The below has to be compiled out if paranoid checks are disabled */
-
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err)
return err;
/* The area we are writing to has to contain all 0xFF bytes */
- err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+ err = ubi_self_check_all_ff(ubi, pnum, offset, len);
if (err)
return err;
@@ -273,18 +265,18 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
* We write to the data area of the physical eraseblock. Make
* sure it has valid EC and VID headers.
*/
- err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ err = self_check_peb_ec_hdr(ubi, pnum);
if (err)
return err;
- err = paranoid_check_peb_vid_hdr(ubi, pnum);
+ err = self_check_peb_vid_hdr(ubi, pnum);
if (err)
return err;
}
if (ubi_dbg_is_write_failure(ubi)) {
- dbg_err("cannot write %d bytes to PEB %d:%d "
+ ubi_err("cannot write %d bytes to PEB %d:%d "
"(emulated)", len, pnum, offset);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EIO;
}
@@ -293,13 +285,13 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
if (err) {
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
"%zd bytes", err, len, pnum, offset, written);
- ubi_dbg_dump_stack();
- ubi_dbg_dump_flash(ubi, pnum, offset, len);
+ dump_stack();
+ ubi_dump_flash(ubi, pnum, offset, len);
} else
ubi_assert(written == len);
if (!err) {
- err = ubi_dbg_check_write(ubi, buf, pnum, offset, len);
+ err = self_check_write(ubi, buf, pnum, offset, len);
if (err)
return err;
@@ -310,7 +302,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
offset += len;
len = ubi->peb_size - offset;
if (len)
- err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+ err = ubi_self_check_all_ff(ubi, pnum, offset, len);
}
return err;
@@ -364,13 +356,13 @@ retry:
err = mtd_erase(ubi->mtd, &ei);
if (err) {
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d while erasing PEB %d, retry",
- err, pnum);
+ ubi_warn("error %d while erasing PEB %d, retry",
+ err, pnum);
yield();
goto retry;
}
ubi_err("cannot erase PEB %d, error %d", pnum, err);
- ubi_dbg_dump_stack();
+ dump_stack();
return err;
}
@@ -383,21 +375,21 @@ retry:
if (ei.state == MTD_ERASE_FAILED) {
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error while erasing PEB %d, retry", pnum);
+ ubi_warn("error while erasing PEB %d, retry", pnum);
yield();
goto retry;
}
ubi_err("cannot erase PEB %d", pnum);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EIO;
}
- err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+ err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
if (err)
return err;
if (ubi_dbg_is_erase_failure(ubi)) {
- dbg_err("cannot erase PEB %d (emulated)", pnum);
+ ubi_err("cannot erase PEB %d (emulated)", pnum);
return -EIO;
}
@@ -521,8 +513,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* It is important to first invalidate the EC header, and then the VID
* header. Otherwise a power cut may lead to valid EC header and
* invalid VID header, in which case UBI will treat this PEB as
- * corrupted and will try to preserve it, and print scary warnings (see
- * the header comment in scan.c for more information).
+ * corrupted and will try to preserve it, and print scary warnings.
*/
addr = (loff_t)pnum * ubi->peb_size;
err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
@@ -563,7 +554,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
*/
ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
pnum, err, err1);
- ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
+ ubi_dump_flash(ubi, pnum, 0, ubi->peb_size);
return -EIO;
}
@@ -589,7 +580,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err != 0)
return err;
@@ -721,8 +712,8 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
bad:
ubi_err("bad EC header");
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
return 1;
}
@@ -803,7 +794,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
- ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dump_ec_hdr(ec_hdr);
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
@@ -817,7 +808,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
- ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dump_ec_hdr(ec_hdr);
}
dbg_bld("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
@@ -874,7 +865,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
ec_hdr->hdr_crc = cpu_to_be32(crc);
- err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+ err = self_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
return err;
@@ -905,40 +896,40 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) {
- dbg_err("bad copy_flag");
+ ubi_err("bad copy_flag");
goto bad;
}
if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
data_pad < 0) {
- dbg_err("negative values");
+ ubi_err("negative values");
goto bad;
}
if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
- dbg_err("bad vol_id");
+ ubi_err("bad vol_id");
goto bad;
}
if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
- dbg_err("bad compat");
+ ubi_err("bad compat");
goto bad;
}
if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
compat != UBI_COMPAT_REJECT) {
- dbg_err("bad compat");
+ ubi_err("bad compat");
goto bad;
}
if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
- dbg_err("bad vol_type");
+ ubi_err("bad vol_type");
goto bad;
}
if (data_pad >= ubi->leb_size / 2) {
- dbg_err("bad data_pad");
+ ubi_err("bad data_pad");
goto bad;
}
@@ -950,45 +941,45 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
* mapped logical eraseblocks.
*/
if (used_ebs == 0) {
- dbg_err("zero used_ebs");
+ ubi_err("zero used_ebs");
goto bad;
}
if (data_size == 0) {
- dbg_err("zero data_size");
+ ubi_err("zero data_size");
goto bad;
}
if (lnum < used_ebs - 1) {
if (data_size != usable_leb_size) {
- dbg_err("bad data_size");
+ ubi_err("bad data_size");
goto bad;
}
} else if (lnum == used_ebs - 1) {
if (data_size == 0) {
- dbg_err("bad data_size at last LEB");
+ ubi_err("bad data_size at last LEB");
goto bad;
}
} else {
- dbg_err("too high lnum");
+ ubi_err("too high lnum");
goto bad;
}
} else {
if (copy_flag == 0) {
if (data_crc != 0) {
- dbg_err("non-zero data CRC");
+ ubi_err("non-zero data CRC");
goto bad;
}
if (data_size != 0) {
- dbg_err("non-zero data_size");
+ ubi_err("non-zero data_size");
goto bad;
}
} else {
if (data_size == 0) {
- dbg_err("zero data_size of copy");
+ ubi_err("zero data_size of copy");
goto bad;
}
}
if (used_ebs != 0) {
- dbg_err("bad used_ebs");
+ ubi_err("bad used_ebs");
goto bad;
}
}
@@ -997,8 +988,8 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
bad:
ubi_err("bad VID header");
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
return 1;
}
@@ -1054,7 +1045,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
@@ -1068,7 +1059,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
}
dbg_bld("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
@@ -1112,7 +1103,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
dbg_io("write VID header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ err = self_check_peb_ec_hdr(ubi, pnum);
if (err)
return err;
@@ -1121,7 +1112,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
vid_hdr->hdr_crc = cpu_to_be32(crc);
- err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+ err = self_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
return err;
@@ -1131,17 +1122,15 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+ * self_check_not_bad - ensure that a physical eraseblock is not bad.
* @ubi: UBI device description object
* @pnum: physical eraseblock number to check
*
* This function returns zero if the physical eraseblock is good, %-EINVAL if
* it is bad and a negative error code if an error occurred.
*/
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum)
{
int err;
@@ -1152,13 +1141,13 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
if (!err)
return err;
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ dump_stack();
return err > 0 ? -EINVAL : err;
}
/**
- * paranoid_check_ec_hdr - check if an erase counter header is all right.
+ * self_check_ec_hdr - check if an erase counter header is all right.
* @ubi: UBI device description object
* @pnum: physical eraseblock number the erase counter header belongs to
* @ec_hdr: the erase counter header to check
@@ -1166,8 +1155,8 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
* This function returns zero if the erase counter header contains valid
* values, and %-EINVAL if not.
*/
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_ec_hdr *ec_hdr)
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr)
{
int err;
uint32_t magic;
@@ -1184,27 +1173,27 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
err = validate_ec_hdr(ubi, ec_hdr);
if (err) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
goto fail;
}
return 0;
fail:
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_peb_ec_hdr - check erase counter header.
+ * self_check_peb_ec_hdr - check erase counter header.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
*
* This function returns zero if the erase counter header is all right and and
* a negative error code if not or if an error occurred.
*/
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
{
int err;
uint32_t crc, hdr_crc;
@@ -1225,14 +1214,14 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
err = -EINVAL;
goto exit;
}
- err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+ err = self_check_ec_hdr(ubi, pnum, ec_hdr);
exit:
kfree(ec_hdr);
@@ -1240,7 +1229,7 @@ exit:
}
/**
- * paranoid_check_vid_hdr - check that a volume identifier header is all right.
+ * self_check_vid_hdr - check that a volume identifier header is all right.
* @ubi: UBI device description object
* @pnum: physical eraseblock number the volume identifier header belongs to
* @vid_hdr: the volume identifier header to check
@@ -1248,8 +1237,8 @@ exit:
* This function returns zero if the volume identifier header is all right, and
* %-EINVAL if not.
*/
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_vid_hdr *vid_hdr)
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr)
{
int err;
uint32_t magic;
@@ -1266,29 +1255,29 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
err = validate_vid_hdr(ubi, vid_hdr);
if (err) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
goto fail;
}
return err;
fail:
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_peb_vid_hdr - check volume identifier header.
+ * self_check_peb_vid_hdr - check volume identifier header.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
*
* This function returns zero if the volume identifier header is all right,
* and a negative error code if not or if an error occurred.
*/
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
{
int err;
uint32_t crc, hdr_crc;
@@ -1313,14 +1302,14 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
err = -EINVAL;
goto exit;
}
- err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+ err = self_check_vid_hdr(ubi, pnum, vid_hdr);
exit:
ubi_free_vid_hdr(ubi, vid_hdr);
@@ -1328,7 +1317,7 @@ exit:
}
/**
- * ubi_dbg_check_write - make sure write succeeded.
+ * self_check_write - make sure write succeeded.
* @ubi: UBI device description object
* @buf: buffer with data which were written
* @pnum: physical eraseblock number the data were written to
@@ -1339,8 +1328,8 @@ exit:
* the original data buffer - the data have to match. Returns zero if the data
* match and a negative error code if not or in case of failure.
*/
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len)
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len)
{
int err, i;
size_t read;
@@ -1368,7 +1357,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
if (c == c1)
continue;
- ubi_err("paranoid check failed for PEB %d:%d, len %d",
+ ubi_err("self-check failed for PEB %d:%d, len %d",
pnum, offset, len);
ubi_msg("data differ at position %d", i);
dump_len = max_t(int, 128, len - i);
@@ -1380,7 +1369,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
buf1 + i, dump_len, 1);
- ubi_dbg_dump_stack();
+ dump_stack();
err = -EINVAL;
goto out_free;
}
@@ -1394,7 +1383,7 @@ out_free:
}
/**
- * ubi_dbg_check_all_ff - check that a region of flash is empty.
+ * ubi_self_check_all_ff - check that a region of flash is empty.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
* @offset: the starting offset within the physical eraseblock to check
@@ -1404,7 +1393,7 @@ out_free:
* @offset of the physical eraseblock @pnum, and a negative error code if not
* or if an error occurred.
*/
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
size_t read;
int err;
@@ -1438,14 +1427,12 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
return 0;
fail:
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
ubi_msg("hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL;
error:
- ubi_dbg_dump_stack();
+ dump_stack();
vfree(buf);
return err;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 9fdb353..3aac1ac 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -221,7 +221,7 @@ out_free:
kfree(desc);
out_put_ubi:
ubi_put_device(ubi);
- dbg_err("cannot open device %d, volume %d, error %d",
+ ubi_err("cannot open device %d, volume %d, error %d",
ubi_num, vol_id, err);
return ERR_PTR(err);
}
@@ -426,11 +426,9 @@ EXPORT_SYMBOL_GPL(ubi_leb_read);
* @buf: data to write
* @offset: offset within the logical eraseblock where to write
* @len: how many bytes to write
- * @dtype: expected data type
*
* This function writes @len bytes of data from @buf to offset @offset of
- * logical eraseblock @lnum. The @dtype argument describes expected lifetime of
- * the data.
+ * logical eraseblock @lnum.
*
* This function takes care of physical eraseblock write failures. If write to
* the physical eraseblock write operation fails, the logical eraseblock is
@@ -447,7 +445,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_read);
* returns immediately with %-EBADF code.
*/
int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int offset, int len, int dtype)
+ int offset, int len)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -466,17 +464,13 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (len == 0)
return 0;
- return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len);
}
EXPORT_SYMBOL_GPL(ubi_leb_write);
@@ -486,7 +480,6 @@ EXPORT_SYMBOL_GPL(ubi_leb_write);
* @lnum: logical eraseblock number to change
* @buf: data to write
* @len: how many bytes to write
- * @dtype: expected data type
*
* This function changes the contents of a logical eraseblock atomically. @buf
* has to contain new logical eraseblock data, and @len - the length of the
@@ -497,7 +490,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_write);
* code in case of failure.
*/
int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int len, int dtype)
+ int len)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -515,17 +508,13 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (len == 0)
return 0;
- return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
+ return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len);
}
EXPORT_SYMBOL_GPL(ubi_leb_change);
@@ -562,7 +551,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
if (err)
return err;
- return ubi_wl_flush(ubi);
+ return ubi_wl_flush(ubi, vol->vol_id, lnum);
}
EXPORT_SYMBOL_GPL(ubi_leb_erase);
@@ -626,7 +615,6 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap);
* ubi_leb_map - map logical eraseblock to a physical eraseblock.
* @desc: volume descriptor
* @lnum: logical eraseblock number
- * @dtype: expected data type
*
* This function maps an un-mapped logical eraseblock @lnum to a physical
* eraseblock. This means, that after a successful invocation of this
@@ -639,7 +627,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap);
* eraseblock is already mapped, and other negative error codes in case of
* other failures.
*/
-int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -652,17 +640,13 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
if (lnum < 0 || lnum >= vol->reserved_pebs)
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (vol->eba_tbl[lnum] >= 0)
return -EBADMSG;
- return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
}
EXPORT_SYMBOL_GPL(ubi_leb_map);
@@ -720,6 +704,33 @@ int ubi_sync(int ubi_num)
}
EXPORT_SYMBOL_GPL(ubi_sync);
+/**
+ * ubi_flush - flush UBI work queue.
+ * @ubi_num: UBI device to flush work queue
+ * @vol_id: volume id to flush for
+ * @lnum: logical eraseblock number to flush for
+ *
+ * This function executes all pending works for a particular volume id / logical
+ * eraseblock number pair. If either value is set to %UBI_ALL, then it acts as
+ * a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_flush(int ubi_num, int vol_id, int lnum)
+{
+ struct ubi_device *ubi;
+ int err = 0;
+
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ err = ubi_wl_flush(ubi, vol_id, lnum);
+ ubi_put_device(ubi);
+ return err;
+}
+EXPORT_SYMBOL_GPL(ubi_flush);
+
BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
/**
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
deleted file mode 100644
index d48aef1..0000000
--- a/drivers/mtd/ubi/scan.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- *
- * 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
- *
- * Author: Artem Bityutskiy (Битюцкий Артём)
- */
-
-#ifndef __UBI_SCAN_H__
-#define __UBI_SCAN_H__
-
-/* The erase counter value for this physical eraseblock is unknown */
-#define UBI_SCAN_UNKNOWN_EC (-1)
-
-/**
- * struct ubi_scan_leb - scanning information about a physical eraseblock.
- * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown)
- * @pnum: physical eraseblock number
- * @lnum: logical eraseblock number
- * @scrub: if this physical eraseblock needs scrubbing
- * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
- * @sqnum: sequence number
- * @u: unions RB-tree or @list links
- * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
- * @u.list: link in one of the eraseblock lists
- *
- * One object of this type is allocated for each physical eraseblock during
- * scanning.
- */
-struct ubi_scan_leb {
- int ec;
- int pnum;
- int lnum;
- unsigned int scrub:1;
- unsigned int copy_flag:1;
- unsigned long long sqnum;
- union {
- struct rb_node rb;
- struct list_head list;
- } u;
-};
-
-/**
- * struct ubi_scan_volume - scanning information about a volume.
- * @vol_id: volume ID
- * @highest_lnum: highest logical eraseblock number in this volume
- * @leb_count: number of logical eraseblocks in this volume
- * @vol_type: volume type
- * @used_ebs: number of used logical eraseblocks in this volume (only for
- * static volumes)
- * @last_data_size: amount of data in the last logical eraseblock of this
- * volume (always equivalent to the usable logical eraseblock
- * size in case of dynamic volumes)
- * @data_pad: how many bytes at the end of logical eraseblocks of this volume
- * are not used (due to volume alignment)
- * @compat: compatibility flags of this volume
- * @rb: link in the volume RB-tree
- * @root: root of the RB-tree containing all the eraseblock belonging to this
- * volume (&struct ubi_scan_leb objects)
- *
- * One object of this type is allocated for each volume during scanning.
- */
-struct ubi_scan_volume {
- int vol_id;
- int highest_lnum;
- int leb_count;
- int vol_type;
- int used_ebs;
- int last_data_size;
- int data_pad;
- int compat;
- struct rb_node rb;
- struct rb_root root;
-};
-
-/**
- * struct ubi_scan_info - UBI scanning information.
- * @volumes: root of the volume RB-tree
- * @corr: list of corrupted physical eraseblocks
- * @free: list of free physical eraseblocks
- * @erase: list of physical eraseblocks which have to be erased
- * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
- * those belonging to "preserve"-compatible internal volumes)
- * @corr_peb_count: count of PEBs in the @corr list
- * @empty_peb_count: count of PEBs which are presumably empty (contain only
- * 0xFF bytes)
- * @alien_peb_count: count of PEBs in the @alien list
- * @bad_peb_count: count of bad physical eraseblocks
- * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
- * as bad yet, but which look like bad
- * @vols_found: number of volumes found during scanning
- * @highest_vol_id: highest volume ID
- * @is_empty: flag indicating whether the MTD device is empty or not
- * @min_ec: lowest erase counter value
- * @max_ec: highest erase counter value
- * @max_sqnum: highest sequence number value
- * @mean_ec: mean erase counter value
- * @ec_sum: a temporary variable used when calculating @mean_ec
- * @ec_count: a temporary variable used when calculating @mean_ec
- * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
- *
- * This data structure contains the result of scanning and may be used by other
- * UBI sub-systems to build final UBI data structures, further error-recovery
- * and so on.
- */
-struct ubi_scan_info {
- struct rb_root volumes;
- struct list_head corr;
- struct list_head free;
- struct list_head erase;
- struct list_head alien;
- int corr_peb_count;
- int empty_peb_count;
- int alien_peb_count;
- int bad_peb_count;
- int maybe_bad_peb_count;
- int vols_found;
- int highest_vol_id;
- int is_empty;
- int min_ec;
- int max_ec;
- unsigned long long max_sqnum;
- int mean_ec;
- uint64_t ec_sum;
- int ec_count;
- struct kmem_cache *scan_leb_slab;
-};
-
-struct ubi_device;
-struct ubi_vid_hdr;
-
-/*
- * ubi_scan_move_to_list - move a PEB from the volume tree to a list.
- *
- * @sv: volume scanning information
- * @seb: scanning eraseblock information
- * @list: the list to move to
- */
-static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
- struct ubi_scan_leb *seb,
- struct list_head *list)
-{
- rb_erase(&seb->u.rb, &sv->root);
- list_add_tail(&seb->u.list, list);
-}
-
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
- int bitflips);
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
- int vol_id);
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
- int lnum);
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
- struct ubi_scan_info *si);
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
- int pnum, int ec);
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
-void ubi_scan_destroy_si(struct ubi_scan_info *si);
-
-#endif /* !__UBI_SCAN_H__ */
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 6fb8ec2..468ffbc 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -149,10 +149,10 @@ enum {
* The @image_seq field is used to validate a UBI image that has been prepared
* for a UBI device. The @image_seq value can be any value, but it must be the
* same on all eraseblocks. UBI will ensure that all new erase counter headers
- * also contain this value, and will check the value when scanning at start-up.
+ * also contain this value, and will check the value when attaching the flash.
* One way to make use of @image_seq is to increase its value by one every time
* an image is flashed over an existing image, then, if the flashing does not
- * complete, UBI will detect the error when scanning.
+ * complete, UBI will detect the error when attaching the media.
*/
struct ubi_ec_hdr {
__be32 magic;
@@ -298,8 +298,8 @@ struct ubi_vid_hdr {
#define UBI_INT_VOL_COUNT 1
/*
- * Starting ID of internal volumes. There is reserved room for 4096 internal
- * volumes.
+ * Starting ID of internal volumes: 0x7fffefff.
+ * There is reserved room for 4096 internal volumes.
*/
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index b162790..a1a81c9 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include "ubi-media.h"
-#include "scan.h"
/* Maximum number of supported UBI devices */
#define UBI_MAX_DEVICES 32
@@ -66,7 +65,10 @@
/* Background thread name pattern */
#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
-/* This marker in the EBA table means that the LEB is um-mapped */
+/*
+ * This marker in the EBA table means that the LEB is um-mapped.
+ * NOTE! It has to have the same value as %UBI_ALL.
+ */
#define UBI_LEB_UNMAPPED -1
/*
@@ -82,6 +84,9 @@
*/
#define UBI_PROT_QUEUE_LEN 10
+/* The volume ID/LEB number/erase counter is unknown */
+#define UBI_UNKNOWN -1
+
/*
* Error codes returned by the I/O sub-system.
*
@@ -222,8 +227,6 @@ struct ubi_volume_desc;
* @upd_ebs: how many eraseblocks are expected to be updated
* @ch_lnum: LEB number which is being changing by the atomic LEB change
* operation
- * @ch_dtype: data persistency type which is being changing by the atomic LEB
- * change operation
* @upd_bytes: how many bytes are expected to be received for volume update or
* atomic LEB change
* @upd_received: how many bytes were already received for volume update or
@@ -270,7 +273,6 @@ struct ubi_volume {
int upd_ebs;
int ch_lnum;
- int ch_dtype;
long long upd_bytes;
long long upd_received;
void *upd_buf;
@@ -477,6 +479,124 @@ struct ubi_device {
struct ubi_debug_info *dbg;
};
+/**
+ * struct ubi_ainf_peb - attach information about a physical eraseblock.
+ * @ec: erase counter (%UBI_UNKNOWN if it is unknown)
+ * @pnum: physical eraseblock number
+ * @vol_id: ID of the volume this LEB belongs to
+ * @lnum: logical eraseblock number
+ * @scrub: if this physical eraseblock needs scrubbing
+ * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
+ * @sqnum: sequence number
+ * @u: unions RB-tree or @list links
+ * @u.rb: link in the per-volume RB-tree of &struct ubi_ainf_peb objects
+ * @u.list: link in one of the eraseblock lists
+ *
+ * One object of this type is allocated for each physical eraseblock when
+ * attaching an MTD device. Note, if this PEB does not belong to any LEB /
+ * volume, the @vol_id and @lnum fields are initialized to %UBI_UNKNOWN.
+ */
+struct ubi_ainf_peb {
+ int ec;
+ int pnum;
+ int vol_id;
+ int lnum;
+ unsigned int scrub:1;
+ unsigned int copy_flag:1;
+ unsigned long long sqnum;
+ union {
+ struct rb_node rb;
+ struct list_head list;
+ } u;
+};
+
+/**
+ * struct ubi_ainf_volume - attaching information about a volume.
+ * @vol_id: volume ID
+ * @highest_lnum: highest logical eraseblock number in this volume
+ * @leb_count: number of logical eraseblocks in this volume
+ * @vol_type: volume type
+ * @used_ebs: number of used logical eraseblocks in this volume (only for
+ * static volumes)
+ * @last_data_size: amount of data in the last logical eraseblock of this
+ * volume (always equivalent to the usable logical eraseblock
+ * size in case of dynamic volumes)
+ * @data_pad: how many bytes at the end of logical eraseblocks of this volume
+ * are not used (due to volume alignment)
+ * @compat: compatibility flags of this volume
+ * @rb: link in the volume RB-tree
+ * @root: root of the RB-tree containing all the eraseblock belonging to this
+ * volume (&struct ubi_ainf_peb objects)
+ *
+ * One object of this type is allocated for each volume when attaching an MTD
+ * device.
+ */
+struct ubi_ainf_volume {
+ int vol_id;
+ int highest_lnum;
+ int leb_count;
+ int vol_type;
+ int used_ebs;
+ int last_data_size;
+ int data_pad;
+ int compat;
+ struct rb_node rb;
+ struct rb_root root;
+};
+
+/**
+ * struct ubi_attach_info - MTD device attaching information.
+ * @volumes: root of the volume RB-tree
+ * @corr: list of corrupted physical eraseblocks
+ * @free: list of free physical eraseblocks
+ * @erase: list of physical eraseblocks which have to be erased
+ * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
+ * those belonging to "preserve"-compatible internal volumes)
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @empty_peb_count: count of PEBs which are presumably empty (contain only
+ * 0xFF bytes)
+ * @alien_peb_count: count of PEBs in the @alien list
+ * @bad_peb_count: count of bad physical eraseblocks
+ * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
+ * as bad yet, but which look like bad
+ * @vols_found: number of volumes found
+ * @highest_vol_id: highest volume ID
+ * @is_empty: flag indicating whether the MTD device is empty or not
+ * @min_ec: lowest erase counter value
+ * @max_ec: highest erase counter value
+ * @max_sqnum: highest sequence number value
+ * @mean_ec: mean erase counter value
+ * @ec_sum: a temporary variable used when calculating @mean_ec
+ * @ec_count: a temporary variable used when calculating @mean_ec
+ * @aeb_slab_cache: slab cache for &struct ubi_ainf_peb objects
+ *
+ * This data structure contains the result of attaching an MTD device and may
+ * be used by other UBI sub-systems to build final UBI data structures, further
+ * error-recovery and so on.
+ */
+struct ubi_attach_info {
+ struct rb_root volumes;
+ struct list_head corr;
+ struct list_head free;
+ struct list_head erase;
+ struct list_head alien;
+ int corr_peb_count;
+ int empty_peb_count;
+ int alien_peb_count;
+ int bad_peb_count;
+ int maybe_bad_peb_count;
+ int vols_found;
+ int highest_vol_id;
+ int is_empty;
+ int min_ec;
+ int max_ec;
+ unsigned long long max_sqnum;
+ int mean_ec;
+ uint64_t ec_sum;
+ int ec_count;
+ struct kmem_cache *aeb_slab_cache;
+};
+
#include "debug.h"
extern struct kmem_cache *ubi_wl_entry_slab;
@@ -487,12 +607,23 @@ extern struct class *ubi_class;
extern struct mutex ubi_devices_mutex;
extern struct blocking_notifier_head ubi_notifiers;
+/* scan.c */
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+ int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+ int vol_id);
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+ struct ubi_attach_info *ai);
+int ubi_attach(struct ubi_device *ubi);
+void ubi_destroy_ai(struct ubi_attach_info *ai);
+
/* vtbl.c */
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec);
int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list);
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* vmt.c */
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
@@ -525,22 +656,22 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
void *buf, int offset, int len, int check);
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
- const void *buf, int offset, int len, int dtype);
+ const void *buf, int offset, int len);
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype,
- int used_ebs);
+ int lnum, const void *buf, int len, int used_ebs);
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype);
+ int lnum, const void *buf, int len);
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
struct ubi_vid_hdr *vid_hdr);
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* wl.c */
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture);
-int ubi_wl_flush(struct ubi_device *ubi);
+int ubi_wl_get_peb(struct ubi_device *ubi);
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+ int pnum, int torture);
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum);
int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
void ubi_wl_close(struct ubi_device *ubi);
int ubi_thread(void *u);
@@ -573,6 +704,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_notify_all(struct ubi_device *ubi, int ntype,
struct notifier_block *nb);
int ubi_enumerate_volumes(struct notifier_block *nb);
+void ubi_free_internal_volumes(struct ubi_device *ubi);
/* kapi.c */
void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
@@ -593,6 +725,21 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
rb = rb_next(rb), \
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
+/*
+ * ubi_move_aeb_to_list - move a PEB from the volume tree to a list.
+ *
+ * @av: volume attaching information
+ * @aeb: attaching eraseblock information
+ * @list: the list to move to
+ */
+static inline void ubi_move_aeb_to_list(struct ubi_ainf_volume *av,
+ struct ubi_ainf_peb *aeb,
+ struct list_head *list)
+{
+ rb_erase(&aeb->u.rb, &av->root);
+ list_add_tail(&aeb->u.list, list);
+}
+
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object
@@ -667,7 +814,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi)
if (!ubi->ro_mode) {
ubi->ro_mode = 1;
ubi_warn("switch to read-only mode");
- ubi_dbg_dump_stack();
+ dump_stack();
}
}
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 425bf5a..9f2ebd8 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -147,7 +147,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
}
if (bytes == 0) {
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
if (err)
return err;
@@ -186,14 +186,12 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
dbg_gen("start changing LEB %d:%d, %u bytes",
vol->vol_id, req->lnum, req->bytes);
if (req->bytes == 0)
- return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
- req->dtype);
+ return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0);
vol->upd_bytes = req->bytes;
vol->upd_received = 0;
vol->changing_leb = 1;
vol->ch_lnum = req->lnum;
- vol->ch_dtype = req->dtype;
vol->upd_buf = vmalloc(req->bytes);
if (!vol->upd_buf)
@@ -246,8 +244,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
return 0;
}
- err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len,
- UBI_UNKNOWN);
+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len);
} else {
/*
* When writing static volume, and this is the last logical
@@ -259,8 +256,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
* contain zeros, not random trash.
*/
memset(buf + len, 0, vol->usable_leb_size - len);
- err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
- UBI_UNKNOWN, used_ebs);
+ err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, used_ebs);
}
return err;
@@ -365,7 +361,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
ubi_assert(vol->upd_received <= vol->upd_bytes);
if (vol->upd_received == vol->upd_bytes) {
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
if (err)
return err;
/* The update is finished, clear the update marker */
@@ -421,7 +417,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
len - vol->upd_bytes);
len = ubi_calc_data_len(ubi, vol->upd_buf, len);
err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
- vol->upd_buf, len, UBI_UNKNOWN);
+ vol->upd_buf, len);
if (err)
return err;
}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 863835f..0669cff 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -29,11 +29,7 @@
#include <linux/export.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_volumes(struct ubi_device *ubi);
-#else
-#define paranoid_check_volumes(ubi) 0
-#endif
+static int self_check_volumes(struct ubi_device *ubi);
static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -227,7 +223,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
}
if (vol_id == UBI_VOL_NUM_AUTO) {
- dbg_err("out of volume IDs");
+ ubi_err("out of volume IDs");
err = -ENFILE;
goto out_unlock;
}
@@ -241,7 +237,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Ensure that this volume does not exist */
err = -EEXIST;
if (ubi->volumes[vol_id]) {
- dbg_err("volume %d already exists", vol_id);
+ ubi_err("volume %d already exists", vol_id);
goto out_unlock;
}
@@ -250,7 +246,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
!strcmp(ubi->volumes[i]->name, req->name)) {
- dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
+ ubi_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
@@ -261,9 +257,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
- dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
+ ubi_err("not enough PEBs, only %d available", ubi->avail_pebs);
if (ubi->corr_peb_count)
- dbg_err("%d PEBs are corrupted and not used",
+ ubi_err("%d PEBs are corrupted and not used",
ubi->corr_peb_count);
err = -ENOSPC;
goto out_unlock;
@@ -284,7 +280,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
* Finish all pending erases because there may be some LEBs belonging
* to the same volume ID.
*/
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
if (err)
goto out_acc;
@@ -360,8 +356,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
spin_unlock(&ubi->volumes_lock);
ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while creating volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_sysfs:
@@ -461,8 +456,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
spin_unlock(&ubi->volumes_lock);
ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
- if (!no_vtbl && paranoid_check_volumes(ubi))
- dbg_err("check failed while removing volume %d", vol_id);
+ if (!no_vtbl)
+ self_check_volumes(ubi);
return err;
@@ -500,7 +495,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (vol->vol_type == UBI_STATIC_VOLUME &&
reserved_pebs < vol->used_ebs) {
- dbg_err("too small size %d, %d LEBs contain data",
+ ubi_err("too small size %d, %d LEBs contain data",
reserved_pebs, vol->used_ebs);
return -EINVAL;
}
@@ -529,10 +524,10 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (pebs > 0) {
spin_lock(&ubi->volumes_lock);
if (pebs > ubi->avail_pebs) {
- dbg_err("not enough PEBs: requested %d, available %d",
+ ubi_err("not enough PEBs: requested %d, available %d",
pebs, ubi->avail_pebs);
if (ubi->corr_peb_count)
- dbg_err("%d PEBs are corrupted and not used",
+ ubi_err("%d PEBs are corrupted and not used",
ubi->corr_peb_count);
spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
@@ -588,8 +583,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
}
ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while re-sizing volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_acc:
@@ -638,8 +632,8 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
}
}
- if (!err && paranoid_check_volumes(ubi))
- ;
+ if (!err)
+ self_check_volumes(ubi);
return err;
}
@@ -686,8 +680,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
return err;
}
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while adding volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_cdev:
@@ -712,16 +705,14 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
volume_sysfs_close(vol);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_volume - check volume information.
+ * self_check_volume - check volume information.
* @ubi: UBI device description object
* @vol_id: volume ID
*
* Returns zero if volume is all right and a a negative error code if not.
*/
-static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
+static int self_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
@@ -771,7 +762,7 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
}
if (vol->upd_marker && vol->corrupted) {
- dbg_err("update marker and corrupted simultaneously");
+ ubi_err("update marker and corrupted simultaneously");
goto fail;
}
@@ -853,22 +844,22 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
return 0;
fail:
- ubi_err("paranoid check failed for volume %d", vol_id);
+ ubi_err("self-check failed for volume %d", vol_id);
if (vol)
- ubi_dbg_dump_vol_info(vol);
- ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ ubi_dump_vol_info(vol);
+ ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
dump_stack();
spin_unlock(&ubi->volumes_lock);
return -EINVAL;
}
/**
- * paranoid_check_volumes - check information about all volumes.
+ * self_check_volumes - check information about all volumes.
* @ubi: UBI device description object
*
* Returns zero if volumes are all right and a a negative error code if not.
*/
-static int paranoid_check_volumes(struct ubi_device *ubi)
+static int self_check_volumes(struct ubi_device *ubi)
{
int i, err = 0;
@@ -876,11 +867,10 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
return 0;
for (i = 0; i < ubi->vtbl_slots; i++) {
- err = paranoid_check_volume(ubi, i);
+ err = self_check_volume(ubi, i);
if (err)
break;
}
return err;
}
-#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 17cec0c..437bc19 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -37,16 +37,15 @@
* LEB 1. This scheme guarantees recoverability from unclean reboots.
*
* In this UBI implementation the on-flash volume table does not contain any
- * information about how many data static volumes contain. This information may
- * be found from the scanning data.
+ * information about how much data static volumes contain.
*
* But it would still be beneficial to store this information in the volume
* table. For example, suppose we have a static volume X, and all its physical
* eraseblocks became bad for some reasons. Suppose we are attaching the
- * corresponding MTD device, the scanning has found no logical eraseblocks
+ * corresponding MTD device, for some reason we find no logical eraseblocks
* corresponding to the volume X. According to the volume table volume X does
* exist. So we don't know whether it is just empty or all its physical
- * eraseblocks went bad. So we cannot alarm the user about this corruption.
+ * eraseblocks went bad. So we cannot alarm the user properly.
*
* The volume table also stores so-called "update marker", which is used for
* volume updates. Before updating the volume, the update marker is set, and
@@ -62,11 +61,7 @@
#include <asm/div64.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static void paranoid_vtbl_check(const struct ubi_device *ubi);
-#else
-#define paranoid_vtbl_check(ubi)
-#endif
+static void self_vtbl_check(const struct ubi_device *ubi);
/* Empty volume table record */
static struct ubi_vtbl_record empty_vtbl_record;
@@ -106,12 +101,12 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
- ubi->vtbl_size, UBI_LONGTERM);
+ ubi->vtbl_size);
if (err)
return err;
}
- paranoid_vtbl_check(ubi);
+ self_vtbl_check(ubi);
return 0;
}
@@ -158,7 +153,7 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
- ubi->vtbl_size, UBI_LONGTERM);
+ ubi->vtbl_size);
if (err)
return err;
}
@@ -197,7 +192,7 @@ static int vtbl_check(const struct ubi_device *ubi,
if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
i, crc, be32_to_cpu(vtbl[i].crc));
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[i], i);
return 1;
}
@@ -229,7 +224,7 @@ static int vtbl_check(const struct ubi_device *ubi,
n = ubi->leb_size % alignment;
if (data_pad != n) {
- dbg_err("bad data_pad, has to be %d", n);
+ ubi_err("bad data_pad, has to be %d", n);
err = 6;
goto bad;
}
@@ -245,7 +240,7 @@ static int vtbl_check(const struct ubi_device *ubi,
}
if (reserved_pebs > ubi->good_peb_count) {
- dbg_err("too large reserved_pebs %d, good PEBs %d",
+ ubi_err("too large reserved_pebs %d, good PEBs %d",
reserved_pebs, ubi->good_peb_count);
err = 9;
goto bad;
@@ -277,8 +272,8 @@ static int vtbl_check(const struct ubi_device *ubi,
!strncmp(vtbl[i].name, vtbl[n].name, len1)) {
ubi_err("volumes %d and %d have the same name"
" \"%s\"", i, n, vtbl[i].name);
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
- ubi_dbg_dump_vtbl_record(&vtbl[n], n);
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[n], n);
return -EINVAL;
}
}
@@ -288,26 +283,26 @@ static int vtbl_check(const struct ubi_device *ubi,
bad:
ubi_err("volume table check failed: record %d, error %d", i, err);
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[i], i);
return -EINVAL;
}
/**
* create_vtbl - create a copy of volume table.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @copy: number of the volume table copy
* @vtbl: contents of the volume table
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_attach_info *ai,
int copy, void *vtbl)
{
int err, tries = 0;
struct ubi_vid_hdr *vid_hdr;
- struct ubi_scan_leb *new_seb;
+ struct ubi_ainf_peb *new_aeb;
ubi_msg("create volume table (copy #%d)", copy + 1);
@@ -316,9 +311,9 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
return -ENOMEM;
retry:
- new_seb = ubi_scan_get_free_peb(ubi, si);
- if (IS_ERR(new_seb)) {
- err = PTR_ERR(new_seb);
+ new_aeb = ubi_early_get_peb(ubi, ai);
+ if (IS_ERR(new_aeb)) {
+ err = PTR_ERR(new_aeb);
goto out_free;
}
@@ -328,25 +323,24 @@ retry:
vid_hdr->data_size = vid_hdr->used_ebs =
vid_hdr->data_pad = cpu_to_be32(0);
vid_hdr->lnum = cpu_to_be32(copy);
- vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->sqnum = cpu_to_be64(++ai->max_sqnum);
/* The EC header is already there, write the VID header */
- err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+ err = ubi_io_write_vid_hdr(ubi, new_aeb->pnum, vid_hdr);
if (err)
goto write_error;
/* Write the layout volume contents */
- err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
+ err = ubi_io_write_data(ubi, vtbl, new_aeb->pnum, 0, ubi->vtbl_size);
if (err)
goto write_error;
/*
- * And add it to the scanning information. Don't delete the old version
- * of this LEB as it will be deleted and freed in 'ubi_scan_add_used()'.
+ * And add it to the attaching information. Don't delete the old version
+ * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'.
*/
- err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
- vid_hdr, 0);
- kfree(new_seb);
+ err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0);
+ kfree(new_aeb);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -356,10 +350,10 @@ write_error:
* Probably this physical eraseblock went bad, try to pick
* another one.
*/
- list_add(&new_seb->u.list, &si->erase);
+ list_add(&new_aeb->u.list, &ai->erase);
goto retry;
}
- kfree(new_seb);
+ kfree(new_aeb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -369,20 +363,20 @@ out_free:
/**
* process_lvol - process the layout volume.
* @ubi: UBI device description object
- * @si: scanning information
- * @sv: layout volume scanning information
+ * @ai: attaching information
+ * @av: layout volume attaching information
*
* This function is responsible for reading the layout volume, ensuring it is
* not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure.
*/
static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
- struct ubi_scan_info *si,
- struct ubi_scan_volume *sv)
+ struct ubi_attach_info *ai,
+ struct ubi_ainf_volume *av)
{
int err;
struct rb_node *rb;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
@@ -414,14 +408,14 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
dbg_gen("check layout volume");
/* Read both LEB 0 and LEB 1 into memory */
- ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = vzalloc(ubi->vtbl_size);
- if (!leb[seb->lnum]) {
+ ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+ leb[aeb->lnum] = vzalloc(ubi->vtbl_size);
+ if (!leb[aeb->lnum]) {
err = -ENOMEM;
goto out_free;
}
- err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+ err = ubi_io_read_data(ubi, leb[aeb->lnum], aeb->pnum, 0,
ubi->vtbl_size);
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
/*
@@ -429,12 +423,12 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
* uncorrectable ECC error, but we have our own CRC and
* the data will be checked later. If the data is OK,
* the PEB will be scrubbed (because we set
- * seb->scrub). If the data is not OK, the contents of
+ * aeb->scrub). If the data is not OK, the contents of
* the PEB will be recovered from the second copy, and
- * seb->scrub will be cleared in
- * 'ubi_scan_add_used()'.
+ * aeb->scrub will be cleared in
+ * 'ubi_add_to_av()'.
*/
- seb->scrub = 1;
+ aeb->scrub = 1;
else if (err)
goto out_free;
}
@@ -453,7 +447,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
ubi->vtbl_size);
if (leb_corrupted[1]) {
ubi_warn("volume table copy #2 is corrupted");
- err = create_vtbl(ubi, si, 1, leb[0]);
+ err = create_vtbl(ubi, ai, 1, leb[0]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
@@ -476,7 +470,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
}
ubi_warn("volume table copy #1 is corrupted");
- err = create_vtbl(ubi, si, 0, leb[1]);
+ err = create_vtbl(ubi, ai, 0, leb[1]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
@@ -494,13 +488,13 @@ out_free:
/**
* create_empty_lvol - create empty layout volume.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns volume table contents in case of success and a
* negative error code in case of failure.
*/
static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+ struct ubi_attach_info *ai)
{
int i;
struct ubi_vtbl_record *vtbl;
@@ -515,7 +509,7 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
int err;
- err = create_vtbl(ubi, si, i, vtbl);
+ err = create_vtbl(ubi, ai, i, vtbl);
if (err) {
vfree(vtbl);
return ERR_PTR(err);
@@ -528,18 +522,19 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
/**
* init_volumes - initialize volume information for existing volumes.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: scanning information
* @vtbl: volume table
*
* This function allocates volume description objects for existing volumes.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
-static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+static int init_volumes(struct ubi_device *ubi,
+ const struct ubi_attach_info *ai,
const struct ubi_vtbl_record *vtbl)
{
int i, reserved_pebs = 0;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
for (i = 0; i < ubi->vtbl_slots; i++) {
@@ -595,8 +590,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
/* Static volumes only */
- sv = ubi_scan_find_sv(si, i);
- if (!sv) {
+ av = ubi_find_av(ai, i);
+ if (!av) {
/*
* No eraseblocks belonging to this volume found. We
* don't actually know whether this static volume is
@@ -608,22 +603,22 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
continue;
}
- if (sv->leb_count != sv->used_ebs) {
+ if (av->leb_count != av->used_ebs) {
/*
* We found a static volume which misses several
* eraseblocks. Treat it as corrupted.
*/
ubi_warn("static volume %d misses %d LEBs - corrupted",
- sv->vol_id, sv->used_ebs - sv->leb_count);
+ av->vol_id, av->used_ebs - av->leb_count);
vol->corrupted = 1;
continue;
}
- vol->used_ebs = sv->used_ebs;
+ vol->used_ebs = av->used_ebs;
vol->used_bytes =
(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
- vol->used_bytes += sv->last_data_size;
- vol->last_eb_bytes = sv->last_data_size;
+ vol->used_bytes += av->last_data_size;
+ vol->last_eb_bytes = av->last_data_size;
}
/* And add the layout volume */
@@ -664,105 +659,104 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
/**
- * check_sv - check volume scanning information.
+ * check_av - check volume attaching information.
* @vol: UBI volume description object
- * @sv: volume scanning information
+ * @av: volume attaching information
*
- * This function returns zero if the volume scanning information is consistent
+ * This function returns zero if the volume attaching information is consistent
* to the data read from the volume tabla, and %-EINVAL if not.
*/
-static int check_sv(const struct ubi_volume *vol,
- const struct ubi_scan_volume *sv)
+static int check_av(const struct ubi_volume *vol,
+ const struct ubi_ainf_volume *av)
{
int err;
- if (sv->highest_lnum >= vol->reserved_pebs) {
+ if (av->highest_lnum >= vol->reserved_pebs) {
err = 1;
goto bad;
}
- if (sv->leb_count > vol->reserved_pebs) {
+ if (av->leb_count > vol->reserved_pebs) {
err = 2;
goto bad;
}
- if (sv->vol_type != vol->vol_type) {
+ if (av->vol_type != vol->vol_type) {
err = 3;
goto bad;
}
- if (sv->used_ebs > vol->reserved_pebs) {
+ if (av->used_ebs > vol->reserved_pebs) {
err = 4;
goto bad;
}
- if (sv->data_pad != vol->data_pad) {
+ if (av->data_pad != vol->data_pad) {
err = 5;
goto bad;
}
return 0;
bad:
- ubi_err("bad scanning information, error %d", err);
- ubi_dbg_dump_sv(sv);
- ubi_dbg_dump_vol_info(vol);
+ ubi_err("bad attaching information, error %d", err);
+ ubi_dump_av(av);
+ ubi_dump_vol_info(vol);
return -EINVAL;
}
/**
- * check_scanning_info - check that scanning information.
+ * check_attaching_info - check that attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* Even though we protect on-flash data by CRC checksums, we still don't trust
- * the media. This function ensures that scanning information is consistent to
- * the information read from the volume table. Returns zero if the scanning
+ * the media. This function ensures that attaching information is consistent to
+ * the information read from the volume table. Returns zero if the attaching
* information is OK and %-EINVAL if it is not.
*/
-static int check_scanning_info(const struct ubi_device *ubi,
- struct ubi_scan_info *si)
+static int check_attaching_info(const struct ubi_device *ubi,
+ struct ubi_attach_info *ai)
{
int err, i;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
- if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
- ubi_err("scanning found %d volumes, maximum is %d + %d",
- si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
+ if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
+ ubi_err("found %d volumes while attaching, maximum is %d + %d",
+ ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
return -EINVAL;
}
- if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
- si->highest_vol_id < UBI_INTERNAL_VOL_START) {
- ubi_err("too large volume ID %d found by scanning",
- si->highest_vol_id);
+ if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
+ ai->highest_vol_id < UBI_INTERNAL_VOL_START) {
+ ubi_err("too large volume ID %d found", ai->highest_vol_id);
return -EINVAL;
}
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
cond_resched();
- sv = ubi_scan_find_sv(si, i);
+ av = ubi_find_av(ai, i);
vol = ubi->volumes[i];
if (!vol) {
- if (sv)
- ubi_scan_rm_volume(si, sv);
+ if (av)
+ ubi_remove_av(ai, av);
continue;
}
if (vol->reserved_pebs == 0) {
ubi_assert(i < ubi->vtbl_slots);
- if (!sv)
+ if (!av)
continue;
/*
- * During scanning we found a volume which does not
+ * During attaching we found a volume which does not
* exist according to the information in the volume
* table. This must have happened due to an unclean
* reboot while the volume was being removed. Discard
* these eraseblocks.
*/
- ubi_msg("finish volume %d removal", sv->vol_id);
- ubi_scan_rm_volume(si, sv);
- } else if (sv) {
- err = check_sv(vol, sv);
+ ubi_msg("finish volume %d removal", av->vol_id);
+ ubi_remove_av(ai, av);
+ } else if (av) {
+ err = check_av(vol, av);
if (err)
return err;
}
@@ -774,16 +768,16 @@ static int check_scanning_info(const struct ubi_device *ubi,
/**
* ubi_read_volume_table - read the volume table.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function reads volume table, checks it, recover from errors if needed,
* or creates it if needed. Returns zero in case of success and a negative
* error code in case of failure.
*/
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int i, err;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
@@ -798,8 +792,8 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
- if (!sv) {
+ av = ubi_find_av(ai, UBI_LAYOUT_VOLUME_ID);
+ if (!av) {
/*
* No logical eraseblocks belonging to the layout volume were
* found. This could mean that the flash is just empty. In
@@ -808,8 +802,8 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
* But if flash is not empty this must be a corruption or the
* MTD device just contains garbage.
*/
- if (si->is_empty) {
- ubi->vtbl = create_empty_lvol(ubi, si);
+ if (ai->is_empty) {
+ ubi->vtbl = create_empty_lvol(ubi, ai);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
} else {
@@ -817,14 +811,14 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return -EINVAL;
}
} else {
- if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
+ if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) {
/* This must not happen with proper UBI images */
- dbg_err("too many LEBs (%d) in layout volume",
- sv->leb_count);
+ ubi_err("too many LEBs (%d) in layout volume",
+ av->leb_count);
return -EINVAL;
}
- ubi->vtbl = process_lvol(ubi, si, sv);
+ ubi->vtbl = process_lvol(ubi, ai, av);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
}
@@ -835,15 +829,15 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
* The layout volume is OK, initialize the corresponding in-RAM data
* structures.
*/
- err = init_volumes(ubi, si, ubi->vtbl);
+ err = init_volumes(ubi, ai, ubi->vtbl);
if (err)
goto out_free;
/*
- * Make sure that the scanning information is consistent to the
+ * Make sure that the attaching information is consistent to the
* information stored in the volume table.
*/
- err = check_scanning_info(ubi, si);
+ err = check_attaching_info(ubi, ai);
if (err)
goto out_free;
@@ -858,21 +852,17 @@ out_free:
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_vtbl_check - check volume table.
+ * self_vtbl_check - check volume table.
* @ubi: UBI device description object
*/
-static void paranoid_vtbl_check(const struct ubi_device *ubi)
+static void self_vtbl_check(const struct ubi_device *ubi)
{
if (!ubi->dbg->chk_gen)
return;
if (vtbl_check(ubi, ubi->vtbl)) {
- ubi_err("paranoid check failed");
+ ubi_err("self-check failed");
BUG();
}
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf..9df100a 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -41,12 +41,6 @@
* physical eraseblocks with low erase counter to free physical eraseblocks
* with high erase counter.
*
- * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
- * an "optimal" physical eraseblock. For example, when it is known that the
- * physical eraseblock will be "put" soon because it contains short-term data,
- * the WL sub-system may pick a free physical eraseblock with low erase
- * counter, and so forth.
- *
* If the WL sub-system fails to erase a physical eraseblock, it marks it as
* bad.
*
@@ -70,8 +64,7 @@
* to the user; instead, we first want to let users fill them up with data;
*
* o there is a chance that the user will put the physical eraseblock very
- * soon, so it makes sense not to move it for some time, but wait; this is
- * especially important in case of "short term" physical eraseblocks.
+ * soon, so it makes sense not to move it for some time, but wait.
*
* Physical eraseblocks stay protected only for limited time. But the "time" is
* measured in erase cycles in this case. This is implemented with help of the
@@ -147,6 +140,8 @@
* @list: a link in the list of pending works
* @func: worker function
* @e: physical eraseblock to erase
+ * @vol_id: the volume ID on which this erasure is being performed
+ * @lnum: the logical eraseblock number
* @torture: if the physical eraseblock has to be tortured
*
* The @func pointer points to the worker function. If the @cancel argument is
@@ -159,21 +154,16 @@ struct ubi_work {
int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
/* The below fields are only relevant to erasure works */
struct ubi_wl_entry *e;
+ int vol_id;
+ int lnum;
int torture;
};
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
- struct ubi_wl_entry *e,
- struct rb_root *root);
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
- struct ubi_wl_entry *e);
-#else
-#define paranoid_check_ec(ubi, pnum, ec) 0
-#define paranoid_check_in_wl_tree(ubi, e, root)
-#define paranoid_check_in_pq(ubi, e) 0
-#endif
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec);
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e, struct rb_root *root);
+static int self_check_in_pq(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e);
/**
* wl_tree_add - add a wear-leveling entry to a WL RB-tree.
@@ -383,19 +373,15 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
/**
* ubi_wl_get_peb - get a physical eraseblock.
* @ubi: UBI device description object
- * @dtype: type of data which will be stored in this physical eraseblock
*
* This function returns a physical eraseblock in case of success and a
* negative error code in case of failure. Might sleep.
*/
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+int ubi_wl_get_peb(struct ubi_device *ubi)
{
int err;
struct ubi_wl_entry *e, *first, *last;
- ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
- dtype == UBI_UNKNOWN);
-
retry:
spin_lock(&ubi->wl_lock);
if (!ubi->free.rb_node) {
@@ -413,45 +399,15 @@ retry:
goto retry;
}
- switch (dtype) {
- case UBI_LONGTERM:
- /*
- * For long term data we pick a physical eraseblock with high
- * erase counter. But the highest erase counter we can pick is
- * bounded by the the lowest erase counter plus
- * %WL_FREE_MAX_DIFF.
- */
- e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- break;
- case UBI_UNKNOWN:
- /*
- * For unknown data we pick a physical eraseblock with medium
- * erase counter. But we by no means can pick a physical
- * eraseblock with erase counter greater or equivalent than the
- * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
- */
- first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
- u.rb);
- last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
-
- if (last->ec - first->ec < WL_FREE_MAX_DIFF)
- e = rb_entry(ubi->free.rb_node,
- struct ubi_wl_entry, u.rb);
- else
- e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
- break;
- case UBI_SHORTTERM:
- /*
- * For short term data we pick a physical eraseblock with the
- * lowest erase counter as we expect it will be erased soon.
- */
- e = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
- break;
- default:
- BUG();
- }
+ first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
+ last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
+
+ if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+ e = rb_entry(ubi->free.rb_node, struct ubi_wl_entry, u.rb);
+ else
+ e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
- paranoid_check_in_wl_tree(ubi, e, &ubi->free);
+ self_check_in_wl_tree(ubi, e, &ubi->free);
/*
* Move the physical eraseblock to the protection queue where it will
@@ -462,8 +418,8 @@ retry:
prot_queue_add(ubi, e);
spin_unlock(&ubi->wl_lock);
- err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
- ubi->peb_size - ubi->vid_hdr_aloffset);
+ err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+ ubi->peb_size - ubi->vid_hdr_aloffset);
if (err) {
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
return err;
@@ -488,7 +444,7 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)
if (!e)
return -ENODEV;
- if (paranoid_check_in_pq(ubi, e))
+ if (self_check_in_pq(ubi, e))
return -ENODEV;
list_del(&e->u.list);
@@ -514,7 +470,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
- err = paranoid_check_ec(ubi, e->pnum, e->ec);
+ err = self_check_ec(ubi, e->pnum, e->ec);
if (err)
return -EINVAL;
@@ -627,13 +583,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
* schedule_erase - schedule an erase work.
* @ubi: UBI device description object
* @e: the WL entry of the physical eraseblock to erase
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
* @torture: if the physical eraseblock has to be tortured
*
* This function returns zero in case of success and a %-ENOMEM in case of
* failure.
*/
static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
- int torture)
+ int vol_id, int lnum, int torture)
{
struct ubi_work *wl_wrk;
@@ -646,6 +604,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
wl_wrk->func = &erase_worker;
wl_wrk->e = e;
+ wl_wrk->vol_id = vol_id;
+ wl_wrk->lnum = lnum;
wl_wrk->torture = torture;
schedule_ubi_work(ubi, wl_wrk);
@@ -714,7 +674,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
e1->ec, e2->ec);
goto out_cancel;
}
- paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
+ self_check_in_wl_tree(ubi, e1, &ubi->used);
rb_erase(&e1->u.rb, &ubi->used);
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
e1->pnum, e1->ec, e2->pnum, e2->ec);
@@ -723,12 +683,12 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
scrubbing = 1;
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- paranoid_check_in_wl_tree(ubi, e1, &ubi->scrub);
+ self_check_in_wl_tree(ubi, e1, &ubi->scrub);
rb_erase(&e1->u.rb, &ubi->scrub);
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
}
- paranoid_check_in_wl_tree(ubi, e2, &ubi->free);
+ self_check_in_wl_tree(ubi, e2, &ubi->free);
rb_erase(&e2->u.rb, &ubi->free);
ubi->move_from = e1;
ubi->move_to = e2;
@@ -846,7 +806,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi->move_to_put = ubi->wl_scheduled = 0;
spin_unlock(&ubi->wl_lock);
- err = schedule_erase(ubi, e1, 0);
+ err = schedule_erase(ubi, e1, vol_id, lnum, 0);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e1);
if (e2)
@@ -861,7 +821,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
*/
dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase",
e2->pnum, vol_id, lnum);
- err = schedule_erase(ubi, e2, 0);
+ err = schedule_erase(ubi, e2, vol_id, lnum, 0);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro;
@@ -900,7 +860,7 @@ out_not_moved:
spin_unlock(&ubi->wl_lock);
ubi_free_vid_hdr(ubi, vid_hdr);
- err = schedule_erase(ubi, e2, torture);
+ err = schedule_erase(ubi, e2, vol_id, lnum, torture);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro;
@@ -1019,6 +979,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
{
struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum, err, need;
+ int vol_id = wl_wrk->vol_id;
+ int lnum = wl_wrk->lnum;
if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1027,7 +989,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return 0;
}
- dbg_wl("erase PEB %d EC %d", pnum, e->ec);
+ dbg_wl("erase PEB %d EC %d LEB %d:%d",
+ pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
err = sync_erase(ubi, e, wl_wrk->torture);
if (!err) {
@@ -1057,7 +1020,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int err1;
/* Re-schedule the LEB for erasure */
- err1 = schedule_erase(ubi, e, 0);
+ err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
if (err1) {
err = err1;
goto out_ro;
@@ -1125,6 +1088,8 @@ out_ro:
/**
* ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
* @ubi: UBI device description object
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
* @pnum: physical eraseblock to return
* @torture: if this physical eraseblock has to be tortured
*
@@ -1133,7 +1098,8 @@ out_ro:
* occurred to this @pnum and it has to be tested. This function returns zero
* in case of success, and a negative error code in case of failure.
*/
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+ int pnum, int torture)
{
int err;
struct ubi_wl_entry *e;
@@ -1175,13 +1141,13 @@ retry:
return 0;
} else {
if (in_wl_tree(e, &ubi->used)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+ self_check_in_wl_tree(ubi, e, &ubi->used);
rb_erase(&e->u.rb, &ubi->used);
} else if (in_wl_tree(e, &ubi->scrub)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->scrub);
+ self_check_in_wl_tree(ubi, e, &ubi->scrub);
rb_erase(&e->u.rb, &ubi->scrub);
} else if (in_wl_tree(e, &ubi->erroneous)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->erroneous);
+ self_check_in_wl_tree(ubi, e, &ubi->erroneous);
rb_erase(&e->u.rb, &ubi->erroneous);
ubi->erroneous_peb_count -= 1;
ubi_assert(ubi->erroneous_peb_count >= 0);
@@ -1199,7 +1165,7 @@ retry:
}
spin_unlock(&ubi->wl_lock);
- err = schedule_erase(ubi, e, torture);
+ err = schedule_erase(ubi, e, vol_id, lnum, torture);
if (err) {
spin_lock(&ubi->wl_lock);
wl_tree_add(e, &ubi->used);
@@ -1248,7 +1214,7 @@ retry:
}
if (in_wl_tree(e, &ubi->used)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+ self_check_in_wl_tree(ubi, e, &ubi->used);
rb_erase(&e->u.rb, &ubi->used);
} else {
int err;
@@ -1275,44 +1241,55 @@ retry:
/**
* ubi_wl_flush - flush all pending works.
* @ubi: UBI device description object
+ * @vol_id: the volume id to flush for
+ * @lnum: the logical eraseblock number to flush for
*
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function executes all pending works for a particular volume id /
+ * logical eraseblock number pair. If either value is set to %UBI_ALL, then it
+ * acts as a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
*/
-int ubi_wl_flush(struct ubi_device *ubi)
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum)
{
- int err;
+ int err = 0;
+ int found = 1;
/*
* Erase while the pending works queue is not empty, but not more than
* the number of currently pending works.
*/
- dbg_wl("flush (%d pending works)", ubi->works_count);
- while (ubi->works_count) {
- err = do_work(ubi);
- if (err)
- return err;
- }
+ dbg_wl("flush pending work for LEB %d:%d (%d pending works)",
+ vol_id, lnum, ubi->works_count);
- /*
- * Make sure all the works which have been done in parallel are
- * finished.
- */
down_write(&ubi->work_sem);
- up_write(&ubi->work_sem);
+ while (found) {
+ struct ubi_work *wrk;
+ found = 0;
- /*
- * And in case last was the WL worker and it canceled the LEB
- * movement, flush again.
- */
- while (ubi->works_count) {
- dbg_wl("flush more (%d pending works)", ubi->works_count);
- err = do_work(ubi);
- if (err)
- return err;
+ spin_lock(&ubi->wl_lock);
+ list_for_each_entry(wrk, &ubi->works, list) {
+ if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) &&
+ (lnum == UBI_ALL || wrk->lnum == lnum)) {
+ list_del(&wrk->list);
+ ubi->works_count -= 1;
+ ubi_assert(ubi->works_count >= 0);
+ spin_unlock(&ubi->wl_lock);
+
+ err = wrk->func(ubi, wrk, 0);
+ if (err)
+ goto out;
+ spin_lock(&ubi->wl_lock);
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock(&ubi->wl_lock);
}
- return 0;
+out:
+ up_write(&ubi->work_sem);
+ return err;
}
/**
@@ -1421,26 +1398,26 @@ static void cancel_pending(struct ubi_device *ubi)
}
/**
- * ubi_wl_init_scan - initialize the WL sub-system using scanning information.
+ * ubi_wl_init - initialize the WL sub-system using attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns zero in case of success, and a negative error code in
* case of failure.
*/
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int err, i;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb, *tmp;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb, *tmp;
struct ubi_wl_entry *e;
ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT;
spin_lock_init(&ubi->wl_lock);
mutex_init(&ubi->move_mutex);
init_rwsem(&ubi->work_sem);
- ubi->max_ec = si->max_ec;
+ ubi->max_ec = ai->max_ec;
INIT_LIST_HEAD(&ubi->works);
sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
@@ -1454,48 +1431,48 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
INIT_LIST_HEAD(&ubi->pq[i]);
ubi->pq_head = 0;
- list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
+ list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi->lookuptbl[e->pnum] = e;
- if (schedule_erase(ubi, e, 0)) {
+ if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
kmem_cache_free(ubi_wl_entry_slab, e);
goto out_free;
}
}
- list_for_each_entry(seb, &si->free, u.list) {
+ list_for_each_entry(aeb, &ai->free, u.list) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi_assert(e->ec >= 0);
wl_tree_add(e, &ubi->free);
ubi->lookuptbl[e->pnum] = e;
}
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi->lookuptbl[e->pnum] = e;
- if (!seb->scrub) {
+ if (!aeb->scrub) {
dbg_wl("add PEB %d EC %d to the used tree",
e->pnum, e->ec);
wl_tree_add(e, &ubi->used);
@@ -1567,10 +1544,8 @@ void ubi_wl_close(struct ubi_device *ubi)
kfree(ubi->lookuptbl);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_ec - make sure that the erase counter of a PEB is correct.
+ * self_check_ec - make sure that the erase counter of a PEB is correct.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
* @ec: the erase counter to check
@@ -1579,7 +1554,7 @@ void ubi_wl_close(struct ubi_device *ubi)
* is equivalent to @ec, and a negative error code if not or if an error
* occurred.
*/
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
int err;
long long read_ec;
@@ -1601,9 +1576,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec);
- ubi_dbg_dump_stack();
+ dump_stack();
err = 1;
} else
err = 0;
@@ -1614,7 +1589,7 @@ out_free:
}
/**
- * paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
+ * self_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
* @ubi: UBI device description object
* @e: the wear-leveling entry to check
* @root: the root of the tree
@@ -1622,9 +1597,8 @@ out_free:
* This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
* is not.
*/
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
- struct ubi_wl_entry *e,
- struct rb_root *root)
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e, struct rb_root *root)
{
if (!ubi->dbg->chk_gen)
return 0;
@@ -1632,22 +1606,22 @@ static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
if (in_wl_tree(e, root))
return 0;
- ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
+ ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ",
e->pnum, e->ec, root);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_in_pq - check if wear-leveling entry is in the protection
+ * self_check_in_pq - check if wear-leveling entry is in the protection
* queue.
* @ubi: UBI device description object
* @e: the wear-leveling entry to check
*
* This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
*/
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
- struct ubi_wl_entry *e)
+static int self_check_in_pq(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e)
{
struct ubi_wl_entry *p;
int i;
@@ -1660,10 +1634,8 @@ static int paranoid_check_in_pq(const struct ubi_device *ubi,
if (p == e)
return 0;
- ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue",
+ ubi_err("self-check failed for PEB %d, EC %d, Protect queue",
e->pnum, e->ec);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 1efb083..38c0690 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#define DRV_NAME "flexcan"
@@ -927,11 +928,16 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
struct flexcan_priv *priv;
struct resource *mem;
struct clk *clk = NULL;
+ struct pinctrl *pinctrl;
void __iomem *base;
resource_size_t mem_size;
int err, irq;
u32 clock_freq = 0;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
if (pdev->dev.of_node) {
const u32 *clock_freq_p;
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index b60d6c5..03df9a8 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -75,7 +75,7 @@ config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
depends on PCI
---help---
- This driver is for the the PCIcanx and PCIcan cards (1, 2 or
+ This driver is for the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
config CAN_PLX_PCI
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index 1234a14..b153666 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -2549,8 +2549,7 @@ typhoon_init(void)
static void __exit
typhoon_cleanup(void)
{
- if (typhoon_fw)
- release_firmware(typhoon_fw);
+ release_firmware(typhoon_fw);
pci_unregister_driver(&typhoon_driver);
}
diff --git a/drivers/net/ethernet/amd/ariadne.c b/drivers/net/ethernet/amd/ariadne.c
index f4c228e..f2958df 100644
--- a/drivers/net/ethernet/amd/ariadne.c
+++ b/drivers/net/ethernet/amd/ariadne.c
@@ -213,10 +213,10 @@ static int ariadne_rx(struct net_device *dev)
(const void *)priv->rx_buff[entry],
pkt_len);
skb->protocol = eth_type_trans(skb, dev);
- netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n",
+ netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data %p len %u\n",
((u_short *)skb->data)[6],
skb->data + 6, skb->data,
- (int)skb->data, (int)skb->len);
+ skb->data, skb->len);
netif_rx(skb);
dev->stats.rx_packets++;
@@ -566,10 +566,10 @@ static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb,
/* Fill in a Tx ring entry */
- netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n",
+ netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data %p len %u\n",
((u_short *)skb->data)[6],
skb->data + 6, skb->data,
- (int)skb->data, (int)skb->len);
+ skb->data, skb->len);
local_irq_save(flags);
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index 70ed79c..84219df 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -558,21 +558,18 @@ static unsigned long __init lance_probe1( struct net_device *dev,
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
return 0;
}
- dev->irq = (unsigned short)IRQ_AUTO_5;
+ dev->irq = IRQ_AUTO_5;
}
else {
- /* For VME-RieblCards, request a free VME int;
- * (This must be unsigned long, since dev->irq is short and the
- * IRQ_MACHSPEC bit would be cut off...)
- */
- unsigned long irq = atari_register_vme_int();
+ /* For VME-RieblCards, request a free VME int */
+ unsigned int irq = atari_register_vme_int();
if (!irq) {
printk( "Lance: request for VME interrupt failed\n" );
return 0;
}
if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
"Riebl-VME Ethernet", dev)) {
- printk( "Lance: request for irq %ld failed\n", irq );
+ printk( "Lance: request for irq %u failed\n", irq );
return 0;
}
dev->irq = irq;
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 39b92f5..edeeb51 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -195,15 +195,6 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define TG3_RX_OFFSET(tp) (NET_SKB_PAD)
#endif
-/* This driver uses the new build_skb() API providing a frag as skb->head
- * This strategy permits better GRO aggregation, better TCP coalescing, and
- * better splice() implementation (avoids a copy from head to a page), at
- * minimal memory cost.
- * In this 2048 bytes block, we have enough room to store the MTU=1500 frame
- * and the struct skb_shared_info.
- */
-#define TG3_FRAGSIZE 2048
-
/* minimum number of free TX descriptors required to wake up TX process */
#define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4)
#define TG3_TX_BD_DMA_MAX_2K 2048
@@ -5631,25 +5622,6 @@ static void tg3_tx(struct tg3_napi *tnapi)
}
}
-static void *tg3_frag_alloc(struct tg3_rx_prodring_set *tpr)
-{
- void *data;
-
- if (tpr->rx_page_size < TG3_FRAGSIZE) {
- struct page *page = alloc_page(GFP_ATOMIC);
-
- if (!page)
- return NULL;
- atomic_add((PAGE_SIZE / TG3_FRAGSIZE) - 1, &page->_count);
- tpr->rx_page_addr = page_address(page);
- tpr->rx_page_size = PAGE_SIZE;
- }
- data = tpr->rx_page_addr;
- tpr->rx_page_addr += TG3_FRAGSIZE;
- tpr->rx_page_size -= TG3_FRAGSIZE;
- return data;
-}
-
static void tg3_frag_free(bool is_frag, void *data)
{
if (is_frag)
@@ -5668,7 +5640,7 @@ static void tg3_rx_data_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz)
pci_unmap_single(tp->pdev, dma_unmap_addr(ri, mapping),
map_sz, PCI_DMA_FROMDEVICE);
- tg3_frag_free(skb_size <= TG3_FRAGSIZE, ri->data);
+ tg3_frag_free(skb_size <= PAGE_SIZE, ri->data);
ri->data = NULL;
}
@@ -5721,9 +5693,9 @@ static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
*/
skb_size = SKB_DATA_ALIGN(data_size + TG3_RX_OFFSET(tp)) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- if (skb_size <= TG3_FRAGSIZE) {
- data = tg3_frag_alloc(tpr);
- *frag_size = TG3_FRAGSIZE;
+ if (skb_size <= PAGE_SIZE) {
+ data = netdev_alloc_frag(skb_size);
+ *frag_size = skb_size;
} else {
data = kmalloc(skb_size, GFP_ATOMIC);
*frag_size = 0;
@@ -5736,7 +5708,7 @@ static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
data_size,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(tp->pdev, mapping))) {
- tg3_frag_free(skb_size <= TG3_FRAGSIZE, data);
+ tg3_frag_free(skb_size <= PAGE_SIZE, data);
return -EIO;
}
@@ -15911,8 +15883,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (dev) {
struct tg3 *tp = netdev_priv(dev);
- if (tp->fw)
- release_firmware(tp->fw);
+ release_firmware(tp->fw);
tg3_reset_task_cancel(tp);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 7c85545..93865f8 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2815,8 +2815,6 @@ struct tg3_rx_prodring_set {
struct ring_info *rx_jmb_buffers;
dma_addr_t rx_std_mapping;
dma_addr_t rx_jmb_mapping;
- void *rx_page_addr;
- unsigned int rx_page_size;
};
#define TG3_IRQ_MAX_VECS_RSS 5
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 25c4e7f..67cd2ed 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -3520,9 +3520,7 @@ static void __exit
bnad_module_exit(void)
{
pci_unregister_driver(&bnad_pci_driver);
-
- if (bfi_fw)
- release_firmware(bfi_fw);
+ release_firmware(bfi_fw);
}
module_init(bnad_module_init);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 0fe1885..ec2dafe 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -51,6 +51,8 @@
#define FW_VERSION_MINOR 1
#define FW_VERSION_MICRO 0
+#define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
+
enum {
MAX_NPORTS = 4, /* max # of ports */
SERNUM_LEN = 24, /* Serial # length */
@@ -64,6 +66,15 @@ enum {
MEM_MC
};
+enum {
+ MEMWIN0_APERTURE = 65536,
+ MEMWIN0_BASE = 0x30000,
+ MEMWIN1_APERTURE = 32768,
+ MEMWIN1_BASE = 0x28000,
+ MEMWIN2_APERTURE = 2048,
+ MEMWIN2_BASE = 0x1b800,
+};
+
enum dev_master {
MASTER_CANT,
MASTER_MAY,
@@ -403,6 +414,9 @@ struct sge_txq {
struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */
struct sge_qstat *stat; /* queue status entry */
dma_addr_t phys_addr; /* physical address of the ring */
+ spinlock_t db_lock;
+ int db_disabled;
+ unsigned short db_pidx;
};
struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
@@ -475,6 +489,7 @@ struct adapter {
void __iomem *regs;
struct pci_dev *pdev;
struct device *pdev_dev;
+ unsigned int mbox;
unsigned int fn;
unsigned int flags;
@@ -504,6 +519,8 @@ struct adapter {
void **tid_release_head;
spinlock_t tid_release_lock;
struct work_struct tid_release_task;
+ struct work_struct db_full_task;
+ struct work_struct db_drop_task;
bool tid_release_task_busy;
struct dentry *debugfs_root;
@@ -605,6 +622,7 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
void t4_sge_init(struct adapter *adap);
void t4_sge_start(struct adapter *adap);
void t4_sge_stop(struct adapter *adap);
+extern int dbfifo_int_thresh;
#define for_each_port(adapter, iter) \
for (iter = 0; iter < (adapter)->params.nports; ++iter)
@@ -719,4 +737,9 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid);
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
+void t4_db_full(struct adapter *adapter);
+void t4_db_dropped(struct adapter *adapter);
+int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len);
+int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
+ u32 addr, u32 val);
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index b126b98..e1f96fb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -149,15 +149,6 @@ static unsigned int pfvfres_pmask(struct adapter *adapter,
#endif
enum {
- MEMWIN0_APERTURE = 65536,
- MEMWIN0_BASE = 0x30000,
- MEMWIN1_APERTURE = 32768,
- MEMWIN1_BASE = 0x28000,
- MEMWIN2_APERTURE = 2048,
- MEMWIN2_BASE = 0x1b800,
-};
-
-enum {
MAX_TXQ_ENTRIES = 16384,
MAX_CTRL_TXQ_ENTRIES = 1024,
MAX_RSPQ_ENTRIES = 16384,
@@ -371,6 +362,15 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
uhash | mhash, sleep);
}
+int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
+module_param(dbfifo_int_thresh, int, 0644);
+MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
+
+int dbfifo_drain_delay = 1000; /* usecs to sleep while draining the dbfifo */
+module_param(dbfifo_drain_delay, int, 0644);
+MODULE_PARM_DESC(dbfifo_drain_delay,
+ "usecs to sleep while draining the dbfifo");
+
/*
* Set Rx properties of a port, such as promiscruity, address filters, and MTU.
* If @mtu is -1 it is left unchanged.
@@ -389,6 +389,8 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
return ret;
}
+static struct workqueue_struct *workq;
+
/**
* link_start - enable a port
* @dev: the port to enable
@@ -2196,7 +2198,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
adap->tid_release_head = (void **)((uintptr_t)p | chan);
if (!adap->tid_release_task_busy) {
adap->tid_release_task_busy = true;
- schedule_work(&adap->tid_release_task);
+ queue_work(workq, &adap->tid_release_task);
}
spin_unlock_bh(&adap->tid_release_lock);
}
@@ -2366,6 +2368,16 @@ unsigned int cxgb4_port_chan(const struct net_device *dev)
}
EXPORT_SYMBOL(cxgb4_port_chan);
+unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
+{
+ struct adapter *adap = netdev2adap(dev);
+ u32 v;
+
+ v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
+ return lpfifo ? G_LP_COUNT(v) : G_HP_COUNT(v);
+}
+EXPORT_SYMBOL(cxgb4_dbfifo_count);
+
/**
* cxgb4_port_viid - get the VI id of a port
* @dev: the net device for the port
@@ -2413,6 +2425,59 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
}
EXPORT_SYMBOL(cxgb4_iscsi_init);
+int cxgb4_flush_eq_cache(struct net_device *dev)
+{
+ struct adapter *adap = netdev2adap(dev);
+ int ret;
+
+ ret = t4_fwaddrspace_write(adap, adap->mbox,
+ 0xe1000000 + A_SGE_CTXT_CMD, 0x20000000);
+ return ret;
+}
+EXPORT_SYMBOL(cxgb4_flush_eq_cache);
+
+static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx)
+{
+ u32 addr = t4_read_reg(adap, A_SGE_DBQ_CTXT_BADDR) + 24 * qid + 8;
+ __be64 indices;
+ int ret;
+
+ ret = t4_mem_win_read_len(adap, addr, (__be32 *)&indices, 8);
+ if (!ret) {
+ indices = be64_to_cpu(indices);
+ *cidx = (indices >> 25) & 0xffff;
+ *pidx = (indices >> 9) & 0xffff;
+ }
+ return ret;
+}
+
+int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx,
+ u16 size)
+{
+ struct adapter *adap = netdev2adap(dev);
+ u16 hw_pidx, hw_cidx;
+ int ret;
+
+ ret = read_eq_indices(adap, qid, &hw_pidx, &hw_cidx);
+ if (ret)
+ goto out;
+
+ if (pidx != hw_pidx) {
+ u16 delta;
+
+ if (pidx >= hw_pidx)
+ delta = pidx - hw_pidx;
+ else
+ delta = size - hw_pidx + pidx;
+ wmb();
+ t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
+ V_QID(qid) | V_PIDX(delta));
+ }
+out:
+ return ret;
+}
+EXPORT_SYMBOL(cxgb4_sync_txq_pidx);
+
static struct pci_driver cxgb4_driver;
static void check_neigh_update(struct neighbour *neigh)
@@ -2446,6 +2511,144 @@ static struct notifier_block cxgb4_netevent_nb = {
.notifier_call = netevent_cb
};
+static void drain_db_fifo(struct adapter *adap, int usecs)
+{
+ u32 v;
+
+ do {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(usecs));
+ v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
+ if (G_LP_COUNT(v) == 0 && G_HP_COUNT(v) == 0)
+ break;
+ } while (1);
+}
+
+static void disable_txq_db(struct sge_txq *q)
+{
+ spin_lock_irq(&q->db_lock);
+ q->db_disabled = 1;
+ spin_unlock_irq(&q->db_lock);
+}
+
+static void enable_txq_db(struct sge_txq *q)
+{
+ spin_lock_irq(&q->db_lock);
+ q->db_disabled = 0;
+ spin_unlock_irq(&q->db_lock);
+}
+
+static void disable_dbs(struct adapter *adap)
+{
+ int i;
+
+ for_each_ethrxq(&adap->sge, i)
+ disable_txq_db(&adap->sge.ethtxq[i].q);
+ for_each_ofldrxq(&adap->sge, i)
+ disable_txq_db(&adap->sge.ofldtxq[i].q);
+ for_each_port(adap, i)
+ disable_txq_db(&adap->sge.ctrlq[i].q);
+}
+
+static void enable_dbs(struct adapter *adap)
+{
+ int i;
+
+ for_each_ethrxq(&adap->sge, i)
+ enable_txq_db(&adap->sge.ethtxq[i].q);
+ for_each_ofldrxq(&adap->sge, i)
+ enable_txq_db(&adap->sge.ofldtxq[i].q);
+ for_each_port(adap, i)
+ enable_txq_db(&adap->sge.ctrlq[i].q);
+}
+
+static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
+{
+ u16 hw_pidx, hw_cidx;
+ int ret;
+
+ spin_lock_bh(&q->db_lock);
+ ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
+ if (ret)
+ goto out;
+ if (q->db_pidx != hw_pidx) {
+ u16 delta;
+
+ if (q->db_pidx >= hw_pidx)
+ delta = q->db_pidx - hw_pidx;
+ else
+ delta = q->size - hw_pidx + q->db_pidx;
+ wmb();
+ t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
+ V_QID(q->cntxt_id) | V_PIDX(delta));
+ }
+out:
+ q->db_disabled = 0;
+ spin_unlock_bh(&q->db_lock);
+ if (ret)
+ CH_WARN(adap, "DB drop recovery failed.\n");
+}
+static void recover_all_queues(struct adapter *adap)
+{
+ int i;
+
+ for_each_ethrxq(&adap->sge, i)
+ sync_txq_pidx(adap, &adap->sge.ethtxq[i].q);
+ for_each_ofldrxq(&adap->sge, i)
+ sync_txq_pidx(adap, &adap->sge.ofldtxq[i].q);
+ for_each_port(adap, i)
+ sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
+}
+
+static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
+{
+ mutex_lock(&uld_mutex);
+ if (adap->uld_handle[CXGB4_ULD_RDMA])
+ ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
+ cmd);
+ mutex_unlock(&uld_mutex);
+}
+
+static void process_db_full(struct work_struct *work)
+{
+ struct adapter *adap;
+
+ adap = container_of(work, struct adapter, db_full_task);
+
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
+ drain_db_fifo(adap, dbfifo_drain_delay);
+ t4_set_reg_field(adap, A_SGE_INT_ENABLE3,
+ F_DBFIFO_HP_INT | F_DBFIFO_LP_INT,
+ F_DBFIFO_HP_INT | F_DBFIFO_LP_INT);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
+}
+
+static void process_db_drop(struct work_struct *work)
+{
+ struct adapter *adap;
+
+ adap = container_of(work, struct adapter, db_drop_task);
+
+ t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0);
+ disable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
+ drain_db_fifo(adap, 1);
+ recover_all_queues(adap);
+ enable_dbs(adap);
+}
+
+void t4_db_full(struct adapter *adap)
+{
+ t4_set_reg_field(adap, A_SGE_INT_ENABLE3,
+ F_DBFIFO_HP_INT | F_DBFIFO_LP_INT, 0);
+ queue_work(workq, &adap->db_full_task);
+}
+
+void t4_db_dropped(struct adapter *adap)
+{
+ queue_work(workq, &adap->db_drop_task);
+}
+
static void uld_attach(struct adapter *adap, unsigned int uld)
{
void *handle;
@@ -2479,6 +2682,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
lli.fw_vers = adap->params.fw_vers;
+ lli.dbfifo_int_thresh = dbfifo_int_thresh;
handle = ulds[uld].add(&lli);
if (IS_ERR(handle)) {
@@ -2649,6 +2853,8 @@ static void cxgb_down(struct adapter *adapter)
{
t4_intr_disable(adapter);
cancel_work_sync(&adapter->tid_release_task);
+ cancel_work_sync(&adapter->db_full_task);
+ cancel_work_sync(&adapter->db_drop_task);
adapter->tid_release_task_busy = false;
adapter->tid_release_head = NULL;
@@ -3593,6 +3799,7 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
+ adapter->mbox = func;
adapter->fn = func;
adapter->msg_enable = dflt_msg_enable;
memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@@ -3601,6 +3808,8 @@ static int __devinit init_one(struct pci_dev *pdev,
spin_lock_init(&adapter->tid_release_lock);
INIT_WORK(&adapter->tid_release_task, process_tid_release_list);
+ INIT_WORK(&adapter->db_full_task, process_db_full);
+ INIT_WORK(&adapter->db_drop_task, process_db_drop);
err = t4_prep_adapter(adapter);
if (err)
@@ -3788,6 +3997,10 @@ static int __init cxgb4_init_module(void)
{
int ret;
+ workq = create_singlethread_workqueue("cxgb4");
+ if (!workq)
+ return -ENOMEM;
+
/* Debugfs support is optional, just warn if this fails */
cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (!cxgb4_debugfs_root)
@@ -3803,6 +4016,8 @@ static void __exit cxgb4_cleanup_module(void)
{
pci_unregister_driver(&cxgb4_driver);
debugfs_remove(cxgb4_debugfs_root); /* NULL ok */
+ flush_workqueue(workq);
+ destroy_workqueue(workq);
}
module_init(cxgb4_init_module);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index b1d39b8..d79980c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -163,6 +163,12 @@ enum cxgb4_state {
CXGB4_STATE_DETACH
};
+enum cxgb4_control {
+ CXGB4_CONTROL_DB_FULL,
+ CXGB4_CONTROL_DB_EMPTY,
+ CXGB4_CONTROL_DB_DROP,
+};
+
struct pci_dev;
struct l2t_data;
struct net_device;
@@ -212,6 +218,7 @@ struct cxgb4_lld_info {
unsigned short ucq_density; /* # of user CQs/page */
void __iomem *gts_reg; /* address of GTS register */
void __iomem *db_reg; /* address of kernel doorbell */
+ int dbfifo_int_thresh; /* doorbell fifo int threshold */
};
struct cxgb4_uld_info {
@@ -220,11 +227,13 @@ struct cxgb4_uld_info {
int (*rx_handler)(void *handle, const __be64 *rsp,
const struct pkt_gl *gl);
int (*state_change)(void *handle, enum cxgb4_state new_state);
+ int (*control)(void *handle, enum cxgb4_control control, ...);
};
int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
int cxgb4_unregister_uld(enum cxgb4_uld type);
int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
+unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo);
unsigned int cxgb4_port_chan(const struct net_device *dev);
unsigned int cxgb4_port_viid(const struct net_device *dev);
unsigned int cxgb4_port_idx(const struct net_device *dev);
@@ -236,4 +245,6 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
const unsigned int *pgsz_order);
struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len, unsigned int pull_len);
+int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size);
+int cxgb4_flush_eq_cache(struct net_device *dev);
#endif /* !__CXGB4_OFLD_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 2dae795..e111d97 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -767,8 +767,13 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
{
wmb(); /* write descriptors before telling HW */
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(q->cntxt_id) | PIDX(n));
+ spin_lock(&q->db_lock);
+ if (!q->db_disabled) {
+ t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
+ V_QID(q->cntxt_id) | V_PIDX(n));
+ }
+ q->db_pidx = q->pidx;
+ spin_unlock(&q->db_lock);
}
/**
@@ -2081,6 +2086,7 @@ static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id)
q->stops = q->restarts = 0;
q->stat = (void *)&q->desc[q->size];
q->cntxt_id = id;
+ spin_lock_init(&q->db_lock);
adap->sge.egr_map[id - adap->sge.egr_start] = q;
}
@@ -2415,6 +2421,18 @@ void t4_sge_init(struct adapter *adap)
RXPKTCPLMODE |
(STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
+ /*
+ * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
+ * and generate an interrupt when this occurs so we can recover.
+ */
+ t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
+ V_HP_INT_THRESH(M_HP_INT_THRESH) |
+ V_LP_INT_THRESH(M_LP_INT_THRESH),
+ V_HP_INT_THRESH(dbfifo_int_thresh) |
+ V_LP_INT_THRESH(dbfifo_int_thresh));
+ t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP,
+ F_ENABLE_DROP);
+
for (i = v = 0; i < 32; i += 4)
v |= (PAGE_SHIFT - 10) << i;
t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index d1ec111..32e1dd5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -868,11 +868,14 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
+typedef void (*int_handler_t)(struct adapter *adap);
+
struct intr_info {
unsigned int mask; /* bits to check in interrupt status */
const char *msg; /* message to print or NULL */
short stat_idx; /* stat counter to increment or -1 */
unsigned short fatal; /* whether the condition reported is fatal */
+ int_handler_t int_handler; /* platform-specific int handler */
};
/**
@@ -905,6 +908,8 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
} else if (acts->msg && printk_ratelimit())
dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask);
+ if (acts->int_handler)
+ acts->int_handler(adapter);
mask |= acts->mask;
}
status &= mask;
@@ -1013,7 +1018,9 @@ static void sge_intr_handler(struct adapter *adapter)
{ ERR_INVALID_CIDX_INC,
"SGE GTS CIDX increment too large", -1, 0 },
{ ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
- { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 },
+ { F_DBFIFO_LP_INT, NULL, -1, 0, t4_db_full },
+ { F_DBFIFO_HP_INT, NULL, -1, 0, t4_db_full },
+ { F_ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped },
{ ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
{ ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
@@ -1034,10 +1041,10 @@ static void sge_intr_handler(struct adapter *adapter)
};
v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) |
- ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
+ ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
if (v) {
dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n",
- (unsigned long long)v);
+ (unsigned long long)v);
t4_write_reg(adapter, SGE_INT_CAUSE1, v);
t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32);
}
@@ -1513,6 +1520,7 @@ void t4_intr_enable(struct adapter *adapter)
ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 |
ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO |
ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR |
+ F_DBFIFO_HP_INT | F_DBFIFO_LP_INT |
EGRESS_SIZE_ERR);
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK);
t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf);
@@ -1986,6 +1994,54 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
(var).retval_len16 = htonl(FW_LEN16(var)); \
} while (0)
+int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
+ u32 addr, u32 val)
+{
+ struct fw_ldst_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
+ F_FW_CMD_WRITE |
+ V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
+ c.cycles_to_len16 = htonl(FW_LEN16(c));
+ c.u.addrval.addr = htonl(addr);
+ c.u.addrval.val = htonl(val);
+
+ return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+}
+
+/*
+ * t4_mem_win_read_len - read memory through PCIE memory window
+ * @adap: the adapter
+ * @addr: address of first byte requested aligned on 32b.
+ * @data: len bytes to hold the data read
+ * @len: amount of data to read from window. Must be <=
+ * MEMWIN0_APERATURE after adjusting for 16B alignment
+ * requirements of the the memory window.
+ *
+ * Read len bytes of data from MC starting at @addr.
+ */
+int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len)
+{
+ int i;
+ int off;
+
+ /*
+ * Align on a 16B boundary.
+ */
+ off = addr & 15;
+ if ((addr & 3) || (len + off) > MEMWIN0_APERTURE)
+ return -EINVAL;
+
+ t4_write_reg(adap, A_PCIE_MEM_ACCESS_OFFSET, addr & ~15);
+ t4_read_reg(adap, A_PCIE_MEM_ACCESS_OFFSET);
+
+ for (i = 0; i < len; i += 4)
+ *data++ = t4_read_reg(adap, (MEMWIN0_BASE + off + i));
+
+ return 0;
+}
+
/**
* t4_mdio_rd - read a PHY register through MDIO
* @adap: the adapter
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 0adc5bc..111fc32 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -190,6 +190,59 @@
#define SGE_DEBUG_DATA_LOW 0x10d4
#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
+#define S_LP_INT_THRESH 12
+#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH)
+#define S_HP_INT_THRESH 28
+#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH)
+#define A_SGE_DBFIFO_STATUS 0x10a4
+
+#define S_ENABLE_DROP 13
+#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP)
+#define F_ENABLE_DROP V_ENABLE_DROP(1U)
+#define A_SGE_DOORBELL_CONTROL 0x10a8
+
+#define A_SGE_CTXT_CMD 0x11fc
+#define A_SGE_DBQ_CTXT_BADDR 0x1084
+
+#define A_SGE_PF_KDOORBELL 0x0
+
+#define S_QID 15
+#define V_QID(x) ((x) << S_QID)
+
+#define S_PIDX 0
+#define V_PIDX(x) ((x) << S_PIDX)
+
+#define M_LP_COUNT 0x7ffU
+#define S_LP_COUNT 0
+#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT)
+
+#define M_HP_COUNT 0x7ffU
+#define S_HP_COUNT 16
+#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT)
+
+#define A_SGE_INT_ENABLE3 0x1040
+
+#define S_DBFIFO_HP_INT 8
+#define V_DBFIFO_HP_INT(x) ((x) << S_DBFIFO_HP_INT)
+#define F_DBFIFO_HP_INT V_DBFIFO_HP_INT(1U)
+
+#define S_DBFIFO_LP_INT 7
+#define V_DBFIFO_LP_INT(x) ((x) << S_DBFIFO_LP_INT)
+#define F_DBFIFO_LP_INT V_DBFIFO_LP_INT(1U)
+
+#define S_DROPPED_DB 0
+#define V_DROPPED_DB(x) ((x) << S_DROPPED_DB)
+#define F_DROPPED_DB V_DROPPED_DB(1U)
+
+#define S_ERR_DROPPED_DB 18
+#define V_ERR_DROPPED_DB(x) ((x) << S_ERR_DROPPED_DB)
+#define F_ERR_DROPPED_DB V_ERR_DROPPED_DB(1U)
+
+#define A_PCIE_MEM_ACCESS_OFFSET 0x306c
+
+#define M_HP_INT_THRESH 0xfU
+#define M_LP_INT_THRESH 0xfU
+
#define PCIE_PF_CLI 0x44
#define PCIE_INT_CAUSE 0x3004
#define UNXSPLCPLERR 0x20000000U
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index edcfd7e..ad53f79 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -1620,4 +1620,19 @@ struct fw_hdr {
#define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff)
#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
+
+#define S_FW_CMD_OP 24
+#define V_FW_CMD_OP(x) ((x) << S_FW_CMD_OP)
+
+#define S_FW_CMD_REQUEST 23
+#define V_FW_CMD_REQUEST(x) ((x) << S_FW_CMD_REQUEST)
+#define F_FW_CMD_REQUEST V_FW_CMD_REQUEST(1U)
+
+#define S_FW_CMD_WRITE 21
+#define V_FW_CMD_WRITE(x) ((x) << S_FW_CMD_WRITE)
+#define F_FW_CMD_WRITE V_FW_CMD_WRITE(1U)
+
+#define S_FW_LDST_CMD_ADDRSPACE 0
+#define V_FW_LDST_CMD_ADDRSPACE(x) ((x) << S_FW_LDST_CMD_ADDRSPACE)
+
#endif /* _T4FW_INTERFACE_H_ */
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index b9406cb..845b202 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -1,105 +1,27 @@
/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
- * driver for linux.
+ * driver for linux.
+ * Written 1996 by Russell Nelson, with reference to skeleton.c
+ * written 1993-1994 by Donald Becker.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * The author may be reached at nelson@crynwr.com, Crynwr
+ * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
+ *
+ * Other contributors:
+ * Mike Cruse : mcruse@cti-ltd.com
+ * Russ Nelson
+ * Melody Lee : ethernet@crystal.cirrus.com
+ * Alan Cox
+ * Andrew Morton
+ * Oskar Schirmer : oskar@scara.com
+ * Deepak Saxena : dsaxena@plexity.net
+ * Dmitry Pervushin : dpervushin@ru.mvista.com
+ * Deepak Saxena : dsaxena@plexity.net
+ * Domenico Andreoli : cavokz@gmail.com
*/
-/*
- Written 1996 by Russell Nelson, with reference to skeleton.c
- written 1993-1994 by Donald Becker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached at nelson@crynwr.com, Crynwr
- Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
-
- Changelog:
-
- Mike Cruse : mcruse@cti-ltd.com
- : Changes for Linux 2.0 compatibility.
- : Added dev_id parameter in net_interrupt(),
- : request_irq() and free_irq(). Just NULL for now.
-
- Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
- : in net_open() and net_close() so kerneld would know
- : that the module is in use and wouldn't eject the
- : driver prematurely.
-
- Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
- : as an example. Disabled autoprobing in init_module(),
- : not a good thing to do to other devices while Linux
- : is running from all accounts.
-
- Russ Nelson : Jul 13 1998. Added RxOnly DMA support.
-
- Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility.
- : email: ethernet@crystal.cirrus.com
-
- Alan Cox : Removed 1.2 support, added 2.1 extra counters.
-
- Andrew Morton : Kernel 2.3.48
- : Handle kmalloc() failures
- : Other resource allocation fixes
- : Add SMP locks
- : Integrate Russ Nelson's ALLOW_DMA functionality back in.
- : If ALLOW_DMA is true, make DMA runtime selectable
- : Folded in changes from Cirrus (Melody Lee
- : <klee@crystal.cirrus.com>)
- : Don't call netif_wake_queue() in net_send_packet()
- : Fixed an out-of-mem bug in dma_rx()
- : Updated Documentation/networking/cs89x0.txt
-
- Andrew Morton : Kernel 2.3.99-pre1
- : Use skb_reserve to longword align IP header (two places)
- : Remove a delay loop from dma_rx()
- : Replace '100' with HZ
- : Clean up a couple of skb API abuses
- : Added 'cs89x0_dma=N' kernel boot option
- : Correctly initialise lp->lock in non-module compile
-
- Andrew Morton : Kernel 2.3.99-pre4-1
- : MOD_INC/DEC race fix (see
- : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
-
- Andrew Morton : Kernel 2.4.0-test7-pre2
- : Enhanced EEPROM support to cover more devices,
- : abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
- : (Jason Gunthorpe <jgg@ualberta.ca>)
-
- Andrew Morton : Kernel 2.4.0-test11-pre4
- : Use dev->name in request_*() (Andrey Panin)
- : Fix an error-path memleak in init_module()
- : Preserve return value from request_irq()
- : Fix type of `media' module parm (Keith Owens)
- : Use SET_MODULE_OWNER()
- : Tidied up strange request_irq() abuse in net_open().
-
- Andrew Morton : Kernel 2.4.3-pre1
- : Request correct number of pages for DMA (Hugh Dickens)
- : Select PP_ChipID _after_ unregister_netdev in cleanup_module()
- : because unregister_netdev() calls get_stats.
- : Make `version[]' __initdata
- : Uninlined the read/write reg/word functions.
-
- Oskar Schirmer : oskar@scara.com
- : HiCO.SH4 (superh) support added (irq#1, cs89x0_media=)
-
- Deepak Saxena : dsaxena@plexity.net
- : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support
-
- Dmitry Pervushin : dpervushin@ru.mvista.com
- : PNX010X platform support
-
- Deepak Saxena : dsaxena@plexity.net
- : Intel IXDP2351 platform support
-
- Dmitry Pervushin : dpervushin@ru.mvista.com
- : PNX010X platform support
-
- Domenico Andreoli : cavokz@gmail.com
- : QQ2440 platform support
-
-*/
-
/*
* Set this to zero to disable DMA code
@@ -119,14 +41,12 @@
*/
#define DEBUGGING 1
-/*
- Sources:
-
- Crynwr packet driver epktisa.
-
- Crystal Semiconductor data sheets.
+/* Sources:
+ * Crynwr packet driver epktisa.
+ * Crystal Semiconductor data sheets.
+ */
-*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/printk.h>
@@ -147,8 +67,8 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <linux/atomic.h>
#if ALLOW_DMA
@@ -157,35 +77,55 @@
#include "cs89x0.h"
+#define cs89_dbg(val, level, fmt, ...) \
+do { \
+ if (val <= net_debug) \
+ pr_##level(fmt, ##__VA_ARGS__); \
+} while (0)
+
static char version[] __initdata =
-"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton\n";
+ "v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton";
#define DRV_NAME "cs89x0"
/* First, a few definitions that the brave might change.
- A zero-terminated list of I/O addresses to be probed. Some special flags..
- Addr & 1 = Read back the address port, look for signature and reset
- the page window before probing
- Addr & 3 = Reset the page window and probe
- The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
- but it is possible that a Cirrus board could be plugged into the ISA
- slots. */
+ * A zero-terminated list of I/O addresses to be probed. Some special flags..
+ * Addr & 1 = Read back the address port, look for signature and reset
+ * the page window before probing
+ * Addr & 3 = Reset the page window and probe
+ * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
+ * but it is possible that a Cirrus board could be plugged into the ISA
+ * slots.
+ */
/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
- them to system IRQ numbers. This mapping is card specific and is set to
- the configuration of the Cirrus Eval board for this chip. */
+ * them to system IRQ numbers. This mapping is card specific and is set to
+ * the configuration of the Cirrus Eval board for this chip.
+ */
#if defined(CONFIG_MACH_IXDP2351)
#define CS89x0_NONISA_IRQ
-static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
-static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
+static unsigned int netcard_portlist[] __used __initdata = {
+ IXDP2351_VIRT_CS8900_BASE, 0
+};
+static unsigned int cs8900_irq_map[] = {
+ IRQ_IXDP2351_CS8900, 0, 0, 0
+};
#elif defined(CONFIG_ARCH_IXDP2X01)
#define CS89x0_NONISA_IRQ
-static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
-static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+static unsigned int netcard_portlist[] __used __initdata = {
+ IXDP2X01_CS8900_VIRT_BASE, 0
+};
+static unsigned int cs8900_irq_map[] = {
+ IRQ_IXDP2X01_CS8900, 0, 0, 0
+};
#else
#ifndef CONFIG_CS89x0_PLATFORM
-static unsigned int netcard_portlist[] __used __initdata =
- { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
-static unsigned int cs8900_irq_map[] = {10,11,12,5};
+static unsigned int netcard_portlist[] __used __initdata = {
+ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240,
+ 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0
+};
+static unsigned int cs8900_irq_map[] = {
+ 10, 11, 12, 5
+};
#endif
#endif
@@ -222,6 +162,8 @@ struct net_local {
int send_underrun; /* keep track of how many underruns in a row we get */
int force; /* force various values; see FORCE* above. */
spinlock_t lock;
+ void __iomem *virt_addr;/* CS89x0 virtual address. */
+ unsigned long size; /* Length of CS89x0 memory region. */
#if ALLOW_DMA
int use_dma; /* Flag: we're using dma */
int dma; /* DMA channel */
@@ -230,119 +172,42 @@ struct net_local {
unsigned char *end_dma_buff; /* points to the end of the buffer */
unsigned char *rx_dma_ptr; /* points to the next packet */
#endif
-#ifdef CONFIG_CS89x0_PLATFORM
- void __iomem *virt_addr;/* Virtual address for accessing the CS89x0. */
- unsigned long phys_addr;/* Physical address for accessing the CS89x0. */
- unsigned long size; /* Length of CS89x0 memory region. */
-#endif
};
-/* Index to functions, as function prototypes. */
-
-static int cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular);
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void set_multicast_list(struct net_device *dev);
-static void net_timeout(struct net_device *dev);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static void reset_chip(struct net_device *dev);
-static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer);
-static int get_eeprom_cksum(int off, int len, int *buffer);
-static int set_mac_address(struct net_device *dev, void *addr);
-static void count_rx_errors(int status, struct net_device *dev);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void net_poll_controller(struct net_device *dev);
-#endif
-#if ALLOW_DMA
-static void get_dma_channel(struct net_device *dev);
-static void release_dma_buff(struct net_local *lp);
-#endif
-
/* Example routines you must write ;->. */
#define tx_done(dev) 1
/*
* Permit 'cs89x0_dma=N' in the kernel boot environment
*/
-#if !defined(MODULE) && (ALLOW_DMA != 0)
+#if !defined(MODULE)
+#if ALLOW_DMA
static int g_cs89x0_dma;
static int __init dma_fn(char *str)
{
- g_cs89x0_dma = simple_strtol(str,NULL,0);
+ g_cs89x0_dma = simple_strtol(str, NULL, 0);
return 1;
}
__setup("cs89x0_dma=", dma_fn);
-#endif /* !defined(MODULE) && (ALLOW_DMA != 0) */
+#endif /* ALLOW_DMA */
-#ifndef MODULE
static int g_cs89x0_media__force;
static int __init media_fn(char *str)
{
- if (!strcmp(str, "rj45")) g_cs89x0_media__force = FORCE_RJ45;
- else if (!strcmp(str, "aui")) g_cs89x0_media__force = FORCE_AUI;
- else if (!strcmp(str, "bnc")) g_cs89x0_media__force = FORCE_BNC;
+ if (!strcmp(str, "rj45"))
+ g_cs89x0_media__force = FORCE_RJ45;
+ else if (!strcmp(str, "aui"))
+ g_cs89x0_media__force = FORCE_AUI;
+ else if (!strcmp(str, "bnc"))
+ g_cs89x0_media__force = FORCE_BNC;
+
return 1;
}
__setup("cs89x0_media=", media_fn);
-
-
-#ifndef CONFIG_CS89x0_PLATFORM
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, allocate space for the device and return success
- (detachable devices only).
- Return 0 on success.
- */
-
-struct net_device * __init cs89x0_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- unsigned *port;
- int err = 0;
- int irq;
- int io;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
-
- if (net_debug)
- printk("cs89x0:cs89x0_probe(0x%x)\n", io);
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = cs89x0_probe1(dev, io, 0);
- } else if (io != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (port = netcard_portlist; *port; port++) {
- if (cs89x0_probe1(dev, *port, 0) == 0)
- break;
- dev->irq = irq;
- }
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n");
- return ERR_PTR(err);
-}
-#endif
#endif
#if defined(CONFIG_MACH_IXDP2351)
@@ -369,36 +234,22 @@ writeword(unsigned long base_addr, int portno, u16 value)
{
__raw_writel(value, base_addr + (portno << 1));
}
-#else
-static u16
-readword(unsigned long base_addr, int portno)
-{
- return inw(base_addr + portno);
-}
-
-static void
-writeword(unsigned long base_addr, int portno, u16 value)
-{
- outw(value, base_addr + portno);
-}
#endif
-static void
-readwords(unsigned long base_addr, int portno, void *buf, int length)
+static void readwords(struct net_local *lp, int portno, void *buf, int length)
{
u8 *buf8 = (u8 *)buf;
do {
u16 tmp16;
- tmp16 = readword(base_addr, portno);
+ tmp16 = ioread16(lp->virt_addr + portno);
*buf8++ = (u8)tmp16;
*buf8++ = (u8)(tmp16 >> 8);
} while (--length);
}
-static void
-writewords(unsigned long base_addr, int portno, void *buf, int length)
+static void writewords(struct net_local *lp, int portno, void *buf, int length)
{
u8 *buf8 = (u8 *)buf;
@@ -407,32 +258,37 @@ writewords(unsigned long base_addr, int portno, void *buf, int length)
tmp16 = *buf8++;
tmp16 |= (*buf8++) << 8;
- writeword(base_addr, portno, tmp16);
+ iowrite16(tmp16, lp->virt_addr + portno);
} while (--length);
}
static u16
readreg(struct net_device *dev, u16 regno)
{
- writeword(dev->base_addr, ADD_PORT, regno);
- return readword(dev->base_addr, DATA_PORT);
+ struct net_local *lp = netdev_priv(dev);
+
+ iowrite16(regno, lp->virt_addr + ADD_PORT);
+ return ioread16(lp->virt_addr + DATA_PORT);
}
static void
writereg(struct net_device *dev, u16 regno, u16 value)
{
- writeword(dev->base_addr, ADD_PORT, regno);
- writeword(dev->base_addr, DATA_PORT, value);
+ struct net_local *lp = netdev_priv(dev);
+
+ iowrite16(regno, lp->virt_addr + ADD_PORT);
+ iowrite16(value, lp->virt_addr + DATA_PORT);
}
static int __init
wait_eeprom_ready(struct net_device *dev)
{
int timeout = jiffies;
- /* check to see if the EEPROM is ready, a timeout is used -
- just in case EEPROM is ready when SI_BUSY in the
- PP_SelfST is clear */
- while(readreg(dev, PP_SelfST) & SI_BUSY)
+ /* check to see if the EEPROM is ready,
+ * a timeout is used just in case EEPROM is ready when
+ * SI_BUSY in the PP_SelfST is clear
+ */
+ while (readreg(dev, PP_SelfST) & SI_BUSY)
if (jiffies - timeout >= 40)
return -1;
return 0;
@@ -443,17 +299,19 @@ get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
{
int i;
- if (net_debug > 3) printk("EEPROM data from %x for %x:\n",off,len);
+ cs89_dbg(3, info, "EEPROM data from %x for %x:", off, len);
for (i = 0; i < len; i++) {
- if (wait_eeprom_ready(dev) < 0) return -1;
+ if (wait_eeprom_ready(dev) < 0)
+ return -1;
/* Now send the EEPROM read command and EEPROM location to read */
writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
- if (wait_eeprom_ready(dev) < 0) return -1;
+ if (wait_eeprom_ready(dev) < 0)
+ return -1;
buffer[i] = readreg(dev, PP_EEData);
- if (net_debug > 3) printk("%04x ", buffer[i]);
+ cs89_dbg(3, cont, " %04x", buffer[i]);
}
- if (net_debug > 3) printk("\n");
- return 0;
+ cs89_dbg(3, cont, "\n");
+ return 0;
}
static int __init
@@ -470,341 +328,52 @@ get_eeprom_cksum(int off, int len, int *buffer)
return -1;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void net_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- net_interrupt(dev->irq, dev);
- enable_irq(dev->irq);
-}
-#endif
-
-static const struct net_device_ops net_ops = {
- .ndo_open = net_open,
- .ndo_stop = net_close,
- .ndo_tx_timeout = net_timeout,
- .ndo_start_xmit = net_send_packet,
- .ndo_get_stats = net_get_stats,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_set_mac_address = set_mac_address,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = net_poll_controller,
-#endif
- .ndo_change_mtu = eth_change_mtu,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* This is the real probe routine. Linux has a history of friendly device
- probes on the ISA bus. A good device probes avoids doing writes, and
- verifies that the correct device exists and functions.
- Return 0 on success.
- */
-
-static int __init
-cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular)
+static void
+write_irq(struct net_device *dev, int chip_type, int irq)
{
- struct net_local *lp = netdev_priv(dev);
- static unsigned version_printed;
int i;
- int tmp;
- unsigned rev_type = 0;
- int eeprom_buff[CHKSUM_LEN];
- int retval;
-
- /* Initialize the device structure. */
- if (!modular) {
- memset(lp, 0, sizeof(*lp));
- spin_lock_init(&lp->lock);
-#ifndef MODULE
-#if ALLOW_DMA
- if (g_cs89x0_dma) {
- lp->use_dma = 1;
- lp->dma = g_cs89x0_dma;
- lp->dmasize = 16; /* Could make this an option... */
- }
-#endif
- lp->force = g_cs89x0_media__force;
-#endif
-
- }
-
- /* Grab the region so we can find another board if autoIRQ fails. */
- /* WTF is going on here? */
- if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
- printk(KERN_ERR "%s: request_region(0x%lx, 0x%x) failed\n",
- DRV_NAME, ioaddr, NETCARD_IO_EXTENT);
- retval = -EBUSY;
- goto out1;
- }
-
- /* if they give us an odd I/O address, then do ONE write to
- the address port, to get it back to address zero, where we
- expect to find the EISA signature word. An IO with a base of 0x3
- will skip the test for the ADD_PORT. */
- if (ioaddr & 1) {
- if (net_debug > 1)
- printk(KERN_INFO "%s: odd ioaddr 0x%lx\n", dev->name, ioaddr);
- if ((ioaddr & 2) != 2)
- if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
- printk(KERN_ERR "%s: bad signature 0x%x\n",
- dev->name, readword(ioaddr & ~3, ADD_PORT));
- retval = -ENODEV;
- goto out2;
- }
- }
-
- ioaddr &= ~3;
- printk(KERN_DEBUG "PP_addr at %lx[%x]: 0x%x\n",
- ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT));
- writeword(ioaddr, ADD_PORT, PP_ChipID);
-
- tmp = readword(ioaddr, DATA_PORT);
- if (tmp != CHIP_EISA_ID_SIG) {
- printk(KERN_DEBUG "%s: incorrect signature at %lx[%x]: 0x%x!="
- CHIP_EISA_ID_SIG_STR "\n",
- dev->name, ioaddr, DATA_PORT, tmp);
- retval = -ENODEV;
- goto out2;
- }
-
- /* Fill in the 'dev' fields. */
- dev->base_addr = ioaddr;
-
- /* get the chip type */
- rev_type = readreg(dev, PRODUCT_ID_ADD);
- lp->chip_type = rev_type &~ REVISON_BITS;
- lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
-
- /* Check the chip type and revision in order to set the correct send command
- CS8920 revision C and CS8900 revision F can use the faster send. */
- lp->send_cmd = TX_AFTER_381;
- if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
- lp->send_cmd = TX_NOW;
- if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
- lp->send_cmd = TX_NOW;
-
- if (net_debug && version_printed++ == 0)
- printk(version);
-
- printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ",
- dev->name,
- lp->chip_type==CS8900?'0':'2',
- lp->chip_type==CS8920M?"M":"",
- lp->chip_revision,
- dev->base_addr);
-
- reset_chip(dev);
-
- /* Here we read the current configuration of the chip. If there
- is no Extended EEPROM then the idea is to not disturb the chip
- configuration, it should have been correctly setup by automatic
- EEPROM read on reset. So, if the chip says it read the EEPROM
- the driver will always do *something* instead of complain that
- adapter_cnf is 0. */
-
-
- if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
- (EEPROM_OK|EEPROM_PRESENT)) {
- /* Load the MAC. */
- for (i=0; i < ETH_ALEN/2; i++) {
- unsigned int Addr;
- Addr = readreg(dev, PP_IA+i*2);
- dev->dev_addr[i*2] = Addr & 0xFF;
- dev->dev_addr[i*2+1] = Addr >> 8;
- }
-
- /* Load the Adapter Configuration.
- Note: Barring any more specific information from some
- other source (ie EEPROM+Schematics), we would not know
- how to operate a 10Base2 interface on the AUI port.
- However, since we do read the status of HCB1 and use
- settings that always result in calls to control_dc_dc(dev,0)
- a BNC interface should work if the enable pin
- (dc/dc converter) is on HCB1. It will be called AUI
- however. */
-
- lp->adapter_cnf = 0;
- i = readreg(dev, PP_LineCTL);
- /* Preserve the setting of the HCB1 pin. */
- if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
- lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
- /* Save the sqelch bit */
- if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
- lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
- /* Check if the card is in 10Base-t only mode */
- if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
- lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T;
- /* Check if the card is in AUI only mode */
- if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
- lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
- /* Check if the card is in Auto mode. */
- if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
- lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
- A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
-
- if (net_debug > 1)
- printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
- dev->name, i, lp->adapter_cnf);
-
- /* IRQ. Other chips already probe, see below. */
- if (lp->chip_type == CS8900)
- lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
-
- printk( "[Cirrus EEPROM] ");
- }
-
- printk("\n");
-
- /* First check to see if an EEPROM is attached. */
-
- if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
- printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
- else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
- printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n");
- } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
- /* Check if the chip was able to read its own configuration starting
- at 0 in the EEPROM*/
- if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
- (EEPROM_OK|EEPROM_PRESENT))
- printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
-
- } else {
- /* This reads an extended EEPROM that is not documented
- in the CS8900 datasheet. */
-
- /* get transmission control word but keep the autonegotiation bits */
- if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
- /* Store adapter configuration */
- if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
- /* Store ISA configuration */
- lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2];
- dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
-
- /* eeprom_buff has 32-bit ints, so we can't just memcpy it */
- /* store the initial memory base address */
- for (i = 0; i < ETH_ALEN/2; i++) {
- dev->dev_addr[i*2] = eeprom_buff[i];
- dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
- }
- if (net_debug > 1)
- printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n",
- dev->name, lp->adapter_cnf);
- }
-
- /* allow them to force multiple transceivers. If they force multiple, autosense */
- {
- int count = 0;
- if (lp->force & FORCE_RJ45) {lp->adapter_cnf |= A_CNF_10B_T; count++; }
- if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_AUI; count++; }
- if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_10B_2; count++; }
- if (count > 1) {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; }
- else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; }
- else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; }
- else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; }
- }
-
- if (net_debug > 1)
- printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n",
- dev->name, lp->force, lp->adapter_cnf);
-
- /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
-
- /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
-
- /* FIXME: we don't set the Ethernet address on the command line. Use
- ifconfig IFACE hw ether AABBCCDDEEFF */
-
- printk(KERN_INFO "cs89x0 media %s%s%s",
- (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"",
- (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"",
- (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":"");
-
- lp->irq_map = 0xffff;
- /* If this is a CS8900 then no pnp soft */
- if (lp->chip_type != CS8900 &&
- /* Check if the ISA IRQ has been set */
- (i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
- (i != 0 && i < CS8920_NO_INTS))) {
- if (!dev->irq)
- dev->irq = i;
- } else {
- i = lp->isa_config & INT_NO_MASK;
+ if (chip_type == CS8900) {
#ifndef CONFIG_CS89x0_PLATFORM
- if (lp->chip_type == CS8900) {
-#ifdef CS89x0_NONISA_IRQ
- i = cs8900_irq_map[0];
+ /* Search the mapping table for the corresponding IRQ pin. */
+ for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
+ if (cs8900_irq_map[i] == irq)
+ break;
+ /* Not found */
+ if (i == ARRAY_SIZE(cs8900_irq_map))
+ i = 3;
#else
- /* Translate the IRQ using the IRQ mapping table. */
- if (i >= ARRAY_SIZE(cs8900_irq_map))
- printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
- else
- i = cs8900_irq_map[i];
-
- lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
- } else {
- int irq_map_buff[IRQ_MAP_LEN/2];
-
- if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
- IRQ_MAP_LEN/2,
- irq_map_buff) >= 0) {
- if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
- lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8);
- }
-#endif
- }
-#endif
- if (!dev->irq)
- dev->irq = i;
- }
-
- printk(" IRQ %d", dev->irq);
-
-#if ALLOW_DMA
- if (lp->use_dma) {
- get_dma_channel(dev);
- printk(", DMA %d", dev->dma);
- }
- else
+ /* INTRQ0 pin is used for interrupt generation. */
+ i = 0;
#endif
- {
- printk(", programmed I/O");
+ writereg(dev, PP_CS8900_ISAINT, i);
+ } else {
+ writereg(dev, PP_CS8920_ISAINT, irq);
}
-
- /* print the ethernet address. */
- printk(", MAC %pM", dev->dev_addr);
-
- dev->netdev_ops = &net_ops;
- dev->watchdog_timeo = HZ;
-
- printk("\n");
- if (net_debug)
- printk("cs89x0_probe1() successful\n");
-
- retval = register_netdev(dev);
- if (retval)
- goto out3;
- return 0;
-out3:
- writeword(dev->base_addr, ADD_PORT, PP_ChipID);
-out2:
- release_region(ioaddr & ~3, NETCARD_IO_EXTENT);
-out1:
- return retval;
}
+static void
+count_rx_errors(int status, struct net_device *dev)
+{
+ dev->stats.rx_errors++;
+ if (status & RX_RUNT)
+ dev->stats.rx_length_errors++;
+ if (status & RX_EXTRA_DATA)
+ dev->stats.rx_length_errors++;
+ if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA | RX_RUNT)))
+ /* per str 172 */
+ dev->stats.rx_crc_errors++;
+ if (status & RX_DRIBBLE)
+ dev->stats.rx_frame_errors++;
+}
/*********************************
* This page contains DMA routines
-**********************************/
+ *********************************/
#if ALLOW_DMA
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1) >> 17 == (long)(ptr2) >> 17)
static void
get_dma_channel(struct net_device *dev)
@@ -833,11 +402,10 @@ write_dma(struct net_device *dev, int chip_type, int dma)
struct net_local *lp = netdev_priv(dev);
if ((lp->isa_config & ANY_ISA_DMA) == 0)
return;
- if (chip_type == CS8900) {
- writereg(dev, PP_CS8900_ISADMA, dma-5);
- } else {
+ if (chip_type == CS8900)
+ writereg(dev, PP_CS8900_ISADMA, dma - 5);
+ else
writereg(dev, PP_CS8920_ISADMA, dma);
- }
}
static void
@@ -847,18 +415,15 @@ set_dma_cfg(struct net_device *dev)
if (lp->use_dma) {
if ((lp->isa_config & ANY_ISA_DMA) == 0) {
- if (net_debug > 3)
- printk("set_dma_cfg(): no DMA\n");
+ cs89_dbg(3, err, "set_dma_cfg(): no DMA\n");
return;
}
if (lp->isa_config & ISA_RxDMA) {
lp->curr_rx_cfg |= RX_DMA_ONLY;
- if (net_debug > 3)
- printk("set_dma_cfg(): RX_DMA_ONLY\n");
+ cs89_dbg(3, info, "set_dma_cfg(): RX_DMA_ONLY\n");
} else {
lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */
- if (net_debug > 3)
- printk("set_dma_cfg(): AUTO_RX_DMA\n");
+ cs89_dbg(3, info, "set_dma_cfg(): AUTO_RX_DMA\n");
}
}
}
@@ -868,7 +433,7 @@ dma_bufcfg(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
if (lp->use_dma)
- return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0;
+ return (lp->isa_config & ANY_ISA_DMA) ? RX_DMA_ENBL : 0;
else
return 0;
}
@@ -898,13 +463,13 @@ dma_rx(struct net_device *dev)
int status, length;
unsigned char *bp = lp->rx_dma_ptr;
- status = bp[0] + (bp[1]<<8);
- length = bp[2] + (bp[3]<<8);
+ status = bp[0] + (bp[1] << 8);
+ length = bp[2] + (bp[3] << 8);
bp += 4;
- if (net_debug > 5) {
- printk( "%s: receiving DMA packet at %lx, status %x, length %x\n",
- dev->name, (unsigned long)bp, status, length);
- }
+
+ cs89_dbg(5, debug, "%s: receiving DMA packet at %lx, status %x, length %x\n",
+ dev->name, (unsigned long)bp, status, length);
+
if ((status & RX_OK) == 0) {
count_rx_errors(status, dev);
goto skip_this_frame;
@@ -913,14 +478,16 @@ dma_rx(struct net_device *dev)
/* Malloc up new buffer. */
skb = netdev_alloc_skb(dev, length + 2);
if (skb == NULL) {
- if (net_debug) /* I don't think we want to do this to a stressed system */
- printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ /* I don't think we want to do this to a stressed system */
+ cs89_dbg(0, err, "%s: Memory squeeze, dropping packet\n",
+ dev->name);
dev->stats.rx_dropped++;
/* AKPM: advance bp to the next frame */
skip_this_frame:
bp += (length + 3) & ~3;
- if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+ if (bp >= lp->end_dma_buff)
+ bp -= lp->dmasize * 1024;
lp->rx_dma_ptr = bp;
return;
}
@@ -928,63 +495,38 @@ skip_this_frame:
if (bp + length > lp->end_dma_buff) {
int semi_cnt = lp->end_dma_buff - bp;
- memcpy(skb_put(skb,semi_cnt), bp, semi_cnt);
- memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff,
+ memcpy(skb_put(skb, semi_cnt), bp, semi_cnt);
+ memcpy(skb_put(skb, length - semi_cnt), lp->dma_buff,
length - semi_cnt);
} else {
- memcpy(skb_put(skb,length), bp, length);
+ memcpy(skb_put(skb, length), bp, length);
}
bp += (length + 3) & ~3;
- if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+ if (bp >= lp->end_dma_buff)
+ bp -= lp->dmasize*1024;
lp->rx_dma_ptr = bp;
- if (net_debug > 3) {
- printk( "%s: received %d byte DMA packet of type %x\n",
- dev->name, length,
- (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
- }
- skb->protocol=eth_type_trans(skb,dev);
+ cs89_dbg(3, info, "%s: received %d byte DMA packet of type %x\n",
+ dev->name, length,
+ ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
+ skb->data[ETH_ALEN + ETH_ALEN + 1]));
+
+ skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += length;
}
-#endif /* ALLOW_DMA */
-
-static void __init reset_chip(struct net_device *dev)
+static void release_dma_buff(struct net_local *lp)
{
-#if !defined(CONFIG_MACH_MX31ADS)
-#if !defined(CS89x0_NONISA_IRQ)
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-#endif /* CS89x0_NONISA_IRQ */
- int reset_start_time;
-
- writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
-
- /* wait 30 ms */
- msleep(30);
-
-#if !defined(CS89x0_NONISA_IRQ)
- if (lp->chip_type != CS8900) {
- /* Hardware problem requires PNP registers to be reconfigured after a reset */
- writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT);
- outb(dev->irq, ioaddr + DATA_PORT);
- outb(0, ioaddr + DATA_PORT + 1);
-
- writeword(ioaddr, ADD_PORT, PP_CS8920_ISAMemB);
- outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT);
- outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1);
+ if (lp->dma_buff) {
+ free_pages((unsigned long)(lp->dma_buff),
+ get_order(lp->dmasize * 1024));
+ lp->dma_buff = NULL;
}
-#endif /* CS89x0_NONISA_IRQ */
-
- /* Wait until the chip is reset */
- reset_start_time = jiffies;
- while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
- ;
-#endif /* !CONFIG_MACH_MX31ADS */
}
+#endif /* ALLOW_DMA */
static void
control_dc_dc(struct net_device *dev, int on_not_off)
@@ -993,8 +535,9 @@ control_dc_dc(struct net_device *dev, int on_not_off)
unsigned int selfcontrol;
int timenow = jiffies;
/* control the DC to DC convertor in the SelfControl register.
- Note: This is hooked up to a general purpose pin, might not
- always be a DC to DC convertor. */
+ * Note: This is hooked up to a general purpose pin, might not
+ * always be a DC to DC convertor.
+ */
selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
@@ -1008,6 +551,49 @@ control_dc_dc(struct net_device *dev, int on_not_off)
;
}
+/* send a test packet - return true if carrier bits are ok */
+static int
+send_test_pkt(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ char test_packet[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 46, /* A 46 in network order */
+ 0, 0, /* DSAP=0 & SSAP=0 fields */
+ 0xf3, 0 /* Control (Test Req + P bit set) */
+ };
+ long timenow = jiffies;
+
+ writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
+
+ memcpy(test_packet, dev->dev_addr, ETH_ALEN);
+ memcpy(test_packet + ETH_ALEN, dev->dev_addr, ETH_ALEN);
+
+ iowrite16(TX_AFTER_ALL, lp->virt_addr + TX_CMD_PORT);
+ iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT);
+
+ /* Test to see if the chip has allocated memory for the packet */
+ while (jiffies - timenow < 5)
+ if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
+ break;
+ if (jiffies - timenow >= 5)
+ return 0; /* this shouldn't happen */
+
+ /* Write the contents of the packet */
+ writewords(lp, TX_FRAME_PORT, test_packet, (ETH_ZLEN + 1) >> 1);
+
+ cs89_dbg(1, debug, "Sending test packet ");
+ /* wait a couple of jiffies for packet to be received */
+ for (timenow = jiffies; jiffies - timenow < 3;)
+ ;
+ if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
+ cs89_dbg(1, cont, "succeeded\n");
+ return 1;
+ }
+ cs89_dbg(1, cont, "failed\n");
+ return 0;
+}
+
#define DETECTED_NONE 0
#define DETECTED_RJ45H 1
#define DETECTED_RJ45F 2
@@ -1021,40 +607,46 @@ detect_tp(struct net_device *dev)
int timenow = jiffies;
int fdx;
- if (net_debug > 1) printk("%s: Attempting TP\n", dev->name);
+ cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name);
- /* If connected to another full duplex capable 10-Base-T card the link pulses
- seem to be lost when the auto detect bit in the LineCTL is set.
- To overcome this the auto detect bit will be cleared whilst testing the
- 10-Base-T interface. This would not be necessary for the sparrow chip but
- is simpler to do it anyway. */
- writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY);
+ /* If connected to another full duplex capable 10-Base-T card
+ * the link pulses seem to be lost when the auto detect bit in
+ * the LineCTL is set. To overcome this the auto detect bit will
+ * be cleared whilst testing the 10-Base-T interface. This would
+ * not be necessary for the sparrow chip but is simpler to do it
+ * anyway.
+ */
+ writereg(dev, PP_LineCTL, lp->linectl & ~AUI_ONLY);
control_dc_dc(dev, 0);
- /* Delay for the hardware to work out if the TP cable is present - 150ms */
- for (timenow = jiffies; jiffies - timenow < 15; )
- ;
+ /* Delay for the hardware to work out if the TP cable is present
+ * - 150ms
+ */
+ for (timenow = jiffies; jiffies - timenow < 15;)
+ ;
if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
return DETECTED_NONE;
if (lp->chip_type == CS8900) {
- switch (lp->force & 0xf0) {
+ switch (lp->force & 0xf0) {
#if 0
- case FORCE_AUTO:
- printk("%s: cs8900 doesn't autonegotiate\n",dev->name);
- return DETECTED_NONE;
+ case FORCE_AUTO:
+ pr_info("%s: cs8900 doesn't autonegotiate\n",
+ dev->name);
+ return DETECTED_NONE;
#endif
- /* CS8900 doesn't support AUTO, change to HALF*/
- case FORCE_AUTO:
+ /* CS8900 doesn't support AUTO, change to HALF*/
+ case FORCE_AUTO:
lp->force &= ~FORCE_AUTO;
- lp->force |= FORCE_HALF;
+ lp->force |= FORCE_HALF;
break;
case FORCE_HALF:
break;
- case FORCE_FULL:
- writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900);
+ case FORCE_FULL:
+ writereg(dev, PP_TestCTL,
+ readreg(dev, PP_TestCTL) | FDX_8900);
break;
- }
+ }
fdx = readreg(dev, PP_TestCTL) & FDX_8900;
} else {
switch (lp->force & 0xf0) {
@@ -1067,15 +659,15 @@ detect_tp(struct net_device *dev)
case FORCE_FULL:
lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX;
break;
- }
+ }
writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
- printk(KERN_INFO "%s: negotiating duplex...\n",dev->name);
+ pr_info("%s: negotiating duplex...\n", dev->name);
while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
if (jiffies - timenow > 4000) {
- printk(KERN_ERR "**** Full / half duplex auto-negotiation timed out ****\n");
+ pr_err("**** Full / half duplex auto-negotiation timed out ****\n");
break;
}
}
@@ -1088,56 +680,31 @@ detect_tp(struct net_device *dev)
return DETECTED_RJ45H;
}
-/* send a test packet - return true if carrier bits are ok */
static int
-send_test_pkt(struct net_device *dev)
+detect_bnc(struct net_device *dev)
{
- char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
- 0, 46, /* A 46 in network order */
- 0, 0, /* DSAP=0 & SSAP=0 fields */
- 0xf3, 0 /* Control (Test Req + P bit set) */ };
- long timenow = jiffies;
-
- writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
-
- memcpy(test_packet, dev->dev_addr, ETH_ALEN);
- memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);
-
- writeword(dev->base_addr, TX_CMD_PORT, TX_AFTER_ALL);
- writeword(dev->base_addr, TX_LEN_PORT, ETH_ZLEN);
+ struct net_local *lp = netdev_priv(dev);
- /* Test to see if the chip has allocated memory for the packet */
- while (jiffies - timenow < 5)
- if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
- break;
- if (jiffies - timenow >= 5)
- return 0; /* this shouldn't happen */
+ cs89_dbg(1, debug, "%s: Attempting BNC\n", dev->name);
+ control_dc_dc(dev, 1);
- /* Write the contents of the packet */
- writewords(dev->base_addr, TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
+ writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
- if (net_debug > 1) printk("Sending test packet ");
- /* wait a couple of jiffies for packet to be received */
- for (timenow = jiffies; jiffies - timenow < 3; )
- ;
- if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
- if (net_debug > 1) printk("succeeded\n");
- return 1;
- }
- if (net_debug > 1) printk("failed\n");
- return 0;
+ if (send_test_pkt(dev))
+ return DETECTED_BNC;
+ else
+ return DETECTED_NONE;
}
-
static int
detect_aui(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
- if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name);
+ cs89_dbg(1, debug, "%s: Attempting AUI\n", dev->name);
control_dc_dc(dev, 0);
- writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+ writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
if (send_test_pkt(dev))
return DETECTED_AUI;
@@ -1145,45 +712,154 @@ detect_aui(struct net_device *dev)
return DETECTED_NONE;
}
-static int
-detect_bnc(struct net_device *dev)
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
+ struct sk_buff *skb;
+ int status, length;
- if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name);
- control_dc_dc(dev, 1);
+ status = ioread16(lp->virt_addr + RX_FRAME_PORT);
+ length = ioread16(lp->virt_addr + RX_FRAME_PORT);
- writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
+ if ((status & RX_OK) == 0) {
+ count_rx_errors(status, dev);
+ return;
+ }
- if (send_test_pkt(dev))
- return DETECTED_BNC;
- else
- return DETECTED_NONE;
+ /* Malloc up new buffer. */
+ skb = netdev_alloc_skb(dev, length + 2);
+ if (skb == NULL) {
+#if 0 /* Again, this seems a cruel thing to do */
+ pr_warn("%s: Memory squeeze, dropping packet\n", dev->name);
+#endif
+ dev->stats.rx_dropped++;
+ return;
+ }
+ skb_reserve(skb, 2); /* longword align L3 header */
+
+ readwords(lp, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
+ if (length & 1)
+ skb->data[length-1] = ioread16(lp->virt_addr + RX_FRAME_PORT);
+
+ cs89_dbg(3, debug, "%s: received %d byte packet of type %x\n",
+ dev->name, length,
+ (skb->data[ETH_ALEN + ETH_ALEN] << 8) |
+ skb->data[ETH_ALEN + ETH_ALEN + 1]);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
}
+/* The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
-static void
-write_irq(struct net_device *dev, int chip_type, int irq)
+static irqreturn_t net_interrupt(int irq, void *dev_id)
{
- int i;
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+ int status;
+ int handled = 0;
- if (chip_type == CS8900) {
-#ifndef CONFIG_CS89x0_PLATFORM
- /* Search the mapping table for the corresponding IRQ pin. */
- for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
- if (cs8900_irq_map[i] == irq)
- break;
- /* Not found */
- if (i == ARRAY_SIZE(cs8900_irq_map))
- i = 3;
-#else
- /* INTRQ0 pin is used for interrupt generation. */
- i = 0;
+ lp = netdev_priv(dev);
+
+ /* we MUST read all the events out of the ISQ, otherwise we'll never
+ * get interrupted again. As a consequence, we can't have any limit
+ * on the number of times we loop in the interrupt handler. The
+ * hardware guarantees that eventually we'll run out of events. Of
+ * course, if you're on a slow machine, and packets are arriving
+ * faster than you can read them off, you're screwed. Hasta la
+ * vista, baby!
+ */
+ while ((status = ioread16(lp->virt_addr + ISQ_PORT))) {
+ cs89_dbg(4, debug, "%s: event=%04x\n", dev->name, status);
+ handled = 1;
+ switch (status & ISQ_EVENT_MASK) {
+ case ISQ_RECEIVER_EVENT:
+ /* Got a packet(s). */
+ net_rx(dev);
+ break;
+ case ISQ_TRANSMITTER_EVENT:
+ dev->stats.tx_packets++;
+ netif_wake_queue(dev); /* Inform upper layers. */
+ if ((status & (TX_OK |
+ TX_LOST_CRS |
+ TX_SQE_ERROR |
+ TX_LATE_COL |
+ TX_16_COL)) != TX_OK) {
+ if ((status & TX_OK) == 0)
+ dev->stats.tx_errors++;
+ if (status & TX_LOST_CRS)
+ dev->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR)
+ dev->stats.tx_heartbeat_errors++;
+ if (status & TX_LATE_COL)
+ dev->stats.tx_window_errors++;
+ if (status & TX_16_COL)
+ dev->stats.tx_aborted_errors++;
+ }
+ break;
+ case ISQ_BUFFER_EVENT:
+ if (status & READY_FOR_TX) {
+ /* we tried to transmit a packet earlier,
+ * but inexplicably ran out of buffers.
+ * That shouldn't happen since we only ever
+ * load one packet. Shrug. Do the right
+ * thing anyway.
+ */
+ netif_wake_queue(dev); /* Inform upper layers. */
+ }
+ if (status & TX_UNDERRUN) {
+ cs89_dbg(0, err, "%s: transmit underrun\n",
+ dev->name);
+ lp->send_underrun++;
+ if (lp->send_underrun == 3)
+ lp->send_cmd = TX_AFTER_381;
+ else if (lp->send_underrun == 6)
+ lp->send_cmd = TX_AFTER_ALL;
+ /* transmit cycle is done, although
+ * frame wasn't transmitted - this
+ * avoids having to wait for the upper
+ * layers to timeout on us, in the
+ * event of a tx underrun
+ */
+ netif_wake_queue(dev); /* Inform upper layers. */
+ }
+#if ALLOW_DMA
+ if (lp->use_dma && (status & RX_DMA)) {
+ int count = readreg(dev, PP_DmaFrameCnt);
+ while (count) {
+ cs89_dbg(5, debug,
+ "%s: receiving %d DMA frames\n",
+ dev->name, count);
+ if (count > 1)
+ cs89_dbg(2, debug,
+ "%s: receiving %d DMA frames\n",
+ dev->name, count);
+ dma_rx(dev);
+ if (--count == 0)
+ count = readreg(dev, PP_DmaFrameCnt);
+ if (count > 0)
+ cs89_dbg(2, debug,
+ "%s: continuing with %d DMA frames\n",
+ dev->name, count);
+ }
+ }
#endif
- writereg(dev, PP_CS8900_ISAINT, i);
- } else {
- writereg(dev, PP_CS8920_ISAINT, irq);
+ break;
+ case ISQ_RX_MISS_EVENT:
+ dev->stats.rx_missed_errors += (status >> 6);
+ break;
+ case ISQ_TX_COL_EVENT:
+ dev->stats.collisions += (status >> 6);
+ break;
+ }
}
+ return IRQ_RETVAL(handled);
}
/* Open/initialize the board. This is called (in the current kernel)
@@ -1192,7 +868,7 @@ write_irq(struct net_device *dev, int chip_type, int irq)
This routine should set everything up anew at each open, even
registers that "should" only need to be set once at boot, so that
there is non-reboot way to recover if something goes wrong.
- */
+*/
/* AKPM: do we need to do any locking here? */
@@ -1208,14 +884,15 @@ net_open(struct net_device *dev)
/* Allow interrupts to be generated by the chip */
/* Cirrus' release had this: */
#if 0
- writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
#endif
/* And 2.3.47 had this: */
writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
for (i = 2; i < CS8920_NO_INTS; i++) {
if ((1 << i) & lp->irq_map) {
- if (request_irq(i, net_interrupt, 0, dev->name, dev) == 0) {
+ if (request_irq(i, net_interrupt, 0, dev->name,
+ dev) == 0) {
dev->irq = i;
write_irq(dev, lp->chip_type, i);
/* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */
@@ -1226,23 +903,21 @@ net_open(struct net_device *dev)
if (i >= CS8920_NO_INTS) {
writereg(dev, PP_BusCTL, 0); /* disable interrupts. */
- printk(KERN_ERR "cs89x0: can't get an interrupt\n");
+ pr_err("can't get an interrupt\n");
ret = -EAGAIN;
goto bad_out;
}
- }
- else
- {
+ } else {
#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)
if (((1 << dev->irq) & lp->irq_map) == 0) {
- printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
- dev->name, dev->irq, lp->irq_map);
+ pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
+ dev->name, dev->irq, lp->irq_map);
ret = -EAGAIN;
goto bad_out;
}
#endif
/* FIXME: Cirrus' release had this: */
- writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ);
/* And 2.3.47 had this: */
#if 0
writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
@@ -1250,147 +925,168 @@ net_open(struct net_device *dev)
write_irq(dev, lp->chip_type, dev->irq);
ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev);
if (ret) {
- printk(KERN_ERR "cs89x0: request_irq(%d) failed\n", dev->irq);
+ pr_err("request_irq(%d) failed\n", dev->irq);
goto bad_out;
}
}
#if ALLOW_DMA
- if (lp->use_dma) {
- if (lp->isa_config & ANY_ISA_DMA) {
- unsigned long flags;
- lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
- get_order(lp->dmasize * 1024));
-
- if (!lp->dma_buff) {
- printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);
- goto release_irq;
- }
- if (net_debug > 1) {
- printk( "%s: dma %lx %lx\n",
- dev->name,
- (unsigned long)lp->dma_buff,
- (unsigned long)isa_virt_to_bus(lp->dma_buff));
- }
- if ((unsigned long) lp->dma_buff >= MAX_DMA_ADDRESS ||
- !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {
- printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);
- goto release_irq;
- }
- memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */
- if (request_dma(dev->dma, dev->name)) {
- printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);
- goto release_irq;
- }
- write_dma(dev, lp->chip_type, dev->dma);
- lp->rx_dma_ptr = lp->dma_buff;
- lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024;
- spin_lock_irqsave(&lp->lock, flags);
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
- set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
- set_dma_count(dev->dma, lp->dmasize*1024);
- enable_dma(dev->dma);
- spin_unlock_irqrestore(&lp->lock, flags);
+ if (lp->use_dma && (lp->isa_config & ANY_ISA_DMA)) {
+ unsigned long flags;
+ lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
+ get_order(lp->dmasize * 1024));
+ if (!lp->dma_buff) {
+ pr_err("%s: cannot get %dK memory for DMA\n",
+ dev->name, lp->dmasize);
+ goto release_irq;
+ }
+ cs89_dbg(1, debug, "%s: dma %lx %lx\n",
+ dev->name,
+ (unsigned long)lp->dma_buff,
+ (unsigned long)isa_virt_to_bus(lp->dma_buff));
+ if ((unsigned long)lp->dma_buff >= MAX_DMA_ADDRESS ||
+ !dma_page_eq(lp->dma_buff,
+ lp->dma_buff + lp->dmasize * 1024 - 1)) {
+ pr_err("%s: not usable as DMA buffer\n", dev->name);
+ goto release_irq;
}
+ memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */
+ if (request_dma(dev->dma, dev->name)) {
+ pr_err("%s: cannot get dma channel %d\n",
+ dev->name, dev->dma);
+ goto release_irq;
+ }
+ write_dma(dev, lp->chip_type, dev->dma);
+ lp->rx_dma_ptr = lp->dma_buff;
+ lp->end_dma_buff = lp->dma_buff + lp->dmasize * 1024;
+ spin_lock_irqsave(&lp->lock, flags);
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
+ set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
+ set_dma_count(dev->dma, lp->dmasize * 1024);
+ enable_dma(dev->dma);
+ spin_unlock_irqrestore(&lp->lock, flags);
}
#endif /* ALLOW_DMA */
/* set the Ethernet address */
- for (i=0; i < ETH_ALEN/2; i++)
- writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+ for (i = 0; i < ETH_ALEN / 2; i++)
+ writereg(dev, PP_IA + i * 2,
+ (dev->dev_addr[i * 2] |
+ (dev->dev_addr[i * 2 + 1] << 8)));
/* while we're testing the interface, leave interrupts disabled */
writereg(dev, PP_BusCTL, MEMORY_ON);
/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */
- if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
- lp->linectl = LOW_RX_SQUELCH;
+ if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) &&
+ (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
+ lp->linectl = LOW_RX_SQUELCH;
else
- lp->linectl = 0;
-
- /* check to make sure that they have the "right" hardware available */
- switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
- case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;
- case A_CNF_MEDIA_AUI: result = lp->adapter_cnf & A_CNF_AUI; break;
- case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
- default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
- }
- if (!result) {
- printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
+ lp->linectl = 0;
+
+ /* check to make sure that they have the "right" hardware available */
+ switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+ case A_CNF_MEDIA_10B_T:
+ result = lp->adapter_cnf & A_CNF_10B_T;
+ break;
+ case A_CNF_MEDIA_AUI:
+ result = lp->adapter_cnf & A_CNF_AUI;
+ break;
+ case A_CNF_MEDIA_10B_2:
+ result = lp->adapter_cnf & A_CNF_10B_2;
+ break;
+ default:
+ result = lp->adapter_cnf & (A_CNF_10B_T |
+ A_CNF_AUI |
+ A_CNF_10B_2);
+ }
+ if (!result) {
+ pr_err("%s: EEPROM is configured for unavailable media\n",
+ dev->name);
release_dma:
#if ALLOW_DMA
free_dma(dev->dma);
release_irq:
release_dma_buff(lp);
#endif
- writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
- free_irq(dev->irq, dev);
+ writereg(dev, PP_LineCTL,
+ readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
+ free_irq(dev->irq, dev);
ret = -EAGAIN;
goto bad_out;
}
- /* set the hardware to the configured choice */
- switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
+ /* set the hardware to the configured choice */
+ switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
case A_CNF_MEDIA_10B_T:
- result = detect_tp(dev);
- if (result==DETECTED_NONE) {
- printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);
- if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
- result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */
- }
+ result = detect_tp(dev);
+ if (result == DETECTED_NONE) {
+ pr_warn("%s: 10Base-T (RJ-45) has no cable\n",
+ dev->name);
+ if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+ result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */
+ }
break;
case A_CNF_MEDIA_AUI:
- result = detect_aui(dev);
- if (result==DETECTED_NONE) {
- printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);
- if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
- result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */
- }
+ result = detect_aui(dev);
+ if (result == DETECTED_NONE) {
+ pr_warn("%s: 10Base-5 (AUI) has no cable\n", dev->name);
+ if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+ result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */
+ }
break;
case A_CNF_MEDIA_10B_2:
- result = detect_bnc(dev);
- if (result==DETECTED_NONE) {
- printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);
- if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
- result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */
- }
+ result = detect_bnc(dev);
+ if (result == DETECTED_NONE) {
+ pr_warn("%s: 10Base-2 (BNC) has no cable\n", dev->name);
+ if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+ result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */
+ }
break;
case A_CNF_MEDIA_AUTO:
writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
- if (lp->adapter_cnf & A_CNF_10B_T)
- if ((result = detect_tp(dev)) != DETECTED_NONE)
+ if (lp->adapter_cnf & A_CNF_10B_T) {
+ result = detect_tp(dev);
+ if (result != DETECTED_NONE)
break;
- if (lp->adapter_cnf & A_CNF_AUI)
- if ((result = detect_aui(dev)) != DETECTED_NONE)
+ }
+ if (lp->adapter_cnf & A_CNF_AUI) {
+ result = detect_aui(dev);
+ if (result != DETECTED_NONE)
break;
- if (lp->adapter_cnf & A_CNF_10B_2)
- if ((result = detect_bnc(dev)) != DETECTED_NONE)
+ }
+ if (lp->adapter_cnf & A_CNF_10B_2) {
+ result = detect_bnc(dev);
+ if (result != DETECTED_NONE)
break;
- printk(KERN_ERR "%s: no media detected\n", dev->name);
+ }
+ pr_err("%s: no media detected\n", dev->name);
goto release_dma;
}
- switch(result) {
+ switch (result) {
case DETECTED_NONE:
- printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);
+ pr_err("%s: no network cable attached to configured media\n",
+ dev->name);
goto release_dma;
case DETECTED_RJ45H:
- printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
+ pr_info("%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
break;
case DETECTED_RJ45F:
- printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
+ pr_info("%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
break;
case DETECTED_AUI:
- printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);
+ pr_info("%s: using 10Base-5 (AUI)\n", dev->name);
break;
case DETECTED_BNC:
- printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);
+ pr_info("%s: using 10Base-2 (BNC)\n", dev->name);
break;
}
/* Turn on both receive and transmit operations */
- writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
+ writereg(dev, PP_LineCTL,
+ readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
/* Receive only error free packets addressed to this card */
lp->rx_mode = 0;
@@ -1405,358 +1101,653 @@ release_irq:
#endif
writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
- writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
- TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+ writereg(dev, PP_TxCFG, (TX_LOST_CRS_ENBL |
+ TX_SQE_ERROR_ENBL |
+ TX_OK_ENBL |
+ TX_LATE_COL_ENBL |
+ TX_JBR_ENBL |
+ TX_ANY_COL_ENBL |
+ TX_16_COL_ENBL));
- writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
+ writereg(dev, PP_BufCFG, (READY_FOR_TX_ENBL |
+ RX_MISS_COUNT_OVRFLOW_ENBL |
#if ALLOW_DMA
- dma_bufcfg(dev) |
+ dma_bufcfg(dev) |
#endif
- TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+ TX_COL_COUNT_OVRFLOW_ENBL |
+ TX_UNDERRUN_ENBL));
/* now that we've got our act together, enable everything */
- writereg(dev, PP_BusCTL, ENABLE_IRQ
- | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */
+ writereg(dev, PP_BusCTL, (ENABLE_IRQ
+ | (dev->mem_start ? MEMORY_ON : 0) /* turn memory on */
#if ALLOW_DMA
- | dma_busctl(dev)
+ | dma_busctl(dev)
#endif
- );
- netif_start_queue(dev);
- if (net_debug > 1)
- printk("cs89x0: net_open() succeeded\n");
+ ));
+ netif_start_queue(dev);
+ cs89_dbg(1, debug, "net_open() succeeded\n");
return 0;
bad_out:
return ret;
}
+/* The inverse routine to net_open(). */
+static int
+net_close(struct net_device *dev)
+{
+#if ALLOW_DMA
+ struct net_local *lp = netdev_priv(dev);
+#endif
+
+ netif_stop_queue(dev);
+
+ writereg(dev, PP_RxCFG, 0);
+ writereg(dev, PP_TxCFG, 0);
+ writereg(dev, PP_BufCFG, 0);
+ writereg(dev, PP_BusCTL, 0);
+
+ free_irq(dev->irq, dev);
+
+#if ALLOW_DMA
+ if (lp->use_dma && lp->dma) {
+ free_dma(dev->dma);
+ release_dma_buff(lp);
+ }
+#endif
+
+ /* Update the statistics here. */
+ return 0;
+}
+
+/* Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+net_get_stats(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ /* Update the statistics from the device registers. */
+ dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+ dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return &dev->stats;
+}
+
static void net_timeout(struct net_device *dev)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict ?" : "network cable problem");
+ cs89_dbg(0, err, "%s: transmit timed out, %s?\n",
+ dev->name,
+ tx_done(dev) ? "IRQ conflict" : "network cable problem");
/* Try to restart the adaptor. */
netif_wake_queue(dev);
}
-static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
+static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
unsigned long flags;
- if (net_debug > 3) {
- printk("%s: sent %d byte packet of type %x\n",
- dev->name, skb->len,
- (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
- }
+ cs89_dbg(3, debug, "%s: sent %d byte packet of type %x\n",
+ dev->name, skb->len,
+ ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
+ skb->data[ETH_ALEN + ETH_ALEN + 1]));
/* keep the upload from being interrupted, since we
- ask the chip to start transmitting before the
- whole packet has been completely uploaded. */
+ * ask the chip to start transmitting before the
+ * whole packet has been completely uploaded.
+ */
spin_lock_irqsave(&lp->lock, flags);
netif_stop_queue(dev);
/* initiate a transmit sequence */
- writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);
- writeword(dev->base_addr, TX_LEN_PORT, skb->len);
+ iowrite16(lp->send_cmd, lp->virt_addr + TX_CMD_PORT);
+ iowrite16(skb->len, lp->virt_addr + TX_LEN_PORT);
/* Test to see if the chip has allocated memory for the packet */
if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
- /*
- * Gasp! It hasn't. But that shouldn't happen since
+ /* Gasp! It hasn't. But that shouldn't happen since
* we're waiting for TxOk, so return 1 and requeue this packet.
*/
spin_unlock_irqrestore(&lp->lock, flags);
- if (net_debug) printk("cs89x0: Tx buffer not free!\n");
+ cs89_dbg(0, err, "Tx buffer not free!\n");
return NETDEV_TX_BUSY;
}
/* Write the contents of the packet */
- writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+ writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1);
spin_unlock_irqrestore(&lp->lock, flags);
dev->stats.tx_bytes += skb->len;
- dev_kfree_skb (skb);
+ dev_kfree_skb(skb);
- /*
- * We DO NOT call netif_wake_queue() here.
+ /* We DO NOT call netif_wake_queue() here.
* We also DO NOT call netif_start_queue().
*
* Either of these would cause another bottom half run through
- * net_send_packet() before this packet has fully gone out. That causes
- * us to hit the "Gasp!" above and the send is rescheduled. it runs like
- * a dog. We just return and wait for the Tx completion interrupt handler
- * to restart the netdevice layer
+ * net_send_packet() before this packet has fully gone out.
+ * That causes us to hit the "Gasp!" above and the send is rescheduled.
+ * it runs like a dog. We just return and wait for the Tx completion
+ * interrupt handler to restart the netdevice layer
*/
return NETDEV_TX_OK;
}
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
+static void set_multicast_list(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+ unsigned long flags;
-static irqreturn_t net_interrupt(int irq, void *dev_id)
+ spin_lock_irqsave(&lp->lock, flags);
+ if (dev->flags & IFF_PROMISC)
+ lp->rx_mode = RX_ALL_ACCEPT;
+ else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
+ /* The multicast-accept list is initialized to accept-all,
+ * and we rely on higher-level filtering for now.
+ */
+ lp->rx_mode = RX_MULTCAST_ACCEPT;
+ else
+ lp->rx_mode = 0;
+
+ writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+ /* in promiscuous mode, we accept errored packets,
+ * so we have to enable interrupts on them also
+ */
+ writereg(dev, PP_RxCFG,
+ (lp->curr_rx_cfg |
+ (lp->rx_mode == RX_ALL_ACCEPT)
+ ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
+ : 0));
+ spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static int set_mac_address(struct net_device *dev, void *p)
{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr, status;
- int handled = 0;
+ int i;
+ struct sockaddr *addr = p;
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
+ if (netif_running(dev))
+ return -EBUSY;
- /* we MUST read all the events out of the ISQ, otherwise we'll never
- get interrupted again. As a consequence, we can't have any limit
- on the number of times we loop in the interrupt handler. The
- hardware guarantees that eventually we'll run out of events. Of
- course, if you're on a slow machine, and packets are arriving
- faster than you can read them off, you're screwed. Hasta la
- vista, baby! */
- while ((status = readword(dev->base_addr, ISQ_PORT))) {
- if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
- handled = 1;
- switch(status & ISQ_EVENT_MASK) {
- case ISQ_RECEIVER_EVENT:
- /* Got a packet(s). */
- net_rx(dev);
- break;
- case ISQ_TRANSMITTER_EVENT:
- dev->stats.tx_packets++;
- netif_wake_queue(dev); /* Inform upper layers. */
- if ((status & ( TX_OK |
- TX_LOST_CRS |
- TX_SQE_ERROR |
- TX_LATE_COL |
- TX_16_COL)) != TX_OK) {
- if ((status & TX_OK) == 0)
- dev->stats.tx_errors++;
- if (status & TX_LOST_CRS)
- dev->stats.tx_carrier_errors++;
- if (status & TX_SQE_ERROR)
- dev->stats.tx_heartbeat_errors++;
- if (status & TX_LATE_COL)
- dev->stats.tx_window_errors++;
- if (status & TX_16_COL)
- dev->stats.tx_aborted_errors++;
- }
- break;
- case ISQ_BUFFER_EVENT:
- if (status & READY_FOR_TX) {
- /* we tried to transmit a packet earlier,
- but inexplicably ran out of buffers.
- That shouldn't happen since we only ever
- load one packet. Shrug. Do the right
- thing anyway. */
- netif_wake_queue(dev); /* Inform upper layers. */
- }
- if (status & TX_UNDERRUN) {
- if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
- lp->send_underrun++;
- if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
- else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
- /* transmit cycle is done, although
- frame wasn't transmitted - this
- avoids having to wait for the upper
- layers to timeout on us, in the
- event of a tx underrun */
- netif_wake_queue(dev); /* Inform upper layers. */
- }
-#if ALLOW_DMA
- if (lp->use_dma && (status & RX_DMA)) {
- int count = readreg(dev, PP_DmaFrameCnt);
- while(count) {
- if (net_debug > 5)
- printk("%s: receiving %d DMA frames\n", dev->name, count);
- if (net_debug > 2 && count >1)
- printk("%s: receiving %d DMA frames\n", dev->name, count);
- dma_rx(dev);
- if (--count == 0)
- count = readreg(dev, PP_DmaFrameCnt);
- if (net_debug > 2 && count > 0)
- printk("%s: continuing with %d DMA frames\n", dev->name, count);
- }
- }
-#endif
- break;
- case ISQ_RX_MISS_EVENT:
- dev->stats.rx_missed_errors += (status >> 6);
- break;
- case ISQ_TX_COL_EVENT:
- dev->stats.collisions += (status >> 6);
- break;
- }
- }
- return IRQ_RETVAL(handled);
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ cs89_dbg(0, debug, "%s: Setting MAC address to %pM\n",
+ dev->name, dev->dev_addr);
+
+ /* set the Ethernet address */
+ for (i = 0; i < ETH_ALEN / 2; i++)
+ writereg(dev, PP_IA + i * 2,
+ (dev->dev_addr[i * 2] |
+ (dev->dev_addr[i * 2 + 1] << 8)));
+
+ return 0;
}
-static void
-count_rx_errors(int status, struct net_device *dev)
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void net_poll_controller(struct net_device *dev)
{
- dev->stats.rx_errors++;
- if (status & RX_RUNT)
- dev->stats.rx_length_errors++;
- if (status & RX_EXTRA_DATA)
- dev->stats.rx_length_errors++;
- if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA|RX_RUNT)))
- /* per str 172 */
- dev->stats.rx_crc_errors++;
- if (status & RX_DRIBBLE)
- dev->stats.rx_frame_errors++;
+ disable_irq(dev->irq);
+ net_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
}
+#endif
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
+static const struct net_device_ops net_ops = {
+ .ndo_open = net_open,
+ .ndo_stop = net_close,
+ .ndo_tx_timeout = net_timeout,
+ .ndo_start_xmit = net_send_packet,
+ .ndo_get_stats = net_get_stats,
+ .ndo_set_rx_mode = set_multicast_list,
+ .ndo_set_mac_address = set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = net_poll_controller,
+#endif
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static void __init reset_chip(struct net_device *dev)
{
- struct sk_buff *skb;
- int status, length;
+#if !defined(CONFIG_MACH_MX31ADS)
+#if !defined(CS89x0_NONISA_IRQ)
+ struct net_local *lp = netdev_priv(dev);
+#endif /* CS89x0_NONISA_IRQ */
+ int reset_start_time;
- int ioaddr = dev->base_addr;
- status = readword(ioaddr, RX_FRAME_PORT);
- length = readword(ioaddr, RX_FRAME_PORT);
+ writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
- if ((status & RX_OK) == 0) {
- count_rx_errors(status, dev);
- return;
+ /* wait 30 ms */
+ msleep(30);
+
+#if !defined(CS89x0_NONISA_IRQ)
+ if (lp->chip_type != CS8900) {
+ /* Hardware problem requires PNP registers to be reconfigured after a reset */
+ iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT);
+ iowrite8(dev->irq, lp->virt_addr + DATA_PORT);
+ iowrite8(0, lp->virt_addr + DATA_PORT + 1);
+
+ iowrite16(PP_CS8920_ISAMemB, lp->virt_addr + ADD_PORT);
+ iowrite8((dev->mem_start >> 16) & 0xff,
+ lp->virt_addr + DATA_PORT);
+ iowrite8((dev->mem_start >> 8) & 0xff,
+ lp->virt_addr + DATA_PORT + 1);
}
+#endif /* CS89x0_NONISA_IRQ */
- /* Malloc up new buffer. */
- skb = netdev_alloc_skb(dev, length + 2);
- if (skb == NULL) {
-#if 0 /* Again, this seems a cruel thing to do */
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ /* Wait until the chip is reset */
+ reset_start_time = jiffies;
+ while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 &&
+ jiffies - reset_start_time < 2)
+ ;
+#endif /* !CONFIG_MACH_MX31ADS */
+}
+
+/* This is the real probe routine.
+ * Linux has a history of friendly device probes on the ISA bus.
+ * A good device probes avoids doing writes, and
+ * verifies that the correct device exists and functions.
+ * Return 0 on success.
+ */
+static int __init
+cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
+{
+ struct net_local *lp = netdev_priv(dev);
+ int i;
+ int tmp;
+ unsigned rev_type = 0;
+ int eeprom_buff[CHKSUM_LEN];
+ int retval;
+
+ /* Initialize the device structure. */
+ if (!modular) {
+ memset(lp, 0, sizeof(*lp));
+ spin_lock_init(&lp->lock);
+#ifndef MODULE
+#if ALLOW_DMA
+ if (g_cs89x0_dma) {
+ lp->use_dma = 1;
+ lp->dma = g_cs89x0_dma;
+ lp->dmasize = 16; /* Could make this an option... */
+ }
+#endif
+ lp->force = g_cs89x0_media__force;
#endif
- dev->stats.rx_dropped++;
- return;
}
- skb_reserve(skb, 2); /* longword align L3 header */
- readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
- if (length & 1)
- skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT);
+ pr_debug("PP_addr at %p[%x]: 0x%x\n",
+ ioaddr, ADD_PORT, ioread16(ioaddr + ADD_PORT));
+ iowrite16(PP_ChipID, ioaddr + ADD_PORT);
- if (net_debug > 3) {
- printk( "%s: received %d byte packet of type %x\n",
- dev->name, length,
- (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+ tmp = ioread16(ioaddr + DATA_PORT);
+ if (tmp != CHIP_EISA_ID_SIG) {
+ pr_debug("%s: incorrect signature at %p[%x]: 0x%x!="
+ CHIP_EISA_ID_SIG_STR "\n",
+ dev->name, ioaddr, DATA_PORT, tmp);
+ retval = -ENODEV;
+ goto out1;
}
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += length;
-}
+ lp->virt_addr = ioaddr;
-#if ALLOW_DMA
-static void release_dma_buff(struct net_local *lp)
-{
- if (lp->dma_buff) {
- free_pages((unsigned long)(lp->dma_buff), get_order(lp->dmasize * 1024));
- lp->dma_buff = NULL;
+ /* get the chip type */
+ rev_type = readreg(dev, PRODUCT_ID_ADD);
+ lp->chip_type = rev_type & ~REVISON_BITS;
+ lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+
+ /* Check the chip type and revision in order to set the correct
+ * send command. CS8920 revision C and CS8900 revision F can use
+ * the faster send.
+ */
+ lp->send_cmd = TX_AFTER_381;
+ if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
+ lp->send_cmd = TX_NOW;
+ if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
+ lp->send_cmd = TX_NOW;
+
+ pr_info_once("%s\n", version);
+
+ pr_info("%s: cs89%c0%s rev %c found at %p ",
+ dev->name,
+ lp->chip_type == CS8900 ? '0' : '2',
+ lp->chip_type == CS8920M ? "M" : "",
+ lp->chip_revision,
+ lp->virt_addr);
+
+ reset_chip(dev);
+
+ /* Here we read the current configuration of the chip.
+ * If there is no Extended EEPROM then the idea is to not disturb
+ * the chip configuration, it should have been correctly setup by
+ * automatic EEPROM read on reset. So, if the chip says it read
+ * the EEPROM the driver will always do *something* instead of
+ * complain that adapter_cnf is 0.
+ */
+
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
+ (EEPROM_OK | EEPROM_PRESENT)) {
+ /* Load the MAC. */
+ for (i = 0; i < ETH_ALEN / 2; i++) {
+ unsigned int Addr;
+ Addr = readreg(dev, PP_IA + i * 2);
+ dev->dev_addr[i * 2] = Addr & 0xFF;
+ dev->dev_addr[i * 2 + 1] = Addr >> 8;
+ }
+
+ /* Load the Adapter Configuration.
+ * Note: Barring any more specific information from some
+ * other source (ie EEPROM+Schematics), we would not know
+ * how to operate a 10Base2 interface on the AUI port.
+ * However, since we do read the status of HCB1 and use
+ * settings that always result in calls to control_dc_dc(dev,0)
+ * a BNC interface should work if the enable pin
+ * (dc/dc converter) is on HCB1.
+ * It will be called AUI however.
+ */
+
+ lp->adapter_cnf = 0;
+ i = readreg(dev, PP_LineCTL);
+ /* Preserve the setting of the HCB1 pin. */
+ if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
+ lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
+ /* Save the sqelch bit */
+ if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
+ lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
+ /* Check if the card is in 10Base-t only mode */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
+ lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T;
+ /* Check if the card is in AUI only mode */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
+ /* Check if the card is in Auto mode. */
+ if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
+ A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
+
+ cs89_dbg(1, info, "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
+ dev->name, i, lp->adapter_cnf);
+
+ /* IRQ. Other chips already probe, see below. */
+ if (lp->chip_type == CS8900)
+ lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
+
+ pr_cont("[Cirrus EEPROM] ");
}
-}
-#endif
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
-#if ALLOW_DMA
- struct net_local *lp = netdev_priv(dev);
-#endif
+ pr_cont("\n");
- netif_stop_queue(dev);
+ /* First check to see if an EEPROM is attached. */
- writereg(dev, PP_RxCFG, 0);
- writereg(dev, PP_TxCFG, 0);
- writereg(dev, PP_BufCFG, 0);
- writereg(dev, PP_BusCTL, 0);
+ if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
+ pr_warn("No EEPROM, relying on command line....\n");
+ else if (get_eeprom_data(dev, START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
+ pr_warn("EEPROM read failed, relying on command line\n");
+ } else if (get_eeprom_cksum(START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
+ /* Check if the chip was able to read its own configuration starting
+ at 0 in the EEPROM*/
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
+ (EEPROM_OK | EEPROM_PRESENT))
+ pr_warn("Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
- free_irq(dev->irq, dev);
+ } else {
+ /* This reads an extended EEPROM that is not documented
+ * in the CS8900 datasheet.
+ */
-#if ALLOW_DMA
- if (lp->use_dma && lp->dma) {
- free_dma(dev->dma);
- release_dma_buff(lp);
+ /* get transmission control word but keep the autonegotiation bits */
+ if (!lp->auto_neg_cnf)
+ lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET / 2];
+ /* Store adapter configuration */
+ if (!lp->adapter_cnf)
+ lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET / 2];
+ /* Store ISA configuration */
+ lp->isa_config = eeprom_buff[ISA_CNF_OFFSET / 2];
+ dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET / 2] << 8;
+
+ /* eeprom_buff has 32-bit ints, so we can't just memcpy it */
+ /* store the initial memory base address */
+ for (i = 0; i < ETH_ALEN / 2; i++) {
+ dev->dev_addr[i * 2] = eeprom_buff[i];
+ dev->dev_addr[i * 2 + 1] = eeprom_buff[i] >> 8;
+ }
+ cs89_dbg(1, debug, "%s: new adapter_cnf: 0x%x\n",
+ dev->name, lp->adapter_cnf);
}
+
+ /* allow them to force multiple transceivers. If they force multiple, autosense */
+ {
+ int count = 0;
+ if (lp->force & FORCE_RJ45) {
+ lp->adapter_cnf |= A_CNF_10B_T;
+ count++;
+ }
+ if (lp->force & FORCE_AUI) {
+ lp->adapter_cnf |= A_CNF_AUI;
+ count++;
+ }
+ if (lp->force & FORCE_BNC) {
+ lp->adapter_cnf |= A_CNF_10B_2;
+ count++;
+ }
+ if (count > 1)
+ lp->adapter_cnf |= A_CNF_MEDIA_AUTO;
+ else if (lp->force & FORCE_RJ45)
+ lp->adapter_cnf |= A_CNF_MEDIA_10B_T;
+ else if (lp->force & FORCE_AUI)
+ lp->adapter_cnf |= A_CNF_MEDIA_AUI;
+ else if (lp->force & FORCE_BNC)
+ lp->adapter_cnf |= A_CNF_MEDIA_10B_2;
+ }
+
+ cs89_dbg(1, debug, "%s: after force 0x%x, adapter_cnf=0x%x\n",
+ dev->name, lp->force, lp->adapter_cnf);
+
+ /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
+
+ /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
+
+ /* FIXME: we don't set the Ethernet address on the command line. Use
+ * ifconfig IFACE hw ether AABBCCDDEEFF
+ */
+
+ pr_info("media %s%s%s",
+ (lp->adapter_cnf & A_CNF_10B_T) ? "RJ-45," : "",
+ (lp->adapter_cnf & A_CNF_AUI) ? "AUI," : "",
+ (lp->adapter_cnf & A_CNF_10B_2) ? "BNC," : "");
+
+ lp->irq_map = 0xffff;
+
+ /* If this is a CS8900 then no pnp soft */
+ if (lp->chip_type != CS8900 &&
+ /* Check if the ISA IRQ has been set */
+ (i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
+ (i != 0 && i < CS8920_NO_INTS))) {
+ if (!dev->irq)
+ dev->irq = i;
+ } else {
+ i = lp->isa_config & INT_NO_MASK;
+#ifndef CONFIG_CS89x0_PLATFORM
+ if (lp->chip_type == CS8900) {
+#ifdef CS89x0_NONISA_IRQ
+ i = cs8900_irq_map[0];
+#else
+ /* Translate the IRQ using the IRQ mapping table. */
+ if (i >= ARRAY_SIZE(cs8900_irq_map))
+ pr_err("invalid ISA interrupt number %d\n", i);
+ else
+ i = cs8900_irq_map[i];
+
+ lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
+ } else {
+ int irq_map_buff[IRQ_MAP_LEN/2];
+
+ if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
+ IRQ_MAP_LEN / 2,
+ irq_map_buff) >= 0) {
+ if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
+ lp->irq_map = ((irq_map_buff[0] >> 8) |
+ (irq_map_buff[1] << 8));
+ }
#endif
+ }
+#endif
+ if (!dev->irq)
+ dev->irq = i;
+ }
- /* Update the statistics here. */
- return 0;
-}
+ pr_cont(" IRQ %d", dev->irq);
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
+#if ALLOW_DMA
+ if (lp->use_dma) {
+ get_dma_channel(dev);
+ pr_cont(", DMA %d", dev->dma);
+ } else
+#endif
+ pr_cont(", programmed I/O");
- spin_lock_irqsave(&lp->lock, flags);
- /* Update the statistics from the device registers. */
- dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
- dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* print the ethernet address. */
+ pr_cont(", MAC %pM\n", dev->dev_addr);
- return &dev->stats;
+ dev->netdev_ops = &net_ops;
+ dev->watchdog_timeo = HZ;
+
+ cs89_dbg(0, info, "cs89x0_probe1() successful\n");
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out2;
+ return 0;
+out2:
+ iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
+out1:
+ return retval;
}
-static void set_multicast_list(struct net_device *dev)
+#ifndef CONFIG_CS89x0_PLATFORM
+/*
+ * This function converts the I/O port addres used by the cs89x0_probe() and
+ * init_module() functions to the I/O memory address used by the
+ * cs89x0_probe1() function.
+ */
+static int __init
+cs89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modular)
{
struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
+ int ret;
+ void __iomem *io_mem;
- spin_lock_irqsave(&lp->lock, flags);
- if(dev->flags&IFF_PROMISC)
- {
- lp->rx_mode = RX_ALL_ACCEPT;
+ if (!lp)
+ return -ENOMEM;
+
+ dev->base_addr = ioport;
+
+ if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) {
+ ret = -EBUSY;
+ goto out;
}
- else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
- {
- /* The multicast-accept list is initialized to accept-all, and we
- rely on higher-level filtering for now. */
- lp->rx_mode = RX_MULTCAST_ACCEPT;
+
+ io_mem = ioport_map(ioport & ~3, NETCARD_IO_EXTENT);
+ if (!io_mem) {
+ ret = -ENOMEM;
+ goto release;
}
- else
- lp->rx_mode = 0;
- writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+ /* if they give us an odd I/O address, then do ONE write to
+ * the address port, to get it back to address zero, where we
+ * expect to find the EISA signature word. An IO with a base of 0x3
+ * will skip the test for the ADD_PORT.
+ */
+ if (ioport & 1) {
+ cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport);
+ if ((ioport & 2) != 2) {
+ if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) !=
+ ADD_SIG) {
+ pr_err("%s: bad signature 0x%x\n",
+ dev->name, ioread16(io_mem + ADD_PORT));
+ ret = -ENODEV;
+ goto unmap;
+ }
+ }
+ }
- /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
- writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
- (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
- spin_unlock_irqrestore(&lp->lock, flags);
+ ret = cs89x0_probe1(dev, io_mem, modular);
+ if (!ret)
+ goto out;
+unmap:
+ ioport_unmap(io_mem);
+release:
+ release_region(ioport, NETCARD_IO_EXTENT);
+out:
+ return ret;
}
+#ifndef MODULE
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ * Return 0 on success.
+ */
-static int set_mac_address(struct net_device *dev, void *p)
+struct net_device * __init cs89x0_probe(int unit)
{
- int i;
- struct sockaddr *addr = p;
-
- if (netif_running(dev))
- return -EBUSY;
+ struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+ unsigned *port;
+ int err = 0;
+ int irq;
+ int io;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
- if (net_debug)
- printk("%s: Setting MAC address to %pM.\n",
- dev->name, dev->dev_addr);
+ sprintf(dev->name, "eth%d", unit);
+ netdev_boot_setup_check(dev);
+ io = dev->base_addr;
+ irq = dev->irq;
- /* set the Ethernet address */
- for (i=0; i < ETH_ALEN/2; i++)
- writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+ cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io);
- return 0;
+ if (io > 0x1ff) { /* Check a single specified location. */
+ err = cs89x0_ioport_probe(dev, io, 0);
+ } else if (io != 0) { /* Don't probe at all. */
+ err = -ENXIO;
+ } else {
+ for (port = netcard_portlist; *port; port++) {
+ if (cs89x0_ioport_probe(dev, *port, 0) == 0)
+ break;
+ dev->irq = irq;
+ }
+ if (!*port)
+ err = -ENODEV;
+ }
+ if (err)
+ goto out;
+ return dev;
+out:
+ free_netdev(dev);
+ pr_warn("no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n");
+ return ERR_PTR(err);
}
+#endif
+#endif
#if defined(MODULE) && !defined(CONFIG_CS89x0_PLATFORM)
static struct net_device *dev_cs89x0;
-/*
- * Support the 'debug' module parm even if we're compiled for non-debug to
+/* Support the 'debug' module parm even if we're compiled for non-debug to
* avoid breaking someone's startup scripts
*/
@@ -1764,11 +1755,11 @@ static int io;
static int irq;
static int debug;
static char media[8];
-static int duplex=-1;
+static int duplex = -1;
static int use_dma; /* These generate unused var warnings if ALLOW_DMA = 0 */
static int dma;
-static int dmasize=16; /* or 64 */
+static int dmasize = 16; /* or 64 */
module_param(io, int, 0);
module_param(irq, int, 0);
@@ -1801,32 +1792,28 @@ MODULE_PARM_DESC(use_dma , "(ignored)");
MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton");
MODULE_LICENSE("GPL");
-
/*
-* media=t - specify media type
- or media=2
- or media=aui
- or medai=auto
-* duplex=0 - specify forced half/full/autonegotiate duplex
-* debug=# - debug level
-
-
-* Default Chip Configuration:
- * DMA Burst = enabled
- * IOCHRDY Enabled = enabled
- * UseSA = enabled
- * CS8900 defaults to half-duplex if not specified on command-line
- * CS8920 defaults to autoneg if not specified on command-line
- * Use reset defaults for other config parameters
-
-* Assumptions:
- * media type specified is supported (circuitry is present)
- * if memory address is > 1MB, then required mem decode hw is present
- * if 10B-2, then agent other than driver will enable DC/DC converter
- (hw or software util)
-
-
-*/
+ * media=t - specify media type
+ * or media=2
+ * or media=aui
+ * or medai=auto
+ * duplex=0 - specify forced half/full/autonegotiate duplex
+ * debug=# - debug level
+ *
+ * Default Chip Configuration:
+ * DMA Burst = enabled
+ * IOCHRDY Enabled = enabled
+ * UseSA = enabled
+ * CS8900 defaults to half-duplex if not specified on command-line
+ * CS8920 defaults to autoneg if not specified on command-line
+ * Use reset defaults for other config parameters
+ *
+ * Assumptions:
+ * media type specified is supported (circuitry is present)
+ * if memory address is > 1MB, then required mem decode hw is present
+ * if 10B-2, then agent other than driver will enable DC/DC converter
+ * (hw or software util)
+ */
int __init init_module(void)
{
@@ -1856,8 +1843,8 @@ int __init init_module(void)
spin_lock_init(&lp->lock);
- /* boy, they'd better get these right */
- if (!strcmp(media, "rj45"))
+ /* boy, they'd better get these right */
+ if (!strcmp(media, "rj45"))
lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
else if (!strcmp(media, "aui"))
lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI;
@@ -1866,27 +1853,28 @@ int __init init_module(void)
else
lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
- if (duplex==-1)
+ if (duplex == -1)
lp->auto_neg_cnf = AUTO_NEG_ENABLE;
- if (io == 0) {
- printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");
- printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");
- ret = -EPERM;
+ if (io == 0) {
+ pr_err("Module autoprobing not allowed\n");
+ pr_err("Append io=0xNNN\n");
+ ret = -EPERM;
goto out;
- } else if (io <= 0x1ff) {
+ } else if (io <= 0x1ff) {
ret = -ENXIO;
goto out;
}
#if ALLOW_DMA
if (use_dma && dmasize != 16 && dmasize != 64) {
- printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize);
+ pr_err("dma size must be either 16K or 64K, not %dK\n",
+ dmasize);
ret = -EPERM;
goto out;
}
#endif
- ret = cs89x0_probe1(dev, io, 1);
+ ret = cs89x0_ioport_probe(dev, io, 1);
if (ret)
goto out;
@@ -1900,8 +1888,11 @@ out:
void __exit
cleanup_module(void)
{
+ struct net_local *lp = netdev_priv(dev_cs89x0);
+
unregister_netdev(dev_cs89x0);
- writeword(dev_cs89x0->base_addr, ADD_PORT, PP_ChipID);
+ iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
+ ioport_unmap(lp->virt_addr);
release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
free_netdev(dev_cs89x0);
}
@@ -1913,6 +1904,7 @@ static int __init cs89x0_platform_probe(struct platform_device *pdev)
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
struct net_local *lp;
struct resource *mem_res;
+ void __iomem *virt_addr;
int err;
if (!dev)
@@ -1923,29 +1915,28 @@ static int __init cs89x0_platform_probe(struct platform_device *pdev)
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->irq = platform_get_irq(pdev, 0);
if (mem_res == NULL || dev->irq <= 0) {
- dev_warn(&dev->dev, "memory/interrupt resource missing.\n");
+ dev_warn(&dev->dev, "memory/interrupt resource missing\n");
err = -ENXIO;
goto free;
}
- lp->phys_addr = mem_res->start;
lp->size = resource_size(mem_res);
- if (!request_mem_region(lp->phys_addr, lp->size, DRV_NAME)) {
- dev_warn(&dev->dev, "request_mem_region() failed.\n");
+ if (!request_mem_region(mem_res->start, lp->size, DRV_NAME)) {
+ dev_warn(&dev->dev, "request_mem_region() failed\n");
err = -EBUSY;
goto free;
}
- lp->virt_addr = ioremap(lp->phys_addr, lp->size);
- if (!lp->virt_addr) {
- dev_warn(&dev->dev, "ioremap() failed.\n");
+ virt_addr = ioremap(mem_res->start, lp->size);
+ if (!virt_addr) {
+ dev_warn(&dev->dev, "ioremap() failed\n");
err = -ENOMEM;
goto release;
}
- err = cs89x0_probe1(dev, (unsigned long)lp->virt_addr, 0);
+ err = cs89x0_probe1(dev, virt_addr, 0);
if (err) {
- dev_warn(&dev->dev, "no cs8900 or cs8920 detected.\n");
+ dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n");
goto unmap;
}
@@ -1953,9 +1944,9 @@ static int __init cs89x0_platform_probe(struct platform_device *pdev)
return 0;
unmap:
- iounmap(lp->virt_addr);
+ iounmap(virt_addr);
release:
- release_mem_region(lp->phys_addr, lp->size);
+ release_mem_region(mem_res->start, lp->size);
free:
free_netdev(dev);
return err;
@@ -1965,10 +1956,16 @@ static int cs89x0_platform_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct net_local *lp = netdev_priv(dev);
+ struct resource *mem_res;
+ /* This platform_get_resource() call will not return NULL, because
+ * the same call in cs89x0_platform_probe() has returned a non NULL
+ * value.
+ */
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
unregister_netdev(dev);
iounmap(lp->virt_addr);
- release_mem_region(lp->phys_addr, lp->size);
+ release_mem_region(mem_res->start, lp->size);
free_netdev(dev);
return 0;
}
@@ -1996,13 +1993,3 @@ static void __exit cs89x0_cleanup(void)
module_exit(cs89x0_cleanup);
#endif /* CONFIG_CS89x0_PLATFORM */
-
-/*
- * Local variables:
- * version-control: t
- * kept-new-versions: 5
- * c-indent-level: 8
- * tab-width: 8
- * End:
- *
- */
diff --git a/drivers/net/ethernet/emulex/benet/Makefile b/drivers/net/ethernet/emulex/benet/Makefile
index a60cd80..1a91b27 100644
--- a/drivers/net/ethernet/emulex/benet/Makefile
+++ b/drivers/net/ethernet/emulex/benet/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_BE2NET) += be2net.o
-be2net-y := be_main.o be_cmds.o be_ethtool.o
+be2net-y := be_main.o be_cmds.o be_ethtool.o be_roce.o
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index ecf1a81..c5c4c0e 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -32,6 +32,7 @@
#include <linux/u64_stats_sync.h>
#include "be_hw.h"
+#include "be_roce.h"
#define DRV_VER "4.2.220u"
#define DRV_NAME "be2net"
@@ -102,7 +103,8 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */
#define MAX_TX_QS 8
-#define MAX_MSIX_VECTORS MAX_RSS_QS
+#define MAX_ROCE_EQS 5
+#define MAX_MSIX_VECTORS (MAX_RSS_QS + MAX_ROCE_EQS) /* RSS qs + RoCE */
#define BE_TX_BUDGET 256
#define BE_NAPI_WEIGHT 64
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
@@ -405,6 +407,17 @@ struct be_adapter {
u32 tx_fc; /* Tx flow control */
bool stats_cmd_sent;
u8 generation; /* BladeEngine ASIC generation */
+ u32 if_type;
+ struct {
+ u8 __iomem *base; /* Door Bell */
+ u32 size;
+ u32 total_size;
+ u64 io_addr;
+ } roce_db;
+ u32 num_msix_roce_vec;
+ struct ocrdma_dev *ocrdma_dev;
+ struct list_head entry;
+
u32 flash_status;
struct completion flash_compl;
@@ -421,6 +434,7 @@ struct be_adapter {
bool wol;
u32 max_pmac_cnt; /* Max secondary UC MACs programmable */
u32 uc_macs; /* Count of secondary UC MAC programmed */
+ u32 msg_enable;
};
#define be_physfn(adapter) (!adapter->virtfn)
@@ -440,6 +454,10 @@ struct be_adapter {
#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \
(adapter->pdev->device == OC_DEVICE_ID4))
+#define be_roce_supported(adapter) ((adapter->if_type == SLI_INTF_TYPE_3 || \
+ adapter->sli_family == SKYHAWK_SLI_FAMILY) && \
+ (adapter->function_mode & RDMA_ENABLED))
+
extern const struct ethtool_ops be_ethtool_ops;
#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
@@ -596,6 +614,12 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter)
}
}
+static inline bool be_type_2_3(struct be_adapter *adapter)
+{
+ return (adapter->if_type == SLI_INTF_TYPE_2 ||
+ adapter->if_type == SLI_INTF_TYPE_3) ? true : false;
+}
+
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, u8 link_status);
@@ -603,4 +627,18 @@ extern void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func);
extern bool be_is_wol_supported(struct be_adapter *adapter);
extern bool be_pause_supported(struct be_adapter *adapter);
+extern u32 be_get_fw_log_level(struct be_adapter *adapter);
+
+/*
+ * internal function to initialize-cleanup roce device.
+ */
+extern void be_roce_dev_add(struct be_adapter *);
+extern void be_roce_dev_remove(struct be_adapter *);
+
+/*
+ * internal function to open-close roce device during ifup-ifdown.
+ */
+extern void be_roce_dev_open(struct be_adapter *);
+extern void be_roce_dev_close(struct be_adapter *);
+
#endif /* BE_H */
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 43167e8..8d06ea3 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -15,6 +15,7 @@
* Costa Mesa, CA 92626
*/
+#include <linux/module.h>
#include "be.h"
#include "be_cmds.h"
@@ -2589,4 +2590,98 @@ err:
mutex_unlock(&adapter->mbox_lock);
pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
return status;
+
+}
+int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter,
+ struct be_dma_mem *cmd)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_ext_fat_caps *req;
+ int status;
+
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = cmd->va;
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_EXT_FAT_CAPABILITES,
+ cmd->size, wrb, cmd);
+ req->parameter_type = cpu_to_le32(1);
+
+ status = be_mbox_notify_wait(adapter);
+err:
+ mutex_unlock(&adapter->mbox_lock);
+ return status;
+}
+
+int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
+ struct be_dma_mem *cmd,
+ struct be_fat_conf_params *configs)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_set_ext_fat_caps *req;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = cmd->va;
+ memcpy(&req->set_params, configs, sizeof(struct be_fat_conf_params));
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_EXT_FAT_CAPABILITES,
+ cmd->size, wrb, cmd);
+
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
+ int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
+{
+ struct be_adapter *adapter = netdev_priv(netdev_handle);
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *) wrb_payload;
+ struct be_cmd_req_hdr *req;
+ struct be_cmd_resp_hdr *resp;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = embedded_payload(wrb);
+ resp = embedded_payload(wrb);
+
+ be_wrb_cmd_hdr_prepare(req, hdr->subsystem,
+ hdr->opcode, wrb_payload_size, wrb, NULL);
+ memcpy(req, wrb_payload, wrb_payload_size);
+ be_dws_cpu_to_le(req, wrb_payload_size);
+
+ status = be_mcc_notify_wait(adapter);
+ if (cmd_status)
+ *cmd_status = (status & 0xffff);
+ if (ext_status)
+ *ext_status = 0;
+ memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length);
+ be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
}
+EXPORT_SYMBOL(be_roce_mcc_cmd);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 944f031..9625bf4 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -189,6 +189,8 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_GET_PHY_DETAILS 102
#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103
#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
+#define OPCODE_COMMON_GET_EXT_FAT_CAPABILITES 125
+#define OPCODE_COMMON_SET_EXT_FAT_CAPABILITES 126
#define OPCODE_COMMON_GET_MAC_LIST 147
#define OPCODE_COMMON_SET_MAC_LIST 148
#define OPCODE_COMMON_GET_HSW_CONFIG 152
@@ -1060,6 +1062,7 @@ struct be_cmd_resp_modify_eq_delay {
/* The HW can come up in either of the following multi-channel modes
* based on the skew/IPL.
*/
+#define RDMA_ENABLED 0x4
#define FLEX10_MODE 0x400
#define VNIC_MODE 0x20000
#define UMC_ENABLED 0x1000000
@@ -1602,6 +1605,56 @@ static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter)
}
}
+
+/************** get fat capabilites *******************/
+#define MAX_MODULES 27
+#define MAX_MODES 4
+#define MODE_UART 0
+#define FW_LOG_LEVEL_DEFAULT 48
+#define FW_LOG_LEVEL_FATAL 64
+
+struct ext_fat_mode {
+ u8 mode;
+ u8 rsvd0;
+ u16 port_mask;
+ u32 dbg_lvl;
+ u64 fun_mask;
+} __packed;
+
+struct ext_fat_modules {
+ u8 modules_str[32];
+ u32 modules_id;
+ u32 num_modes;
+ struct ext_fat_mode trace_lvl[MAX_MODES];
+} __packed;
+
+struct be_fat_conf_params {
+ u32 max_log_entries;
+ u32 log_entry_size;
+ u8 log_type;
+ u8 max_log_funs;
+ u8 max_log_ports;
+ u8 rsvd0;
+ u32 supp_modes;
+ u32 num_modules;
+ struct ext_fat_modules module[MAX_MODULES];
+} __packed;
+
+struct be_cmd_req_get_ext_fat_caps {
+ struct be_cmd_req_hdr hdr;
+ u32 parameter_type;
+};
+
+struct be_cmd_resp_get_ext_fat_caps {
+ struct be_cmd_resp_hdr hdr;
+ struct be_fat_conf_params get_params;
+};
+
+struct be_cmd_req_set_ext_fat_caps {
+ struct be_cmd_req_hdr hdr;
+ struct be_fat_conf_params set_params;
+};
+
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_cmd_POST(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -1707,4 +1760,9 @@ extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
u32 domain, u16 intf_id);
extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter);
+extern int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter,
+ struct be_dma_mem *cmd);
+extern int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
+ struct be_dma_mem *cmd,
+ struct be_fat_conf_params *cfgs);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 747f68f..63e51d4 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -878,6 +878,81 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
return status;
}
+static u32 be_get_msg_level(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (lancer_chip(adapter)) {
+ dev_err(&adapter->pdev->dev, "Operation not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ return adapter->msg_enable;
+}
+
+static void be_set_fw_log_level(struct be_adapter *adapter, u32 level)
+{
+ struct be_dma_mem extfat_cmd;
+ struct be_fat_conf_params *cfgs;
+ int status;
+ int i, j;
+
+ memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
+ extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
+ extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
+ &extfat_cmd.dma);
+ if (!extfat_cmd.va) {
+ dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
+ __func__);
+ goto err;
+ }
+ status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
+ if (!status) {
+ cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
+ sizeof(struct be_cmd_resp_hdr));
+ for (i = 0; i < cfgs->num_modules; i++) {
+ for (j = 0; j < cfgs->module[i].num_modes; j++) {
+ if (cfgs->module[i].trace_lvl[j].mode ==
+ MODE_UART)
+ cfgs->module[i].trace_lvl[j].dbg_lvl =
+ cpu_to_le32(level);
+ }
+ }
+ status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd,
+ cfgs);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Message level set failed\n");
+ } else {
+ dev_err(&adapter->pdev->dev, "Message level get failed\n");
+ }
+
+ pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
+ extfat_cmd.dma);
+err:
+ return;
+}
+
+static void be_set_msg_level(struct net_device *netdev, u32 level)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (lancer_chip(adapter)) {
+ dev_err(&adapter->pdev->dev, "Operation not supported\n");
+ return;
+ }
+
+ if (adapter->msg_enable == level)
+ return;
+
+ if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW))
+ be_set_fw_log_level(adapter, level & NETIF_MSG_HW ?
+ FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL);
+ adapter->msg_enable = level;
+
+ return;
+}
+
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
@@ -893,6 +968,8 @@ const struct ethtool_ops be_ethtool_ops = {
.set_pauseparam = be_set_pauseparam,
.get_strings = be_get_stat_strings,
.set_phys_id = be_set_phys_id,
+ .get_msglevel = be_get_msg_level,
+ .set_msglevel = be_set_msg_level,
.get_sset_count = be_get_sset_count,
.get_ethtool_stats = be_get_ethtool_stats,
.get_regs_len = be_get_reg_len,
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index f38b58c8..d9fb0c5 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -100,11 +100,13 @@
#define SLI_INTF_REV_SHIFT 4
#define SLI_INTF_FT_MASK 0x00000001
+#define SLI_INTF_TYPE_2 2
+#define SLI_INTF_TYPE_3 3
/* SLI family */
#define BE_SLI_FAMILY 0x0
#define LANCER_A0_SLI_FAMILY 0xA
-
+#define SKYHAWK_SLI_FAMILY 0x2
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index a01f734..08efd30 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2151,10 +2151,17 @@ static uint be_num_rss_want(struct be_adapter *adapter)
static void be_msix_enable(struct be_adapter *adapter)
{
#define BE_MIN_MSIX_VECTORS 1
- int i, status, num_vec;
+ int i, status, num_vec, num_roce_vec = 0;
/* If RSS queues are not used, need a vec for default RX Q */
num_vec = min(be_num_rss_want(adapter), num_online_cpus());
+ if (be_roce_supported(adapter)) {
+ num_roce_vec = min_t(u32, MAX_ROCE_MSIX_VECTORS,
+ (num_online_cpus() + 1));
+ num_roce_vec = min(num_roce_vec, MAX_ROCE_EQS);
+ num_vec += num_roce_vec;
+ num_vec = min(num_vec, MAX_MSIX_VECTORS);
+ }
num_vec = max(num_vec, BE_MIN_MSIX_VECTORS);
for (i = 0; i < num_vec; i++)
@@ -2171,7 +2178,17 @@ static void be_msix_enable(struct be_adapter *adapter)
}
return;
done:
- adapter->num_msix_vec = num_vec;
+ if (be_roce_supported(adapter)) {
+ if (num_vec > num_roce_vec) {
+ adapter->num_msix_vec = num_vec - num_roce_vec;
+ adapter->num_msix_roce_vec =
+ num_vec - adapter->num_msix_vec;
+ } else {
+ adapter->num_msix_vec = num_vec;
+ adapter->num_msix_roce_vec = 0;
+ }
+ } else
+ adapter->num_msix_vec = num_vec;
return;
}
@@ -2283,6 +2300,8 @@ static int be_close(struct net_device *netdev)
struct be_eq_obj *eqo;
int i;
+ be_roce_dev_close(adapter);
+
be_async_mcc_disable(adapter);
if (!lancer_chip(adapter))
@@ -2391,6 +2410,7 @@ static int be_open(struct net_device *netdev)
if (!status)
be_link_status_update(adapter, link_status);
+ be_roce_dev_open(adapter);
return 0;
err:
be_close(adapter->netdev);
@@ -3232,6 +3252,24 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
iounmap(adapter->csr);
if (adapter->db)
iounmap(adapter->db);
+ if (adapter->roce_db.base)
+ pci_iounmap(adapter->pdev, adapter->roce_db.base);
+}
+
+static int lancer_roce_map_pci_bars(struct be_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ u8 __iomem *addr;
+
+ addr = pci_iomap(pdev, 2, 0);
+ if (addr == NULL)
+ return -ENOMEM;
+
+ adapter->roce_db.base = addr;
+ adapter->roce_db.io_addr = pci_resource_start(pdev, 2);
+ adapter->roce_db.size = 8192;
+ adapter->roce_db.total_size = pci_resource_len(pdev, 2);
+ return 0;
}
static int be_map_pci_bars(struct be_adapter *adapter)
@@ -3240,11 +3278,18 @@ static int be_map_pci_bars(struct be_adapter *adapter)
int db_reg;
if (lancer_chip(adapter)) {
- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0),
- pci_resource_len(adapter->pdev, 0));
- if (addr == NULL)
- return -ENOMEM;
- adapter->db = addr;
+ if (be_type_2_3(adapter)) {
+ addr = ioremap_nocache(
+ pci_resource_start(adapter->pdev, 0),
+ pci_resource_len(adapter->pdev, 0));
+ if (addr == NULL)
+ return -ENOMEM;
+ adapter->db = addr;
+ }
+ if (adapter->if_type == SLI_INTF_TYPE_3) {
+ if (lancer_roce_map_pci_bars(adapter))
+ goto pci_map_err;
+ }
return 0;
}
@@ -3269,14 +3314,19 @@ static int be_map_pci_bars(struct be_adapter *adapter)
if (addr == NULL)
goto pci_map_err;
adapter->db = addr;
-
+ if (adapter->sli_family == SKYHAWK_SLI_FAMILY) {
+ adapter->roce_db.size = 4096;
+ adapter->roce_db.io_addr =
+ pci_resource_start(adapter->pdev, db_reg);
+ adapter->roce_db.total_size =
+ pci_resource_len(adapter->pdev, db_reg);
+ }
return 0;
pci_map_err:
be_unmap_pci_bars(adapter);
return -ENOMEM;
}
-
static void be_ctrl_cleanup(struct be_adapter *adapter)
{
struct be_dma_mem *mem = &adapter->mbox_mem_alloced;
@@ -3382,6 +3432,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
if (!adapter)
return;
+ be_roce_dev_remove(adapter);
+
unregister_netdev(adapter->netdev);
be_clear(adapter);
@@ -3403,9 +3455,43 @@ bool be_is_wol_supported(struct be_adapter *adapter)
!be_is_wol_excluded(adapter)) ? true : false;
}
+u32 be_get_fw_log_level(struct be_adapter *adapter)
+{
+ struct be_dma_mem extfat_cmd;
+ struct be_fat_conf_params *cfgs;
+ int status;
+ u32 level = 0;
+ int j;
+
+ memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
+ extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
+ extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
+ &extfat_cmd.dma);
+
+ if (!extfat_cmd.va) {
+ dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
+ __func__);
+ goto err;
+ }
+
+ status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
+ if (!status) {
+ cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
+ sizeof(struct be_cmd_resp_hdr));
+ for (j = 0; j < cfgs->module[0].num_modes; j++) {
+ if (cfgs->module[0].trace_lvl[j].mode == MODE_UART)
+ level = cfgs->module[0].trace_lvl[j].dbg_lvl;
+ }
+ }
+ pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
+ extfat_cmd.dma);
+err:
+ return level;
+}
static int be_get_initial_config(struct be_adapter *adapter)
{
int status;
+ u32 level;
status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
&adapter->function_mode, &adapter->function_caps);
@@ -3443,6 +3529,9 @@ static int be_get_initial_config(struct be_adapter *adapter)
if (be_is_wol_supported(adapter))
adapter->wol = true;
+ level = be_get_fw_log_level(adapter);
+ adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
+
return 0;
}
@@ -3458,17 +3547,27 @@ static int be_dev_type_check(struct be_adapter *adapter)
break;
case BE_DEVICE_ID2:
case OC_DEVICE_ID2:
- case OC_DEVICE_ID5:
adapter->generation = BE_GEN3;
break;
case OC_DEVICE_ID3:
case OC_DEVICE_ID4:
pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
+ adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
+ SLI_INTF_IF_TYPE_SHIFT;
if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
SLI_INTF_IF_TYPE_SHIFT;
-
if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) ||
- if_type != 0x02) {
+ !be_type_2_3(adapter)) {
+ dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
+ return -EINVAL;
+ }
+ adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
+ SLI_INTF_FAMILY_SHIFT);
+ adapter->generation = BE_GEN3;
+ break;
+ case OC_DEVICE_ID5:
+ pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
+ if ((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) {
dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
return -EINVAL;
}
@@ -3737,6 +3836,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status != 0)
goto unsetup;
+ be_roce_dev_add(adapter);
+
dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev),
adapter->port_num);
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c
new file mode 100644
index 0000000..deecc44
--- /dev/null
+++ b/drivers/net/ethernet/emulex/benet/be_roce.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+
+#include "be.h"
+#include "be_cmds.h"
+
+static struct ocrdma_driver *ocrdma_drv;
+static LIST_HEAD(be_adapter_list);
+static DEFINE_MUTEX(be_adapter_list_lock);
+
+static void _be_roce_dev_add(struct be_adapter *adapter)
+{
+ struct be_dev_info dev_info;
+ int i, num_vec;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (!ocrdma_drv)
+ return;
+ if (pdev->device == OC_DEVICE_ID5) {
+ /* only msix is supported on these devices */
+ if (!msix_enabled(adapter))
+ return;
+ /* DPP region address and length */
+ dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2);
+ dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2);
+ } else {
+ dev_info.dpp_unmapped_addr = 0;
+ dev_info.dpp_unmapped_len = 0;
+ }
+ dev_info.pdev = adapter->pdev;
+ if (adapter->sli_family == SKYHAWK_SLI_FAMILY)
+ dev_info.db = adapter->db;
+ else
+ dev_info.db = adapter->roce_db.base;
+ dev_info.unmapped_db = adapter->roce_db.io_addr;
+ dev_info.db_page_size = adapter->roce_db.size;
+ dev_info.db_total_size = adapter->roce_db.total_size;
+ dev_info.netdev = adapter->netdev;
+ memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN);
+ dev_info.dev_family = adapter->sli_family;
+ if (msix_enabled(adapter)) {
+ /* provide all the vectors, so that EQ creation response
+ * can decide which one to use.
+ */
+ num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec;
+ dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX;
+ dev_info.msix.num_vectors = min(num_vec, MAX_ROCE_MSIX_VECTORS);
+ /* provide start index of the vector,
+ * so in case of linear usage,
+ * it can use the base as starting point.
+ */
+ dev_info.msix.start_vector = adapter->num_evt_qs;
+ for (i = 0; i < dev_info.msix.num_vectors; i++) {
+ dev_info.msix.vector_list[i] =
+ adapter->msix_entries[i].vector;
+ }
+ } else {
+ dev_info.msix.num_vectors = 0;
+ dev_info.intr_mode = BE_INTERRUPT_MODE_INTX;
+ }
+ adapter->ocrdma_dev = ocrdma_drv->add(&dev_info);
+}
+
+void be_roce_dev_add(struct be_adapter *adapter)
+{
+ if (be_roce_supported(adapter)) {
+ INIT_LIST_HEAD(&adapter->entry);
+ mutex_lock(&be_adapter_list_lock);
+ list_add_tail(&adapter->entry, &be_adapter_list);
+
+ /* invoke add() routine of roce driver only if
+ * valid driver registered with add method and add() is not yet
+ * invoked on a given adapter.
+ */
+ _be_roce_dev_add(adapter);
+ mutex_unlock(&be_adapter_list_lock);
+ }
+}
+
+void _be_roce_dev_remove(struct be_adapter *adapter)
+{
+ if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev)
+ ocrdma_drv->remove(adapter->ocrdma_dev);
+ adapter->ocrdma_dev = NULL;
+}
+
+void be_roce_dev_remove(struct be_adapter *adapter)
+{
+ if (be_roce_supported(adapter)) {
+ mutex_lock(&be_adapter_list_lock);
+ _be_roce_dev_remove(adapter);
+ list_del(&adapter->entry);
+ mutex_unlock(&be_adapter_list_lock);
+ }
+}
+
+void _be_roce_dev_open(struct be_adapter *adapter)
+{
+ if (ocrdma_drv && adapter->ocrdma_dev &&
+ ocrdma_drv->state_change_handler)
+ ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 0);
+}
+
+void be_roce_dev_open(struct be_adapter *adapter)
+{
+ if (be_roce_supported(adapter)) {
+ mutex_lock(&be_adapter_list_lock);
+ _be_roce_dev_open(adapter);
+ mutex_unlock(&be_adapter_list_lock);
+ }
+}
+
+void _be_roce_dev_close(struct be_adapter *adapter)
+{
+ if (ocrdma_drv && adapter->ocrdma_dev &&
+ ocrdma_drv->state_change_handler)
+ ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1);
+}
+
+void be_roce_dev_close(struct be_adapter *adapter)
+{
+ if (be_roce_supported(adapter)) {
+ mutex_lock(&be_adapter_list_lock);
+ _be_roce_dev_close(adapter);
+ mutex_unlock(&be_adapter_list_lock);
+ }
+}
+
+int be_roce_register_driver(struct ocrdma_driver *drv)
+{
+ struct be_adapter *dev;
+
+ mutex_lock(&be_adapter_list_lock);
+ if (ocrdma_drv) {
+ mutex_unlock(&be_adapter_list_lock);
+ return -EINVAL;
+ }
+ ocrdma_drv = drv;
+ list_for_each_entry(dev, &be_adapter_list, entry) {
+ struct net_device *netdev;
+ _be_roce_dev_add(dev);
+ netdev = dev->netdev;
+ if (netif_running(netdev) && netif_oper_up(netdev))
+ _be_roce_dev_open(dev);
+ }
+ mutex_unlock(&be_adapter_list_lock);
+ return 0;
+}
+EXPORT_SYMBOL(be_roce_register_driver);
+
+void be_roce_unregister_driver(struct ocrdma_driver *drv)
+{
+ struct be_adapter *dev;
+
+ mutex_lock(&be_adapter_list_lock);
+ list_for_each_entry(dev, &be_adapter_list, entry) {
+ if (dev->ocrdma_dev)
+ _be_roce_dev_remove(dev);
+ }
+ ocrdma_drv = NULL;
+ mutex_unlock(&be_adapter_list_lock);
+}
+EXPORT_SYMBOL(be_roce_unregister_driver);
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h
new file mode 100644
index 0000000..db4ea80
--- /dev/null
+++ b/drivers/net/ethernet/emulex/benet/be_roce.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ */
+
+#ifndef BE_ROCE_H
+#define BE_ROCE_H
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+struct ocrdma_dev;
+
+enum be_interrupt_mode {
+ BE_INTERRUPT_MODE_MSIX = 0,
+ BE_INTERRUPT_MODE_INTX = 1,
+ BE_INTERRUPT_MODE_MSI = 2,
+};
+
+#define MAX_ROCE_MSIX_VECTORS 16
+struct be_dev_info {
+ u8 __iomem *db;
+ u64 unmapped_db;
+ u32 db_page_size;
+ u32 db_total_size;
+ u64 dpp_unmapped_addr;
+ u32 dpp_unmapped_len;
+ struct pci_dev *pdev;
+ struct net_device *netdev;
+ u8 mac_addr[ETH_ALEN];
+ u32 dev_family;
+ enum be_interrupt_mode intr_mode;
+ struct {
+ int num_vectors;
+ int start_vector;
+ u32 vector_list[MAX_ROCE_MSIX_VECTORS];
+ } msix;
+};
+
+/* ocrdma driver register's the callback functions with nic driver. */
+struct ocrdma_driver {
+ unsigned char name[32];
+ struct ocrdma_dev *(*add) (struct be_dev_info *dev_info);
+ void (*remove) (struct ocrdma_dev *);
+ void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
+};
+
+enum {
+ BE_DEV_UP = 0,
+ BE_DEV_DOWN = 1
+};
+
+/* APIs for RoCE driver to register callback handlers,
+ * which will be invoked when device is added, removed, ifup, ifdown
+ */
+int be_roce_register_driver(struct ocrdma_driver *drv);
+void be_roce_unregister_driver(struct ocrdma_driver *drv);
+
+/* API for RoCE driver to issue mailbox commands */
+int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
+ int wrb_payload_size, u16 *cmd_status, u16 *ext_status);
+
+#endif /* BE_ROCE_H */
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 7fa0227..8f2cf8c 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -48,6 +48,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
@@ -1543,6 +1544,7 @@ fec_probe(struct platform_device *pdev)
struct resource *r;
const struct of_device_id *of_id;
static int dev_id;
+ struct pinctrl *pinctrl;
of_id = of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
@@ -1610,6 +1612,12 @@ fec_probe(struct platform_device *pdev)
}
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto failed_pin;
+ }
+
fep->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(fep->clk)) {
ret = PTR_ERR(fep->clk);
@@ -1640,6 +1648,7 @@ failed_mii_init:
failed_init:
clk_disable_unprepare(fep->clk);
clk_put(fep->clk);
+failed_pin:
failed_clk:
for (i = 0; i < FEC_IRQ_NUM; i++) {
irq = platform_get_irq(pdev, i);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 37b7d1c..95731c8 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -493,7 +493,11 @@ out:
static void e1000_down_and_stop(struct e1000_adapter *adapter)
{
set_bit(__E1000_DOWN, &adapter->flags);
- cancel_work_sync(&adapter->reset_task);
+
+ /* Only kill reset task if adapter is not resetting */
+ if (!test_bit(__E1000_RESETTING, &adapter->flags))
+ cancel_work_sync(&adapter->reset_task);
+
cancel_delayed_work_sync(&adapter->watchdog_task);
cancel_delayed_work_sync(&adapter->phy_info_task);
cancel_delayed_work_sync(&adapter->fifo_stall_task);
diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c
index 8be20e7..06fef5b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c
@@ -124,9 +124,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
spin_lock(&bitmap->lock);
bitmap_clear(bitmap->table, obj, cnt);
- bitmap->last = min(bitmap->last, obj);
- bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
- & bitmap->mask;
bitmap->avail += cnt;
spin_unlock(&bitmap->lock);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 24429a9..68f5cd6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -118,6 +118,20 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
mlx4_dbg(dev, " %s\n", fname[i]);
}
+static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
+{
+ static const char * const fname[] = {
+ [0] = "RSS support",
+ [1] = "RSS Toeplitz Hash Function support",
+ [2] = "RSS XOR Hash Function support"
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fname); ++i)
+ if (fname[i] && (flags & (1LL << i)))
+ mlx4_dbg(dev, " %s\n", fname[i]);
+}
+
int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
{
struct mlx4_cmd_mailbox *mailbox;
@@ -346,6 +360,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29
#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b
#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d
+#define QUERY_DEV_CAP_RSS_OFFSET 0x2e
#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f
#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33
#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35
@@ -390,6 +405,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98
#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0
+ dev_cap->flags2 = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
@@ -439,6 +455,17 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
else
dev_cap->max_gso_sz = 1 << field;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET);
+ if (field & 0x20)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR;
+ if (field & 0x10)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP;
+ field &= 0xf;
+ if (field) {
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS;
+ dev_cap->max_rss_tbl_sz = 1 << field;
+ } else
+ dev_cap->max_rss_tbl_sz = 0;
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
dev_cap->max_rdma_global = 1 << (field & 0x3f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
@@ -632,8 +659,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
+ mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
dump_dev_cap_flags(dev, dev_cap->flags);
+ dump_dev_cap_flags2(dev, dev_cap->flags2);
out:
mlx4_free_cmd_mailbox(dev, mailbox);
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index e1a5fa5..64c0399 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -79,6 +79,7 @@ struct mlx4_dev_cap {
u64 trans_code[MLX4_MAX_PORTS + 1];
u16 stat_rate_support;
u64 flags;
+ u64 flags2;
int reserved_uars;
int uar_size;
int min_page_sz;
@@ -110,6 +111,7 @@ struct mlx4_dev_cap {
u32 reserved_lkey;
u64 max_icm_sz;
int max_gso_sz;
+ int max_rss_tbl_sz;
u8 supported_port_types[MLX4_MAX_PORTS + 1];
u8 suggested_type[MLX4_MAX_PORTS + 1];
u8 default_sense[MLX4_MAX_PORTS + 1];
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 984ace4..2e024a6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -272,10 +272,12 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.max_msg_sz = dev_cap->max_msg_sz;
dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1);
dev->caps.flags = dev_cap->flags;
+ dev->caps.flags2 = dev_cap->flags2;
dev->caps.bmme_flags = dev_cap->bmme_flags;
dev->caps.reserved_lkey = dev_cap->reserved_lkey;
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
+ dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz;
/* Sense port always allowed on supported devices for ConnectX1 and 2 */
if (dev->pdev->device != 0x1003)
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index d3469d8..8d2666f 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -40,6 +40,7 @@
#include <linux/skbuff.h>
#include <linux/phy.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/types.h>
@@ -340,13 +341,17 @@
*/
#define LPC_POWERDOWN_MACAHB (1 << 31)
-/* Upon the upcoming introduction of device tree usage in LPC32xx,
- * lpc_phy_interface_mode() and use_iram_for_net() will be extended with a
- * device parameter for access to device tree information at runtime, instead
- * of defining the values at compile time
- */
-static inline phy_interface_t lpc_phy_interface_mode(void)
+static phy_interface_t lpc_phy_interface_mode(struct device *dev)
{
+ if (dev && dev->of_node) {
+ const char *mode = of_get_property(dev->of_node,
+ "phy-mode", NULL);
+ if (mode && !strcmp(mode, "mii"))
+ return PHY_INTERFACE_MODE_MII;
+ return PHY_INTERFACE_MODE_RMII;
+ }
+
+ /* non-DT */
#ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT
return PHY_INTERFACE_MODE_MII;
#else
@@ -354,12 +359,16 @@ static inline phy_interface_t lpc_phy_interface_mode(void)
#endif
}
-static inline int use_iram_for_net(void)
+static bool use_iram_for_net(struct device *dev)
{
+ if (dev && dev->of_node)
+ return of_property_read_bool(dev->of_node, "use-iram");
+
+ /* non-DT */
#ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET
- return 1;
+ return true;
#else
- return 0;
+ return false;
#endif
}
@@ -664,7 +673,7 @@ static void __lpc_eth_init(struct netdata_local *pldat)
LPC_ENET_CLRT(pldat->net_base));
writel(LPC_IPGR_LOAD_PART2(0x12), LPC_ENET_IPGR(pldat->net_base));
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
writel(LPC_COMMAND_PASSRUNTFRAME,
LPC_ENET_COMMAND(pldat->net_base));
else {
@@ -804,12 +813,13 @@ static int lpc_mii_probe(struct net_device *ndev)
}
/* Attach to the PHY */
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
netdev_info(ndev, "using MII interface\n");
else
netdev_info(ndev, "using RMII interface\n");
phydev = phy_connect(ndev, dev_name(&phydev->dev),
- &lpc_handle_link_change, 0, lpc_phy_interface_mode());
+ &lpc_handle_link_change, 0,
+ lpc_phy_interface_mode(&pldat->pdev->dev));
if (IS_ERR(phydev)) {
netdev_err(ndev, "Could not attach to PHY\n");
@@ -843,7 +853,7 @@ static int lpc_mii_init(struct netdata_local *pldat)
}
/* Setup MII mode */
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
writel(LPC_COMMAND_PASSRUNTFRAME,
LPC_ENET_COMMAND(pldat->net_base));
else {
@@ -1315,18 +1325,26 @@ static const struct net_device_ops lpc_netdev_ops = {
static int lpc_eth_drv_probe(struct platform_device *pdev)
{
struct resource *res;
- struct resource *dma_res;
struct net_device *ndev;
struct netdata_local *pldat;
struct phy_device *phydev;
dma_addr_t dma_handle;
int irq, ret;
+ u32 tmp;
+
+ /* Setup network interface for RMII or MII mode */
+ tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
+ tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
+ if (lpc_phy_interface_mode(&pdev->dev) == PHY_INTERFACE_MODE_MII)
+ tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS;
+ else
+ tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
+ __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
/* Get platform resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(pdev, 0);
- if ((!res) || (!dma_res) || (irq < 0) || (irq >= NR_IRQS)) {
+ if ((!res) || (irq < 0) || (irq >= NR_IRQS)) {
dev_err(&pdev->dev, "error getting resources.\n");
ret = -ENXIO;
goto err_exit;
@@ -1389,17 +1407,19 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t));
pldat->dma_buff_base_v = 0;
- if (use_iram_for_net()) {
- dma_handle = dma_res->start;
+ if (use_iram_for_net(&pldat->pdev->dev)) {
+ dma_handle = LPC32XX_IRAM_BASE;
if (pldat->dma_buff_size <= lpc32xx_return_iram_size())
pldat->dma_buff_base_v =
- io_p2v(dma_res->start);
+ io_p2v(LPC32XX_IRAM_BASE);
else
netdev_err(ndev,
"IRAM not big enough for net buffers, using SDRAM instead.\n");
}
if (pldat->dma_buff_base_v == 0) {
+ pldat->pdev->dev.coherent_dma_mask = 0xFFFFFFFF;
+ pldat->pdev->dev.dma_mask = &pldat->pdev->dev.coherent_dma_mask;
pldat->dma_buff_size = PAGE_ALIGN(pldat->dma_buff_size);
/* Allocate a chunk of memory for the DMA ethernet buffers
@@ -1488,7 +1508,7 @@ err_out_unregister_netdev:
platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
err_out_dma_unmap:
- if (!use_iram_for_net() ||
+ if (!use_iram_for_net(&pldat->pdev->dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
pldat->dma_buff_base_v,
@@ -1515,7 +1535,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev)
unregister_netdev(ndev);
platform_set_drvdata(pdev, NULL);
- if (!use_iram_for_net() ||
+ if (!use_iram_for_net(&pldat->pdev->dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
pldat->dma_buff_base_v,
@@ -1584,6 +1604,14 @@ static int lpc_eth_drv_resume(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id lpc_eth_match[] = {
+ { .compatible = "nxp,lpc-eth" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpc_eth_match);
+#endif
+
static struct platform_driver lpc_eth_driver = {
.probe = lpc_eth_drv_probe,
.remove = __devexit_p(lpc_eth_drv_remove),
@@ -1593,6 +1621,7 @@ static struct platform_driver lpc_eth_driver = {
#endif
.driver = {
.name = MODNAME,
+ .of_match_table = of_match_ptr(lpc_eth_match),
},
};
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 0d725dc..8694124 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -1260,8 +1260,7 @@ next:
void
netxen_release_firmware(struct netxen_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index d32cf0d..799fd40 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1321,8 +1321,7 @@ next:
void
qlcnic_release_firmware(struct qlcnic_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 4f74b97..00b4f56 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -6051,7 +6051,7 @@ static int rtl_open(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
/*
- * Rx and Tx desscriptors needs 256 bytes alignment.
+ * Rx and Tx descriptors needs 256 bytes alignment.
* dma_alloc_coherent provides more.
*/
tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 8e9fda0..2ed3ab4 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -1,7 +1,7 @@
/*
* Ethernet driver for S6105 on chip network device
* (c)2008 emlix GmbH http://www.emlix.com
- * Authors: Oskar Schirmer <os@emlix.com>
+ * Authors: Oskar Schirmer <oskar@scara.com>
* Daniel Gloeckner <dg@emlix.com>
*
* This program is free software; you can redistribute it and/or
@@ -1070,4 +1070,4 @@ module_exit(s6gmac_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
-MODULE_AUTHOR("Oskar Schirmer <os@emlix.com>");
+MODULE_AUTHOR("Oskar Schirmer <oskar@scara.com>");
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d07bc6d..7096633 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1640,7 +1640,7 @@ static const struct file_operations stmmac_rings_status_fops = {
.open = stmmac_sysfs_ring_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = single_release,
};
static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v)
@@ -1712,7 +1712,7 @@ static const struct file_operations stmmac_dma_cap_fops = {
.open = stmmac_sysfs_dma_cap_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = single_release,
};
static int stmmac_init_fs(struct net_device *dev)
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 8846516..447a693 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -341,8 +341,8 @@ static int bdx_fw_load(struct bdx_priv *priv)
out:
if (master)
WRITE_REG(priv, regINIT_SEMAPHORE, 1);
- if (fw)
- release_firmware(fw);
+
+ release_firmware(fw);
if (rc) {
netdev_err(priv->ndev, "firmware loading failed\n");
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 3575844..5952054 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -211,8 +211,8 @@ config KINGSUN_DONGLE
kingsun-sir.
config EP7211_DONGLE
- tristate "EP7211 I/R support"
- depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+ tristate "Cirrus Logic clps711x I/R support"
+ depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Cirrus logic
EP7211 chipset's infrared module.
@@ -316,7 +316,7 @@ config AU1000_FIR
tristate "Alchemy IrDA SIR/FIR"
depends on IRDA && MIPS_ALCHEMY
help
- Say Y/M here to build suppor the the IrDA peripheral on the
+ Say Y/M here to build support the IrDA peripheral on the
Alchemy Au1000 and Au1100 SoCs.
Say M to build a module; it will be called au1k_ir.ko
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 72f687b..f9a86bd 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1671,7 +1671,7 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Is this really necessary? (no, except maybe for broken devices) */
if (usb_reset_configuration (dev) < 0) {
- err("reset_configuration failed");
+ dev_err(&intf->dev, "reset_configuration failed\n");
ret = -EIO;
goto err_out_3;
}
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 79aebee..7b48338 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -134,14 +134,16 @@ static void kingsun_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("kingsun_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
netif_wake_queue(netdev);
}
@@ -177,7 +179,8 @@ static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
kingsun, 1);
if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
- err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -211,8 +214,9 @@ static void kingsun_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -238,8 +242,9 @@ static void kingsun_rcv_irq(struct urb *urb)
? 1 : 0;
}
} else if (urb->actual_length > 0) {
- err("%s(): Unexpected response length, expected %d got %d",
- __func__, kingsun->max_rx, urb->actual_length);
+ dev_err(&kingsun->usbdev->dev,
+ "%s(): Unexpected response length, expected %d got %d\n",
+ __func__, kingsun->max_rx, urb->actual_length);
}
/* This urb has already been filled in kingsun_net_open */
ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -286,7 +291,7 @@ static int kingsun_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("kingsun-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -298,7 +303,8 @@ static int kingsun_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("kingsun-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev,
+ "first urb-submit failed: %d\n", err);
goto close_irlap;
}
@@ -446,13 +452,15 @@ static int kingsun_probe(struct usb_interface *intf,
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
- err("kingsun-sir: expected 2 endpoints, found %d",
- interface->desc.bNumEndpoints);
+ dev_err(&intf->dev,
+ "kingsun-sir: expected 2 endpoints, found %d\n",
+ interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
- err("kingsun-sir: endpoint 0 is not interrupt IN");
+ dev_err(&intf->dev,
+ "kingsun-sir: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
@@ -460,14 +468,16 @@ static int kingsun_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
- err("%s: endpoint 0 has max packet size %d not in range",
- __FILE__, maxp_in);
+ dev_err(&intf->dev,
+ "endpoint 0 has max packet size %d not in range\n",
+ maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
- err("kingsun-sir: endpoint 1 is not interrupt OUT");
+ dev_err(&intf->dev,
+ "kingsun-sir: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index abe689d..824e2a9 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -247,8 +247,9 @@ static void ks959_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ks959_speed_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&urb->dev->dev,
+ "ks959_speed_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
}
@@ -332,14 +333,16 @@ static void ks959_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("ks959_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ks959_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
return;
}
@@ -358,8 +361,9 @@ static void ks959_send_irq(struct urb *urb)
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- err("ks959_send_irq: failed tx_urb submit: %d",
- ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: failed tx_urb submit: %d\n",
+ ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -407,7 +411,8 @@ static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb,
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -442,8 +447,9 @@ static void ks959_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -536,7 +542,7 @@ static int ks959_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("ks959-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -549,7 +555,8 @@ static int ks959_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("ks959-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev,
+ "first urb-submit failed: %d\n", err);
goto close_irlap;
}
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index f8c0108..5a278ab 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -168,10 +168,10 @@ struct ksdazzle_cb {
static void ksdazzle_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- err("ksdazzle_speed_irq: urb asynchronously failed - %d",
- urb->status);
- }
+ if (urb->status != 0)
+ dev_err(&urb->dev->dev,
+ "ksdazzle_speed_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
/* Send a control request to change speed of the dongle */
@@ -245,14 +245,16 @@ static void ksdazzle_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("ksdazzle_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ksdazzle_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
return;
}
@@ -271,7 +273,9 @@ static void ksdazzle_send_irq(struct urb *urb)
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: failed tx_urb submit: %d\n",
+ ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -320,7 +324,8 @@ static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb,
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -355,8 +360,9 @@ static void ksdazzle_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -430,7 +436,7 @@ static int ksdazzle_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("ksdazzle-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -442,7 +448,7 @@ static int ksdazzle_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("ksdazzle-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err);
goto close_irlap;
}
@@ -590,13 +596,14 @@ static int ksdazzle_probe(struct usb_interface *intf,
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
- err("ksdazzle: expected 2 endpoints, found %d",
- interface->desc.bNumEndpoints);
+ dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n",
+ interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
- err("ksdazzle: endpoint 0 is not interrupt IN");
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
@@ -604,13 +611,16 @@ static int ksdazzle_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
- err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n",
+ maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
- err("ksdazzle: endpoint 1 is not interrupt OUT");
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e6e59a0..876e709 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -904,7 +904,7 @@ static int stir_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", stir->usbdev->devnum);
stir->irlap = irlap_open(netdev, &stir->qos, hwname);
if (!stir->irlap) {
- err("stir4200: irlap_open failed");
+ dev_err(&stir->usbdev->dev, "irlap_open failed\n");
goto err_out5;
}
@@ -913,7 +913,7 @@ static int stir_net_open(struct net_device *netdev)
"%s", stir->netdev->name);
if (IS_ERR(stir->thread)) {
err = PTR_ERR(stir->thread);
- err("stir4200: unable to start kernel thread");
+ dev_err(&stir->usbdev->dev, "unable to start kernel thread\n");
goto err_out6;
}
@@ -1042,7 +1042,7 @@ static int stir_probe(struct usb_interface *intf,
ret = usb_reset_configuration(dev);
if (ret != 0) {
- err("stir4200: usb reset configuration failed");
+ dev_err(&intf->dev, "usb reset configuration failed\n");
goto err_out2;
}
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index af95a98..a031f6b 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -613,7 +613,7 @@ ppp_async_encode(struct asyncppp *ap)
*buf++ = PPP_FLAG;
ap->olim = buf;
- kfree_skb(ap->tpkt);
+ consume_skb(ap->tpkt);
ap->tpkt = NULL;
return 1;
}
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 21d7151..5c05572 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1092,13 +1092,13 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
new_skb->data, skb->len + 2,
compressor_skb_size);
if (len > 0 && (ppp->flags & SC_CCP_UP)) {
- kfree_skb(skb);
+ consume_skb(skb);
skb = new_skb;
skb_put(skb, len);
skb_pull(skb, 2); /* pull off A/C bytes */
} else if (len == 0) {
/* didn't compress, or CCP not up yet */
- kfree_skb(new_skb);
+ consume_skb(new_skb);
new_skb = skb;
} else {
/*
@@ -1112,7 +1112,7 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
if (net_ratelimit())
netdev_err(ppp->dev, "ppp: compressor dropped pkt\n");
kfree_skb(skb);
- kfree_skb(new_skb);
+ consume_skb(new_skb);
new_skb = NULL;
}
return new_skb;
@@ -1178,7 +1178,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
!(ppp->flags & SC_NO_TCP_CCID));
if (cp == skb->data + 2) {
/* didn't compress */
- kfree_skb(new_skb);
+ consume_skb(new_skb);
} else {
if (cp[0] & SL_TYPE_COMPRESSED_TCP) {
proto = PPP_VJC_COMP;
@@ -1187,7 +1187,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
proto = PPP_VJC_UNCOMP;
cp[0] = skb->data[2];
}
- kfree_skb(skb);
+ consume_skb(skb);
skb = new_skb;
cp = skb_put(skb, len + 2);
cp[0] = 0;
@@ -1703,7 +1703,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
}
skb_reserve(ns, 2);
skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len);
- kfree_skb(skb);
+ consume_skb(skb);
skb = ns;
}
else
@@ -1851,7 +1851,7 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
goto err;
}
- kfree_skb(skb);
+ consume_skb(skb);
skb = ns;
skb_put(skb, len);
skb_pull(skb, 2); /* pull off the A/C bytes */
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 55e466c..1a12033 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -588,7 +588,7 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
skb_reserve(npkt,2);
skb_copy_from_linear_data(skb,
skb_put(npkt, skb->len), skb->len);
- kfree_skb(skb);
+ consume_skb(skb);
skb = npkt;
}
skb_push(skb,2);
@@ -656,7 +656,7 @@ ppp_sync_push(struct syncppp *ap)
if (sent < ap->tpkt->len) {
tty_stuffed = 1;
} else {
- kfree_skb(ap->tpkt);
+ consume_skb(ap->tpkt);
ap->tpkt = NULL;
clear_bit(XMIT_FULL, &ap->xmit_flags);
done = 1;
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index dd15b8f..cbf7047 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -984,8 +984,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
if (skb) {
total_len = min_t(size_t, total_len, skb->len);
error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
- if (error == 0)
- error = total_len;
+ if (error == 0) {
+ consume_skb(skb);
+ return total_len;
+ }
}
kfree_skb(skb);
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 72b50f5..1c98321 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -209,7 +209,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
}
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
- kfree_skb(skb);
+ consume_skb(skb);
skb = new_skb;
}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 42b5151..71e2b05 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1647,6 +1647,7 @@ static struct usb_driver asix_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(asix_driver);
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 182cfb4..26c5beb 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -338,16 +338,18 @@ static void catc_irq_done(struct urb *urb)
} else {
catc->rx_urb->dev = catc->usbdev;
if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
- err("submit(rx_urb) status %d", res);
+ dev_err(&catc->usbdev->dev,
+ "submit(rx_urb) status %d\n", res);
}
}
}
resubmit:
res = usb_submit_urb (urb, GFP_ATOMIC);
if (res)
- err ("can't resubmit intr, %s-%s, status %d",
- catc->usbdev->bus->bus_name,
- catc->usbdev->devpath, res);
+ dev_err(&catc->usbdev->dev,
+ "can't resubmit intr, %s-%s, status %d\n",
+ catc->usbdev->bus->bus_name,
+ catc->usbdev->devpath, res);
}
/*
@@ -366,7 +368,8 @@ static int catc_tx_run(struct catc *catc)
catc->tx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
- err("submit(tx_urb), status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n",
+ status);
catc->tx_idx = !catc->tx_idx;
catc->tx_ptr = 0;
@@ -496,7 +499,8 @@ static void catc_ctrl_run(struct catc *catc)
memcpy(catc->ctrl_buf, q->buf, q->len);
if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
- err("submit(ctrl_urb) status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n",
+ status);
}
static void catc_ctrl_done(struct urb *urb)
@@ -555,7 +559,7 @@ static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,
catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);
if (catc->ctrl_head == catc->ctrl_tail) {
- err("ctrl queue full");
+ dev_err(&catc->usbdev->dev, "ctrl queue full\n");
catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
retval = -1;
}
@@ -714,7 +718,8 @@ static int catc_open(struct net_device *netdev)
catc->irq_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
- err("submit(irq_urb) status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n",
+ status);
return -1;
}
@@ -769,7 +774,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
if (usb_set_interface(usbdev,
intf->altsetting->desc.bInterfaceNumber, 1)) {
- err("Can't set altsetting 1.");
+ dev_err(&intf->dev, "Can't set altsetting 1.\n");
return -EIO;
}
@@ -799,7 +804,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if ((!catc->ctrl_urb) || (!catc->tx_urb) ||
(!catc->rx_urb) || (!catc->irq_urb)) {
- err("No free urbs available.");
+ dev_err(&intf->dev, "No free urbs available.\n");
usb_free_urb(catc->ctrl_urb);
usb_free_urb(catc->tx_urb);
usb_free_urb(catc->rx_urb);
@@ -947,6 +952,7 @@ static struct usb_driver catc_driver = {
.probe = catc_probe,
.disconnect = catc_disconnect,
.id_table = catc_id_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(catc_driver);
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 3e41b00..d848d4d 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -457,6 +457,7 @@ static struct usb_driver usbpn_driver = {
.probe = usbpn_probe,
.disconnect = usbpn_disconnect,
.id_table = usbpn_ids,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(usbpn_driver);
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index 685a4e2..434d5af 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -368,6 +368,7 @@ static struct usb_driver eem_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(eem_driver);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 425e201..a03de71 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -486,6 +486,7 @@ static const struct driver_info wwan_info = {
#define HUAWEI_VENDOR_ID 0x12D1
#define NOVATEL_VENDOR_ID 0x1410
+#define ZTE_VENDOR_ID 0x19D2
static const struct usb_device_id products [] = {
/*
@@ -618,6 +619,61 @@ static const struct usb_device_id products [] = {
.bInterfaceProtocol = USB_CDC_PROTO_NONE,
.driver_info = (unsigned long)&wwan_info,
}, {
+ /* ZTE (Vodafone) K3805-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ZTE_VENDOR_ID,
+ .idProduct = 0x1003,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = (unsigned long)&wwan_info,
+}, {
+ /* ZTE (Vodafone) K3806-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ZTE_VENDOR_ID,
+ .idProduct = 0x1015,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = (unsigned long)&wwan_info,
+}, {
+ /* ZTE (Vodafone) K4510-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ZTE_VENDOR_ID,
+ .idProduct = 0x1173,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = (unsigned long)&wwan_info,
+}, {
+ /* ZTE (Vodafone) K3770-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ZTE_VENDOR_ID,
+ .idProduct = 0x1177,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = (unsigned long)&wwan_info,
+}, {
+ /* ZTE (Vodafone) K3772-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ZTE_VENDOR_ID,
+ .idProduct = 0x1181,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = (unsigned long)&wwan_info,
+}, {
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &cdc_info,
@@ -649,6 +705,7 @@ static struct usb_driver cdc_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_driver);
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7adc9f6..4b9513f 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1212,6 +1212,7 @@ static struct usb_driver cdc_ncm_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static const struct ethtool_ops cdc_ncm_ethtool_ops = {
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index b403d93..0d1fe89 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -336,6 +336,7 @@ static struct usb_driver cdc_subset_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.id_table = products,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_subset_driver);
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
index 0e05313..49ab45e 100644
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -327,6 +327,7 @@ static struct usb_driver cx82310_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cx82310_driver);
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index b972263..e0433ce 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -670,6 +670,7 @@ static struct usb_driver dm9601_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(dm9601_driver);
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index 38266bd..db3c802 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -225,6 +225,7 @@ static struct usb_driver gl620a_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(gl620a_driver);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 2d2a688..62f30b4 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -106,13 +106,6 @@
#define MAX_RX_URBS 2
-static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
-{
- if (tty)
- return tty->driver_data;
- return NULL;
-}
-
/*****************************************************************************/
/* Debugging functions */
/*****************************************************************************/
@@ -255,9 +248,8 @@ struct hso_serial {
u8 dtr_state;
unsigned tx_urb_used:1;
+ struct tty_port port;
/* from usb_serial_port */
- struct tty_struct *tty;
- int open_count;
spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial);
@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct ktermios *termios;
if (!serial) {
@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
struct urb *urb;
urb = serial->rx_urb[0];
- if (serial->open_count > 0) {
+ if (serial->port.count > 0) {
count = put_rxbuf_data(urb, serial);
if (count == -1)
return;
@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
DUMP1(urb->transfer_buffer, urb->actual_length);
/* Anyone listening? */
- if (serial->open_count == 0)
+ if (serial->port.count == 0)
return;
if (status == 0) {
@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
static void hso_unthrottle(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
tasklet_hi_schedule(&serial->unthrottle_tasklet);
}
@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
kref_get(&serial->parent->ref);
/* setup */
- spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial;
- tty_kref_put(serial->tty);
- serial->tty = tty_kref_get(tty);
- spin_unlock_irq(&serial->serial_lock);
+ tty_port_tty_set(&serial->port, tty);
/* check for port already opened, if not set the termios */
- serial->open_count++;
- if (serial->open_count == 1) {
+ serial->port.count++;
+ if (serial->port.count == 1) {
serial->rx_state = RX_IDLE;
/* Force default termio settings */
_hso_serial_set_termios(tty, NULL);
@@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
result = hso_start_serial_device(serial->parent, GFP_KERNEL);
if (result) {
hso_stop_serial_device(serial->parent);
- serial->open_count--;
+ serial->port.count--;
kref_put(&serial->parent->ref, hso_serial_ref_free);
}
} else {
@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
/* reset the rts and dtr */
/* do the actual close */
- serial->open_count--;
+ serial->port.count--;
- if (serial->open_count <= 0) {
- serial->open_count = 0;
- spin_lock_irq(&serial->serial_lock);
- if (serial->tty == tty) {
- serial->tty->driver_data = NULL;
- serial->tty = NULL;
- tty_kref_put(tty);
- }
- spin_unlock_irq(&serial->serial_lock);
+ if (serial->port.count <= 0) {
+ serial->port.count = 0;
+ tty_port_tty_set(&serial->port, NULL);
if (!usb_gone)
hso_stop_serial_device(serial->parent);
tasklet_kill(&serial->unthrottle_tasklet);
@@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int space, tx_bytes;
unsigned long flags;
@@ -1422,7 +1405,7 @@ out:
/* how much room is there for writing */
static int hso_serial_write_room(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int room;
unsigned long flags;
@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
/* setup the term */
static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
unsigned long flags;
if (old)
@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags);
- if (serial->open_count)
+ if (serial->port.count)
_hso_serial_set_termios(tty, old);
else
tty->termios = old;
@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* how many characters in the buffer */
static int hso_serial_chars_in_buffer(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int chars;
unsigned long flags;
@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
struct serial_icounter_struct *icount)
{
struct uart_icount cnow;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget = serial->tiocmget;
memset(icount, 0, sizeof(struct serial_icounter_struct));
@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
static int hso_serial_tiocmget(struct tty_struct *tty)
{
int retval;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget;
u16 UART_state_bitmap;
@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
int val = 0;
unsigned long flags;
int if_num;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
/* sanity check */
if (!serial) {
@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
static int hso_serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int ret = 0;
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
D1("Pending read interrupt on port %d\n", i);
spin_lock(&serial->serial_lock);
if (serial->rx_state == RX_IDLE &&
- serial->open_count > 0) {
+ serial->port.count > 0) {
/* Setup and send a ctrl req read on
* port i */
if (!serial->rx_urb_filled[0]) {
@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
- tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
handle_usb_error(status, __func__, serial->parent);
- tty_kref_put(tty);
return;
}
hso_put_activity(serial->parent);
+ tty = tty_port_tty_get(&serial->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req;
int status = urb->status;
- struct tty_struct *tty;
/* sanity check */
if (!serial)
@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
- tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
handle_usb_error(status, __func__, serial->parent);
- tty_kref_put(tty);
return;
}
@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
spin_unlock(&serial->serial_lock);
} else {
+ struct tty_struct *tty = tty_port_tty_get(&serial->port);
hso_put_activity(serial->parent);
- if (tty)
+ if (tty) {
tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
/* response to a write command */
hso_kick_transmit(serial);
}
- tty_kref_put(tty);
}
/* handle RX data for serial port */
@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
return -2;
}
- /* All callers to put_rxbuf_data hold serial_lock */
- tty = tty_kref_get(serial->tty);
+ tty = tty_port_tty_get(&serial->port);
/* Push data to tty */
if (tty) {
@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
write_length_remaining -= curr_write_len;
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
}
if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
}
- tty_kref_put(tty);
return write_length_remaining;
}
@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock);
+ tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs;
/* RX, allocate urb and initialize */
@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
/* Start all serial ports */
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] && (serial_table[i]->interface == iface)) {
- if (dev2ser(serial_table[i])->open_count) {
+ if (dev2ser(serial_table[i])->port.count) {
result =
hso_start_serial_device(serial_table[i], GFP_NOIO);
hso_kick_transmit(dev2ser(serial_table[i]));
@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
if (serial_table[i] &&
(serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]);
- spin_lock_irq(&hso_dev->serial_lock);
- tty = tty_kref_get(hso_dev->tty);
- spin_unlock_irq(&hso_dev->serial_lock);
- if (tty)
+ tty = tty_port_tty_get(&hso_dev->port);
+ if (tty) {
tty_hangup(tty);
+ tty_kref_put(tty);
+ }
mutex_lock(&hso_dev->parent->mutex);
- tty_kref_put(tty);
hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex);
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@@ -3291,6 +3271,7 @@ static struct usb_driver hso_driver = {
.resume = hso_resume,
.reset_resume = hso_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static int __init hso_init(void)
@@ -3312,7 +3293,6 @@ static int __init hso_init(void)
return -ENOMEM;
/* fill in all needed values */
- tty_drv->magic = TTY_DRIVER_MAGIC;
tty_drv->driver_name = driver_name;
tty_drv->name = tty_filename;
@@ -3333,7 +3313,7 @@ static int __init hso_init(void)
if (result) {
printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
__func__, result);
- return result;
+ goto err_free_tty;
}
/* register this module as an usb driver */
@@ -3341,13 +3321,16 @@ static int __init hso_init(void)
if (result) {
printk(KERN_ERR "Could not register hso driver? error: %d\n",
result);
- /* cleanup serial interface */
- tty_unregister_driver(tty_drv);
- return result;
+ goto err_unreg_tty;
}
/* done */
return 0;
+err_unreg_tty:
+ tty_unregister_driver(tty_drv);
+err_free_tty:
+ put_tty_driver(tty_drv);
+ return result;
}
static void __exit hso_exit(void)
@@ -3355,6 +3338,7 @@ static void __exit hso_exit(void)
printk(KERN_INFO "hso: unloaded\n");
tty_unregister_driver(tty_drv);
+ put_tty_driver(tty_drv);
/* deregister the usb driver */
usb_deregister(&hso_driver);
}
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index 12a22a4..8de6417 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -236,6 +236,7 @@ static struct usb_driver int51x1_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(int51x1_driver);
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index dd78c4c..964031e 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -209,7 +209,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
case 0:
break;
default:
- err("%s: urb status: %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+ __func__, status);
return;
}
@@ -222,7 +223,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
skb = dev_alloc_skb(len);
if (!skb) {
- err("%s: dev_alloc_skb: -ENOMEM", __func__);
+ dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
+ __func__);
dev->net->stats.rx_dropped++;
return;
}
@@ -251,7 +253,8 @@ static void ipheth_sndbulk_callback(struct urb *urb)
status != -ENOENT &&
status != -ECONNRESET &&
status != -ESHUTDOWN)
- err("%s: urb status: %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+ __func__, status);
dev_kfree_skb_irq(dev->tx_skb);
netif_wake_queue(dev->net);
@@ -271,7 +274,8 @@ static int ipheth_carrier_set(struct ipheth_device *dev)
dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
- err("%s: usb_control_msg: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+ __func__, retval);
return retval;
}
@@ -308,9 +312,11 @@ static int ipheth_get_macaddr(struct ipheth_device *dev)
IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
- err("%s: usb_control_msg: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+ __func__, retval);
} else if (retval < ETH_ALEN) {
- err("%s: usb_control_msg: short packet: %d bytes",
+ dev_err(&dev->intf->dev,
+ "%s: usb_control_msg: short packet: %d bytes\n",
__func__, retval);
retval = -EINVAL;
} else {
@@ -335,7 +341,8 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
retval = usb_submit_urb(dev->rx_urb, mem_flags);
if (retval)
- err("%s: usb_submit_urb: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+ __func__, retval);
return retval;
}
@@ -396,7 +403,8 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
if (retval) {
- err("%s: usb_submit_urb: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+ __func__, retval);
dev->net->stats.tx_errors++;
dev_kfree_skb_irq(skb);
} else {
@@ -414,7 +422,7 @@ static void ipheth_tx_timeout(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
- err("%s: TX timeout", __func__);
+ dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
dev->net->stats.tx_errors++;
usb_unlink_urb(dev->tx_urb);
}
@@ -464,7 +472,7 @@ static int ipheth_probe(struct usb_interface *intf,
hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
if (hintf == NULL) {
retval = -ENODEV;
- err("Unable to find alternate settings interface");
+ dev_err(&intf->dev, "Unable to find alternate settings interface\n");
goto err_endpoints;
}
@@ -477,7 +485,7 @@ static int ipheth_probe(struct usb_interface *intf,
}
if (!(dev->bulk_in && dev->bulk_out)) {
retval = -ENODEV;
- err("Unable to find endpoints");
+ dev_err(&intf->dev, "Unable to find endpoints\n");
goto err_endpoints;
}
@@ -495,7 +503,7 @@ static int ipheth_probe(struct usb_interface *intf,
retval = ipheth_alloc_urbs(dev);
if (retval) {
- err("error allocating urbs: %d", retval);
+ dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
goto err_alloc_urbs;
}
@@ -506,7 +514,7 @@ static int ipheth_probe(struct usb_interface *intf,
retval = register_netdev(netdev);
if (retval) {
- err("error registering netdev: %d", retval);
+ dev_err(&intf->dev, "error registering netdev: %d\n", retval);
retval = -EIO;
goto err_register_netdev;
}
@@ -546,6 +554,7 @@ static struct usb_driver ipheth_driver = {
.probe = ipheth_probe,
.disconnect = ipheth_disconnect,
.id_table = ipheth_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(ipheth_driver);
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 7562649..92c49e0 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -372,7 +372,8 @@ static struct usb_driver kalmia_driver = {
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
- .resume = usbnet_resume
+ .resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(kalmia_driver);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index df2a2cf..d8ad552 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.resume = kaweth_resume,
.id_table = usb_klsi_table,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
typedef __u8 eth_addr_t[6];
@@ -400,12 +401,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
ret = request_firmware(&fw, fwname, &kaweth->dev->dev);
if (ret) {
- err("Firmware request failed\n");
+ dev_err(&kaweth->intf->dev, "Firmware request failed\n");
return ret;
}
if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
- err("Firmware too big: %zu", fw->size);
+ dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n",
+ fw->size);
release_firmware(fw);
return -ENOSPC;
}
@@ -501,9 +503,10 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf)
}
if (status)
- err ("can't resubmit intr, %s-%s, status %d",
- kaweth->dev->bus->bus_name,
- kaweth->dev->devpath, status);
+ dev_err(&kaweth->intf->dev,
+ "can't resubmit intr, %s-%s, status %d\n",
+ kaweth->dev->bus->bus_name,
+ kaweth->dev->devpath, status);
}
static void int_callback(struct urb *u)
@@ -576,7 +579,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth->suspend_lowmem_rx = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
}
- err("resubmitting rx_urb %d failed", result);
+ dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n",
+ result);
} else {
kaweth->suspend_lowmem_rx = 0;
}
@@ -634,20 +638,21 @@ static void kaweth_usb_receive(struct urb *urb)
spin_unlock(&kaweth->device_lock);
if(status && status != -EREMOTEIO && count != 1) {
- err("%s RX status: %d count: %d packet_len: %d",
- net->name,
- status,
- count,
- (int)pkt_len);
+ dev_err(&kaweth->intf->dev,
+ "%s RX status: %d count: %d packet_len: %d\n",
+ net->name, status, count, (int)pkt_len);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
if(kaweth->net && (count > 2)) {
if(pkt_len > (count - 2)) {
- err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
- err("Packet len & 2047: %x", pkt_len & 2047);
- err("Count 2: %x", count2);
+ dev_err(&kaweth->intf->dev,
+ "Packet length too long for USB frame (pkt_len: %x, count: %x)\n",
+ pkt_len, count);
+ dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n",
+ pkt_len & 2047);
+ dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
@@ -686,7 +691,7 @@ static int kaweth_open(struct net_device *net)
res = usb_autopm_get_interface(kaweth->intf);
if (res) {
- err("Interface cannot be resumed.");
+ dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n");
return -EIO;
}
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
@@ -907,7 +912,8 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
KAWETH_CONTROL_TIMEOUT);
if(result < 0) {
- err("Failed to set Rx mode: %d", result);
+ dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
+ result);
}
else {
dbg("Set Rx mode to %d", packet_filter_bitmap);
@@ -1045,7 +1051,8 @@ static int kaweth_probe(
"kaweth/new_code.bin",
100,
2)) < 0) {
- err("Error downloading firmware (%d)", result);
+ dev_err(&intf->dev, "Error downloading firmware (%d)\n",
+ result);
goto err_fw;
}
@@ -1053,7 +1060,9 @@ static int kaweth_probe(
"kaweth/new_code_fix.bin",
100,
3)) < 0) {
- err("Error downloading firmware fix (%d)", result);
+ dev_err(&intf->dev,
+ "Error downloading firmware fix (%d)\n",
+ result);
goto err_fw;
}
@@ -1061,7 +1070,9 @@ static int kaweth_probe(
"kaweth/trigger_code.bin",
126,
2)) < 0) {
- err("Error downloading trigger code (%d)", result);
+ dev_err(&intf->dev,
+ "Error downloading trigger code (%d)\n",
+ result);
goto err_fw;
}
@@ -1070,13 +1081,14 @@ static int kaweth_probe(
"kaweth/trigger_code_fix.bin",
126,
3)) < 0) {
- err("Error downloading trigger code fix (%d)", result);
+ dev_err(&intf->dev, "Error downloading trigger code fix (%d)\n", result);
goto err_fw;
}
if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
- err("Error triggering firmware (%d)", result);
+ dev_err(&intf->dev, "Error triggering firmware (%d)\n",
+ result);
goto err_fw;
}
@@ -1091,7 +1103,7 @@ err_fw:
result = kaweth_read_configuration(kaweth);
if(result < 0) {
- err("Error reading configuration (%d), no net device created", result);
+ dev_err(&intf->dev, "Error reading configuration (%d), no net device created\n", result);
goto err_free_netdev;
}
@@ -1103,7 +1115,7 @@ err_fw:
if(!memcmp(&kaweth->configuration.hw_addr,
&bcast_addr,
sizeof(bcast_addr))) {
- err("Firmware not functioning properly, no net device created");
+ dev_err(&intf->dev, "Firmware not functioning properly, no net device created\n");
goto err_free_netdev;
}
@@ -1113,7 +1125,7 @@ err_fw:
}
if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
- err("Error setting SOFS wait");
+ dev_err(&intf->dev, "Error setting SOFS wait\n");
goto err_free_netdev;
}
@@ -1123,7 +1135,7 @@ err_fw:
KAWETH_PACKET_FILTER_MULTICAST);
if(result < 0) {
- err("Error setting receive filter");
+ dev_err(&intf->dev, "Error setting receive filter\n");
goto err_free_netdev;
}
@@ -1175,7 +1187,7 @@ err_fw:
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
- err("Error registering netdev.");
+ dev_err(&intf->dev, "Error registering netdev.\n");
goto err_intfdata;
}
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index 45a981f..808d650 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -344,6 +344,7 @@ static struct usb_driver lg_vl600_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(lg_vl600_driver);
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index c434b6b..add1064 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -690,6 +690,7 @@ static struct usb_driver mcs7830_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.reset_resume = mcs7830_reset_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(mcs7830_driver);
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 83f965c..28c4d51 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -587,6 +587,7 @@ static struct usb_driver net1080_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(net1080_driver);
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 7523930..7023220 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1489,6 +1489,7 @@ static struct usb_driver pegasus_driver = {
.id_table = pegasus_ids,
.suspend = pegasus_suspend,
.resume = pegasus_resume,
+ .disable_hub_initiated_lpm = 1,
};
static void __init parse_id(char *id)
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index b2b035e..4584b9a 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -152,6 +152,7 @@ static struct usb_driver plusb_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(plusb_driver);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index d316503b..380dbea 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -356,10 +356,19 @@ static const struct driver_info qmi_wwan_gobi = {
};
/* ZTE suck at making USB descriptors */
+static const struct driver_info qmi_wwan_force_int1 = {
+ .description = "Qualcomm WWAN/QMI device",
+ .flags = FLAG_WWAN,
+ .bind = qmi_wwan_bind_shared,
+ .unbind = qmi_wwan_unbind_shared,
+ .manage_power = qmi_wwan_manage_power,
+ .data = BIT(1), /* interface whitelist bitmap */
+};
+
static const struct driver_info qmi_wwan_force_int4 = {
- .description = "Qualcomm Gobi wwan/QMI device",
+ .description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
- .bind = qmi_wwan_bind_gobi,
+ .bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind_shared,
.manage_power = qmi_wwan_manage_power,
.data = BIT(4), /* interface whitelist bitmap */
@@ -401,6 +410,14 @@ static const struct usb_device_id products[] = {
.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = HUAWEI_VENDOR_ID,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
{ /* Huawei E392, E398 and possibly others in "Windows mode"
* using a combined control and data interface without any CDC
* functional descriptors
@@ -430,6 +447,15 @@ static const struct usb_device_id products[] = {
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
+ { /* ZTE (Vodafone) K3520-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x19d2,
+ .idProduct = 0x0055,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff,
+ .driver_info = (unsigned long)&qmi_wwan_force_int1,
+ },
{ /* ZTE (Vodafone) K3565-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
@@ -457,6 +483,15 @@ static const struct usb_device_id products[] = {
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
+ { /* ZTE (Vodafone) K3765-Z */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x19d2,
+ .idProduct = 0x2002,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff,
+ .driver_info = (unsigned long)&qmi_wwan_force_int4,
+ },
{ /* ZTE (Vodafone) K4505-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
@@ -525,6 +560,7 @@ static struct usb_driver qmi_wwan_driver = {
.resume = qmi_wwan_resume,
.reset_resume = qmi_wwan_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static int __init qmi_wwan_init(void)
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 0d746b3..4a433583 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -638,6 +638,7 @@ static struct usb_driver rndis_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_driver);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index d363b31..0e2c92e 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -203,7 +203,8 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(dev->netdev);
- err("control request submission failed: %d", ret);
+ dev_err(&dev->udev->dev,
+ "control request submission failed: %d\n", ret);
} else
set_bit(RX_REG_SET, &dev->flags);
@@ -516,9 +517,9 @@ resubmit:
if (res == -ENODEV)
netif_device_detach(dev->netdev);
else if (res)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- dev->udev->bus->bus_name,
- dev->udev->devpath, res);
+ dev_err(&dev->udev->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ dev->udev->bus->bus_name, dev->udev->devpath, res);
}
static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
@@ -890,11 +891,11 @@ static int rtl8150_probe(struct usb_interface *intf,
dev->intr_interval = 100; /* 100ms */
if (!alloc_all_urbs(dev)) {
- err("out of memory");
+ dev_err(&intf->dev, "out of memory\n");
goto out;
}
if (!rtl8150_reset(dev)) {
- err("couldn't reset the device");
+ dev_err(&intf->dev, "couldn't reset the device\n");
goto out1;
}
fill_skb_pool(dev);
@@ -903,7 +904,7 @@ static int rtl8150_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
- err("couldn't register the device");
+ dev_err(&intf->dev, "couldn't register the device\n");
goto out2;
}
@@ -947,7 +948,8 @@ static struct usb_driver rtl8150_driver = {
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
.suspend = rtl8150_suspend,
- .resume = rtl8150_resume
+ .resume = rtl8150_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8150_driver);
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index b59cf20..3faef56 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -982,6 +982,7 @@ static struct usb_driver sierra_net_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.no_dynamic_id = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(sierra_net_driver);
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index fb1a087..1c6e515 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1254,6 +1254,7 @@ static struct usb_driver smsc75xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc75xx_driver);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 94ae669..b1112e7 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1297,6 +1297,7 @@ static struct usb_driver smsc95xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc95xx_driver);
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c
index 34db195..35c9030 100644
--- a/drivers/net/usb/zaurus.c
+++ b/drivers/net/usb/zaurus.c
@@ -377,6 +377,7 @@ static struct usb_driver zaurus_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(zaurus_driver);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index fa58c78..9ce6995 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -501,7 +501,9 @@ static void virtnet_napi_enable(struct virtnet_info *vi)
* We synchronize against interrupts via NAPI_STATE_SCHED */
if (napi_schedule_prep(&vi->napi)) {
virtqueue_disable_cb(vi->rvq);
+ local_bh_disable();
__napi_schedule(&vi->napi);
+ local_bh_enable();
}
}
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d70ede7..d58431e 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -203,37 +203,6 @@ config WANXL_BUILD_FIRMWARE
You should never need this option, say N.
-config PC300
- tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
- depends on HDLC && PCI && BROKEN
- ---help---
- This driver is broken because of struct tty_driver change.
-
- Driver for the Cyclades-PC300 synchronous communication boards.
-
- These boards provide synchronous serial interfaces to your
- Linux box (interfaces currently available are RS-232/V.35, X.21 and
- T1/E1). If you wish to support Multilink PPP, please select the
- option later and read the file README.mlppp provided by PC300
- package.
-
- To compile this as a module, choose M here: the module
- will be called pc300.
-
- If unsure, say N.
-
-config PC300_MLPPP
- bool "Cyclades-PC300 MLPPP support"
- depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
- help
- Multilink PPP over the PC300 synchronous communication boards.
-
-comment "Cyclades-PC300 MLPPP support is disabled."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
-comment "Refer to the file README.mlppp, provided by PC300 package."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
config PC300TOO
tristate "Cyclades PC300 RSV/X21 alternative support"
depends on HDLC && PCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 19d14bc..eac709b 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -17,10 +17,6 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
-pc300-y := pc300_drv.o
-pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
-pc300-objs := $(pc300-y)
-
obj-$(CONFIG_HOSTESS_SV11) += z85230.o hostess_sv11.o
obj-$(CONFIG_SEALEVEL_4021) += z85230.o sealevel.o
obj-$(CONFIG_COSA) += cosa.o
@@ -35,7 +31,6 @@ obj-$(CONFIG_SDLA) += sdla.o
obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
-obj-$(CONFIG_PC300) += pc300.o
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 3df0146..efc162e 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1955,7 +1955,7 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
if (ret < 0) {
- err("CMD_SCAN failed: %d", ret);
+ wiphy_err(priv->hw->wiphy, "CMD_SCAN failed: %d\n", ret);
goto exit;
}
@@ -2486,6 +2486,7 @@ static struct usb_driver at76_driver = {
.probe = at76_probe,
.disconnect = at76_disconnect,
.id_table = dev_table,
+ .disable_hub_initiated_lpm = 1,
};
static int __init at76_mod_init(void)
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index ec7f1f5..44a795f 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1182,6 +1182,7 @@ static struct usb_driver ath6kl_usb_driver = {
.disconnect = ath6kl_usb_remove,
.id_table = ath6kl_usb_ids,
.supports_autosuspend = true,
+ .disable_hub_initiated_lpm = 1,
};
static int ath6kl_usb_init(void)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index f67cd95..aa327ad 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1358,6 +1358,7 @@ static struct usb_driver ath9k_hif_usb_driver = {
#endif
.id_table = ath9k_hif_usb_ids,
.soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
};
int ath9k_hif_usb_init(void)
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 89821e4..888152c 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -1159,6 +1159,7 @@ static struct usb_driver carl9170_driver = {
.resume = carl9170_usb_resume,
.reset_resume = carl9170_usb_resume,
#endif /* CONFIG_PM */
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(carl9170_driver);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 1d67ecf..c5a34ff 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1596,7 +1596,8 @@ static struct usb_driver brcmf_usbdrvr = {
.id_table = brcmf_usb_devid_table,
.suspend = brcmf_usb_suspend,
.resume = brcmf_usb_resume,
- .supports_autosuspend = 1
+ .supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
void brcmf_usb_exit(void)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 18a3837..403de96 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -759,7 +759,12 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
IWL_ERR(priv, "alloc_skb failed\n");
return;
}
- hdrlen = min_t(unsigned int, len, skb_tailroom(skb));
+ /* If frame is small enough to fit in skb->head, pull it completely.
+ * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
+ * are more efficient.
+ */
+ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+
memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
fraglen = len - hdrlen;
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 75403e6..cd3b0d4 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1011,6 +1011,7 @@ static struct usb_driver if_usb_driver = {
.suspend = if_usb_suspend,
.resume = if_usb_resume,
.reset_resume = if_usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 7ced130..19a5a92 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -920,6 +920,7 @@ static struct usb_driver if_usb_driver = {
.id_table = if_usb_table,
.suspend = if_usb_suspend,
.resume = if_usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index f634d45..7f53cea2 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1752,6 +1752,7 @@ static struct usb_driver orinoco_driver = {
.probe = ezusb_probe,
.disconnect = ezusb_disconnect,
.id_table = ezusb_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(orinoco_driver);
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index e1eac83..7f207b6 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -1140,6 +1140,7 @@ static struct usb_driver p54u_driver = {
.reset_resume = p54u_resume,
#endif /* CONFIG_PM */
.soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(p54u_driver);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index b91d1bb..c5404eb 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -3765,6 +3765,7 @@ static struct usb_driver rndis_wlan_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_wlan_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index c88fd3e..669aecd 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1980,6 +1980,7 @@ static struct usb_driver rt2500usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2500usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5601302..bf78317 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1302,6 +1302,7 @@ static struct usb_driver rt2800usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2800usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 1551366..77ccbbc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2527,6 +2527,7 @@ static struct usb_driver rt73usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt73usb_driver);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index d811496..4fb1ca1 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1663,6 +1663,7 @@ static struct usb_driver rtl8187_driver = {
.id_table = rtl8187_table,
.probe = rtl8187_probe,
.disconnect = __devexit_p(rtl8187_disconnect),
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8187_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 7737fb0..d228358 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -373,6 +373,7 @@ static struct usb_driver rtl8192cu_driver = {
#ifdef CONFIG_AUTOSUSPEND
.supports_autosuspend = 1,
#endif
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8192cu_driver);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index a66b93b..48273dd 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1905,6 +1905,7 @@ static struct usb_driver zd1201_usb = {
.id_table = zd1201_table,
.suspend = zd1201_suspend,
.resume = zd1201_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(zd1201_usb);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index f766b3e..af83c43 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1542,6 +1542,7 @@ static struct usb_driver driver = {
.disconnect = disconnect,
.pre_reset = pre_reset,
.post_reset = post_reset,
+ .disable_hub_initiated_lpm = 1,
};
struct workqueue_struct *zd_workqueue;
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 66d96f1..7e262a6 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -1,4 +1,5 @@
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 5806449..d9bfd49 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *np, const char *stem)
return id;
}
EXPORT_SYMBOL_GPL(of_alias_get_id);
+
+const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
+ u32 *pu)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur) {
+ curv = prop->value;
+ goto out_val;
+ }
+
+ curv += sizeof(*cur);
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+out_val:
+ *pu = be32_to_cpup(curv);
+ return curv;
+}
+EXPORT_SYMBOL_GPL(of_prop_next_u32);
+
+const char *of_prop_next_string(struct property *prop, const char *cur)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->value;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+ return curv;
+}
+EXPORT_SYMBOL_GPL(of_prop_next_string);
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index e3b76d4..5003458 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -348,7 +348,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
BUG();
return -1;
}
- printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
+ printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n",
pci_name(pcidev),
pcidev->vendor, pcidev->device,
__builtin_return_address(0));
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 8bef6d6..ee78e0e 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -48,23 +48,6 @@ static unsigned char amiga_read_data(struct parport *p)
return ciaa.prb;
}
-#if 0
-static unsigned char control_pc_to_amiga(unsigned char control)
-{
- unsigned char ret = 0;
-
- if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
- ;
- if (control & PARPORT_CONTROL_INIT) /* INITP */
- /* reset connected to cpu reset pin */;
- if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
- /* Not connected */;
- if (control & PARPORT_CONTROL_STROBE) /* Strobe */
- /* Handled only directly by hardware */;
- return ret;
-}
-#endif
-
static unsigned char control_amiga_to_pc(unsigned char control)
{
return PARPORT_CONTROL_SELECT |
@@ -95,25 +78,6 @@ static unsigned char amiga_frob_control( struct parport *p, unsigned char mask,
return old;
}
-#if 0 /* currently unused */
-static unsigned char status_pc_to_amiga(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- /* handled in hardware */;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- /* not connected */;
- return ret;
-}
-#endif
-
static unsigned char status_amiga_to_pc(unsigned char status)
{
unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 0b28fcc..7ad59ac 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -130,15 +130,6 @@ parport_atari_data_forward(struct parport *p)
static void
parport_atari_data_reverse(struct parport *p)
{
-#if 0 /* too dangerous, can kill sound chip */
- unsigned long flags;
-
- local_irq_save(flags);
- /* Soundchip port B as input. */
- sound_ym.rd_data_reg_sel = 7;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40;
- local_irq_restore(flags);
-#endif
}
static struct parport_operations parport_atari_ops = {
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 1c0c642..7578d79 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -147,25 +147,6 @@ DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val);
return old;
}
-#if 0 /* currently unused */
-static unsigned char status_pc_to_mfc3(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- ret |= 8;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- ret |= 16;
- return ret;
-}
-#endif
-
static unsigned char status_mfc3_to_pc(unsigned char status)
{
unsigned char ret = PARPORT_STATUS_BUSY;
@@ -184,14 +165,6 @@ static unsigned char status_mfc3_to_pc(unsigned char status)
return ret;
}
-#if 0 /* currently unused */
-static void mfc3_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK(KERN_DEBUG "write_status %02x\n",status);
- pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
-}
-#endif
-
static unsigned char mfc3_read_status(struct parport *p)
{
unsigned char status;
@@ -201,14 +174,6 @@ DPRINTK(KERN_DEBUG "read_status %02x\n", status);
return status;
}
-#if 0 /* currently unused */
-static void mfc3_change_mode( struct parport *p, int m)
-{
- /* XXX: This port only has one mode, and I am
- not sure about the corresponding PC-style mode*/
-}
-#endif
-
static int use_cnt = 0;
static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 0cb64f5..5abffe5 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -197,54 +197,6 @@ static int change_mode(struct parport *p, int m)
ECR_WRITE(p, oecr);
return 0;
}
-
-#ifdef CONFIG_PARPORT_1284
-/* Find FIFO lossage; FIFO is reset */
-#if 0
-static int get_fifo_residue(struct parport *p)
-{
- int residue;
- int cnfga;
- const struct parport_pc_private *priv = p->physport->private_data;
-
- /* Adjust for the contents of the FIFO. */
- for (residue = priv->fifo_depth; ; residue--) {
- if (inb(ECONTROL(p)) & 0x2)
- /* Full up. */
- break;
-
- outb(0, FIFO(p));
- }
-
- printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
- residue);
-
- /* Reset the FIFO. */
- frob_set_mode(p, ECR_PS2);
-
- /* Now change to config mode and clean up. FIXME */
- frob_set_mode(p, ECR_CNF);
- cnfga = inb(CONFIGA(p));
- printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
-
- if (!(cnfga & (1<<2))) {
- printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
- residue++;
- }
-
- /* Don't care about partial PWords until support is added for
- * PWord != 1 byte. */
-
- /* Back to PS2 mode. */
- frob_set_mode(p, ECR_PS2);
-
- DPRINTK(KERN_DEBUG
- "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n",
- inb(ECONTROL(p)));
- return residue;
-}
-#endif /* 0 */
-#endif /* IEEE 1284 support */
#endif /* FIFO support */
/*
@@ -940,234 +892,6 @@ static size_t parport_pc_ecp_write_block_pio(struct parport *port,
return written;
}
-
-#if 0
-static size_t parport_pc_ecp_read_block_pio(struct parport *port,
- void *buf, size_t length,
- int flags)
-{
- size_t left = length;
- size_t fifofull;
- int r;
- const int fifo = FIFO(port);
- const struct parport_pc_private *priv = port->physport->private_data;
- const int fifo_depth = priv->fifo_depth;
- char *bufp = buf;
-
- port = port->physport;
- DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
- dump_parport_state("enter fcn", port);
-
- /* Special case: a timeout of zero means we cannot call schedule().
- * Also if O_NONBLOCK is set then use the default implementation. */
- if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
- return parport_ieee1284_ecp_read_data(port, buf,
- length, flags);
-
- if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
- /* If the peripheral is allowed to send RLE compressed
- * data, it is possible for a byte to expand to 128
- * bytes in the FIFO. */
- fifofull = 128;
- } else {
- fifofull = fifo_depth;
- }
-
- /* If the caller wants less than a full FIFO's worth of data,
- * go through software emulation. Otherwise we may have to throw
- * away data. */
- if (length < fifofull)
- return parport_ieee1284_ecp_read_data(port, buf,
- length, flags);
-
- if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
- /* change to reverse-idle phase (must be in forward-idle) */
-
- /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
- parport_frob_control(port,
- PARPORT_CONTROL_AUTOFD
- | PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_AUTOFD);
- parport_pc_data_reverse(port); /* Must be in PS2 mode */
- udelay(5);
- /* Event 39: Set nInit low to initiate bus reversal */
- parport_frob_control(port,
- PARPORT_CONTROL_INIT,
- 0);
- /* Event 40: Wait for nAckReverse (PError) to go low */
- r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0);
- if (r) {
- printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) "
- "in ecp_read_block_pio\n", port->name, r);
- return 0;
- }
- }
-
- /* Set up ECP FIFO mode.*/
-/* parport_pc_frob_control(port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD); */
- r = change_mode(port, ECR_ECP); /* ECP FIFO */
- if (r)
- printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n",
- port->name);
-
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
- /* the first byte must be collected manually */
- dump_parport_state("pre 43", port);
- /* Event 43: Wait for nAck to go low */
- r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0);
- if (r) {
- /* timed out while reading -- no data */
- printk(KERN_DEBUG "PIO read timed out (initial byte)\n");
- goto out_no_data;
- }
- /* read byte */
- *bufp++ = inb(DATA(port));
- left--;
- dump_parport_state("43-44", port);
- /* Event 44: nAutoFd (HostAck) goes high to acknowledge */
- parport_pc_frob_control(port,
- PARPORT_CONTROL_AUTOFD,
- 0);
- dump_parport_state("pre 45", port);
- /* Event 45: Wait for nAck to go high */
- /* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK); */
- dump_parport_state("post 45", port);
- r = 0;
- if (r) {
- /* timed out while waiting for peripheral to respond to ack */
- printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
-
- /* keep hold of the byte we've got already */
- goto out_no_data;
- }
- /* Event 46: nAutoFd (HostAck) goes low to accept more data */
- parport_pc_frob_control(port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
-
- dump_parport_state("rev idle", port);
- /* Do the transfer. */
- while (left > fifofull) {
- int ret;
- unsigned long expire = jiffies + port->cad->timeout;
- unsigned char ecrval = inb(ECONTROL(port));
-
- if (need_resched() && time_before(jiffies, expire))
- /* Can't yield the port. */
- schedule();
-
- /* At this point, the FIFO may already be full. In
- * that case ECP is already holding back the
- * peripheral (assuming proper design) with a delayed
- * handshake. Work fast to avoid a peripheral
- * timeout. */
-
- if (ecrval & 0x01) {
- /* FIFO is empty. Wait for interrupt. */
- dump_parport_state("FIFO empty", port);
-
- /* Anyone else waiting for the port? */
- if (port->waithead) {
- printk(KERN_DEBUG "Somebody wants the port\n");
- break;
- }
-
- /* Clear serviceIntr */
- ECR_WRITE(port, ecrval & ~(1<<2));
-false_alarm:
- dump_parport_state("waiting", port);
- ret = parport_wait_event(port, HZ);
- DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n",
- ret);
- if (ret < 0)
- break;
- ret = 0;
- if (!time_before(jiffies, expire)) {
- /* Timed out. */
- dump_parport_state("timeout", port);
- printk(KERN_DEBUG "PIO read timed out\n");
- break;
- }
- ecrval = inb(ECONTROL(port));
- if (!(ecrval & (1<<2))) {
- if (need_resched() &&
- time_before(jiffies, expire)) {
- schedule();
- }
- goto false_alarm;
- }
-
- /* Depending on how the FIFO threshold was
- * set, how long interrupt service took, and
- * how fast the peripheral is, we might be
- * lucky and have a just filled FIFO. */
- continue;
- }
-
- if (ecrval & 0x02) {
- /* FIFO is full. */
- dump_parport_state("FIFO full", port);
- insb(fifo, bufp, fifo_depth);
- bufp += fifo_depth;
- left -= fifo_depth;
- continue;
- }
-
- DPRINTK(KERN_DEBUG
- "*** ecp_read_block_pio: reading one byte from the FIFO\n");
-
- /* FIFO not filled. We will cycle this loop for a while
- * and either the peripheral will fill it faster,
- * tripping a fast empty with insb, or we empty it. */
- *bufp++ = inb(fifo);
- left--;
- }
-
- /* scoop up anything left in the FIFO */
- while (left && !(inb(ECONTROL(port) & 0x01))) {
- *bufp++ = inb(fifo);
- left--;
- }
-
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- dump_parport_state("rev idle2", port);
-
-out_no_data:
-
- /* Go to forward idle mode to shut the peripheral up (event 47). */
- parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
-
- /* event 49: PError goes high */
- r = parport_wait_peripheral(port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
- if (r) {
- printk(KERN_DEBUG
- "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
- port->name, r);
- }
-
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- /* Finish up. */
- {
- int lost = get_fifo_residue(port);
- if (lost)
- /* Shouldn't happen with compliant peripherals. */
- printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
- port->name, lost);
- }
-
- dump_parport_state("fwd idle", port);
- return length - left;
-}
-#endif /* 0 */
#endif /* IEEE 1284 support */
#endif /* Allowed to use FIFO/DMA */
@@ -2351,7 +2075,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
if (p->base_hi && priv->ecr)
- printk(" (0x%lx)", p->base_hi);
+ printk(KERN_CONT " (0x%lx)", p->base_hi);
if (p->irq == PARPORT_IRQ_AUTO) {
p->irq = PARPORT_IRQ_NONE;
parport_irq_probe(p);
@@ -2362,7 +2086,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
p->irq = PARPORT_IRQ_NONE;
}
if (p->irq != PARPORT_IRQ_NONE) {
- printk(", irq %d", p->irq);
+ printk(KERN_CONT ", irq %d", p->irq);
priv->ctr_writable |= 0x10;
if (p->dma == PARPORT_DMA_AUTO) {
@@ -2386,21 +2110,21 @@ struct parport *parport_pc_probe_port(unsigned long int base,
/* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
#endif /* IEEE 1284 support */
if (p->dma != PARPORT_DMA_NONE) {
- printk(", dma %d", p->dma);
+ printk(KERN_CONT ", dma %d", p->dma);
p->modes |= PARPORT_MODE_DMA;
} else
- printk(", using FIFO");
+ printk(KERN_CONT ", using FIFO");
} else
/* We can't use the DMA channel after all. */
p->dma = PARPORT_DMA_NONE;
#endif /* Allowed to use FIFO/DMA */
- printk(" [");
+ printk(KERN_CONT " [");
#define printmode(x) \
{\
if (p->modes & PARPORT_MODE_##x) {\
- printk("%s%s", f ? "," : "", #x);\
+ printk(KERN_CONT "%s%s", f ? "," : "", #x);\
f++;\
} \
}
@@ -2416,9 +2140,9 @@ struct parport *parport_pc_probe_port(unsigned long int base,
}
#undef printmode
#ifndef CONFIG_PARPORT_1284
- printk("(,...)");
+ printk(KERN_CONT "(,...)");
#endif /* CONFIG_PARPORT_1284 */
- printk("]\n");
+ printk(KERN_CONT "]\n");
if (probedirq != PARPORT_IRQ_NONE)
printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9390a53..983a2d2 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -82,27 +82,6 @@ static unsigned char parport_sunbpp_read_data(struct parport *p)
return sbus_readb(&regs->p_dr);
}
-#if 0
-static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
-{
- struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
- unsigned char value_tcr = sbus_readb(&regs->p_tcr);
- unsigned char value_or = sbus_readb(&regs->p_or);
-
- if (status & PARPORT_CONTROL_STROBE)
- value_tcr |= P_TCR_DS;
- if (status & PARPORT_CONTROL_AUTOFD)
- value_or |= P_OR_AFXN;
- if (status & PARPORT_CONTROL_INIT)
- value_or |= P_OR_INIT;
- if (status & PARPORT_CONTROL_SELECT)
- value_or |= P_OR_SLCT_IN;
-
- sbus_writeb(value_or, &regs->p_or);
- sbus_writeb(value_tcr, &regs->p_tcr);
-}
-#endif
-
static unsigned char status_sunbpp_to_pc(struct parport *p)
{
struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 165274c..01c001f 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -2,7 +2,7 @@
# Makefile for the PCI bus specific drivers.
#
-obj-y += access.o bus.o probe.o remove.o pci.o \
+obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
irq.o vpd.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
new file mode 100644
index 0000000..a68dc61
--- /dev/null
+++ b/drivers/pci/host-bridge.c
@@ -0,0 +1,96 @@
+/*
+ * host bridge related code
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+
+#include "pci.h"
+
+static struct pci_bus *find_pci_root_bus(struct pci_dev *dev)
+{
+ struct pci_bus *bus;
+
+ bus = dev->bus;
+ while (bus->parent)
+ bus = bus->parent;
+
+ return bus;
+}
+
+static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev)
+{
+ struct pci_bus *bus = find_pci_root_bus(dev);
+
+ return to_pci_host_bridge(bus->bridge);
+}
+
+void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
+ void (*release_fn)(struct pci_host_bridge *),
+ void *release_data)
+{
+ bridge->release_fn = release_fn;
+ bridge->release_data = release_data;
+}
+
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+ return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
+{
+ struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ if (resource_contains(window->res, res)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ region->start = res->start - offset;
+ region->end = res->end - offset;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+static bool region_contains(struct pci_bus_region *region1,
+ struct pci_bus_region *region2)
+{
+ return region1->start <= region2->start && region1->end >= region2->end;
+}
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ struct pci_bus_region bus_region;
+
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ bus_region.start = window->res->start - window->offset;
+ bus_region.end = window->res->end - window->offset;
+
+ if (region_contains(&bus_region, region)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ res->start = region->start + offset;
+ res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 1929c0c..61e2fef 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -223,7 +223,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
[PCI_D0] = ACPI_STATE_D0,
[PCI_D1] = ACPI_STATE_D1,
[PCI_D2] = ACPI_STATE_D2,
- [PCI_D3hot] = ACPI_STATE_D3_HOT,
+ [PCI_D3hot] = ACPI_STATE_D3,
[PCI_D3cold] = ACPI_STATE_D3
};
int error = -EINVAL;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 6b54b23..bf0cee6 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -421,6 +421,12 @@ static void pci_device_shutdown(struct device *dev)
pci_msix_shutdown(pci_dev);
/*
+ * Turn off Bus Master bit on the device to tell it to not
+ * continue to do DMA
+ */
+ pci_disable_device(pci_dev);
+
+ /*
* Devices may be enabled to wake up by runtime PM, but they need not
* be supposed to wake up the system from its "power off" state (e.g.
* ACPI S5). Therefore disable wakeup for all devices that aren't
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 111569c..8f16900 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
+#include <asm-generic/pci-bridge.h>
#include <asm/setup.h>
#include "pci.h"
@@ -3164,18 +3165,12 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
return 0;
}
-static int pci_dev_reset(struct pci_dev *dev, int probe)
+static int __pci_dev_reset(struct pci_dev *dev, int probe)
{
int rc;
might_sleep();
- if (!probe) {
- pci_cfg_access_lock(dev);
- /* block PM suspend, driver probe, etc. */
- device_lock(&dev->dev);
- }
-
rc = pci_dev_specific_reset(dev, probe);
if (rc != -ENOTTY)
goto done;
@@ -3194,14 +3189,27 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
rc = pci_parent_bus_reset(dev, probe);
done:
+ return rc;
+}
+
+static int pci_dev_reset(struct pci_dev *dev, int probe)
+{
+ int rc;
+
+ if (!probe) {
+ pci_cfg_access_lock(dev);
+ /* block PM suspend, driver probe, etc. */
+ device_lock(&dev->dev);
+ }
+
+ rc = __pci_dev_reset(dev, probe);
+
if (!probe) {
device_unlock(&dev->dev);
pci_cfg_access_unlock(dev);
}
-
return rc;
}
-
/**
* __pci_reset_function - reset a PCI device function
* @dev: PCI device to reset
@@ -3246,7 +3254,7 @@ EXPORT_SYMBOL_GPL(__pci_reset_function);
*/
int __pci_reset_function_locked(struct pci_dev *dev)
{
- return pci_dev_reset(dev, 1);
+ return __pci_dev_reset(dev, 0);
}
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
@@ -3893,6 +3901,8 @@ static int __init pci_setup(char *str)
pcie_bus_config = PCIE_BUS_PERFORMANCE;
} else if (!strncmp(str, "pcie_bus_peer2peer", 18)) {
pcie_bus_config = PCIE_BUS_PEER2PEER;
+ } else if (!strncmp(str, "pcie_scan_all", 13)) {
+ pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 2f589a5..75915b3 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -249,7 +249,7 @@ static int get_port_device_capability(struct pci_dev *dev)
int services = 0, pos;
u16 reg16;
u32 reg32;
- int cap_mask;
+ int cap_mask = 0;
int err;
if (pcie_ports_disabled)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5e1ca3c..658ac97 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -10,18 +10,16 @@
#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/pci-aspm.h>
+#include <asm-generic/pci-bridge.h>
#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
-static LIST_HEAD(pci_host_bridges);
-
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
-
static int find_anything(struct device *dev, void *data)
{
return 1;
@@ -44,82 +42,6 @@ int no_pci_devices(void)
}
EXPORT_SYMBOL(no_pci_devices);
-static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
-{
- struct pci_bus *bus;
- struct pci_host_bridge *bridge;
-
- bus = dev->bus;
- while (bus->parent)
- bus = bus->parent;
-
- list_for_each_entry(bridge, &pci_host_bridges, list) {
- if (bridge->bus == bus)
- return bridge;
- }
-
- return NULL;
-}
-
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
- return res1->start <= res2->start && res1->end >= res2->end;
-}
-
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- struct pci_host_bridge *bridge = pci_host_bridge(dev);
- struct pci_host_bridge_window *window;
- resource_size_t offset = 0;
-
- list_for_each_entry(window, &bridge->windows, list) {
- if (resource_type(res) != resource_type(window->res))
- continue;
-
- if (resource_contains(window->res, res)) {
- offset = window->offset;
- break;
- }
- }
-
- region->start = res->start - offset;
- region->end = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-static bool region_contains(struct pci_bus_region *region1,
- struct pci_bus_region *region2)
-{
- return region1->start <= region2->start && region1->end >= region2->end;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- struct pci_host_bridge *bridge = pci_host_bridge(dev);
- struct pci_host_bridge_window *window;
- struct pci_bus_region bus_region;
- resource_size_t offset = 0;
-
- list_for_each_entry(window, &bridge->windows, list) {
- if (resource_type(res) != resource_type(window->res))
- continue;
-
- bus_region.start = window->res->start - window->offset;
- bus_region.end = window->res->end - window->offset;
-
- if (region_contains(&bus_region, region)) {
- offset = window->offset;
- break;
- }
- }
-
- res->start = region->start + offset;
- res->end = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
/*
* PCI Bus Class
*/
@@ -501,6 +423,19 @@ static struct pci_bus * pci_alloc_bus(void)
return b;
}
+static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
+{
+ struct pci_host_bridge *bridge;
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (bridge) {
+ INIT_LIST_HEAD(&bridge->windows);
+ bridge->bus = b;
+ }
+
+ return bridge;
+}
+
static unsigned char pcix_bus_speed[] = {
PCI_SPEED_UNKNOWN, /* 0 */
PCI_SPEED_66MHz_PCIX, /* 1 */
@@ -1201,7 +1136,14 @@ int pci_cfg_space_size(struct pci_dev *dev)
static void pci_release_bus_bridge_dev(struct device *dev)
{
- kfree(dev);
+ struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
+
+ if (bridge->release_fn)
+ bridge->release_fn(bridge);
+
+ pci_free_resource_list(&bridge->windows);
+
+ kfree(bridge);
}
struct pci_dev *alloc_pci_dev(void)
@@ -1395,10 +1337,13 @@ static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
static int only_one_child(struct pci_bus *bus)
{
struct pci_dev *parent = bus->self;
+
if (!parent || !pci_is_pcie(parent))
return 0;
- if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
- parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
+ if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ return 1;
+ if (parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM &&
+ !pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
return 1;
return 0;
}
@@ -1650,28 +1595,19 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
int error;
struct pci_host_bridge *bridge;
struct pci_bus *b, *b2;
- struct device *dev;
struct pci_host_bridge_window *window, *n;
struct resource *res;
resource_size_t offset;
char bus_addr[64];
char *fmt;
- bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
- if (!bridge)
- return NULL;
b = pci_alloc_bus();
if (!b)
- goto err_bus;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- goto err_dev;
+ return NULL;
b->sysdata = sysdata;
b->ops = ops;
-
b2 = pci_find_bus(pci_domain_nr(b), bus);
if (b2) {
/* If we already got to this bus through a different bridge, ignore it */
@@ -1679,13 +1615,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
goto err_out;
}
- dev->parent = parent;
- dev->release = pci_release_bus_bridge_dev;
- dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
- error = device_register(dev);
+ bridge = pci_alloc_host_bridge(b);
+ if (!bridge)
+ goto err_out;
+
+ bridge->dev.parent = parent;
+ bridge->dev.release = pci_release_bus_bridge_dev;
+ dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+ error = device_register(&bridge->dev);
if (error)
- goto dev_reg_err;
- b->bridge = get_device(dev);
+ goto bridge_dev_reg_err;
+ b->bridge = get_device(&bridge->dev);
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
@@ -1704,9 +1644,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
b->number = b->secondary = bus;
- bridge->bus = b;
- INIT_LIST_HEAD(&bridge->windows);
-
if (parent)
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
else
@@ -1732,25 +1669,18 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
}
down_write(&pci_bus_sem);
- list_add_tail(&bridge->list, &pci_host_bridges);
list_add_tail(&b->node, &pci_root_buses);
up_write(&pci_bus_sem);
return b;
class_dev_reg_err:
- device_unregister(dev);
-dev_reg_err:
- down_write(&pci_bus_sem);
- list_del(&bridge->list);
- list_del(&b->node);
- up_write(&pci_bus_sem);
+ put_device(&bridge->dev);
+ device_unregister(&bridge->dev);
+bridge_dev_reg_err:
+ kfree(bridge);
err_out:
- kfree(dev);
-err_dev:
kfree(b);
-err_bus:
- kfree(bridge);
return NULL;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 953ec3f..2a75216 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3097,16 +3097,74 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
return 0;
}
+#include "../gpu/drm/i915/i915_reg.h"
+#define MSG_CTL 0x45010
+#define NSDE_PWR_STATE 0xd0100
+#define IGD_OPERATION_TIMEOUT 10000 /* set timeout 10 seconds */
+
+static int reset_ivb_igd(struct pci_dev *dev, int probe)
+{
+ void __iomem *mmio_base;
+ unsigned long timeout;
+ u32 val;
+
+ if (probe)
+ return 0;
+
+ mmio_base = pci_iomap(dev, 0, 0);
+ if (!mmio_base)
+ return -ENOMEM;
+
+ iowrite32(0x00000002, mmio_base + MSG_CTL);
+
+ /*
+ * Clobbering SOUTH_CHICKEN2 register is fine only if the next
+ * driver loaded sets the right bits. However, this's a reset and
+ * the bits have been set by i915 previously, so we clobber
+ * SOUTH_CHICKEN2 register directly here.
+ */
+ iowrite32(0x00000005, mmio_base + SOUTH_CHICKEN2);
+
+ val = ioread32(mmio_base + PCH_PP_CONTROL) & 0xfffffffe;
+ iowrite32(val, mmio_base + PCH_PP_CONTROL);
+
+ timeout = jiffies + msecs_to_jiffies(IGD_OPERATION_TIMEOUT);
+ do {
+ val = ioread32(mmio_base + PCH_PP_STATUS);
+ if ((val & 0xb0000000) == 0)
+ goto reset_complete;
+ msleep(10);
+ } while (time_before(jiffies, timeout));
+ dev_warn(&dev->dev, "timeout during reset\n");
+
+reset_complete:
+ iowrite32(0x00000002, mmio_base + NSDE_PWR_STATE);
+
+ pci_iounmap(dev, mmio_base);
+ return 0;
+}
+
#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
+#define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156
+#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M_VGA,
+ reset_ivb_igd },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA,
+ reset_ivb_igd },
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
reset_intel_generic_dev },
{ 0 }
};
+/*
+ * These device-specific reset methods are here rather than in a driver
+ * because when a host assigns a device to a guest VM, the host may need
+ * to reset the device but probably doesn't have a driver for it.
+ */
int pci_dev_specific_reset(struct pci_dev *dev, int probe)
{
const struct pci_dev_reset_methods *i;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index bba3ab2..8fd255f 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -217,7 +217,7 @@ config PCMCIA_PXA2XX
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
- || MACH_COLIBRI320)
+ || MACH_COLIBRI320 || MACH_H4700)
select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111
select PCMCIA_SOC_COMMON
help
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 47525de..7745b51 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -69,6 +69,7 @@ pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o
pxa2xx-obj-$(CONFIG_MACH_COLIBRI) += pxa2xx_colibri.o
pxa2xx-obj-$(CONFIG_MACH_COLIBRI320) += pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_H4700) += pxa2xx_hx4700.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/pxa2xx_hx4700.c b/drivers/pcmcia/pxa2xx_hx4700.c
new file mode 100644
index 0000000..7dfef3e
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_hx4700.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <mach/hx4700.h>
+
+#include "soc_common.h"
+
+static struct gpio gpios[] = {
+ { GPIO114_HX4700_CF_RESET, GPIOF_OUT_INIT_LOW, "CF reset" },
+ { EGPIO4_CF_3V3_ON, GPIOF_OUT_INIT_LOW, "CF 3.3V enable" },
+};
+
+static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ int ret;
+
+ ret = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+ if (ret)
+ goto out;
+
+ /*
+ * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq().
+ * The asic3 default IRQ type is level trigger low level detect, exactly
+ * the the signal present on GPIOD4_CF_nCD when a CF card is inserted.
+ * If the IRQ type is not changed, the asic3 interrupt handler will loop
+ * repeatedly because it is unable to clear the level trigger interrupt.
+ */
+ irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH);
+
+ skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD;
+ skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+ skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB;
+ skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+out:
+ return ret;
+}
+
+static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ gpio_free_array(gpios, ARRAY_SIZE(gpios));
+}
+
+static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ state->vs_3v = 1;
+ state->vs_Xv = 0;
+}
+
+static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ switch (state->Vcc) {
+ case 0:
+ gpio_set_value(EGPIO4_CF_3V3_ON, 0);
+ break;
+ case 33:
+ gpio_set_value(EGPIO4_CF_3V3_ON, 1);
+ break;
+ default:
+ printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc);
+ return -EINVAL;
+ }
+
+ gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0);
+
+ return 0;
+}
+
+static struct pcmcia_low_level hx4700_pcmcia_ops = {
+ .owner = THIS_MODULE,
+ .nr = 1,
+ .hw_init = hx4700_pcmcia_hw_init,
+ .hw_shutdown = hx4700_pcmcia_hw_shutdown,
+ .socket_state = hx4700_pcmcia_socket_state,
+ .configure_socket = hx4700_pcmcia_configure_socket,
+};
+
+static struct platform_device *hx4700_pcmcia_device;
+
+static int __init hx4700_pcmcia_init(void)
+{
+ struct platform_device *pdev;
+
+ if (!machine_is_h4700())
+ return -ENODEV;
+
+ pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1,
+ &hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ hx4700_pcmcia_device = pdev;
+
+ return 0;
+}
+
+static void __exit hx4700_pcmcia_exit(void)
+{
+ platform_device_unregister(hx4700_pcmcia_device);
+}
+
+module_init(hx4700_pcmcia_init);
+module_exit(hx4700_pcmcia_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index abfb964..c6e6ae0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -4,7 +4,6 @@
config PINCTRL
bool
- depends on EXPERIMENTAL
if PINCTRL
@@ -27,6 +26,35 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINCTRL_IMX
+ bool
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_IMX51
+ bool "IMX51 pinctrl driver"
+ depends on OF
+ depends on SOC_IMX51
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx51 pinctrl driver
+
+config PINCTRL_IMX53
+ bool "IMX53 pinctrl driver"
+ depends on OF
+ depends on SOC_IMX53
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx53 pinctrl driver
+
+config PINCTRL_IMX6Q
+ bool "IMX6Q pinctrl driver"
+ depends on OF
+ depends on SOC_IMX6Q
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx6q pinctrl driver
+
config PINCTRL_PXA3xx
bool
select PINMUX
@@ -37,6 +65,31 @@ config PINCTRL_MMP2
select PINCTRL_PXA3xx
select PINCONF
+config PINCTRL_MXS
+ bool
+
+config PINCTRL_IMX23
+ bool
+ select PINMUX
+ select PINCONF
+ select PINCTRL_MXS
+
+config PINCTRL_IMX28
+ bool
+ select PINMUX
+ select PINCONF
+ select PINCTRL_MXS
+
+config PINCTRL_NOMADIK
+ bool "Nomadik pin controller driver"
+ depends on ARCH_U8500 || ARCH_NOMADIK
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_DB8500
+ bool "DB8500 pin controller driver"
+ depends on PINCTRL_NOMADIK && ARCH_U8500
+
config PINCTRL_PXA168
bool "PXA168 pin controller driver"
depends on ARCH_MMP
@@ -84,6 +137,8 @@ config PINCTRL_COH901
COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
ports of 8 GPIO pins each.
+source "drivers/pinctrl/spear/Kconfig"
+
endmenu
endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 6d4150b..8c07437 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -5,9 +5,21 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
obj-$(CONFIG_PINCTRL) += core.o
obj-$(CONFIG_PINMUX) += pinmux.o
obj-$(CONFIG_PINCONF) += pinconf.o
+ifeq ($(CONFIG_OF),y)
+obj-$(CONFIG_PINCTRL) += devicetree.o
+endif
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
+obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o
+obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o
+obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o
obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
+obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
+obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o
+obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
+obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o
obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
@@ -16,3 +28,5 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
+
+obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index df6296c..c3b331b 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -23,9 +23,11 @@
#include <linux/sysfs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/machine.h>
#include "core.h"
+#include "devicetree.h"
#include "pinmux.h"
#include "pinconf.h"
@@ -41,11 +43,13 @@ struct pinctrl_maps {
unsigned num_maps;
};
+static bool pinctrl_dummy_state;
+
/* Mutex taken by all entry points */
DEFINE_MUTEX(pinctrl_mutex);
/* Global list of pin control devices (struct pinctrl_dev) */
-static LIST_HEAD(pinctrldev_list);
+LIST_HEAD(pinctrldev_list);
/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
@@ -59,6 +63,19 @@ static LIST_HEAD(pinctrl_maps);
_i_ < _maps_node_->num_maps; \
i++, _map_ = &_maps_node_->maps[_i_])
+/**
+ * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
+ *
+ * Usually this function is called by platforms without pinctrl driver support
+ * but run with some shared drivers using pinctrl APIs.
+ * After calling this function, the pinctrl core will return successfully
+ * with creating a dummy state for the driver to keep going smoothly.
+ */
+void pinctrl_provide_dummies(void)
+{
+ pinctrl_dummy_state = true;
+}
+
const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
{
/* We're not allowed to register devices without name */
@@ -124,6 +141,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
}
/**
+ * pin_get_name_from_id() - look up a pin name from a pin id
+ * @pctldev: the pin control device to lookup the pin on
+ * @name: the name of the pin to look up
+ */
+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
+{
+ const struct pin_desc *desc;
+
+ desc = pin_desc_get(pctldev, pin);
+ if (desc == NULL) {
+ dev_err(pctldev->dev, "failed to get pin(%d) name\n",
+ pin);
+ return NULL;
+ }
+
+ return desc->name;
+}
+
+/**
* pin_is_valid() - check if pin exists on controller
* @pctldev: the pin control device to check the pin on
* @pin: pin to check, use the local pin controller index number
@@ -255,7 +291,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
*
* Find the pin controller handling a certain GPIO pin from the pinspace of
* the GPIO subsystem, return the device and the matching GPIO range. Returns
- * negative if the GPIO range could not be found in any device.
+ * -EPROBE_DEFER if the GPIO range could not be found in any device since it
+ * may still have not been registered.
*/
static int pinctrl_get_device_gpio_range(unsigned gpio,
struct pinctrl_dev **outdev,
@@ -275,7 +312,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
}
}
- return -EINVAL;
+ return -EPROBE_DEFER;
}
/**
@@ -318,9 +355,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ unsigned ngroups = pctlops->get_groups_count(pctldev);
unsigned group_selector = 0;
- while (pctlops->list_groups(pctldev, group_selector) >= 0) {
+ while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
group_selector);
if (!strcmp(gname, pin_group)) {
@@ -360,7 +398,7 @@ int pinctrl_request_gpio(unsigned gpio)
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
mutex_unlock(&pinctrl_mutex);
- return -EINVAL;
+ return ret;
}
/* Convert to the pin controllers number space */
@@ -516,11 +554,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
if (setting->pctldev == NULL) {
- dev_err(p->dev, "unknown pinctrl device %s in map entry",
+ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
map->ctrl_dev_name);
kfree(setting);
- /* Eventually, this should trigger deferred probe */
- return -ENODEV;
+ /*
+ * OK let us guess that the driver is not there yet, and
+ * let's defer obtaining this pinctrl handle to later...
+ */
+ return -EPROBE_DEFER;
}
switch (map->type) {
@@ -579,6 +620,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
}
p->dev = dev;
INIT_LIST_HEAD(&p->states);
+ INIT_LIST_HEAD(&p->dt_maps);
+
+ ret = pinctrl_dt_to_map(p);
+ if (ret < 0) {
+ kfree(p);
+ return ERR_PTR(ret);
+ }
devname = dev_name(dev);
@@ -662,6 +710,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
kfree(state);
}
+ pinctrl_dt_free_maps(p);
+
if (inlist)
list_del(&p->node);
kfree(p);
@@ -685,8 +735,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
struct pinctrl_state *state;
state = find_state(p, name);
- if (!state)
- return ERR_PTR(-ENODEV);
+ if (!state) {
+ if (pinctrl_dummy_state) {
+ /* create dummy state */
+ dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
+ name);
+ state = create_state(p, name);
+ if (IS_ERR(state))
+ return state;
+ } else {
+ return ERR_PTR(-ENODEV);
+ }
+ }
return state;
}
@@ -787,15 +847,63 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
}
EXPORT_SYMBOL_GPL(pinctrl_select_state);
+static void devm_pinctrl_release(struct device *dev, void *res)
+{
+ pinctrl_put(*(struct pinctrl **)res);
+}
+
/**
- * pinctrl_register_mappings() - register a set of pin controller mappings
- * @maps: the pincontrol mappings table to register. This should probably be
- * marked with __initdata so it can be discarded after boot. This
- * function will perform a shallow copy for the mapping entries.
- * @num_maps: the number of maps in the mapping table
+ * struct devm_pinctrl_get() - Resource managed pinctrl_get()
+ * @dev: the device to obtain the handle for
+ *
+ * If there is a need to explicitly destroy the returned struct pinctrl,
+ * devm_pinctrl_put() should be used, rather than plain pinctrl_put().
*/
-int pinctrl_register_mappings(struct pinctrl_map const *maps,
- unsigned num_maps)
+struct pinctrl *devm_pinctrl_get(struct device *dev)
+{
+ struct pinctrl **ptr, *p;
+
+ ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ p = pinctrl_get(dev);
+ if (!IS_ERR(p)) {
+ *ptr = p;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return p;
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_get);
+
+static int devm_pinctrl_match(struct device *dev, void *res, void *data)
+{
+ struct pinctrl **p = res;
+
+ return *p == data;
+}
+
+/**
+ * devm_pinctrl_put() - Resource managed pinctrl_put()
+ * @p: the pinctrl handle to release
+ *
+ * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_pinctrl_put(struct pinctrl *p)
+{
+ WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
+ devm_pinctrl_match, p));
+ pinctrl_put(p);
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_put);
+
+int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ bool dup, bool locked)
{
int i, ret;
struct pinctrl_maps *maps_node;
@@ -829,13 +937,13 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_validate_map(&maps[i], i);
if (ret < 0)
- return 0;
+ return ret;
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_validate_map(&maps[i], i);
if (ret < 0)
- return 0;
+ return ret;
break;
default:
pr_err("failed to register map %s (%d): invalid type given\n",
@@ -851,20 +959,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
}
maps_node->num_maps = num_maps;
- maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
- if (!maps_node->maps) {
- pr_err("failed to duplicate mapping table\n");
- kfree(maps_node);
- return -ENOMEM;
+ if (dup) {
+ maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
+ GFP_KERNEL);
+ if (!maps_node->maps) {
+ pr_err("failed to duplicate mapping table\n");
+ kfree(maps_node);
+ return -ENOMEM;
+ }
+ } else {
+ maps_node->maps = maps;
}
- mutex_lock(&pinctrl_mutex);
+ if (!locked)
+ mutex_lock(&pinctrl_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps);
- mutex_unlock(&pinctrl_mutex);
+ if (!locked)
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
+/**
+ * pinctrl_register_mappings() - register a set of pin controller mappings
+ * @maps: the pincontrol mappings table to register. This should probably be
+ * marked with __initdata so it can be discarded after boot. This
+ * function will perform a shallow copy for the mapping entries.
+ * @num_maps: the number of maps in the mapping table
+ */
+int pinctrl_register_mappings(struct pinctrl_map const *maps,
+ unsigned num_maps)
+{
+ return pinctrl_register_map(maps, num_maps, true, false);
+}
+
+void pinctrl_unregister_map(struct pinctrl_map const *map)
+{
+ struct pinctrl_maps *maps_node;
+
+ list_for_each_entry(maps_node, &pinctrl_maps, node) {
+ if (maps_node->maps == map) {
+ list_del(&maps_node->node);
+ return;
+ }
+ }
+}
+
#ifdef CONFIG_DEBUG_FS
static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -906,15 +1046,17 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
- unsigned selector = 0;
+ unsigned ngroups, selector = 0;
+ ngroups = ops->get_groups_count(pctldev);
mutex_lock(&pinctrl_mutex);
seq_puts(s, "registered pin groups:\n");
- while (ops->list_groups(pctldev, selector) >= 0) {
+ while (selector < ngroups) {
const unsigned *pins;
unsigned num_pins;
const char *gname = ops->get_group_name(pctldev, selector);
+ const char *pname;
int ret;
int i;
@@ -924,10 +1066,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
seq_printf(s, "%s [ERROR GETTING PINS]\n",
gname);
else {
- seq_printf(s, "group: %s, pins = [ ", gname);
- for (i = 0; i < num_pins; i++)
- seq_printf(s, "%d ", pins[i]);
- seq_puts(s, "]\n");
+ seq_printf(s, "group: %s\n", gname);
+ for (i = 0; i < num_pins; i++) {
+ pname = pin_get_name(pctldev, pins[i]);
+ if (WARN_ON(!pname))
+ return -EINVAL;
+ seq_printf(s, "pin %d (%s)\n", pins[i], pname);
+ }
+ seq_puts(s, "\n");
}
selector++;
}
@@ -1226,11 +1372,14 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
if (!ops ||
- !ops->list_groups ||
+ !ops->get_groups_count ||
!ops->get_group_name ||
!ops->get_group_pins)
return -EINVAL;
+ if (ops->dt_node_to_map && !ops->dt_free_map)
+ return -EINVAL;
+
return 0;
}
@@ -1268,37 +1417,29 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
/* check core ops for sanity */
ret = pinctrl_check_ops(pctldev);
if (ret) {
- pr_err("%s pinctrl ops lacks necessary functions\n",
- pctldesc->name);
+ dev_err(dev, "pinctrl ops lacks necessary functions\n");
goto out_err;
}
/* If we're implementing pinmuxing, check the ops for sanity */
if (pctldesc->pmxops) {
ret = pinmux_check_ops(pctldev);
- if (ret) {
- pr_err("%s pinmux ops lacks necessary functions\n",
- pctldesc->name);
+ if (ret)
goto out_err;
- }
}
/* If we're implementing pinconfig, check the ops for sanity */
if (pctldesc->confops) {
ret = pinconf_check_ops(pctldev);
- if (ret) {
- pr_err("%s pin config ops lacks necessary functions\n",
- pctldesc->name);
+ if (ret)
goto out_err;
- }
}
/* Register all the pins */
- pr_debug("try to register %d pins on %s...\n",
- pctldesc->npins, pctldesc->name);
+ dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins);
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
if (ret) {
- pr_err("error during pin registration\n");
+ dev_err(dev, "error during pin registration\n");
pinctrl_free_pindescs(pctldev, pctldesc->pins,
pctldesc->npins);
goto out_err;
@@ -1313,8 +1454,15 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct pinctrl_state *s =
pinctrl_lookup_state_locked(pctldev->p,
PINCTRL_STATE_DEFAULT);
- if (!IS_ERR(s))
- pinctrl_select_state_locked(pctldev->p, s);
+ if (IS_ERR(s)) {
+ dev_dbg(dev, "failed to lookup the default state\n");
+ } else {
+ ret = pinctrl_select_state_locked(pctldev->p, s);
+ if (ret) {
+ dev_err(dev,
+ "failed to select default state\n");
+ }
+ }
}
mutex_unlock(&pinctrl_mutex);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 17ecf65..1f40ff6 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -52,12 +52,15 @@ struct pinctrl_dev {
* @dev: the device using this pin control handle
* @states: a list of states for this device
* @state: the current state
+ * @dt_maps: the mapping table chunks dynamically parsed from device tree for
+ * this device, if any
*/
struct pinctrl {
struct list_head node;
struct device *dev;
struct list_head states;
struct pinctrl_state *state;
+ struct list_head dt_maps;
};
/**
@@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
* struct pinctrl_setting - an individual mux or config setting
* @node: list node for struct pinctrl_settings's @settings field
* @type: the type of setting
- * @pctldev: pin control device handling to be programmed
+ * @pctldev: pin control device handling to be programmed. Not used for
+ * PIN_MAP_TYPE_DUMMY_STATE.
* @data: Data specific to the setting type
*/
struct pinctrl_setting {
@@ -144,6 +148,7 @@ struct pin_desc {
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group);
@@ -153,4 +158,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
}
+int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ bool dup, bool locked);
+void pinctrl_unregister_map(struct pinctrl_map const *map);
+
extern struct mutex pinctrl_mutex;
+extern struct list_head pinctrldev_list;
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
new file mode 100644
index 0000000..fcb1de4
--- /dev/null
+++ b/drivers/pinctrl/devicetree.c
@@ -0,0 +1,249 @@
+/*
+ * Device tree integration for the pin control subsystem
+ *
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "devicetree.h"
+
+/**
+ * struct pinctrl_dt_map - mapping table chunk parsed from device tree
+ * @node: list node for struct pinctrl's @dt_maps field
+ * @pctldev: the pin controller that allocated this struct, and will free it
+ * @maps: the mapping table entries
+ */
+struct pinctrl_dt_map {
+ struct list_head node;
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_map *map;
+ unsigned num_maps;
+};
+
+static void dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ if (pctldev) {
+ struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ ops->dt_free_map(pctldev, map, num_maps);
+ } else {
+ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
+ kfree(map);
+ }
+}
+
+void pinctrl_dt_free_maps(struct pinctrl *p)
+{
+ struct pinctrl_dt_map *dt_map, *n1;
+
+ list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
+ pinctrl_unregister_map(dt_map->map);
+ list_del(&dt_map->node);
+ dt_free_map(dt_map->pctldev, dt_map->map,
+ dt_map->num_maps);
+ kfree(dt_map);
+ }
+
+ of_node_put(p->dev->of_node);
+}
+
+static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
+ struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+ struct pinctrl_dt_map *dt_map;
+
+ /* Initialize common mapping table entry fields */
+ for (i = 0; i < num_maps; i++) {
+ map[i].dev_name = dev_name(p->dev);
+ map[i].name = statename;
+ if (pctldev)
+ map[i].ctrl_dev_name = dev_name(pctldev->dev);
+ }
+
+ /* Remember the converted mapping table entries */
+ dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
+ if (!dt_map) {
+ dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
+ dt_free_map(pctldev, map, num_maps);
+ return -ENOMEM;
+ }
+
+ dt_map->pctldev = pctldev;
+ dt_map->map = map;
+ dt_map->num_maps = num_maps;
+ list_add_tail(&dt_map->node, &p->dt_maps);
+
+ return pinctrl_register_map(map, num_maps, false, true);
+}
+
+static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
+{
+ struct pinctrl_dev *pctldev;
+
+ list_for_each_entry(pctldev, &pinctrldev_list, node)
+ if (pctldev->dev->of_node == np)
+ return pctldev;
+
+ return NULL;
+}
+
+static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
+ struct device_node *np_config)
+{
+ struct device_node *np_pctldev;
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_ops *ops;
+ int ret;
+ struct pinctrl_map *map;
+ unsigned num_maps;
+
+ /* Find the pin controller containing np_config */
+ np_pctldev = of_node_get(np_config);
+ for (;;) {
+ np_pctldev = of_get_next_parent(np_pctldev);
+ if (!np_pctldev || of_node_is_root(np_pctldev)) {
+ dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
+ np_config->full_name);
+ of_node_put(np_pctldev);
+ /* OK let's just assume this will appear later then */
+ return -EPROBE_DEFER;
+ }
+ pctldev = find_pinctrl_by_of_node(np_pctldev);
+ if (pctldev)
+ break;
+ }
+ of_node_put(np_pctldev);
+
+ /*
+ * Call pinctrl driver to parse device tree node, and
+ * generate mapping table entries
+ */
+ ops = pctldev->desc->pctlops;
+ if (!ops->dt_node_to_map) {
+ dev_err(p->dev, "pctldev %s doesn't support DT\n",
+ dev_name(pctldev->dev));
+ return -ENODEV;
+ }
+ ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
+ if (ret < 0)
+ return ret;
+
+ /* Stash the mapping table chunk away for later use */
+ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
+}
+
+static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
+{
+ struct pinctrl_map *map;
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
+ return -ENOMEM;
+ }
+
+ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
+ map->type = PIN_MAP_TYPE_DUMMY_STATE;
+
+ return dt_remember_or_free_map(p, statename, NULL, map, 1);
+}
+
+int pinctrl_dt_to_map(struct pinctrl *p)
+{
+ struct device_node *np = p->dev->of_node;
+ int state, ret;
+ char *propname;
+ struct property *prop;
+ const char *statename;
+ const __be32 *list;
+ int size, config;
+ phandle phandle;
+ struct device_node *np_config;
+
+ /* CONFIG_OF enabled, p->dev not instantiated from DT */
+ if (!np) {
+ dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
+ return 0;
+ }
+
+ /* We may store pointers to property names within the node */
+ of_node_get(np);
+
+ /* For each defined state ID */
+ for (state = 0; ; state++) {
+ /* Retrieve the pinctrl-* property */
+ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
+ prop = of_find_property(np, propname, &size);
+ kfree(propname);
+ if (!prop)
+ break;
+ list = prop->value;
+ size /= sizeof(*list);
+
+ /* Determine whether pinctrl-names property names the state */
+ ret = of_property_read_string_index(np, "pinctrl-names",
+ state, &statename);
+ /*
+ * If not, statename is just the integer state ID. But rather
+ * than dynamically allocate it and have to free it later,
+ * just point part way into the property name for the string.
+ */
+ if (ret < 0) {
+ /* strlen("pinctrl-") == 8 */
+ statename = prop->name + 8;
+ }
+
+ /* For every referenced pin configuration node in it */
+ for (config = 0; config < size; config++) {
+ phandle = be32_to_cpup(list++);
+
+ /* Look up the pin configuration node */
+ np_config = of_find_node_by_phandle(phandle);
+ if (!np_config) {
+ dev_err(p->dev,
+ "prop %s index %i invalid phandle\n",
+ prop->name, config);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Parse the node */
+ ret = dt_to_map_one_config(p, statename, np_config);
+ of_node_put(np_config);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* No entries in DT? Generate a dummy state table entry */
+ if (!size) {
+ ret = dt_remember_dummy_state(p, statename);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ pinctrl_dt_free_maps(p);
+ return ret;
+}
diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
new file mode 100644
index 0000000..760bc49
--- /dev/null
+++ b/drivers/pinctrl/devicetree.h
@@ -0,0 +1,35 @@
+/*
+ * Internal interface to pinctrl device tree integration
+ *
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef CONFIG_OF
+
+void pinctrl_dt_free_maps(struct pinctrl *p);
+int pinctrl_dt_to_map(struct pinctrl *p);
+
+#else
+
+static inline int pinctrl_dt_to_map(struct pinctrl *p)
+{
+ return 0;
+}
+
+static inline void pinctrl_dt_free_maps(struct pinctrl *p)
+{
+}
+
+#endif
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 7321e86..43f474c 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -28,11 +28,17 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev)
const struct pinconf_ops *ops = pctldev->desc->confops;
/* We must be able to read out pin status */
- if (!ops->pin_config_get && !ops->pin_config_group_get)
+ if (!ops->pin_config_get && !ops->pin_config_group_get) {
+ dev_err(pctldev->dev,
+ "pinconf must be able to read out pin status\n");
return -EINVAL;
+ }
/* We have to be able to config the pins in SOME way */
- if (!ops->pin_config_set && !ops->pin_config_group_set)
+ if (!ops->pin_config_set && !ops->pin_config_group_set) {
+ dev_err(pctldev->dev,
+ "pinconf has to be able to set a pins config\n");
return -EINVAL;
+ }
return 0;
}
@@ -44,9 +50,9 @@ int pinconf_validate_map(struct pinctrl_map const *map, int i)
return -EINVAL;
}
- if (map->data.configs.num_configs &&
+ if (!map->data.configs.num_configs ||
!map->data.configs.configs) {
- pr_err("failed to register map %s (%d): no configs ptr given\n",
+ pr_err("failed to register map %s (%d): no configs given\n",
map->name, i);
return -EINVAL;
}
@@ -379,8 +385,16 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
{
+ struct pinctrl_dev *pctldev;
+ const struct pinconf_ops *confops;
int i;
+ pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+ if (pctldev)
+ confops = pctldev->desc->confops;
+ else
+ confops = NULL;
+
switch (map->type) {
case PIN_MAP_TYPE_CONFIGS_PIN:
seq_printf(s, "pin ");
@@ -394,8 +408,15 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
seq_printf(s, "%s\n", map->data.configs.group_or_pin);
- for (i = 0; i < map->data.configs.num_configs; i++)
- seq_printf(s, "config %08lx\n", map->data.configs.configs[i]);
+ for (i = 0; i < map->data.configs.num_configs; i++) {
+ seq_printf(s, "config ");
+ if (confops && confops->pin_config_config_dbg_show)
+ confops->pin_config_config_dbg_show(pctldev, s,
+ map->data.configs.configs[i]);
+ else
+ seq_printf(s, "%08lx", map->data.configs.configs[i]);
+ seq_printf(s, "\n");
+ }
}
void pinconf_show_setting(struct seq_file *s,
@@ -403,6 +424,7 @@ void pinconf_show_setting(struct seq_file *s,
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ const struct pinconf_ops *confops = pctldev->desc->confops;
struct pin_desc *desc;
int i;
@@ -428,8 +450,15 @@ void pinconf_show_setting(struct seq_file *s,
* FIXME: We should really get the pin controler to dump the config
* values, so they can be decoded to something meaningful.
*/
- for (i = 0; i < setting->data.configs.num_configs; i++)
- seq_printf(s, " %08lx", setting->data.configs.configs[i]);
+ for (i = 0; i < setting->data.configs.num_configs; i++) {
+ seq_printf(s, " ");
+ if (confops && confops->pin_config_config_dbg_show)
+ confops->pin_config_config_dbg_show(pctldev, s,
+ setting->data.configs.configs[i]);
+ else
+ seq_printf(s, "%08lx",
+ setting->data.configs.configs[i]);
+ }
seq_printf(s, "\n");
}
@@ -448,10 +477,14 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
static int pinconf_pins_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
+ const struct pinconf_ops *ops = pctldev->desc->confops;
unsigned i, pin;
+ if (!ops || !ops->pin_config_get)
+ return 0;
+
seq_puts(s, "Pin config settings per pin\n");
- seq_puts(s, "Format: pin (name): pinmux setting array\n");
+ seq_puts(s, "Format: pin (name): configs\n");
mutex_lock(&pinctrl_mutex);
@@ -495,17 +528,18 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
const struct pinconf_ops *ops = pctldev->desc->confops;
+ unsigned ngroups = pctlops->get_groups_count(pctldev);
unsigned selector = 0;
if (!ops || !ops->pin_config_group_get)
return 0;
seq_puts(s, "Pin config settings per pin group\n");
- seq_puts(s, "Format: group (name): pinmux setting array\n");
+ seq_puts(s, "Format: group (name): configs\n");
mutex_lock(&pinctrl_mutex);
- while (pctlops->list_groups(pctldev, selector) >= 0) {
+ while (selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev, selector);
seq_printf(s, "%u (%s):", selector, gname);
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 54510de..e3ed8cb 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -19,11 +19,6 @@ int pinconf_map_to_setting(struct pinctrl_map const *map,
struct pinctrl_setting *setting);
void pinconf_free_setting(struct pinctrl_setting const *setting);
int pinconf_apply_setting(struct pinctrl_setting const *setting);
-void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
-void pinconf_show_setting(struct seq_file *s,
- struct pinctrl_setting const *setting);
-void pinconf_init_device_debugfs(struct dentry *devroot,
- struct pinctrl_dev *pctldev);
/*
* You will only be interested in these if you're using PINCONF
@@ -61,6 +56,18 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
return 0;
}
+#endif
+
+#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
+
+void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
+void pinconf_show_setting(struct seq_file *s,
+ struct pinctrl_setting const *setting);
+void pinconf_init_device_debugfs(struct dentry *devroot,
+ struct pinctrl_dev *pctldev);
+
+#else
+
static inline void pinconf_show_map(struct seq_file *s,
struct pinctrl_map const *map)
{
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 0797eba..55697a5 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -174,7 +174,7 @@ struct u300_gpio_confdata {
/* Initial configuration */
-static const struct __initdata u300_gpio_confdata
+static const struct __initconst u300_gpio_confdata
bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
/* Port 0, pins 0-7 */
{
@@ -255,7 +255,7 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
}
};
-static const struct __initdata u300_gpio_confdata
+static const struct __initconst u300_gpio_confdata
bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
/* Port 0, pins 0-7 */
{
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
new file mode 100644
index 0000000..f6e7c67
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -0,0 +1,620 @@
+/*
+ * Core driver for the imx pin controller
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinctrl-imx.h"
+
+#define IMX_PMX_DUMP(info, p, m, c, n) \
+{ \
+ int i, j; \
+ printk("Format: Pin Mux Config\n"); \
+ for (i = 0; i < n; i++) { \
+ j = p[i]; \
+ printk("%s %d 0x%lx\n", \
+ info->pins[j].name, \
+ m[i], c[i]); \
+ } \
+}
+
+/* The bits in CONFIG cell defined in binding doc*/
+#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */
+#define IMX_PAD_SION 0x40000000 /* set SION */
+
+/**
+ * @dev: a pointer back to containing device
+ * @base: the offset to the controller in virtual memory
+ */
+struct imx_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *base;
+ const struct imx_pinctrl_soc_info *info;
+};
+
+static const struct imx_pin_reg *imx_find_pin_reg(
+ const struct imx_pinctrl_soc_info *info,
+ unsigned pin, bool is_mux, unsigned mux)
+{
+ const struct imx_pin_reg *pin_reg = NULL;
+ int i;
+
+ for (i = 0; i < info->npin_regs; i++) {
+ pin_reg = &info->pin_regs[i];
+ if (pin_reg->pid != pin)
+ continue;
+ if (!is_mux)
+ break;
+ else if (pin_reg->mux_mode == (mux & IMX_MUX_MASK))
+ break;
+ }
+
+ if (!pin_reg) {
+ dev_err(info->dev, "Pin(%s): unable to find pin reg map\n",
+ info->pins[pin].name);
+ return NULL;
+ }
+
+ return pin_reg;
+}
+
+static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
+ const struct imx_pinctrl_soc_info *info,
+ const char *name)
+{
+ const struct imx_pin_group *grp = NULL;
+ int i;
+
+ for (i = 0; i < info->ngroups; i++) {
+ if (!strcmp(info->groups[i].name, name)) {
+ grp = &info->groups[i];
+ break;
+ }
+ }
+
+ return grp;
+}
+
+static int imx_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ return info->ngroups;
+}
+
+static const char *imx_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ return info->groups[selector].name;
+}
+
+static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *npins)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *npins = info->groups[selector].npins;
+
+ return 0;
+}
+
+static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_group *grp;
+ struct pinctrl_map *new_map;
+ struct device_node *parent;
+ int map_num = 1;
+ int i;
+
+ /*
+ * first find the group of this node and check if we need create
+ * config maps for pins
+ */
+ grp = imx_pinctrl_find_group_by_name(info, np->name);
+ if (!grp) {
+ dev_err(info->dev, "unable to find group for node %s\n",
+ np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < grp->npins; i++) {
+ if (!(grp->configs[i] & IMX_NO_PAD_CTL))
+ map_num++;
+ }
+
+ new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ *map = new_map;
+ *num_maps = map_num;
+
+ /* create mux map */
+ parent = of_get_parent(np);
+ if (!parent)
+ return -EINVAL;
+ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+ new_map[0].data.mux.function = parent->name;
+ new_map[0].data.mux.group = np->name;
+ of_node_put(parent);
+
+ /* create config map */
+ new_map++;
+ for (i = 0; i < grp->npins; i++) {
+ if (!(grp->configs[i] & IMX_NO_PAD_CTL)) {
+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[i].data.configs.group_or_pin =
+ pin_get_name(pctldev, grp->pins[i]);
+ new_map[i].data.configs.configs = &grp->configs[i];
+ new_map[i].data.configs.num_configs = 1;
+ }
+ }
+
+ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+ new_map->data.mux.function, new_map->data.mux.group, map_num);
+
+ return 0;
+}
+
+static void imx_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ kfree(map);
+}
+
+static struct pinctrl_ops imx_pctrl_ops = {
+ .get_groups_count = imx_get_groups_count,
+ .get_group_name = imx_get_group_name,
+ .get_group_pins = imx_get_group_pins,
+ .pin_dbg_show = imx_pin_dbg_show,
+ .dt_node_to_map = imx_dt_node_to_map,
+ .dt_free_map = imx_dt_free_map,
+
+};
+
+static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ const unsigned *pins, *mux;
+ unsigned int npins, pin_id;
+ int i;
+
+ /*
+ * Configure the mux mode for each pin in the group for a specific
+ * function.
+ */
+ pins = info->groups[group].pins;
+ npins = info->groups[group].npins;
+ mux = info->groups[group].mux_mode;
+
+ WARN_ON(!pins || !npins || !mux);
+
+ dev_dbg(ipctl->dev, "enable function %s group %s\n",
+ info->functions[selector].name, info->groups[group].name);
+
+ for (i = 0; i < npins; i++) {
+ pin_id = pins[i];
+
+ pin_reg = imx_find_pin_reg(info, pin_id, 1, mux[i]);
+ if (!pin_reg)
+ return -EINVAL;
+
+ if (!pin_reg->mux_reg) {
+ dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ writel(mux[i], ipctl->base + pin_reg->mux_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->mux_reg, mux[i]);
+
+ /* some pins also need select input setting, set it if found */
+ if (pin_reg->input_reg) {
+ writel(pin_reg->input_val, ipctl->base + pin_reg->input_reg);
+ dev_dbg(ipctl->dev,
+ "==>select_input: offset 0x%x val 0x%x\n",
+ pin_reg->input_reg, pin_reg->input_val);
+ }
+ }
+
+ return 0;
+}
+
+static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ return info->nfunctions;
+}
+
+static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ return info->functions[selector].name;
+}
+
+static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].num_groups;
+
+ return 0;
+}
+
+static struct pinmux_ops imx_pmx_ops = {
+ .get_functions_count = imx_pmx_get_funcs_count,
+ .get_function_name = imx_pmx_get_func_name,
+ .get_function_groups = imx_pmx_get_groups,
+ .enable = imx_pmx_enable,
+};
+
+static int imx_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+
+ pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
+ if (!pin_reg)
+ return -EINVAL;
+
+ if (!pin_reg->conf_reg) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ *config = readl(ipctl->base + pin_reg->conf_reg);
+
+ return 0;
+}
+
+static int imx_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long config)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+
+ pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
+ if (!pin_reg)
+ return -EINVAL;
+
+ if (!pin_reg->conf_reg) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ dev_dbg(ipctl->dev, "pinconf set pin %s\n",
+ info->pins[pin_id].name);
+
+ writel(config, ipctl->base + pin_reg->conf_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
+ pin_reg->conf_reg, config);
+
+ return 0;
+}
+
+static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin_id)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ unsigned long config;
+
+ pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
+ if (!pin_reg || !pin_reg->conf_reg) {
+ seq_printf(s, "N/A");
+ return;
+ }
+
+ config = readl(ipctl->base + pin_reg->conf_reg);
+ seq_printf(s, "0x%lx", config);
+}
+
+static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned group)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ struct imx_pin_group *grp;
+ unsigned long config;
+ const char *name;
+ int i, ret;
+
+ if (group > info->ngroups)
+ return;
+
+ seq_printf(s, "\n");
+ grp = &info->groups[group];
+ for (i = 0; i < grp->npins; i++) {
+ name = pin_get_name(pctldev, grp->pins[i]);
+ ret = imx_pinconf_get(pctldev, grp->pins[i], &config);
+ if (ret)
+ return;
+ seq_printf(s, "%s: 0x%lx", name, config);
+ }
+}
+
+struct pinconf_ops imx_pinconf_ops = {
+ .pin_config_get = imx_pinconf_get,
+ .pin_config_set = imx_pinconf_set,
+ .pin_config_dbg_show = imx_pinconf_dbg_show,
+ .pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc imx_pinctrl_desc = {
+ .pctlops = &imx_pctrl_ops,
+ .pmxops = &imx_pmx_ops,
+ .confops = &imx_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+/* decode pin id and mux from pin function id got from device tree*/
+static int imx_pinctrl_get_pin_id_and_mux(const struct imx_pinctrl_soc_info *info,
+ unsigned int pin_func_id, unsigned int *pin_id,
+ unsigned int *mux)
+{
+ if (pin_func_id > info->npin_regs)
+ return -EINVAL;
+
+ *pin_id = info->pin_regs[pin_func_id].pid;
+ *mux = info->pin_regs[pin_func_id].mux_mode;
+
+ return 0;
+}
+
+static int __devinit imx_pinctrl_parse_groups(struct device_node *np,
+ struct imx_pin_group *grp,
+ struct imx_pinctrl_soc_info *info,
+ u32 index)
+{
+ unsigned int pin_func_id;
+ int ret, size;
+ const const __be32 *list;
+ int i, j;
+ u32 config;
+
+ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+ /* Initialise group */
+ grp->name = np->name;
+
+ /*
+ * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, "fsl,pins", &size);
+ /* we do not check return since it's safe node passed down */
+ size /= sizeof(*list);
+ if (!size || size % 2) {
+ dev_err(info->dev, "wrong pins number or pins and configs should be pairs\n");
+ return -EINVAL;
+ }
+
+ grp->npins = size / 2;
+ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+ GFP_KERNEL);
+ grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+ GFP_KERNEL);
+ grp->configs = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned long),
+ GFP_KERNEL);
+ for (i = 0, j = 0; i < size; i += 2, j++) {
+ pin_func_id = be32_to_cpu(*list++);
+ ret = imx_pinctrl_get_pin_id_and_mux(info, pin_func_id,
+ &grp->pins[j], &grp->mux_mode[j]);
+ if (ret) {
+ dev_err(info->dev, "get invalid pin function id\n");
+ return -EINVAL;
+ }
+ /* SION bit is in mux register */
+ config = be32_to_cpu(*list++);
+ if (config & IMX_PAD_SION)
+ grp->mux_mode[j] |= IOMUXC_CONFIG_SION;
+ grp->configs[j] = config & ~IMX_PAD_SION;
+ }
+
+#ifdef DEBUG
+ IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins);
+#endif
+ return 0;
+}
+
+static int __devinit imx_pinctrl_parse_functions(struct device_node *np,
+ struct imx_pinctrl_soc_info *info, u32 index)
+{
+ struct device_node *child;
+ struct imx_pmx_func *func;
+ struct imx_pin_group *grp;
+ int ret;
+ static u32 grp_index;
+ u32 i = 0;
+
+ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+ func = &info->functions[index];
+
+ /* Initialise function */
+ func->name = np->name;
+ func->num_groups = of_get_child_count(np);
+ if (func->num_groups <= 0) {
+ dev_err(info->dev, "no groups defined\n");
+ return -EINVAL;
+ }
+ func->groups = devm_kzalloc(info->dev,
+ func->num_groups * sizeof(char *), GFP_KERNEL);
+
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &info->groups[grp_index++];
+ ret = imx_pinctrl_parse_groups(child, grp, info, i++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit imx_pinctrl_probe_dt(struct platform_device *pdev,
+ struct imx_pinctrl_soc_info *info)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ int ret;
+ u32 nfuncs = 0;
+ u32 i = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ nfuncs = of_get_child_count(np);
+ if (nfuncs <= 0) {
+ dev_err(&pdev->dev, "no functions defined\n");
+ return -EINVAL;
+ }
+
+ info->nfunctions = nfuncs;
+ info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
+ GFP_KERNEL);
+ if (!info->functions)
+ return -ENOMEM;
+
+ info->ngroups = 0;
+ for_each_child_of_node(np, child)
+ info->ngroups += of_get_child_count(child);
+ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
+ GFP_KERNEL);
+ if (!info->groups)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ ret = imx_pinctrl_parse_functions(child, info, i++);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse function\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int __devinit imx_pinctrl_probe(struct platform_device *pdev,
+ struct imx_pinctrl_soc_info *info)
+{
+ struct imx_pinctrl *ipctl;
+ struct resource *res;
+ int ret;
+
+ if (!info || !info->pins || !info->npins
+ || !info->pin_regs || !info->npin_regs) {
+ dev_err(&pdev->dev, "wrong pinctrl info\n");
+ return -EINVAL;
+ }
+ info->dev = &pdev->dev;
+
+ /* Create state holders etc for this driver */
+ ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
+ if (!ipctl)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ ipctl->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!ipctl->base)
+ return -EBUSY;
+
+ imx_pinctrl_desc.name = dev_name(&pdev->dev);
+ imx_pinctrl_desc.pins = info->pins;
+ imx_pinctrl_desc.npins = info->npins;
+
+ ret = imx_pinctrl_probe_dt(pdev, info);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to probe dt properties\n");
+ return ret;
+ }
+
+ ipctl->info = info;
+ ipctl->dev = info->dev;
+ platform_set_drvdata(pdev, ipctl);
+ ipctl->pctl = pinctrl_register(&imx_pinctrl_desc, &pdev->dev, ipctl);
+ if (!ipctl->pctl) {
+ dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
+
+ return 0;
+}
+
+int __devexit imx_pinctrl_remove(struct platform_device *pdev)
+{
+ struct imx_pinctrl *ipctl = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(ipctl->pctl);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-imx.h b/drivers/pinctrl/pinctrl-imx.h
new file mode 100644
index 0000000..9b65e78
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx.h
@@ -0,0 +1,106 @@
+/*
+ * IMX pinmux core definitions
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.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.
+ */
+
+#ifndef __DRIVERS_PINCTRL_IMX_H
+#define __DRIVERS_PINCTRL_IMX_H
+
+struct platform_device;
+
+/**
+ * struct imx_pin_group - describes an IMX pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @npins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @mux_mode: the mux mode for each pin in this group. The size of this
+ * array is the same as pins.
+ * @configs: the config for each pin in this group. The size of this
+ * array is the same as pins.
+ */
+struct imx_pin_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned npins;
+ unsigned int *mux_mode;
+ unsigned long *configs;
+};
+
+/**
+ * struct imx_pmx_func - describes IMX pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct imx_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned num_groups;
+};
+
+/**
+ * struct imx_pin_reg - describe a pin reg map
+ * The last 3 members are used for select input setting
+ * @pid: pin id
+ * @mux_reg: mux register offset
+ * @conf_reg: config register offset
+ * @mux_mode: mux mode
+ * @input_reg: select input register offset for this mux if any
+ * 0 if no select input setting needed.
+ * @input_val: the value set to select input register
+ */
+struct imx_pin_reg {
+ u16 pid;
+ u16 mux_reg;
+ u16 conf_reg;
+ u8 mux_mode;
+ u16 input_reg;
+ u8 input_val;
+};
+
+struct imx_pinctrl_soc_info {
+ struct device *dev;
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ const struct imx_pin_reg *pin_regs;
+ unsigned int npin_regs;
+ struct imx_pin_group *groups;
+ unsigned int ngroups;
+ struct imx_pmx_func *functions;
+ unsigned int nfunctions;
+};
+
+#define NO_MUX 0x0
+#define NO_PAD 0x0
+
+#define IMX_PIN_REG(id, conf, mux, mode, input, val) \
+ { \
+ .pid = id, \
+ .conf_reg = conf, \
+ .mux_reg = mux, \
+ .mux_mode = mode, \
+ .input_reg = input, \
+ .input_val = val, \
+ }
+
+#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+
+#define PAD_CTL_MASK(len) ((1 << len) - 1)
+#define IMX_MUX_MASK 0x7
+#define IOMUXC_CONFIG_SION (0x1 << 4)
+
+int imx_pinctrl_probe(struct platform_device *pdev,
+ struct imx_pinctrl_soc_info *info);
+int imx_pinctrl_remove(struct platform_device *pdev);
+#endif /* __DRIVERS_PINCTRL_IMX_H */
diff --git a/drivers/pinctrl/pinctrl-imx23.c b/drivers/pinctrl/pinctrl-imx23.c
new file mode 100644
index 0000000..75d3eff
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx23.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mxs.h"
+
+enum imx23_pin_enum {
+ GPMI_D00 = PINID(0, 0),
+ GPMI_D01 = PINID(0, 1),
+ GPMI_D02 = PINID(0, 2),
+ GPMI_D03 = PINID(0, 3),
+ GPMI_D04 = PINID(0, 4),
+ GPMI_D05 = PINID(0, 5),
+ GPMI_D06 = PINID(0, 6),
+ GPMI_D07 = PINID(0, 7),
+ GPMI_D08 = PINID(0, 8),
+ GPMI_D09 = PINID(0, 9),
+ GPMI_D10 = PINID(0, 10),
+ GPMI_D11 = PINID(0, 11),
+ GPMI_D12 = PINID(0, 12),
+ GPMI_D13 = PINID(0, 13),
+ GPMI_D14 = PINID(0, 14),
+ GPMI_D15 = PINID(0, 15),
+ GPMI_CLE = PINID(0, 16),
+ GPMI_ALE = PINID(0, 17),
+ GPMI_CE2N = PINID(0, 18),
+ GPMI_RDY0 = PINID(0, 19),
+ GPMI_RDY1 = PINID(0, 20),
+ GPMI_RDY2 = PINID(0, 21),
+ GPMI_RDY3 = PINID(0, 22),
+ GPMI_WPN = PINID(0, 23),
+ GPMI_WRN = PINID(0, 24),
+ GPMI_RDN = PINID(0, 25),
+ AUART1_CTS = PINID(0, 26),
+ AUART1_RTS = PINID(0, 27),
+ AUART1_RX = PINID(0, 28),
+ AUART1_TX = PINID(0, 29),
+ I2C_SCL = PINID(0, 30),
+ I2C_SDA = PINID(0, 31),
+ LCD_D00 = PINID(1, 0),
+ LCD_D01 = PINID(1, 1),
+ LCD_D02 = PINID(1, 2),
+ LCD_D03 = PINID(1, 3),
+ LCD_D04 = PINID(1, 4),
+ LCD_D05 = PINID(1, 5),
+ LCD_D06 = PINID(1, 6),
+ LCD_D07 = PINID(1, 7),
+ LCD_D08 = PINID(1, 8),
+ LCD_D09 = PINID(1, 9),
+ LCD_D10 = PINID(1, 10),
+ LCD_D11 = PINID(1, 11),
+ LCD_D12 = PINID(1, 12),
+ LCD_D13 = PINID(1, 13),
+ LCD_D14 = PINID(1, 14),
+ LCD_D15 = PINID(1, 15),
+ LCD_D16 = PINID(1, 16),
+ LCD_D17 = PINID(1, 17),
+ LCD_RESET = PINID(1, 18),
+ LCD_RS = PINID(1, 19),
+ LCD_WR = PINID(1, 20),
+ LCD_CS = PINID(1, 21),
+ LCD_DOTCK = PINID(1, 22),
+ LCD_ENABLE = PINID(1, 23),
+ LCD_HSYNC = PINID(1, 24),
+ LCD_VSYNC = PINID(1, 25),
+ PWM0 = PINID(1, 26),
+ PWM1 = PINID(1, 27),
+ PWM2 = PINID(1, 28),
+ PWM3 = PINID(1, 29),
+ PWM4 = PINID(1, 30),
+ SSP1_CMD = PINID(2, 0),
+ SSP1_DETECT = PINID(2, 1),
+ SSP1_DATA0 = PINID(2, 2),
+ SSP1_DATA1 = PINID(2, 3),
+ SSP1_DATA2 = PINID(2, 4),
+ SSP1_DATA3 = PINID(2, 5),
+ SSP1_SCK = PINID(2, 6),
+ ROTARYA = PINID(2, 7),
+ ROTARYB = PINID(2, 8),
+ EMI_A00 = PINID(2, 9),
+ EMI_A01 = PINID(2, 10),
+ EMI_A02 = PINID(2, 11),
+ EMI_A03 = PINID(2, 12),
+ EMI_A04 = PINID(2, 13),
+ EMI_A05 = PINID(2, 14),
+ EMI_A06 = PINID(2, 15),
+ EMI_A07 = PINID(2, 16),
+ EMI_A08 = PINID(2, 17),
+ EMI_A09 = PINID(2, 18),
+ EMI_A10 = PINID(2, 19),
+ EMI_A11 = PINID(2, 20),
+ EMI_A12 = PINID(2, 21),
+ EMI_BA0 = PINID(2, 22),
+ EMI_BA1 = PINID(2, 23),
+ EMI_CASN = PINID(2, 24),
+ EMI_CE0N = PINID(2, 25),
+ EMI_CE1N = PINID(2, 26),
+ GPMI_CE1N = PINID(2, 27),
+ GPMI_CE0N = PINID(2, 28),
+ EMI_CKE = PINID(2, 29),
+ EMI_RASN = PINID(2, 30),
+ EMI_WEN = PINID(2, 31),
+ EMI_D00 = PINID(3, 0),
+ EMI_D01 = PINID(3, 1),
+ EMI_D02 = PINID(3, 2),
+ EMI_D03 = PINID(3, 3),
+ EMI_D04 = PINID(3, 4),
+ EMI_D05 = PINID(3, 5),
+ EMI_D06 = PINID(3, 6),
+ EMI_D07 = PINID(3, 7),
+ EMI_D08 = PINID(3, 8),
+ EMI_D09 = PINID(3, 9),
+ EMI_D10 = PINID(3, 10),
+ EMI_D11 = PINID(3, 11),
+ EMI_D12 = PINID(3, 12),
+ EMI_D13 = PINID(3, 13),
+ EMI_D14 = PINID(3, 14),
+ EMI_D15 = PINID(3, 15),
+ EMI_DQM0 = PINID(3, 16),
+ EMI_DQM1 = PINID(3, 17),
+ EMI_DQS0 = PINID(3, 18),
+ EMI_DQS1 = PINID(3, 19),
+ EMI_CLK = PINID(3, 20),
+ EMI_CLKN = PINID(3, 21),
+};
+
+static const struct pinctrl_pin_desc imx23_pins[] = {
+ MXS_PINCTRL_PIN(GPMI_D00),
+ MXS_PINCTRL_PIN(GPMI_D01),
+ MXS_PINCTRL_PIN(GPMI_D02),
+ MXS_PINCTRL_PIN(GPMI_D03),
+ MXS_PINCTRL_PIN(GPMI_D04),
+ MXS_PINCTRL_PIN(GPMI_D05),
+ MXS_PINCTRL_PIN(GPMI_D06),
+ MXS_PINCTRL_PIN(GPMI_D07),
+ MXS_PINCTRL_PIN(GPMI_D08),
+ MXS_PINCTRL_PIN(GPMI_D09),
+ MXS_PINCTRL_PIN(GPMI_D10),
+ MXS_PINCTRL_PIN(GPMI_D11),
+ MXS_PINCTRL_PIN(GPMI_D12),
+ MXS_PINCTRL_PIN(GPMI_D13),
+ MXS_PINCTRL_PIN(GPMI_D14),
+ MXS_PINCTRL_PIN(GPMI_D15),
+ MXS_PINCTRL_PIN(GPMI_CLE),
+ MXS_PINCTRL_PIN(GPMI_ALE),
+ MXS_PINCTRL_PIN(GPMI_CE2N),
+ MXS_PINCTRL_PIN(GPMI_RDY0),
+ MXS_PINCTRL_PIN(GPMI_RDY1),
+ MXS_PINCTRL_PIN(GPMI_RDY2),
+ MXS_PINCTRL_PIN(GPMI_RDY3),
+ MXS_PINCTRL_PIN(GPMI_WPN),
+ MXS_PINCTRL_PIN(GPMI_WRN),
+ MXS_PINCTRL_PIN(GPMI_RDN),
+ MXS_PINCTRL_PIN(AUART1_CTS),
+ MXS_PINCTRL_PIN(AUART1_RTS),
+ MXS_PINCTRL_PIN(AUART1_RX),
+ MXS_PINCTRL_PIN(AUART1_TX),
+ MXS_PINCTRL_PIN(I2C_SCL),
+ MXS_PINCTRL_PIN(I2C_SDA),
+ MXS_PINCTRL_PIN(LCD_D00),
+ MXS_PINCTRL_PIN(LCD_D01),
+ MXS_PINCTRL_PIN(LCD_D02),
+ MXS_PINCTRL_PIN(LCD_D03),
+ MXS_PINCTRL_PIN(LCD_D04),
+ MXS_PINCTRL_PIN(LCD_D05),
+ MXS_PINCTRL_PIN(LCD_D06),
+ MXS_PINCTRL_PIN(LCD_D07),
+ MXS_PINCTRL_PIN(LCD_D08),
+ MXS_PINCTRL_PIN(LCD_D09),
+ MXS_PINCTRL_PIN(LCD_D10),
+ MXS_PINCTRL_PIN(LCD_D11),
+ MXS_PINCTRL_PIN(LCD_D12),
+ MXS_PINCTRL_PIN(LCD_D13),
+ MXS_PINCTRL_PIN(LCD_D14),
+ MXS_PINCTRL_PIN(LCD_D15),
+ MXS_PINCTRL_PIN(LCD_D16),
+ MXS_PINCTRL_PIN(LCD_D17),
+ MXS_PINCTRL_PIN(LCD_RESET),
+ MXS_PINCTRL_PIN(LCD_RS),
+ MXS_PINCTRL_PIN(LCD_WR),
+ MXS_PINCTRL_PIN(LCD_CS),
+ MXS_PINCTRL_PIN(LCD_DOTCK),
+ MXS_PINCTRL_PIN(LCD_ENABLE),
+ MXS_PINCTRL_PIN(LCD_HSYNC),
+ MXS_PINCTRL_PIN(LCD_VSYNC),
+ MXS_PINCTRL_PIN(PWM0),
+ MXS_PINCTRL_PIN(PWM1),
+ MXS_PINCTRL_PIN(PWM2),
+ MXS_PINCTRL_PIN(PWM3),
+ MXS_PINCTRL_PIN(PWM4),
+ MXS_PINCTRL_PIN(SSP1_CMD),
+ MXS_PINCTRL_PIN(SSP1_DETECT),
+ MXS_PINCTRL_PIN(SSP1_DATA0),
+ MXS_PINCTRL_PIN(SSP1_DATA1),
+ MXS_PINCTRL_PIN(SSP1_DATA2),
+ MXS_PINCTRL_PIN(SSP1_DATA3),
+ MXS_PINCTRL_PIN(SSP1_SCK),
+ MXS_PINCTRL_PIN(ROTARYA),
+ MXS_PINCTRL_PIN(ROTARYB),
+ MXS_PINCTRL_PIN(EMI_A00),
+ MXS_PINCTRL_PIN(EMI_A01),
+ MXS_PINCTRL_PIN(EMI_A02),
+ MXS_PINCTRL_PIN(EMI_A03),
+ MXS_PINCTRL_PIN(EMI_A04),
+ MXS_PINCTRL_PIN(EMI_A05),
+ MXS_PINCTRL_PIN(EMI_A06),
+ MXS_PINCTRL_PIN(EMI_A07),
+ MXS_PINCTRL_PIN(EMI_A08),
+ MXS_PINCTRL_PIN(EMI_A09),
+ MXS_PINCTRL_PIN(EMI_A10),
+ MXS_PINCTRL_PIN(EMI_A11),
+ MXS_PINCTRL_PIN(EMI_A12),
+ MXS_PINCTRL_PIN(EMI_BA0),
+ MXS_PINCTRL_PIN(EMI_BA1),
+ MXS_PINCTRL_PIN(EMI_CASN),
+ MXS_PINCTRL_PIN(EMI_CE0N),
+ MXS_PINCTRL_PIN(EMI_CE1N),
+ MXS_PINCTRL_PIN(GPMI_CE1N),
+ MXS_PINCTRL_PIN(GPMI_CE0N),
+ MXS_PINCTRL_PIN(EMI_CKE),
+ MXS_PINCTRL_PIN(EMI_RASN),
+ MXS_PINCTRL_PIN(EMI_WEN),
+ MXS_PINCTRL_PIN(EMI_D00),
+ MXS_PINCTRL_PIN(EMI_D01),
+ MXS_PINCTRL_PIN(EMI_D02),
+ MXS_PINCTRL_PIN(EMI_D03),
+ MXS_PINCTRL_PIN(EMI_D04),
+ MXS_PINCTRL_PIN(EMI_D05),
+ MXS_PINCTRL_PIN(EMI_D06),
+ MXS_PINCTRL_PIN(EMI_D07),
+ MXS_PINCTRL_PIN(EMI_D08),
+ MXS_PINCTRL_PIN(EMI_D09),
+ MXS_PINCTRL_PIN(EMI_D10),
+ MXS_PINCTRL_PIN(EMI_D11),
+ MXS_PINCTRL_PIN(EMI_D12),
+ MXS_PINCTRL_PIN(EMI_D13),
+ MXS_PINCTRL_PIN(EMI_D14),
+ MXS_PINCTRL_PIN(EMI_D15),
+ MXS_PINCTRL_PIN(EMI_DQM0),
+ MXS_PINCTRL_PIN(EMI_DQM1),
+ MXS_PINCTRL_PIN(EMI_DQS0),
+ MXS_PINCTRL_PIN(EMI_DQS1),
+ MXS_PINCTRL_PIN(EMI_CLK),
+ MXS_PINCTRL_PIN(EMI_CLKN),
+};
+
+static struct mxs_regs imx23_regs = {
+ .muxsel = 0x100,
+ .drive = 0x200,
+ .pull = 0x400,
+};
+
+static struct mxs_pinctrl_soc_data imx23_pinctrl_data = {
+ .regs = &imx23_regs,
+ .pins = imx23_pins,
+ .npins = ARRAY_SIZE(imx23_pins),
+};
+
+static int __devinit imx23_pinctrl_probe(struct platform_device *pdev)
+{
+ return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data);
+}
+
+static struct of_device_id imx23_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "fsl,imx23-pinctrl", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx23_pinctrl_of_match);
+
+static struct platform_driver imx23_pinctrl_driver = {
+ .driver = {
+ .name = "imx23-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = imx23_pinctrl_of_match,
+ },
+ .probe = imx23_pinctrl_probe,
+ .remove = __devexit_p(mxs_pinctrl_remove),
+};
+
+static int __init imx23_pinctrl_init(void)
+{
+ return platform_driver_register(&imx23_pinctrl_driver);
+}
+arch_initcall(imx23_pinctrl_init);
+
+static void __exit imx23_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx23_pinctrl_driver);
+}
+module_exit(imx23_pinctrl_exit);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX23 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-imx28.c b/drivers/pinctrl/pinctrl-imx28.c
new file mode 100644
index 0000000..b973026
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx28.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mxs.h"
+
+enum imx28_pin_enum {
+ GPMI_D00 = PINID(0, 0),
+ GPMI_D01 = PINID(0, 1),
+ GPMI_D02 = PINID(0, 2),
+ GPMI_D03 = PINID(0, 3),
+ GPMI_D04 = PINID(0, 4),
+ GPMI_D05 = PINID(0, 5),
+ GPMI_D06 = PINID(0, 6),
+ GPMI_D07 = PINID(0, 7),
+ GPMI_CE0N = PINID(0, 16),
+ GPMI_CE1N = PINID(0, 17),
+ GPMI_CE2N = PINID(0, 18),
+ GPMI_CE3N = PINID(0, 19),
+ GPMI_RDY0 = PINID(0, 20),
+ GPMI_RDY1 = PINID(0, 21),
+ GPMI_RDY2 = PINID(0, 22),
+ GPMI_RDY3 = PINID(0, 23),
+ GPMI_RDN = PINID(0, 24),
+ GPMI_WRN = PINID(0, 25),
+ GPMI_ALE = PINID(0, 26),
+ GPMI_CLE = PINID(0, 27),
+ GPMI_RESETN = PINID(0, 28),
+ LCD_D00 = PINID(1, 0),
+ LCD_D01 = PINID(1, 1),
+ LCD_D02 = PINID(1, 2),
+ LCD_D03 = PINID(1, 3),
+ LCD_D04 = PINID(1, 4),
+ LCD_D05 = PINID(1, 5),
+ LCD_D06 = PINID(1, 6),
+ LCD_D07 = PINID(1, 7),
+ LCD_D08 = PINID(1, 8),
+ LCD_D09 = PINID(1, 9),
+ LCD_D10 = PINID(1, 10),
+ LCD_D11 = PINID(1, 11),
+ LCD_D12 = PINID(1, 12),
+ LCD_D13 = PINID(1, 13),
+ LCD_D14 = PINID(1, 14),
+ LCD_D15 = PINID(1, 15),
+ LCD_D16 = PINID(1, 16),
+ LCD_D17 = PINID(1, 17),
+ LCD_D18 = PINID(1, 18),
+ LCD_D19 = PINID(1, 19),
+ LCD_D20 = PINID(1, 20),
+ LCD_D21 = PINID(1, 21),
+ LCD_D22 = PINID(1, 22),
+ LCD_D23 = PINID(1, 23),
+ LCD_RD_E = PINID(1, 24),
+ LCD_WR_RWN = PINID(1, 25),
+ LCD_RS = PINID(1, 26),
+ LCD_CS = PINID(1, 27),
+ LCD_VSYNC = PINID(1, 28),
+ LCD_HSYNC = PINID(1, 29),
+ LCD_DOTCLK = PINID(1, 30),
+ LCD_ENABLE = PINID(1, 31),
+ SSP0_DATA0 = PINID(2, 0),
+ SSP0_DATA1 = PINID(2, 1),
+ SSP0_DATA2 = PINID(2, 2),
+ SSP0_DATA3 = PINID(2, 3),
+ SSP0_DATA4 = PINID(2, 4),
+ SSP0_DATA5 = PINID(2, 5),
+ SSP0_DATA6 = PINID(2, 6),
+ SSP0_DATA7 = PINID(2, 7),
+ SSP0_CMD = PINID(2, 8),
+ SSP0_DETECT = PINID(2, 9),
+ SSP0_SCK = PINID(2, 10),
+ SSP1_SCK = PINID(2, 12),
+ SSP1_CMD = PINID(2, 13),
+ SSP1_DATA0 = PINID(2, 14),
+ SSP1_DATA3 = PINID(2, 15),
+ SSP2_SCK = PINID(2, 16),
+ SSP2_MOSI = PINID(2, 17),
+ SSP2_MISO = PINID(2, 18),
+ SSP2_SS0 = PINID(2, 19),
+ SSP2_SS1 = PINID(2, 20),
+ SSP2_SS2 = PINID(2, 21),
+ SSP3_SCK = PINID(2, 24),
+ SSP3_MOSI = PINID(2, 25),
+ SSP3_MISO = PINID(2, 26),
+ SSP3_SS0 = PINID(2, 27),
+ AUART0_RX = PINID(3, 0),
+ AUART0_TX = PINID(3, 1),
+ AUART0_CTS = PINID(3, 2),
+ AUART0_RTS = PINID(3, 3),
+ AUART1_RX = PINID(3, 4),
+ AUART1_TX = PINID(3, 5),
+ AUART1_CTS = PINID(3, 6),
+ AUART1_RTS = PINID(3, 7),
+ AUART2_RX = PINID(3, 8),
+ AUART2_TX = PINID(3, 9),
+ AUART2_CTS = PINID(3, 10),
+ AUART2_RTS = PINID(3, 11),
+ AUART3_RX = PINID(3, 12),
+ AUART3_TX = PINID(3, 13),
+ AUART3_CTS = PINID(3, 14),
+ AUART3_RTS = PINID(3, 15),
+ PWM0 = PINID(3, 16),
+ PWM1 = PINID(3, 17),
+ PWM2 = PINID(3, 18),
+ SAIF0_MCLK = PINID(3, 20),
+ SAIF0_LRCLK = PINID(3, 21),
+ SAIF0_BITCLK = PINID(3, 22),
+ SAIF0_SDATA0 = PINID(3, 23),
+ I2C0_SCL = PINID(3, 24),
+ I2C0_SDA = PINID(3, 25),
+ SAIF1_SDATA0 = PINID(3, 26),
+ SPDIF = PINID(3, 27),
+ PWM3 = PINID(3, 28),
+ PWM4 = PINID(3, 29),
+ LCD_RESET = PINID(3, 30),
+ ENET0_MDC = PINID(4, 0),
+ ENET0_MDIO = PINID(4, 1),
+ ENET0_RX_EN = PINID(4, 2),
+ ENET0_RXD0 = PINID(4, 3),
+ ENET0_RXD1 = PINID(4, 4),
+ ENET0_TX_CLK = PINID(4, 5),
+ ENET0_TX_EN = PINID(4, 6),
+ ENET0_TXD0 = PINID(4, 7),
+ ENET0_TXD1 = PINID(4, 8),
+ ENET0_RXD2 = PINID(4, 9),
+ ENET0_RXD3 = PINID(4, 10),
+ ENET0_TXD2 = PINID(4, 11),
+ ENET0_TXD3 = PINID(4, 12),
+ ENET0_RX_CLK = PINID(4, 13),
+ ENET0_COL = PINID(4, 14),
+ ENET0_CRS = PINID(4, 15),
+ ENET_CLK = PINID(4, 16),
+ JTAG_RTCK = PINID(4, 20),
+ EMI_D00 = PINID(5, 0),
+ EMI_D01 = PINID(5, 1),
+ EMI_D02 = PINID(5, 2),
+ EMI_D03 = PINID(5, 3),
+ EMI_D04 = PINID(5, 4),
+ EMI_D05 = PINID(5, 5),
+ EMI_D06 = PINID(5, 6),
+ EMI_D07 = PINID(5, 7),
+ EMI_D08 = PINID(5, 8),
+ EMI_D09 = PINID(5, 9),
+ EMI_D10 = PINID(5, 10),
+ EMI_D11 = PINID(5, 11),
+ EMI_D12 = PINID(5, 12),
+ EMI_D13 = PINID(5, 13),
+ EMI_D14 = PINID(5, 14),
+ EMI_D15 = PINID(5, 15),
+ EMI_ODT0 = PINID(5, 16),
+ EMI_DQM0 = PINID(5, 17),
+ EMI_ODT1 = PINID(5, 18),
+ EMI_DQM1 = PINID(5, 19),
+ EMI_DDR_OPEN_FB = PINID(5, 20),
+ EMI_CLK = PINID(5, 21),
+ EMI_DQS0 = PINID(5, 22),
+ EMI_DQS1 = PINID(5, 23),
+ EMI_DDR_OPEN = PINID(5, 26),
+ EMI_A00 = PINID(6, 0),
+ EMI_A01 = PINID(6, 1),
+ EMI_A02 = PINID(6, 2),
+ EMI_A03 = PINID(6, 3),
+ EMI_A04 = PINID(6, 4),
+ EMI_A05 = PINID(6, 5),
+ EMI_A06 = PINID(6, 6),
+ EMI_A07 = PINID(6, 7),
+ EMI_A08 = PINID(6, 8),
+ EMI_A09 = PINID(6, 9),
+ EMI_A10 = PINID(6, 10),
+ EMI_A11 = PINID(6, 11),
+ EMI_A12 = PINID(6, 12),
+ EMI_A13 = PINID(6, 13),
+ EMI_A14 = PINID(6, 14),
+ EMI_BA0 = PINID(6, 16),
+ EMI_BA1 = PINID(6, 17),
+ EMI_BA2 = PINID(6, 18),
+ EMI_CASN = PINID(6, 19),
+ EMI_RASN = PINID(6, 20),
+ EMI_WEN = PINID(6, 21),
+ EMI_CE0N = PINID(6, 22),
+ EMI_CE1N = PINID(6, 23),
+ EMI_CKE = PINID(6, 24),
+};
+
+static const struct pinctrl_pin_desc imx28_pins[] = {
+ MXS_PINCTRL_PIN(GPMI_D00),
+ MXS_PINCTRL_PIN(GPMI_D01),
+ MXS_PINCTRL_PIN(GPMI_D02),
+ MXS_PINCTRL_PIN(GPMI_D03),
+ MXS_PINCTRL_PIN(GPMI_D04),
+ MXS_PINCTRL_PIN(GPMI_D05),
+ MXS_PINCTRL_PIN(GPMI_D06),
+ MXS_PINCTRL_PIN(GPMI_D07),
+ MXS_PINCTRL_PIN(GPMI_CE0N),
+ MXS_PINCTRL_PIN(GPMI_CE1N),
+ MXS_PINCTRL_PIN(GPMI_CE2N),
+ MXS_PINCTRL_PIN(GPMI_CE3N),
+ MXS_PINCTRL_PIN(GPMI_RDY0),
+ MXS_PINCTRL_PIN(GPMI_RDY1),
+ MXS_PINCTRL_PIN(GPMI_RDY2),
+ MXS_PINCTRL_PIN(GPMI_RDY3),
+ MXS_PINCTRL_PIN(GPMI_RDN),
+ MXS_PINCTRL_PIN(GPMI_WRN),
+ MXS_PINCTRL_PIN(GPMI_ALE),
+ MXS_PINCTRL_PIN(GPMI_CLE),
+ MXS_PINCTRL_PIN(GPMI_RESETN),
+ MXS_PINCTRL_PIN(LCD_D00),
+ MXS_PINCTRL_PIN(LCD_D01),
+ MXS_PINCTRL_PIN(LCD_D02),
+ MXS_PINCTRL_PIN(LCD_D03),
+ MXS_PINCTRL_PIN(LCD_D04),
+ MXS_PINCTRL_PIN(LCD_D05),
+ MXS_PINCTRL_PIN(LCD_D06),
+ MXS_PINCTRL_PIN(LCD_D07),
+ MXS_PINCTRL_PIN(LCD_D08),
+ MXS_PINCTRL_PIN(LCD_D09),
+ MXS_PINCTRL_PIN(LCD_D10),
+ MXS_PINCTRL_PIN(LCD_D11),
+ MXS_PINCTRL_PIN(LCD_D12),
+ MXS_PINCTRL_PIN(LCD_D13),
+ MXS_PINCTRL_PIN(LCD_D14),
+ MXS_PINCTRL_PIN(LCD_D15),
+ MXS_PINCTRL_PIN(LCD_D16),
+ MXS_PINCTRL_PIN(LCD_D17),
+ MXS_PINCTRL_PIN(LCD_D18),
+ MXS_PINCTRL_PIN(LCD_D19),
+ MXS_PINCTRL_PIN(LCD_D20),
+ MXS_PINCTRL_PIN(LCD_D21),
+ MXS_PINCTRL_PIN(LCD_D22),
+ MXS_PINCTRL_PIN(LCD_D23),
+ MXS_PINCTRL_PIN(LCD_RD_E),
+ MXS_PINCTRL_PIN(LCD_WR_RWN),
+ MXS_PINCTRL_PIN(LCD_RS),
+ MXS_PINCTRL_PIN(LCD_CS),
+ MXS_PINCTRL_PIN(LCD_VSYNC),
+ MXS_PINCTRL_PIN(LCD_HSYNC),
+ MXS_PINCTRL_PIN(LCD_DOTCLK),
+ MXS_PINCTRL_PIN(LCD_ENABLE),
+ MXS_PINCTRL_PIN(SSP0_DATA0),
+ MXS_PINCTRL_PIN(SSP0_DATA1),
+ MXS_PINCTRL_PIN(SSP0_DATA2),
+ MXS_PINCTRL_PIN(SSP0_DATA3),
+ MXS_PINCTRL_PIN(SSP0_DATA4),
+ MXS_PINCTRL_PIN(SSP0_DATA5),
+ MXS_PINCTRL_PIN(SSP0_DATA6),
+ MXS_PINCTRL_PIN(SSP0_DATA7),
+ MXS_PINCTRL_PIN(SSP0_CMD),
+ MXS_PINCTRL_PIN(SSP0_DETECT),
+ MXS_PINCTRL_PIN(SSP0_SCK),
+ MXS_PINCTRL_PIN(SSP1_SCK),
+ MXS_PINCTRL_PIN(SSP1_CMD),
+ MXS_PINCTRL_PIN(SSP1_DATA0),
+ MXS_PINCTRL_PIN(SSP1_DATA3),
+ MXS_PINCTRL_PIN(SSP2_SCK),
+ MXS_PINCTRL_PIN(SSP2_MOSI),
+ MXS_PINCTRL_PIN(SSP2_MISO),
+ MXS_PINCTRL_PIN(SSP2_SS0),
+ MXS_PINCTRL_PIN(SSP2_SS1),
+ MXS_PINCTRL_PIN(SSP2_SS2),
+ MXS_PINCTRL_PIN(SSP3_SCK),
+ MXS_PINCTRL_PIN(SSP3_MOSI),
+ MXS_PINCTRL_PIN(SSP3_MISO),
+ MXS_PINCTRL_PIN(SSP3_SS0),
+ MXS_PINCTRL_PIN(AUART0_RX),
+ MXS_PINCTRL_PIN(AUART0_TX),
+ MXS_PINCTRL_PIN(AUART0_CTS),
+ MXS_PINCTRL_PIN(AUART0_RTS),
+ MXS_PINCTRL_PIN(AUART1_RX),
+ MXS_PINCTRL_PIN(AUART1_TX),
+ MXS_PINCTRL_PIN(AUART1_CTS),
+ MXS_PINCTRL_PIN(AUART1_RTS),
+ MXS_PINCTRL_PIN(AUART2_RX),
+ MXS_PINCTRL_PIN(AUART2_TX),
+ MXS_PINCTRL_PIN(AUART2_CTS),
+ MXS_PINCTRL_PIN(AUART2_RTS),
+ MXS_PINCTRL_PIN(AUART3_RX),
+ MXS_PINCTRL_PIN(AUART3_TX),
+ MXS_PINCTRL_PIN(AUART3_CTS),
+ MXS_PINCTRL_PIN(AUART3_RTS),
+ MXS_PINCTRL_PIN(PWM0),
+ MXS_PINCTRL_PIN(PWM1),
+ MXS_PINCTRL_PIN(PWM2),
+ MXS_PINCTRL_PIN(SAIF0_MCLK),
+ MXS_PINCTRL_PIN(SAIF0_LRCLK),
+ MXS_PINCTRL_PIN(SAIF0_BITCLK),
+ MXS_PINCTRL_PIN(SAIF0_SDATA0),
+ MXS_PINCTRL_PIN(I2C0_SCL),
+ MXS_PINCTRL_PIN(I2C0_SDA),
+ MXS_PINCTRL_PIN(SAIF1_SDATA0),
+ MXS_PINCTRL_PIN(SPDIF),
+ MXS_PINCTRL_PIN(PWM3),
+ MXS_PINCTRL_PIN(PWM4),
+ MXS_PINCTRL_PIN(LCD_RESET),
+ MXS_PINCTRL_PIN(ENET0_MDC),
+ MXS_PINCTRL_PIN(ENET0_MDIO),
+ MXS_PINCTRL_PIN(ENET0_RX_EN),
+ MXS_PINCTRL_PIN(ENET0_RXD0),
+ MXS_PINCTRL_PIN(ENET0_RXD1),
+ MXS_PINCTRL_PIN(ENET0_TX_CLK),
+ MXS_PINCTRL_PIN(ENET0_TX_EN),
+ MXS_PINCTRL_PIN(ENET0_TXD0),
+ MXS_PINCTRL_PIN(ENET0_TXD1),
+ MXS_PINCTRL_PIN(ENET0_RXD2),
+ MXS_PINCTRL_PIN(ENET0_RXD3),
+ MXS_PINCTRL_PIN(ENET0_TXD2),
+ MXS_PINCTRL_PIN(ENET0_TXD3),
+ MXS_PINCTRL_PIN(ENET0_RX_CLK),
+ MXS_PINCTRL_PIN(ENET0_COL),
+ MXS_PINCTRL_PIN(ENET0_CRS),
+ MXS_PINCTRL_PIN(ENET_CLK),
+ MXS_PINCTRL_PIN(JTAG_RTCK),
+ MXS_PINCTRL_PIN(EMI_D00),
+ MXS_PINCTRL_PIN(EMI_D01),
+ MXS_PINCTRL_PIN(EMI_D02),
+ MXS_PINCTRL_PIN(EMI_D03),
+ MXS_PINCTRL_PIN(EMI_D04),
+ MXS_PINCTRL_PIN(EMI_D05),
+ MXS_PINCTRL_PIN(EMI_D06),
+ MXS_PINCTRL_PIN(EMI_D07),
+ MXS_PINCTRL_PIN(EMI_D08),
+ MXS_PINCTRL_PIN(EMI_D09),
+ MXS_PINCTRL_PIN(EMI_D10),
+ MXS_PINCTRL_PIN(EMI_D11),
+ MXS_PINCTRL_PIN(EMI_D12),
+ MXS_PINCTRL_PIN(EMI_D13),
+ MXS_PINCTRL_PIN(EMI_D14),
+ MXS_PINCTRL_PIN(EMI_D15),
+ MXS_PINCTRL_PIN(EMI_ODT0),
+ MXS_PINCTRL_PIN(EMI_DQM0),
+ MXS_PINCTRL_PIN(EMI_ODT1),
+ MXS_PINCTRL_PIN(EMI_DQM1),
+ MXS_PINCTRL_PIN(EMI_DDR_OPEN_FB),
+ MXS_PINCTRL_PIN(EMI_CLK),
+ MXS_PINCTRL_PIN(EMI_DQS0),
+ MXS_PINCTRL_PIN(EMI_DQS1),
+ MXS_PINCTRL_PIN(EMI_DDR_OPEN),
+ MXS_PINCTRL_PIN(EMI_A00),
+ MXS_PINCTRL_PIN(EMI_A01),
+ MXS_PINCTRL_PIN(EMI_A02),
+ MXS_PINCTRL_PIN(EMI_A03),
+ MXS_PINCTRL_PIN(EMI_A04),
+ MXS_PINCTRL_PIN(EMI_A05),
+ MXS_PINCTRL_PIN(EMI_A06),
+ MXS_PINCTRL_PIN(EMI_A07),
+ MXS_PINCTRL_PIN(EMI_A08),
+ MXS_PINCTRL_PIN(EMI_A09),
+ MXS_PINCTRL_PIN(EMI_A10),
+ MXS_PINCTRL_PIN(EMI_A11),
+ MXS_PINCTRL_PIN(EMI_A12),
+ MXS_PINCTRL_PIN(EMI_A13),
+ MXS_PINCTRL_PIN(EMI_A14),
+ MXS_PINCTRL_PIN(EMI_BA0),
+ MXS_PINCTRL_PIN(EMI_BA1),
+ MXS_PINCTRL_PIN(EMI_BA2),
+ MXS_PINCTRL_PIN(EMI_CASN),
+ MXS_PINCTRL_PIN(EMI_RASN),
+ MXS_PINCTRL_PIN(EMI_WEN),
+ MXS_PINCTRL_PIN(EMI_CE0N),
+ MXS_PINCTRL_PIN(EMI_CE1N),
+ MXS_PINCTRL_PIN(EMI_CKE),
+};
+
+static struct mxs_regs imx28_regs = {
+ .muxsel = 0x100,
+ .drive = 0x300,
+ .pull = 0x600,
+};
+
+static struct mxs_pinctrl_soc_data imx28_pinctrl_data = {
+ .regs = &imx28_regs,
+ .pins = imx28_pins,
+ .npins = ARRAY_SIZE(imx28_pins),
+};
+
+static int __devinit imx28_pinctrl_probe(struct platform_device *pdev)
+{
+ return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data);
+}
+
+static struct of_device_id imx28_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "fsl,imx28-pinctrl", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx28_pinctrl_of_match);
+
+static struct platform_driver imx28_pinctrl_driver = {
+ .driver = {
+ .name = "imx28-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = imx28_pinctrl_of_match,
+ },
+ .probe = imx28_pinctrl_probe,
+ .remove = __devexit_p(mxs_pinctrl_remove),
+};
+
+static int __init imx28_pinctrl_init(void)
+{
+ return platform_driver_register(&imx28_pinctrl_driver);
+}
+arch_initcall(imx28_pinctrl_init);
+
+static void __exit imx28_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx28_pinctrl_driver);
+}
+module_exit(imx28_pinctrl_exit);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX28 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-imx51.c b/drivers/pinctrl/pinctrl-imx51.c
new file mode 100644
index 0000000..689b3c8
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx51.c
@@ -0,0 +1,1322 @@
+/*
+ * imx51 pinctrl driver based on imx pinmux core
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx51_pads {
+ MX51_PAD_EIM_D16 = 1,
+ MX51_PAD_EIM_D17 = 2,
+ MX51_PAD_EIM_D18 = 3,
+ MX51_PAD_EIM_D19 = 4,
+ MX51_PAD_EIM_D20 = 5,
+ MX51_PAD_EIM_D21 = 6,
+ MX51_PAD_EIM_D22 = 7,
+ MX51_PAD_EIM_D23 = 8,
+ MX51_PAD_EIM_D24 = 9,
+ MX51_PAD_EIM_D25 = 10,
+ MX51_PAD_EIM_D26 = 11,
+ MX51_PAD_EIM_D27 = 12,
+ MX51_PAD_EIM_D28 = 13,
+ MX51_PAD_EIM_D29 = 14,
+ MX51_PAD_EIM_D30 = 15,
+ MX51_PAD_EIM_D31 = 16,
+ MX51_PAD_EIM_A16 = 17,
+ MX51_PAD_EIM_A17 = 18,
+ MX51_PAD_EIM_A18 = 19,
+ MX51_PAD_EIM_A19 = 20,
+ MX51_PAD_EIM_A20 = 21,
+ MX51_PAD_EIM_A21 = 22,
+ MX51_PAD_EIM_A22 = 23,
+ MX51_PAD_EIM_A23 = 24,
+ MX51_PAD_EIM_A24 = 25,
+ MX51_PAD_EIM_A25 = 26,
+ MX51_PAD_EIM_A26 = 27,
+ MX51_PAD_EIM_A27 = 28,
+ MX51_PAD_EIM_EB0 = 29,
+ MX51_PAD_EIM_EB1 = 30,
+ MX51_PAD_EIM_EB2 = 31,
+ MX51_PAD_EIM_EB3 = 32,
+ MX51_PAD_EIM_OE = 33,
+ MX51_PAD_EIM_CS0 = 34,
+ MX51_PAD_EIM_CS1 = 35,
+ MX51_PAD_EIM_CS2 = 36,
+ MX51_PAD_EIM_CS3 = 37,
+ MX51_PAD_EIM_CS4 = 38,
+ MX51_PAD_EIM_CS5 = 39,
+ MX51_PAD_EIM_DTACK = 40,
+ MX51_PAD_EIM_LBA = 41,
+ MX51_PAD_EIM_CRE = 42,
+ MX51_PAD_DRAM_CS1 = 43,
+ MX51_PAD_NANDF_WE_B = 44,
+ MX51_PAD_NANDF_RE_B = 45,
+ MX51_PAD_NANDF_ALE = 46,
+ MX51_PAD_NANDF_CLE = 47,
+ MX51_PAD_NANDF_WP_B = 48,
+ MX51_PAD_NANDF_RB0 = 49,
+ MX51_PAD_NANDF_RB1 = 50,
+ MX51_PAD_NANDF_RB2 = 51,
+ MX51_PAD_NANDF_RB3 = 52,
+ MX51_PAD_GPIO_NAND = 53,
+ MX51_PAD_NANDF_CS0 = 54,
+ MX51_PAD_NANDF_CS1 = 55,
+ MX51_PAD_NANDF_CS2 = 56,
+ MX51_PAD_NANDF_CS3 = 57,
+ MX51_PAD_NANDF_CS4 = 58,
+ MX51_PAD_NANDF_CS5 = 59,
+ MX51_PAD_NANDF_CS6 = 60,
+ MX51_PAD_NANDF_CS7 = 61,
+ MX51_PAD_NANDF_RDY_INT = 62,
+ MX51_PAD_NANDF_D15 = 63,
+ MX51_PAD_NANDF_D14 = 64,
+ MX51_PAD_NANDF_D13 = 65,
+ MX51_PAD_NANDF_D12 = 66,
+ MX51_PAD_NANDF_D11 = 67,
+ MX51_PAD_NANDF_D10 = 68,
+ MX51_PAD_NANDF_D9 = 69,
+ MX51_PAD_NANDF_D8 = 70,
+ MX51_PAD_NANDF_D7 = 71,
+ MX51_PAD_NANDF_D6 = 72,
+ MX51_PAD_NANDF_D5 = 73,
+ MX51_PAD_NANDF_D4 = 74,
+ MX51_PAD_NANDF_D3 = 75,
+ MX51_PAD_NANDF_D2 = 76,
+ MX51_PAD_NANDF_D1 = 77,
+ MX51_PAD_NANDF_D0 = 78,
+ MX51_PAD_CSI1_D8 = 79,
+ MX51_PAD_CSI1_D9 = 80,
+ MX51_PAD_CSI1_D10 = 81,
+ MX51_PAD_CSI1_D11 = 82,
+ MX51_PAD_CSI1_D12 = 83,
+ MX51_PAD_CSI1_D13 = 84,
+ MX51_PAD_CSI1_D14 = 85,
+ MX51_PAD_CSI1_D15 = 86,
+ MX51_PAD_CSI1_D16 = 87,
+ MX51_PAD_CSI1_D17 = 88,
+ MX51_PAD_CSI1_D18 = 89,
+ MX51_PAD_CSI1_D19 = 90,
+ MX51_PAD_CSI1_VSYNC = 91,
+ MX51_PAD_CSI1_HSYNC = 92,
+ MX51_PAD_CSI1_PIXCLK = 93,
+ MX51_PAD_CSI1_MCLK = 94,
+ MX51_PAD_CSI2_D12 = 95,
+ MX51_PAD_CSI2_D13 = 96,
+ MX51_PAD_CSI2_D14 = 97,
+ MX51_PAD_CSI2_D15 = 98,
+ MX51_PAD_CSI2_D16 = 99,
+ MX51_PAD_CSI2_D17 = 100,
+ MX51_PAD_CSI2_D18 = 101,
+ MX51_PAD_CSI2_D19 = 102,
+ MX51_PAD_CSI2_VSYNC = 103,
+ MX51_PAD_CSI2_HSYNC = 104,
+ MX51_PAD_CSI2_PIXCLK = 105,
+ MX51_PAD_I2C1_CLK = 106,
+ MX51_PAD_I2C1_DAT = 107,
+ MX51_PAD_AUD3_BB_TXD = 108,
+ MX51_PAD_AUD3_BB_RXD = 109,
+ MX51_PAD_AUD3_BB_CK = 110,
+ MX51_PAD_AUD3_BB_FS = 111,
+ MX51_PAD_CSPI1_MOSI = 112,
+ MX51_PAD_CSPI1_MISO = 113,
+ MX51_PAD_CSPI1_SS0 = 114,
+ MX51_PAD_CSPI1_SS1 = 115,
+ MX51_PAD_CSPI1_RDY = 116,
+ MX51_PAD_CSPI1_SCLK = 117,
+ MX51_PAD_UART1_RXD = 118,
+ MX51_PAD_UART1_TXD = 119,
+ MX51_PAD_UART1_RTS = 120,
+ MX51_PAD_UART1_CTS = 121,
+ MX51_PAD_UART2_RXD = 122,
+ MX51_PAD_UART2_TXD = 123,
+ MX51_PAD_UART3_RXD = 124,
+ MX51_PAD_UART3_TXD = 125,
+ MX51_PAD_OWIRE_LINE = 126,
+ MX51_PAD_KEY_ROW0 = 127,
+ MX51_PAD_KEY_ROW1 = 128,
+ MX51_PAD_KEY_ROW2 = 129,
+ MX51_PAD_KEY_ROW3 = 130,
+ MX51_PAD_KEY_COL0 = 131,
+ MX51_PAD_KEY_COL1 = 132,
+ MX51_PAD_KEY_COL2 = 133,
+ MX51_PAD_KEY_COL3 = 134,
+ MX51_PAD_KEY_COL4 = 135,
+ MX51_PAD_KEY_COL5 = 136,
+ MX51_PAD_USBH1_CLK = 137,
+ MX51_PAD_USBH1_DIR = 138,
+ MX51_PAD_USBH1_STP = 139,
+ MX51_PAD_USBH1_NXT = 140,
+ MX51_PAD_USBH1_DATA0 = 141,
+ MX51_PAD_USBH1_DATA1 = 142,
+ MX51_PAD_USBH1_DATA2 = 143,
+ MX51_PAD_USBH1_DATA3 = 144,
+ MX51_PAD_USBH1_DATA4 = 145,
+ MX51_PAD_USBH1_DATA5 = 146,
+ MX51_PAD_USBH1_DATA6 = 147,
+ MX51_PAD_USBH1_DATA7 = 148,
+ MX51_PAD_DI1_PIN11 = 149,
+ MX51_PAD_DI1_PIN12 = 150,
+ MX51_PAD_DI1_PIN13 = 151,
+ MX51_PAD_DI1_D0_CS = 152,
+ MX51_PAD_DI1_D1_CS = 153,
+ MX51_PAD_DISPB2_SER_DIN = 154,
+ MX51_PAD_DISPB2_SER_DIO = 155,
+ MX51_PAD_DISPB2_SER_CLK = 156,
+ MX51_PAD_DISPB2_SER_RS = 157,
+ MX51_PAD_DISP1_DAT0 = 158,
+ MX51_PAD_DISP1_DAT1 = 159,
+ MX51_PAD_DISP1_DAT2 = 160,
+ MX51_PAD_DISP1_DAT3 = 161,
+ MX51_PAD_DISP1_DAT4 = 162,
+ MX51_PAD_DISP1_DAT5 = 163,
+ MX51_PAD_DISP1_DAT6 = 164,
+ MX51_PAD_DISP1_DAT7 = 165,
+ MX51_PAD_DISP1_DAT8 = 166,
+ MX51_PAD_DISP1_DAT9 = 167,
+ MX51_PAD_DISP1_DAT10 = 168,
+ MX51_PAD_DISP1_DAT11 = 169,
+ MX51_PAD_DISP1_DAT12 = 170,
+ MX51_PAD_DISP1_DAT13 = 171,
+ MX51_PAD_DISP1_DAT14 = 172,
+ MX51_PAD_DISP1_DAT15 = 173,
+ MX51_PAD_DISP1_DAT16 = 174,
+ MX51_PAD_DISP1_DAT17 = 175,
+ MX51_PAD_DISP1_DAT18 = 176,
+ MX51_PAD_DISP1_DAT19 = 177,
+ MX51_PAD_DISP1_DAT20 = 178,
+ MX51_PAD_DISP1_DAT21 = 179,
+ MX51_PAD_DISP1_DAT22 = 180,
+ MX51_PAD_DISP1_DAT23 = 181,
+ MX51_PAD_DI1_PIN3 = 182,
+ MX51_PAD_DI1_PIN2 = 183,
+ MX51_PAD_DI_GP2 = 184,
+ MX51_PAD_DI_GP3 = 185,
+ MX51_PAD_DI2_PIN4 = 186,
+ MX51_PAD_DI2_PIN2 = 187,
+ MX51_PAD_DI2_PIN3 = 188,
+ MX51_PAD_DI2_DISP_CLK = 189,
+ MX51_PAD_DI_GP4 = 190,
+ MX51_PAD_DISP2_DAT0 = 191,
+ MX51_PAD_DISP2_DAT1 = 192,
+ MX51_PAD_DISP2_DAT2 = 193,
+ MX51_PAD_DISP2_DAT3 = 194,
+ MX51_PAD_DISP2_DAT4 = 195,
+ MX51_PAD_DISP2_DAT5 = 196,
+ MX51_PAD_DISP2_DAT6 = 197,
+ MX51_PAD_DISP2_DAT7 = 198,
+ MX51_PAD_DISP2_DAT8 = 199,
+ MX51_PAD_DISP2_DAT9 = 200,
+ MX51_PAD_DISP2_DAT10 = 201,
+ MX51_PAD_DISP2_DAT11 = 202,
+ MX51_PAD_DISP2_DAT12 = 203,
+ MX51_PAD_DISP2_DAT13 = 204,
+ MX51_PAD_DISP2_DAT14 = 205,
+ MX51_PAD_DISP2_DAT15 = 206,
+ MX51_PAD_SD1_CMD = 207,
+ MX51_PAD_SD1_CLK = 208,
+ MX51_PAD_SD1_DATA0 = 209,
+ MX51_PAD_EIM_DA0 = 210,
+ MX51_PAD_EIM_DA1 = 211,
+ MX51_PAD_EIM_DA2 = 212,
+ MX51_PAD_EIM_DA3 = 213,
+ MX51_PAD_SD1_DATA1 = 214,
+ MX51_PAD_EIM_DA4 = 215,
+ MX51_PAD_EIM_DA5 = 216,
+ MX51_PAD_EIM_DA6 = 217,
+ MX51_PAD_EIM_DA7 = 218,
+ MX51_PAD_SD1_DATA2 = 219,
+ MX51_PAD_EIM_DA10 = 220,
+ MX51_PAD_EIM_DA11 = 221,
+ MX51_PAD_EIM_DA8 = 222,
+ MX51_PAD_EIM_DA9 = 223,
+ MX51_PAD_SD1_DATA3 = 224,
+ MX51_PAD_GPIO1_0 = 225,
+ MX51_PAD_GPIO1_1 = 226,
+ MX51_PAD_EIM_DA12 = 227,
+ MX51_PAD_EIM_DA13 = 228,
+ MX51_PAD_EIM_DA14 = 229,
+ MX51_PAD_EIM_DA15 = 230,
+ MX51_PAD_SD2_CMD = 231,
+ MX51_PAD_SD2_CLK = 232,
+ MX51_PAD_SD2_DATA0 = 233,
+ MX51_PAD_SD2_DATA1 = 234,
+ MX51_PAD_SD2_DATA2 = 235,
+ MX51_PAD_SD2_DATA3 = 236,
+ MX51_PAD_GPIO1_2 = 237,
+ MX51_PAD_GPIO1_3 = 238,
+ MX51_PAD_PMIC_INT_REQ = 239,
+ MX51_PAD_GPIO1_4 = 240,
+ MX51_PAD_GPIO1_5 = 241,
+ MX51_PAD_GPIO1_6 = 242,
+ MX51_PAD_GPIO1_7 = 243,
+ MX51_PAD_GPIO1_8 = 244,
+ MX51_PAD_GPIO1_9 = 245,
+};
+
+/* imx51 register maps */
+static struct imx_pin_reg imx51_pin_regs[] = {
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 5, 0x000, 0), /* MX51_PAD_EIM_D16__AUD4_RXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 7, 0x8d8, 0), /* MX51_PAD_EIM_D16__AUD5_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 0, 0x000, 0), /* MX51_PAD_EIM_D16__EIM_D16 */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 1, 0x000, 0), /* MX51_PAD_EIM_D16__GPIO2_0 */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 4, 0x9b4, 0), /* MX51_PAD_EIM_D16__I2C1_SDA */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 3, 0x000, 0), /* MX51_PAD_EIM_D16__UART2_CTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 2, 0x000, 0), /* MX51_PAD_EIM_D16__USBH2_DATA0 */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 7, 0x8d4, 0), /* MX51_PAD_EIM_D17__AUD5_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 0, 0x000, 0), /* MX51_PAD_EIM_D17__EIM_D17 */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 1, 0x000, 0), /* MX51_PAD_EIM_D17__GPIO2_1 */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 3, 0x9ec, 0), /* MX51_PAD_EIM_D17__UART2_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 4, 0x000, 0), /* MX51_PAD_EIM_D17__UART3_CTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 2, 0x000, 0), /* MX51_PAD_EIM_D17__USBH2_DATA1 */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 7, 0x8e4, 0), /* MX51_PAD_EIM_D18__AUD5_TXC */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 0, 0x000, 0), /* MX51_PAD_EIM_D18__EIM_D18 */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 1, 0x000, 0), /* MX51_PAD_EIM_D18__GPIO2_2 */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 3, 0x000, 0), /* MX51_PAD_EIM_D18__UART2_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 4, 0x9f0, 1), /* MX51_PAD_EIM_D18__UART3_RTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 2, 0x000, 0), /* MX51_PAD_EIM_D18__USBH2_DATA2 */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 5, 0x000, 0), /* MX51_PAD_EIM_D19__AUD4_RXC */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 7, 0x8e8, 0), /* MX51_PAD_EIM_D19__AUD5_TXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 0, 0x000, 0), /* MX51_PAD_EIM_D19__EIM_D19 */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 1, 0x000, 0), /* MX51_PAD_EIM_D19__GPIO2_3 */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 4, 0x9b0, 0), /* MX51_PAD_EIM_D19__I2C1_SCL */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 3, 0x9e8, 1), /* MX51_PAD_EIM_D19__UART2_RTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 2, 0x000, 0), /* MX51_PAD_EIM_D19__USBH2_DATA3 */
+ IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 5, 0x8c8, 0), /* MX51_PAD_EIM_D20__AUD4_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 0, 0x000, 0), /* MX51_PAD_EIM_D20__EIM_D20 */
+ IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 1, 0x000, 0), /* MX51_PAD_EIM_D20__GPIO2_4 */
+ IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 4, 0x000, 0), /* MX51_PAD_EIM_D20__SRTC_ALARM_DEB */
+ IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 2, 0x000, 0), /* MX51_PAD_EIM_D20__USBH2_DATA4 */
+ IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 5, 0x8c4, 0), /* MX51_PAD_EIM_D21__AUD4_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 0, 0x000, 0), /* MX51_PAD_EIM_D21__EIM_D21 */
+ IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 1, 0x000, 0), /* MX51_PAD_EIM_D21__GPIO2_5 */
+ IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 3, 0x000, 0), /* MX51_PAD_EIM_D21__SRTC_ALARM_DEB */
+ IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 2, 0x000, 0), /* MX51_PAD_EIM_D21__USBH2_DATA5 */
+ IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 5, 0x8cc, 0), /* MX51_PAD_EIM_D22__AUD4_TXC */
+ IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 0, 0x000, 0), /* MX51_PAD_EIM_D22__EIM_D22 */
+ IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 1, 0x000, 0), /* MX51_PAD_EIM_D22__GPIO2_6 */
+ IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 2, 0x000, 0), /* MX51_PAD_EIM_D22__USBH2_DATA6 */
+ IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 5, 0x8d0, 0), /* MX51_PAD_EIM_D23__AUD4_TXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 0, 0x000, 0), /* MX51_PAD_EIM_D23__EIM_D23 */
+ IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 1, 0x000, 0), /* MX51_PAD_EIM_D23__GPIO2_7 */
+ IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 4, 0x000, 0), /* MX51_PAD_EIM_D23__SPDIF_OUT1 */
+ IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 2, 0x000, 0), /* MX51_PAD_EIM_D23__USBH2_DATA7 */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 5, 0x8f8, 0), /* MX51_PAD_EIM_D24__AUD6_RXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 0, 0x000, 0), /* MX51_PAD_EIM_D24__EIM_D24 */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 1, 0x000, 0), /* MX51_PAD_EIM_D24__GPIO2_8 */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 4, 0x9bc, 0), /* MX51_PAD_EIM_D24__I2C2_SDA */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 3, 0x000, 0), /* MX51_PAD_EIM_D24__UART3_CTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 2, 0x000, 0), /* MX51_PAD_EIM_D24__USBOTG_DATA0 */
+ IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 0, 0x000, 0), /* MX51_PAD_EIM_D25__EIM_D25 */
+ IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 1, 0x9c8, 0), /* MX51_PAD_EIM_D25__KEY_COL6 */
+ IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 4, 0x000, 0), /* MX51_PAD_EIM_D25__UART2_CTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 3, 0x9f4, 0), /* MX51_PAD_EIM_D25__UART3_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 2, 0x000, 0), /* MX51_PAD_EIM_D25__USBOTG_DATA1 */
+ IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 0, 0x000, 0), /* MX51_PAD_EIM_D26__EIM_D26 */
+ IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 1, 0x9cc, 0), /* MX51_PAD_EIM_D26__KEY_COL7 */
+ IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 4, 0x9e8, 3), /* MX51_PAD_EIM_D26__UART2_RTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 3, 0x000, 0), /* MX51_PAD_EIM_D26__UART3_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 2, 0x000, 0), /* MX51_PAD_EIM_D26__USBOTG_DATA2 */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 5, 0x8f4, 0), /* MX51_PAD_EIM_D27__AUD6_RXC */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 0, 0x000, 0), /* MX51_PAD_EIM_D27__EIM_D27 */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 1, 0x000, 0), /* MX51_PAD_EIM_D27__GPIO2_9 */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 4, 0x9b8, 0), /* MX51_PAD_EIM_D27__I2C2_SCL */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 3, 0x9f0, 3), /* MX51_PAD_EIM_D27__UART3_RTS */
+ IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 2, 0x000, 0), /* MX51_PAD_EIM_D27__USBOTG_DATA3 */
+ IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 5, 0x8f0, 0), /* MX51_PAD_EIM_D28__AUD6_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 0, 0x000, 0), /* MX51_PAD_EIM_D28__EIM_D28 */
+ IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 1, 0x9d0, 0), /* MX51_PAD_EIM_D28__KEY_ROW4 */
+ IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 2, 0x000, 0), /* MX51_PAD_EIM_D28__USBOTG_DATA4 */
+ IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 5, 0x8ec, 0), /* MX51_PAD_EIM_D29__AUD6_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 0, 0x000, 0), /* MX51_PAD_EIM_D29__EIM_D29 */
+ IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 1, 0x9d4, 0), /* MX51_PAD_EIM_D29__KEY_ROW5 */
+ IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 2, 0x000, 0), /* MX51_PAD_EIM_D29__USBOTG_DATA5 */
+ IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 5, 0x8fc, 0), /* MX51_PAD_EIM_D30__AUD6_TXC */
+ IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 0, 0x000, 0), /* MX51_PAD_EIM_D30__EIM_D30 */
+ IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 1, 0x9d8, 0), /* MX51_PAD_EIM_D30__KEY_ROW6 */
+ IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 2, 0x000, 0), /* MX51_PAD_EIM_D30__USBOTG_DATA6 */
+ IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 5, 0x900, 0), /* MX51_PAD_EIM_D31__AUD6_TXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 0, 0x000, 0), /* MX51_PAD_EIM_D31__EIM_D31 */
+ IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 1, 0x9dc, 0), /* MX51_PAD_EIM_D31__KEY_ROW7 */
+ IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 2, 0x000, 0), /* MX51_PAD_EIM_D31__USBOTG_DATA7 */
+ IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 0, 0x000, 0), /* MX51_PAD_EIM_A16__EIM_A16 */
+ IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 1, 0x000, 0), /* MX51_PAD_EIM_A16__GPIO2_10 */
+ IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 7, 0x000, 0), /* MX51_PAD_EIM_A16__OSC_FREQ_SEL0 */
+ IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 0, 0x000, 0), /* MX51_PAD_EIM_A17__EIM_A17 */
+ IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 1, 0x000, 0), /* MX51_PAD_EIM_A17__GPIO2_11 */
+ IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 7, 0x000, 0), /* MX51_PAD_EIM_A17__OSC_FREQ_SEL1 */
+ IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 7, 0x000, 0), /* MX51_PAD_EIM_A18__BOOT_LPB0 */
+ IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 0, 0x000, 0), /* MX51_PAD_EIM_A18__EIM_A18 */
+ IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 1, 0x000, 0), /* MX51_PAD_EIM_A18__GPIO2_12 */
+ IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 7, 0x000, 0), /* MX51_PAD_EIM_A19__BOOT_LPB1 */
+ IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 0, 0x000, 0), /* MX51_PAD_EIM_A19__EIM_A19 */
+ IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 1, 0x000, 0), /* MX51_PAD_EIM_A19__GPIO2_13 */
+ IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 7, 0x000, 0), /* MX51_PAD_EIM_A20__BOOT_UART_SRC0 */
+ IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 0, 0x000, 0), /* MX51_PAD_EIM_A20__EIM_A20 */
+ IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 1, 0x000, 0), /* MX51_PAD_EIM_A20__GPIO2_14 */
+ IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 7, 0x000, 0), /* MX51_PAD_EIM_A21__BOOT_UART_SRC1 */
+ IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 0, 0x000, 0), /* MX51_PAD_EIM_A21__EIM_A21 */
+ IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 1, 0x000, 0), /* MX51_PAD_EIM_A21__GPIO2_15 */
+ IMX_PIN_REG(MX51_PAD_EIM_A22, 0x448, 0x0b4, 0, 0x000, 0), /* MX51_PAD_EIM_A22__EIM_A22 */
+ IMX_PIN_REG(MX51_PAD_EIM_A22, 0x448, 0x0b4, 1, 0x000, 0), /* MX51_PAD_EIM_A22__GPIO2_16 */
+ IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 7, 0x000, 0), /* MX51_PAD_EIM_A23__BOOT_HPN_EN */
+ IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 0, 0x000, 0), /* MX51_PAD_EIM_A23__EIM_A23 */
+ IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 1, 0x000, 0), /* MX51_PAD_EIM_A23__GPIO2_17 */
+ IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 0, 0x000, 0), /* MX51_PAD_EIM_A24__EIM_A24 */
+ IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 1, 0x000, 0), /* MX51_PAD_EIM_A24__GPIO2_18 */
+ IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 2, 0x000, 0), /* MX51_PAD_EIM_A24__USBH2_CLK */
+ IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 6, 0x000, 0), /* MX51_PAD_EIM_A25__DISP1_PIN4 */
+ IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 0, 0x000, 0), /* MX51_PAD_EIM_A25__EIM_A25 */
+ IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 1, 0x000, 0), /* MX51_PAD_EIM_A25__GPIO2_19 */
+ IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 2, 0x000, 0), /* MX51_PAD_EIM_A25__USBH2_DIR */
+ IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 5, 0x9a0, 0), /* MX51_PAD_EIM_A26__CSI1_DATA_EN */
+ IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 6, 0x908, 0), /* MX51_PAD_EIM_A26__DISP2_EXT_CLK */
+ IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 0, 0x000, 0), /* MX51_PAD_EIM_A26__EIM_A26 */
+ IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 1, 0x000, 0), /* MX51_PAD_EIM_A26__GPIO2_20 */
+ IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 2, 0x000, 0), /* MX51_PAD_EIM_A26__USBH2_STP */
+ IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 5, 0x99c, 0), /* MX51_PAD_EIM_A27__CSI2_DATA_EN */
+ IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 6, 0x9a4, 0), /* MX51_PAD_EIM_A27__DISP1_PIN1 */
+ IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 0, 0x000, 0), /* MX51_PAD_EIM_A27__EIM_A27 */
+ IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 1, 0x000, 0), /* MX51_PAD_EIM_A27__GPIO2_21 */
+ IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 2, 0x000, 0), /* MX51_PAD_EIM_A27__USBH2_NXT */
+ IMX_PIN_REG(MX51_PAD_EIM_EB0, 0x460, 0x0cc, 0, 0x000, 0), /* MX51_PAD_EIM_EB0__EIM_EB0 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB1, 0x464, 0x0d0, 0, 0x000, 0), /* MX51_PAD_EIM_EB1__EIM_EB1 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 6, 0x8e0, 0), /* MX51_PAD_EIM_EB2__AUD5_RXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 5, 0x000, 0), /* MX51_PAD_EIM_EB2__CSI1_D2 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 0, 0x000, 0), /* MX51_PAD_EIM_EB2__EIM_EB2 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 3, 0x954, 0), /* MX51_PAD_EIM_EB2__FEC_MDIO */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 1, 0x000, 0), /* MX51_PAD_EIM_EB2__GPIO2_22 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 7, 0x000, 0), /* MX51_PAD_EIM_EB2__GPT_CMPOUT1 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 6, 0x8dc, 0), /* MX51_PAD_EIM_EB3__AUD5_RXC */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 5, 0x000, 0), /* MX51_PAD_EIM_EB3__CSI1_D3 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 0, 0x000, 0), /* MX51_PAD_EIM_EB3__EIM_EB3 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 3, 0x95c, 0), /* MX51_PAD_EIM_EB3__FEC_RDATA1 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 1, 0x000, 0), /* MX51_PAD_EIM_EB3__GPIO2_23 */
+ IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 7, 0x000, 0), /* MX51_PAD_EIM_EB3__GPT_CMPOUT2 */
+ IMX_PIN_REG(MX51_PAD_EIM_OE, 0x470, 0x0dc, 0, 0x000, 0), /* MX51_PAD_EIM_OE__EIM_OE */
+ IMX_PIN_REG(MX51_PAD_EIM_OE, 0x470, 0x0dc, 1, 0x000, 0), /* MX51_PAD_EIM_OE__GPIO2_24 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS0, 0x474, 0x0e0, 0, 0x000, 0), /* MX51_PAD_EIM_CS0__EIM_CS0 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS0, 0x474, 0x0e0, 1, 0x000, 0), /* MX51_PAD_EIM_CS0__GPIO2_25 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS1, 0x478, 0x0e4, 0, 0x000, 0), /* MX51_PAD_EIM_CS1__EIM_CS1 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS1, 0x478, 0x0e4, 1, 0x000, 0), /* MX51_PAD_EIM_CS1__GPIO2_26 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 6, 0x8d8, 1), /* MX51_PAD_EIM_CS2__AUD5_TXD */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 5, 0x000, 0), /* MX51_PAD_EIM_CS2__CSI1_D4 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 0, 0x000, 0), /* MX51_PAD_EIM_CS2__EIM_CS2 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 3, 0x960, 0), /* MX51_PAD_EIM_CS2__FEC_RDATA2 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 1, 0x000, 0), /* MX51_PAD_EIM_CS2__GPIO2_27 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 2, 0x000, 0), /* MX51_PAD_EIM_CS2__USBOTG_STP */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 6, 0x8d4, 1), /* MX51_PAD_EIM_CS3__AUD5_RXD */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 5, 0x000, 0), /* MX51_PAD_EIM_CS3__CSI1_D5 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 0, 0x000, 0), /* MX51_PAD_EIM_CS3__EIM_CS3 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 3, 0x964, 0), /* MX51_PAD_EIM_CS3__FEC_RDATA3 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 1, 0x000, 0), /* MX51_PAD_EIM_CS3__GPIO2_28 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 2, 0x000, 0), /* MX51_PAD_EIM_CS3__USBOTG_NXT */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 6, 0x8e4, 1), /* MX51_PAD_EIM_CS4__AUD5_TXC */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 5, 0x000, 0), /* MX51_PAD_EIM_CS4__CSI1_D6 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 0, 0x000, 0), /* MX51_PAD_EIM_CS4__EIM_CS4 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 3, 0x970, 0), /* MX51_PAD_EIM_CS4__FEC_RX_ER */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 1, 0x000, 0), /* MX51_PAD_EIM_CS4__GPIO2_29 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 2, 0x000, 0), /* MX51_PAD_EIM_CS4__USBOTG_CLK */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 6, 0x8e8, 1), /* MX51_PAD_EIM_CS5__AUD5_TXFS */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 5, 0x000, 0), /* MX51_PAD_EIM_CS5__CSI1_D7 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 4, 0x904, 0), /* MX51_PAD_EIM_CS5__DISP1_EXT_CLK */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 0, 0x000, 0), /* MX51_PAD_EIM_CS5__EIM_CS5 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 3, 0x950, 0), /* MX51_PAD_EIM_CS5__FEC_CRS */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 1, 0x000, 0), /* MX51_PAD_EIM_CS5__GPIO2_30 */
+ IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 2, 0x000, 0), /* MX51_PAD_EIM_CS5__USBOTG_DIR */
+ IMX_PIN_REG(MX51_PAD_EIM_DTACK, 0x48c, 0x0f8, 0, 0x000, 0), /* MX51_PAD_EIM_DTACK__EIM_DTACK */
+ IMX_PIN_REG(MX51_PAD_EIM_DTACK, 0x48c, 0x0f8, 1, 0x000, 0), /* MX51_PAD_EIM_DTACK__GPIO2_31 */
+ IMX_PIN_REG(MX51_PAD_EIM_LBA, 0x494, 0x0fc, 0, 0x000, 0), /* MX51_PAD_EIM_LBA__EIM_LBA */
+ IMX_PIN_REG(MX51_PAD_EIM_LBA, 0x494, 0x0fc, 1, 0x978, 0), /* MX51_PAD_EIM_LBA__GPIO3_1 */
+ IMX_PIN_REG(MX51_PAD_EIM_CRE, 0x4a0, 0x100, 0, 0x000, 0), /* MX51_PAD_EIM_CRE__EIM_CRE */
+ IMX_PIN_REG(MX51_PAD_EIM_CRE, 0x4a0, 0x100, 1, 0x97c, 0), /* MX51_PAD_EIM_CRE__GPIO3_2 */
+ IMX_PIN_REG(MX51_PAD_DRAM_CS1, 0x4d0, 0x104, 0, 0x000, 0), /* MX51_PAD_DRAM_CS1__DRAM_CS1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 3, 0x980, 0), /* MX51_PAD_NANDF_WE_B__GPIO3_3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 0, 0x000, 0), /* MX51_PAD_NANDF_WE_B__NANDF_WE_B */
+ IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 1, 0x000, 0), /* MX51_PAD_NANDF_WE_B__PATA_DIOW */
+ IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 2, 0x93c, 0), /* MX51_PAD_NANDF_WE_B__SD3_DATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 3, 0x984, 0), /* MX51_PAD_NANDF_RE_B__GPIO3_4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 0, 0x000, 0), /* MX51_PAD_NANDF_RE_B__NANDF_RE_B */
+ IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 1, 0x000, 0), /* MX51_PAD_NANDF_RE_B__PATA_DIOR */
+ IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 2, 0x940, 0), /* MX51_PAD_NANDF_RE_B__SD3_DATA1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 3, 0x988, 0), /* MX51_PAD_NANDF_ALE__GPIO3_5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 0, 0x000, 0), /* MX51_PAD_NANDF_ALE__NANDF_ALE */
+ IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 1, 0x000, 0), /* MX51_PAD_NANDF_ALE__PATA_BUFFER_EN */
+ IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 3, 0x98c, 0), /* MX51_PAD_NANDF_CLE__GPIO3_6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 0, 0x000, 0), /* MX51_PAD_NANDF_CLE__NANDF_CLE */
+ IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 1, 0x000, 0), /* MX51_PAD_NANDF_CLE__PATA_RESET_B */
+ IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 3, 0x990, 0), /* MX51_PAD_NANDF_WP_B__GPIO3_7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 0, 0x000, 0), /* MX51_PAD_NANDF_WP_B__NANDF_WP_B */
+ IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 1, 0x000, 0), /* MX51_PAD_NANDF_WP_B__PATA_DMACK */
+ IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 2, 0x944, 0), /* MX51_PAD_NANDF_WP_B__SD3_DATA2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 5, 0x930, 0), /* MX51_PAD_NANDF_RB0__ECSPI2_SS1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 3, 0x994, 0), /* MX51_PAD_NANDF_RB0__GPIO3_8 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 0, 0x000, 0), /* MX51_PAD_NANDF_RB0__NANDF_RB0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 1, 0x000, 0), /* MX51_PAD_NANDF_RB0__PATA_DMARQ */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 2, 0x948, 0), /* MX51_PAD_NANDF_RB0__SD3_DATA3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 6, 0x91c, 0), /* MX51_PAD_NANDF_RB1__CSPI_MOSI */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 2, 0x000, 0), /* MX51_PAD_NANDF_RB1__ECSPI2_RDY */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 3, 0x000, 0), /* MX51_PAD_NANDF_RB1__GPIO3_9 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 0, 0x000, 0), /* MX51_PAD_NANDF_RB1__NANDF_RB1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 1, 0x000, 0), /* MX51_PAD_NANDF_RB1__PATA_IORDY */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 5, 0x000, 0), /* MX51_PAD_NANDF_RB1__SD4_CMD */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 5, 0x9a8, 0), /* MX51_PAD_NANDF_RB2__DISP2_WAIT */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 2, 0x000, 0), /* MX51_PAD_NANDF_RB2__ECSPI2_SCLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 1, 0x94c, 0), /* MX51_PAD_NANDF_RB2__FEC_COL */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 3, 0x000, 0), /* MX51_PAD_NANDF_RB2__GPIO3_10 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 0, 0x000, 0), /* MX51_PAD_NANDF_RB2__NANDF_RB2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 7, 0x000, 0), /* MX51_PAD_NANDF_RB2__USBH3_H3_DP */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 6, 0xa20, 0), /* MX51_PAD_NANDF_RB2__USBH3_NXT */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 5, 0x000, 0), /* MX51_PAD_NANDF_RB3__DISP1_WAIT */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 2, 0x000, 0), /* MX51_PAD_NANDF_RB3__ECSPI2_MISO */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 1, 0x968, 0), /* MX51_PAD_NANDF_RB3__FEC_RX_CLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 3, 0x000, 0), /* MX51_PAD_NANDF_RB3__GPIO3_11 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 0, 0x000, 0), /* MX51_PAD_NANDF_RB3__NANDF_RB3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 6, 0x9f8, 0), /* MX51_PAD_NANDF_RB3__USBH3_CLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 7, 0x000, 0), /* MX51_PAD_NANDF_RB3__USBH3_H3_DM */
+ IMX_PIN_REG(MX51_PAD_GPIO_NAND, 0x514, 0x12c, 0, 0x998, 0), /* MX51_PAD_GPIO_NAND__GPIO_NAND */
+ IMX_PIN_REG(MX51_PAD_GPIO_NAND, 0x514, 0x12c, 1, 0x000, 0), /* MX51_PAD_GPIO_NAND__PATA_INTRQ */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS0, 0x518, 0x130, 3, 0x000, 0), /* MX51_PAD_NANDF_CS0__GPIO3_16 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS0, 0x518, 0x130, 0, 0x000, 0), /* MX51_PAD_NANDF_CS0__NANDF_CS0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS1, 0x51c, 0x134, 3, 0x000, 0), /* MX51_PAD_NANDF_CS1__GPIO3_17 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS1, 0x51c, 0x134, 0, 0x000, 0), /* MX51_PAD_NANDF_CS1__NANDF_CS1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 6, 0x914, 0), /* MX51_PAD_NANDF_CS2__CSPI_SCLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 2, 0x000, 0), /* MX51_PAD_NANDF_CS2__FEC_TX_ER */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 3, 0x000, 0), /* MX51_PAD_NANDF_CS2__GPIO3_18 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 0, 0x000, 0), /* MX51_PAD_NANDF_CS2__NANDF_CS2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 1, 0x000, 0), /* MX51_PAD_NANDF_CS2__PATA_CS_0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 5, 0x000, 0), /* MX51_PAD_NANDF_CS2__SD4_CLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 7, 0x000, 0), /* MX51_PAD_NANDF_CS2__USBH3_H1_DP */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 2, 0x000, 0), /* MX51_PAD_NANDF_CS3__FEC_MDC */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 3, 0x000, 0), /* MX51_PAD_NANDF_CS3__GPIO3_19 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 0, 0x000, 0), /* MX51_PAD_NANDF_CS3__NANDF_CS3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 1, 0x000, 0), /* MX51_PAD_NANDF_CS3__PATA_CS_1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 5, 0x000, 0), /* MX51_PAD_NANDF_CS3__SD4_DAT0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 7, 0x000, 0), /* MX51_PAD_NANDF_CS3__USBH3_H1_DM */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 2, 0x000, 0), /* MX51_PAD_NANDF_CS4__FEC_TDATA1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 3, 0x000, 0), /* MX51_PAD_NANDF_CS4__GPIO3_20 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 0, 0x000, 0), /* MX51_PAD_NANDF_CS4__NANDF_CS4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 1, 0x000, 0), /* MX51_PAD_NANDF_CS4__PATA_DA_0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 5, 0x000, 0), /* MX51_PAD_NANDF_CS4__SD4_DAT1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 7, 0xa24, 0), /* MX51_PAD_NANDF_CS4__USBH3_STP */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 2, 0x000, 0), /* MX51_PAD_NANDF_CS5__FEC_TDATA2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 3, 0x000, 0), /* MX51_PAD_NANDF_CS5__GPIO3_21 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 0, 0x000, 0), /* MX51_PAD_NANDF_CS5__NANDF_CS5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 1, 0x000, 0), /* MX51_PAD_NANDF_CS5__PATA_DA_1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 5, 0x000, 0), /* MX51_PAD_NANDF_CS5__SD4_DAT2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 7, 0xa1c, 0), /* MX51_PAD_NANDF_CS5__USBH3_DIR */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 7, 0x928, 0), /* MX51_PAD_NANDF_CS6__CSPI_SS3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 2, 0x000, 0), /* MX51_PAD_NANDF_CS6__FEC_TDATA3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 3, 0x000, 0), /* MX51_PAD_NANDF_CS6__GPIO3_22 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 0, 0x000, 0), /* MX51_PAD_NANDF_CS6__NANDF_CS6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 1, 0x000, 0), /* MX51_PAD_NANDF_CS6__PATA_DA_2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 5, 0x000, 0), /* MX51_PAD_NANDF_CS6__SD4_DAT3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 1, 0x000, 0), /* MX51_PAD_NANDF_CS7__FEC_TX_EN */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 3, 0x000, 0), /* MX51_PAD_NANDF_CS7__GPIO3_23 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 0, 0x000, 0), /* MX51_PAD_NANDF_CS7__NANDF_CS7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 5, 0x000, 0), /* MX51_PAD_NANDF_CS7__SD3_CLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 2, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__ECSPI2_SS0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 1, 0x974, 0), /* MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK */
+ IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 3, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__GPIO3_24 */
+ IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 0, 0x938, 0), /* MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT */
+ IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 5, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__SD3_CMD */
+ IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 2, 0x000, 0), /* MX51_PAD_NANDF_D15__ECSPI2_MOSI */
+ IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 3, 0x000, 0), /* MX51_PAD_NANDF_D15__GPIO3_25 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 0, 0x000, 0), /* MX51_PAD_NANDF_D15__NANDF_D15 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 1, 0x000, 0), /* MX51_PAD_NANDF_D15__PATA_DATA15 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 5, 0x000, 0), /* MX51_PAD_NANDF_D15__SD3_DAT7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 2, 0x934, 0), /* MX51_PAD_NANDF_D14__ECSPI2_SS3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 3, 0x000, 0), /* MX51_PAD_NANDF_D14__GPIO3_26 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 0, 0x000, 0), /* MX51_PAD_NANDF_D14__NANDF_D14 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 1, 0x000, 0), /* MX51_PAD_NANDF_D14__PATA_DATA14 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 5, 0x000, 0), /* MX51_PAD_NANDF_D14__SD3_DAT6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 2, 0x000, 0), /* MX51_PAD_NANDF_D13__ECSPI2_SS2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 3, 0x000, 0), /* MX51_PAD_NANDF_D13__GPIO3_27 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 0, 0x000, 0), /* MX51_PAD_NANDF_D13__NANDF_D13 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 1, 0x000, 0), /* MX51_PAD_NANDF_D13__PATA_DATA13 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 5, 0x000, 0), /* MX51_PAD_NANDF_D13__SD3_DAT5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 2, 0x930, 1), /* MX51_PAD_NANDF_D12__ECSPI2_SS1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 3, 0x000, 0), /* MX51_PAD_NANDF_D12__GPIO3_28 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 0, 0x000, 0), /* MX51_PAD_NANDF_D12__NANDF_D12 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 1, 0x000, 0), /* MX51_PAD_NANDF_D12__PATA_DATA12 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 5, 0x000, 0), /* MX51_PAD_NANDF_D12__SD3_DAT4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 2, 0x96c, 0), /* MX51_PAD_NANDF_D11__FEC_RX_DV */
+ IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 3, 0x000, 0), /* MX51_PAD_NANDF_D11__GPIO3_29 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 0, 0x000, 0), /* MX51_PAD_NANDF_D11__NANDF_D11 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 1, 0x000, 0), /* MX51_PAD_NANDF_D11__PATA_DATA11 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 5, 0x948, 1), /* MX51_PAD_NANDF_D11__SD3_DATA3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 3, 0x000, 0), /* MX51_PAD_NANDF_D10__GPIO3_30 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 0, 0x000, 0), /* MX51_PAD_NANDF_D10__NANDF_D10 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 1, 0x000, 0), /* MX51_PAD_NANDF_D10__PATA_DATA10 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 5, 0x944, 1), /* MX51_PAD_NANDF_D10__SD3_DATA2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 2, 0x958, 0), /* MX51_PAD_NANDF_D9__FEC_RDATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 3, 0x000, 0), /* MX51_PAD_NANDF_D9__GPIO3_31 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 0, 0x000, 0), /* MX51_PAD_NANDF_D9__NANDF_D9 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 1, 0x000, 0), /* MX51_PAD_NANDF_D9__PATA_DATA9 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 5, 0x940, 1), /* MX51_PAD_NANDF_D9__SD3_DATA1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 2, 0x000, 0), /* MX51_PAD_NANDF_D8__FEC_TDATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 3, 0x000, 0), /* MX51_PAD_NANDF_D8__GPIO4_0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 0, 0x000, 0), /* MX51_PAD_NANDF_D8__NANDF_D8 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 1, 0x000, 0), /* MX51_PAD_NANDF_D8__PATA_DATA8 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 5, 0x93c, 1), /* MX51_PAD_NANDF_D8__SD3_DATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 3, 0x000, 0), /* MX51_PAD_NANDF_D7__GPIO4_1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 0, 0x000, 0), /* MX51_PAD_NANDF_D7__NANDF_D7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 1, 0x000, 0), /* MX51_PAD_NANDF_D7__PATA_DATA7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 5, 0x9fc, 0), /* MX51_PAD_NANDF_D7__USBH3_DATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 3, 0x000, 0), /* MX51_PAD_NANDF_D6__GPIO4_2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 0, 0x000, 0), /* MX51_PAD_NANDF_D6__NANDF_D6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 1, 0x000, 0), /* MX51_PAD_NANDF_D6__PATA_DATA6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 2, 0x000, 0), /* MX51_PAD_NANDF_D6__SD4_LCTL */
+ IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 5, 0xa00, 0), /* MX51_PAD_NANDF_D6__USBH3_DATA1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 3, 0x000, 0), /* MX51_PAD_NANDF_D5__GPIO4_3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 0, 0x000, 0), /* MX51_PAD_NANDF_D5__NANDF_D5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 1, 0x000, 0), /* MX51_PAD_NANDF_D5__PATA_DATA5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 2, 0x000, 0), /* MX51_PAD_NANDF_D5__SD4_WP */
+ IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 5, 0xa04, 0), /* MX51_PAD_NANDF_D5__USBH3_DATA2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 3, 0x000, 0), /* MX51_PAD_NANDF_D4__GPIO4_4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 0, 0x000, 0), /* MX51_PAD_NANDF_D4__NANDF_D4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 1, 0x000, 0), /* MX51_PAD_NANDF_D4__PATA_DATA4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 2, 0x000, 0), /* MX51_PAD_NANDF_D4__SD4_CD */
+ IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 5, 0xa08, 0), /* MX51_PAD_NANDF_D4__USBH3_DATA3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 3, 0x000, 0), /* MX51_PAD_NANDF_D3__GPIO4_5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 0, 0x000, 0), /* MX51_PAD_NANDF_D3__NANDF_D3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 1, 0x000, 0), /* MX51_PAD_NANDF_D3__PATA_DATA3 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 2, 0x000, 0), /* MX51_PAD_NANDF_D3__SD4_DAT4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 5, 0xa0c, 0), /* MX51_PAD_NANDF_D3__USBH3_DATA4 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 3, 0x000, 0), /* MX51_PAD_NANDF_D2__GPIO4_6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 0, 0x000, 0), /* MX51_PAD_NANDF_D2__NANDF_D2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 1, 0x000, 0), /* MX51_PAD_NANDF_D2__PATA_DATA2 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 2, 0x000, 0), /* MX51_PAD_NANDF_D2__SD4_DAT5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 5, 0xa10, 0), /* MX51_PAD_NANDF_D2__USBH3_DATA5 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 3, 0x000, 0), /* MX51_PAD_NANDF_D1__GPIO4_7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 0, 0x000, 0), /* MX51_PAD_NANDF_D1__NANDF_D1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 1, 0x000, 0), /* MX51_PAD_NANDF_D1__PATA_DATA1 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 2, 0x000, 0), /* MX51_PAD_NANDF_D1__SD4_DAT6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 5, 0xa14, 0), /* MX51_PAD_NANDF_D1__USBH3_DATA6 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 3, 0x000, 0), /* MX51_PAD_NANDF_D0__GPIO4_8 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 0, 0x000, 0), /* MX51_PAD_NANDF_D0__NANDF_D0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 1, 0x000, 0), /* MX51_PAD_NANDF_D0__PATA_DATA0 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 2, 0x000, 0), /* MX51_PAD_NANDF_D0__SD4_DAT7 */
+ IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 5, 0xa18, 0), /* MX51_PAD_NANDF_D0__USBH3_DATA7 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D8, 0x57c, 0x194, 0, 0x000, 0), /* MX51_PAD_CSI1_D8__CSI1_D8 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D8, 0x57c, 0x194, 3, 0x998, 1), /* MX51_PAD_CSI1_D8__GPIO3_12 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D9, 0x580, 0x198, 0, 0x000, 0), /* MX51_PAD_CSI1_D9__CSI1_D9 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D9, 0x580, 0x198, 3, 0x000, 0), /* MX51_PAD_CSI1_D9__GPIO3_13 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D10, 0x584, 0x19c, 0, 0x000, 0), /* MX51_PAD_CSI1_D10__CSI1_D10 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D11, 0x588, 0x1a0, 0, 0x000, 0), /* MX51_PAD_CSI1_D11__CSI1_D11 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D12, 0x58c, 0x1a4, 0, 0x000, 0), /* MX51_PAD_CSI1_D12__CSI1_D12 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D13, 0x590, 0x1a8, 0, 0x000, 0), /* MX51_PAD_CSI1_D13__CSI1_D13 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D14, 0x594, 0x1ac, 0, 0x000, 0), /* MX51_PAD_CSI1_D14__CSI1_D14 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D15, 0x598, 0x1b0, 0, 0x000, 0), /* MX51_PAD_CSI1_D15__CSI1_D15 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D16, 0x59c, 0x1b4, 0, 0x000, 0), /* MX51_PAD_CSI1_D16__CSI1_D16 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D17, 0x5a0, 0x1b8, 0, 0x000, 0), /* MX51_PAD_CSI1_D17__CSI1_D17 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D18, 0x5a4, 0x1bc, 0, 0x000, 0), /* MX51_PAD_CSI1_D18__CSI1_D18 */
+ IMX_PIN_REG(MX51_PAD_CSI1_D19, 0x5a8, 0x1c0, 0, 0x000, 0), /* MX51_PAD_CSI1_D19__CSI1_D19 */
+ IMX_PIN_REG(MX51_PAD_CSI1_VSYNC, 0x5ac, 0x1c4, 0, 0x000, 0), /* MX51_PAD_CSI1_VSYNC__CSI1_VSYNC */
+ IMX_PIN_REG(MX51_PAD_CSI1_VSYNC, 0x5ac, 0x1c4, 3, 0x000, 0), /* MX51_PAD_CSI1_VSYNC__GPIO3_14 */
+ IMX_PIN_REG(MX51_PAD_CSI1_HSYNC, 0x5b0, 0x1c8, 0, 0x000, 0), /* MX51_PAD_CSI1_HSYNC__CSI1_HSYNC */
+ IMX_PIN_REG(MX51_PAD_CSI1_HSYNC, 0x5b0, 0x1c8, 3, 0x000, 0), /* MX51_PAD_CSI1_HSYNC__GPIO3_15 */
+ IMX_PIN_REG(MX51_PAD_CSI1_PIXCLK, 0x5b4, NO_MUX, 0, 0x000, 0), /* MX51_PAD_CSI1_PIXCLK__CSI1_PIXCLK */
+ IMX_PIN_REG(MX51_PAD_CSI1_MCLK, 0x5b8, NO_MUX, 0, 0x000, 0), /* MX51_PAD_CSI1_MCLK__CSI1_MCLK */
+ IMX_PIN_REG(MX51_PAD_CSI2_D12, 0x5bc, 0x1cc, 0, 0x000, 0), /* MX51_PAD_CSI2_D12__CSI2_D12 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D12, 0x5bc, 0x1cc, 3, 0x000, 0), /* MX51_PAD_CSI2_D12__GPIO4_9 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D13, 0x5c0, 0x1d0, 0, 0x000, 0), /* MX51_PAD_CSI2_D13__CSI2_D13 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D13, 0x5c0, 0x1d0, 3, 0x000, 0), /* MX51_PAD_CSI2_D13__GPIO4_10 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D14, 0x5c4, 0x1d4, 0, 0x000, 0), /* MX51_PAD_CSI2_D14__CSI2_D14 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D15, 0x5c8, 0x1d8, 0, 0x000, 0), /* MX51_PAD_CSI2_D15__CSI2_D15 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D16, 0x5cc, 0x1dc, 0, 0x000, 0), /* MX51_PAD_CSI2_D16__CSI2_D16 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D17, 0x5d0, 0x1e0, 0, 0x000, 0), /* MX51_PAD_CSI2_D17__CSI2_D17 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D18, 0x5d4, 0x1e4, 0, 0x000, 0), /* MX51_PAD_CSI2_D18__CSI2_D18 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D18, 0x5d4, 0x1e4, 3, 0x000, 0), /* MX51_PAD_CSI2_D18__GPIO4_11 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D19, 0x5d8, 0x1e8, 0, 0x000, 0), /* MX51_PAD_CSI2_D19__CSI2_D19 */
+ IMX_PIN_REG(MX51_PAD_CSI2_D19, 0x5d8, 0x1e8, 3, 0x000, 0), /* MX51_PAD_CSI2_D19__GPIO4_12 */
+ IMX_PIN_REG(MX51_PAD_CSI2_VSYNC, 0x5dc, 0x1ec, 0, 0x000, 0), /* MX51_PAD_CSI2_VSYNC__CSI2_VSYNC */
+ IMX_PIN_REG(MX51_PAD_CSI2_VSYNC, 0x5dc, 0x1ec, 3, 0x000, 0), /* MX51_PAD_CSI2_VSYNC__GPIO4_13 */
+ IMX_PIN_REG(MX51_PAD_CSI2_HSYNC, 0x5e0, 0x1f0, 0, 0x000, 0), /* MX51_PAD_CSI2_HSYNC__CSI2_HSYNC */
+ IMX_PIN_REG(MX51_PAD_CSI2_HSYNC, 0x5e0, 0x1f0, 3, 0x000, 0), /* MX51_PAD_CSI2_HSYNC__GPIO4_14 */
+ IMX_PIN_REG(MX51_PAD_CSI2_PIXCLK, 0x5e4, 0x1f4, 0, 0x000, 0), /* MX51_PAD_CSI2_PIXCLK__CSI2_PIXCLK */
+ IMX_PIN_REG(MX51_PAD_CSI2_PIXCLK, 0x5e4, 0x1f4, 3, 0x000, 0), /* MX51_PAD_CSI2_PIXCLK__GPIO4_15 */
+ IMX_PIN_REG(MX51_PAD_I2C1_CLK, 0x5e8, 0x1f8, 3, 0x000, 0), /* MX51_PAD_I2C1_CLK__GPIO4_16 */
+ IMX_PIN_REG(MX51_PAD_I2C1_CLK, 0x5e8, 0x1f8, 0, 0x000, 0), /* MX51_PAD_I2C1_CLK__I2C1_CLK */
+ IMX_PIN_REG(MX51_PAD_I2C1_DAT, 0x5ec, 0x1fc, 3, 0x000, 0), /* MX51_PAD_I2C1_DAT__GPIO4_17 */
+ IMX_PIN_REG(MX51_PAD_I2C1_DAT, 0x5ec, 0x1fc, 0, 0x000, 0), /* MX51_PAD_I2C1_DAT__I2C1_DAT */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_TXD, 0x5f0, 0x200, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_TXD__AUD3_TXD */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_TXD, 0x5f0, 0x200, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_TXD__GPIO4_18 */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_RXD__AUD3_RXD */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_RXD__GPIO4_19 */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 1, 0x9f4, 2), /* MX51_PAD_AUD3_BB_RXD__UART3_RXD */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_CK, 0x5f8, 0x208, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_CK__AUD3_TXC */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_CK, 0x5f8, 0x208, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_CK__GPIO4_20 */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__AUD3_TXFS */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__GPIO4_21 */
+ IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 1, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__UART3_TXD */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 0, 0x000, 0), /* MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 3, 0x000, 0), /* MX51_PAD_CSPI1_MOSI__GPIO4_22 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 1, 0x9b4, 1), /* MX51_PAD_CSPI1_MOSI__I2C1_SDA */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 1, 0x8c4, 1), /* MX51_PAD_CSPI1_MISO__AUD4_RXD */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 0, 0x000, 0), /* MX51_PAD_CSPI1_MISO__ECSPI1_MISO */
+ IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 3, 0x000, 0), /* MX51_PAD_CSPI1_MISO__GPIO4_23 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 1, 0x8cc, 1), /* MX51_PAD_CSPI1_SS0__AUD4_TXC */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 0, 0x000, 0), /* MX51_PAD_CSPI1_SS0__ECSPI1_SS0 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 3, 0x000, 0), /* MX51_PAD_CSPI1_SS0__GPIO4_24 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 1, 0x8c8, 1), /* MX51_PAD_CSPI1_SS1__AUD4_TXD */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 0, 0x000, 0), /* MX51_PAD_CSPI1_SS1__ECSPI1_SS1 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 3, 0x000, 0), /* MX51_PAD_CSPI1_SS1__GPIO4_25 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 1, 0x8d0, 1), /* MX51_PAD_CSPI1_RDY__AUD4_TXFS */
+ IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 0, 0x000, 0), /* MX51_PAD_CSPI1_RDY__ECSPI1_RDY */
+ IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 3, 0x000, 0), /* MX51_PAD_CSPI1_RDY__GPIO4_26 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 0, 0x000, 0), /* MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 3, 0x000, 0), /* MX51_PAD_CSPI1_SCLK__GPIO4_27 */
+ IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 1, 0x9b0, 1), /* MX51_PAD_CSPI1_SCLK__I2C1_SCL */
+ IMX_PIN_REG(MX51_PAD_UART1_RXD, 0x618, 0x228, 3, 0x000, 0), /* MX51_PAD_UART1_RXD__GPIO4_28 */
+ IMX_PIN_REG(MX51_PAD_UART1_RXD, 0x618, 0x228, 0, 0x9e4, 0), /* MX51_PAD_UART1_RXD__UART1_RXD */
+ IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 3, 0x000, 0), /* MX51_PAD_UART1_TXD__GPIO4_29 */
+ IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 1, 0x000, 0), /* MX51_PAD_UART1_TXD__PWM2_PWMO */
+ IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 0, 0x000, 0), /* MX51_PAD_UART1_TXD__UART1_TXD */
+ IMX_PIN_REG(MX51_PAD_UART1_RTS, 0x620, 0x230, 3, 0x000, 0), /* MX51_PAD_UART1_RTS__GPIO4_30 */
+ IMX_PIN_REG(MX51_PAD_UART1_RTS, 0x620, 0x230, 0, 0x9e0, 0), /* MX51_PAD_UART1_RTS__UART1_RTS */
+ IMX_PIN_REG(MX51_PAD_UART1_CTS, 0x624, 0x234, 3, 0x000, 0), /* MX51_PAD_UART1_CTS__GPIO4_31 */
+ IMX_PIN_REG(MX51_PAD_UART1_CTS, 0x624, 0x234, 0, 0x000, 0), /* MX51_PAD_UART1_CTS__UART1_CTS */
+ IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 1, 0x000, 0), /* MX51_PAD_UART2_RXD__FIRI_TXD */
+ IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 3, 0x000, 0), /* MX51_PAD_UART2_RXD__GPIO1_20 */
+ IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 0, 0x9ec, 2), /* MX51_PAD_UART2_RXD__UART2_RXD */
+ IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 1, 0x000, 0), /* MX51_PAD_UART2_TXD__FIRI_RXD */
+ IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 3, 0x000, 0), /* MX51_PAD_UART2_TXD__GPIO1_21 */
+ IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 0, 0x000, 0), /* MX51_PAD_UART2_TXD__UART2_TXD */
+ IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 2, 0x000, 0), /* MX51_PAD_UART3_RXD__CSI1_D0 */
+ IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 3, 0x000, 0), /* MX51_PAD_UART3_RXD__GPIO1_22 */
+ IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 0, 0x000, 0), /* MX51_PAD_UART3_RXD__UART1_DTR */
+ IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 1, 0x9f4, 4), /* MX51_PAD_UART3_RXD__UART3_RXD */
+ IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 2, 0x000, 0), /* MX51_PAD_UART3_TXD__CSI1_D1 */
+ IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 3, 0x000, 0), /* MX51_PAD_UART3_TXD__GPIO1_23 */
+ IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 0, 0x000, 0), /* MX51_PAD_UART3_TXD__UART1_DSR */
+ IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 1, 0x000, 0), /* MX51_PAD_UART3_TXD__UART3_TXD */
+ IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 3, 0x000, 0), /* MX51_PAD_OWIRE_LINE__GPIO1_24 */
+ IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 0, 0x000, 0), /* MX51_PAD_OWIRE_LINE__OWIRE_LINE */
+ IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 6, 0x000, 0), /* MX51_PAD_OWIRE_LINE__SPDIF_OUT */
+ IMX_PIN_REG(MX51_PAD_KEY_ROW0, 0x63c, 0x24c, 0, 0x000, 0), /* MX51_PAD_KEY_ROW0__KEY_ROW0 */
+ IMX_PIN_REG(MX51_PAD_KEY_ROW1, 0x640, 0x250, 0, 0x000, 0), /* MX51_PAD_KEY_ROW1__KEY_ROW1 */
+ IMX_PIN_REG(MX51_PAD_KEY_ROW2, 0x644, 0x254, 0, 0x000, 0), /* MX51_PAD_KEY_ROW2__KEY_ROW2 */
+ IMX_PIN_REG(MX51_PAD_KEY_ROW3, 0x648, 0x258, 0, 0x000, 0), /* MX51_PAD_KEY_ROW3__KEY_ROW3 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL0, 0x64c, 0x25c, 0, 0x000, 0), /* MX51_PAD_KEY_COL0__KEY_COL0 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL0, 0x64c, 0x25c, 7, 0x90c, 0), /* MX51_PAD_KEY_COL0__PLL1_BYP */
+ IMX_PIN_REG(MX51_PAD_KEY_COL1, 0x650, 0x260, 0, 0x000, 0), /* MX51_PAD_KEY_COL1__KEY_COL1 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL1, 0x650, 0x260, 7, 0x910, 0), /* MX51_PAD_KEY_COL1__PLL2_BYP */
+ IMX_PIN_REG(MX51_PAD_KEY_COL2, 0x654, 0x264, 0, 0x000, 0), /* MX51_PAD_KEY_COL2__KEY_COL2 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL2, 0x654, 0x264, 7, 0x000, 0), /* MX51_PAD_KEY_COL2__PLL3_BYP */
+ IMX_PIN_REG(MX51_PAD_KEY_COL3, 0x658, 0x268, 0, 0x000, 0), /* MX51_PAD_KEY_COL3__KEY_COL3 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 3, 0x9b8, 1), /* MX51_PAD_KEY_COL4__I2C2_SCL */
+ IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 0, 0x000, 0), /* MX51_PAD_KEY_COL4__KEY_COL4 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 6, 0x000, 0), /* MX51_PAD_KEY_COL4__SPDIF_OUT1 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 1, 0x000, 0), /* MX51_PAD_KEY_COL4__UART1_RI */
+ IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 2, 0x9f0, 4), /* MX51_PAD_KEY_COL4__UART3_RTS */
+ IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 3, 0x9bc, 1), /* MX51_PAD_KEY_COL5__I2C2_SDA */
+ IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 0, 0x000, 0), /* MX51_PAD_KEY_COL5__KEY_COL5 */
+ IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 1, 0x000, 0), /* MX51_PAD_KEY_COL5__UART1_DCD */
+ IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 2, 0x000, 0), /* MX51_PAD_KEY_COL5__UART3_CTS */
+ IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 1, 0x914, 1), /* MX51_PAD_USBH1_CLK__CSPI_SCLK */
+ IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 2, 0x000, 0), /* MX51_PAD_USBH1_CLK__GPIO1_25 */
+ IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 5, 0x9b8, 2), /* MX51_PAD_USBH1_CLK__I2C2_SCL */
+ IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 0, 0x000, 0), /* MX51_PAD_USBH1_CLK__USBH1_CLK */
+ IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 1, 0x91c, 1), /* MX51_PAD_USBH1_DIR__CSPI_MOSI */
+ IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 2, 0x000, 0), /* MX51_PAD_USBH1_DIR__GPIO1_26 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 5, 0x9bc, 2), /* MX51_PAD_USBH1_DIR__I2C2_SDA */
+ IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 0, 0x000, 0), /* MX51_PAD_USBH1_DIR__USBH1_DIR */
+ IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 1, 0x000, 0), /* MX51_PAD_USBH1_STP__CSPI_RDY */
+ IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 2, 0x000, 0), /* MX51_PAD_USBH1_STP__GPIO1_27 */
+ IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 5, 0x9f4, 6), /* MX51_PAD_USBH1_STP__UART3_RXD */
+ IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 0, 0x000, 0), /* MX51_PAD_USBH1_STP__USBH1_STP */
+ IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 1, 0x918, 0), /* MX51_PAD_USBH1_NXT__CSPI_MISO */
+ IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 2, 0x000, 0), /* MX51_PAD_USBH1_NXT__GPIO1_28 */
+ IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 5, 0x000, 0), /* MX51_PAD_USBH1_NXT__UART3_TXD */
+ IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 0, 0x000, 0), /* MX51_PAD_USBH1_NXT__USBH1_NXT */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA0__GPIO1_11 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA0__UART2_CTS */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA0__USBH1_DATA0 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA1__GPIO1_12 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 1, 0x9ec, 4), /* MX51_PAD_USBH1_DATA1__UART2_RXD */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA1__USBH1_DATA1 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA2__GPIO1_13 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA2__UART2_TXD */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA2__USBH1_DATA2 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA3__GPIO1_14 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 1, 0x9e8, 5), /* MX51_PAD_USBH1_DATA3__UART2_RTS */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA3__USBH1_DATA3 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA4__CSPI_SS0 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA4__GPIO1_15 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA4__USBH1_DATA4 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 1, 0x920, 0), /* MX51_PAD_USBH1_DATA5__CSPI_SS1 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA5__GPIO1_16 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA5__USBH1_DATA5 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 1, 0x928, 1), /* MX51_PAD_USBH1_DATA6__CSPI_SS3 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA6__GPIO1_17 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA6__USBH1_DATA6 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA7__ECSPI1_SS3 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 5, 0x934, 1), /* MX51_PAD_USBH1_DATA7__ECSPI2_SS3 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA7__GPIO1_18 */
+ IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA7__USBH1_DATA7 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 0, 0x000, 0), /* MX51_PAD_DI1_PIN11__DI1_PIN11 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 7, 0x000, 0), /* MX51_PAD_DI1_PIN11__ECSPI1_SS2 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 4, 0x000, 0), /* MX51_PAD_DI1_PIN11__GPIO3_0 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN12, 0x6ac, 0x2ac, 0, 0x000, 0), /* MX51_PAD_DI1_PIN12__DI1_PIN12 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN12, 0x6ac, 0x2ac, 4, 0x978, 1), /* MX51_PAD_DI1_PIN12__GPIO3_1 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN13, 0x6b0, 0x2b0, 0, 0x000, 0), /* MX51_PAD_DI1_PIN13__DI1_PIN13 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN13, 0x6b0, 0x2b0, 4, 0x97c, 1), /* MX51_PAD_DI1_PIN13__GPIO3_2 */
+ IMX_PIN_REG(MX51_PAD_DI1_D0_CS, 0x6b4, 0x2b4, 0, 0x000, 0), /* MX51_PAD_DI1_D0_CS__DI1_D0_CS */
+ IMX_PIN_REG(MX51_PAD_DI1_D0_CS, 0x6b4, 0x2b4, 4, 0x980, 1), /* MX51_PAD_DI1_D0_CS__GPIO3_3 */
+ IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 0, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DI1_D1_CS */
+ IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 2, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DISP1_PIN14 */
+ IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 3, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DISP1_PIN5 */
+ IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 4, 0x984, 1), /* MX51_PAD_DI1_D1_CS__GPIO3_4 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 2, 0x9a4, 1), /* MX51_PAD_DISPB2_SER_DIN__DISP1_PIN1 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 0, 0x9c4, 0), /* MX51_PAD_DISPB2_SER_DIN__DISPB2_SER_DIN */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 4, 0x988, 1), /* MX51_PAD_DISPB2_SER_DIN__GPIO3_5 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_DIO__DISP1_PIN6 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 0, 0x9c4, 1), /* MX51_PAD_DISPB2_SER_DIO__DISPB2_SER_DIO */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 4, 0x98c, 1), /* MX51_PAD_DISPB2_SER_DIO__GPIO3_6 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISP1_PIN17 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISP1_PIN7 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISPB2_SER_CLK */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 4, 0x990, 1), /* MX51_PAD_DISPB2_SER_CLK__GPIO3_7 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_EXT_CLK */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_PIN16 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_PIN8 */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS */
+ IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 4, 0x994, 1), /* MX51_PAD_DISPB2_SER_RS__GPIO3_8 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT0, 0x6cc, 0x2cc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT0__DISP1_DAT0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT1, 0x6d0, 0x2d0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT1__DISP1_DAT1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT2, 0x6d4, 0x2d4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT2__DISP1_DAT2 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT3, 0x6d8, 0x2d8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT3__DISP1_DAT3 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT4, 0x6dc, 0x2dc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT4__DISP1_DAT4 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT5, 0x6e0, 0x2e0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT5__DISP1_DAT5 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT6, 0x6e4, 0x2e4, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT6__BOOT_USB_SRC */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT6, 0x6e4, 0x2e4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT6__DISP1_DAT6 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT7, 0x6e8, 0x2e8, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT7__BOOT_EEPROM_CFG */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT7, 0x6e8, 0x2e8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT7__DISP1_DAT7 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT8, 0x6ec, 0x2ec, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT8__BOOT_SRC0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT8, 0x6ec, 0x2ec, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT8__DISP1_DAT8 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT9, 0x6f0, 0x2f0, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT9__BOOT_SRC1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT9, 0x6f0, 0x2f0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT9__DISP1_DAT9 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT10, 0x6f4, 0x2f4, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT10__BOOT_SPARE_SIZE */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT10, 0x6f4, 0x2f4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT10__DISP1_DAT10 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT11, 0x6f8, 0x2f8, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT11__BOOT_LPB_FREQ2 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT11, 0x6f8, 0x2f8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT11__DISP1_DAT11 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT12, 0x6fc, 0x2fc, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT12__BOOT_MLC_SEL */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT12, 0x6fc, 0x2fc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT12__DISP1_DAT12 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT13, 0x700, 0x300, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT13__BOOT_MEM_CTL0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT13, 0x700, 0x300, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT13__DISP1_DAT13 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT14, 0x704, 0x304, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT14__BOOT_MEM_CTL1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT14, 0x704, 0x304, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT14__DISP1_DAT14 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT15, 0x708, 0x308, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT15__BOOT_BUS_WIDTH */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT15, 0x708, 0x308, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT15__DISP1_DAT15 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT16, 0x70c, 0x30c, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT16__BOOT_PAGE_SIZE0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT16, 0x70c, 0x30c, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT16__DISP1_DAT16 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT17, 0x710, 0x310, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT17__BOOT_PAGE_SIZE1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT17, 0x710, 0x310, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT17__DISP1_DAT17 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT18__BOOT_WEIM_MUXED0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP1_DAT18 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP2_PIN11 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP2_PIN5 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT19__BOOT_WEIM_MUXED1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP1_DAT19 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP2_PIN12 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP2_PIN6 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT20__BOOT_MEM_TYPE0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP1_DAT20 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP2_PIN13 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP2_PIN7 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT21__BOOT_MEM_TYPE1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP1_DAT21 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP2_PIN14 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP2_PIN8 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT22__BOOT_LPB_FREQ0 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP1_DAT22 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 6, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP2_D0_CS */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP2_DAT16 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT23__BOOT_LPB_FREQ1 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP1_DAT23 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 6, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_D1_CS */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_DAT17 */
+ IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_SER_CS */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN3, 0x72c, 0x32c, 0, 0x000, 0), /* MX51_PAD_DI1_PIN3__DI1_PIN3 */
+ IMX_PIN_REG(MX51_PAD_DI1_PIN2, 0x734, 0x330, 0, 0x000, 0), /* MX51_PAD_DI1_PIN2__DI1_PIN2 */
+ IMX_PIN_REG(MX51_PAD_DI_GP2, 0x740, 0x338, 0, 0x000, 0), /* MX51_PAD_DI_GP2__DISP1_SER_CLK */
+ IMX_PIN_REG(MX51_PAD_DI_GP2, 0x740, 0x338, 2, 0x9a8, 1), /* MX51_PAD_DI_GP2__DISP2_WAIT */
+ IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 3, 0x9a0, 1), /* MX51_PAD_DI_GP3__CSI1_DATA_EN */
+ IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 0, 0x9c0, 0), /* MX51_PAD_DI_GP3__DISP1_SER_DIO */
+ IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 2, 0x000, 0), /* MX51_PAD_DI_GP3__FEC_TX_ER */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 3, 0x99c, 1), /* MX51_PAD_DI2_PIN4__CSI2_DATA_EN */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 0, 0x000, 0), /* MX51_PAD_DI2_PIN4__DI2_PIN4 */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 2, 0x950, 1), /* MX51_PAD_DI2_PIN4__FEC_CRS */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN2, 0x74c, 0x344, 0, 0x000, 0), /* MX51_PAD_DI2_PIN2__DI2_PIN2 */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN2, 0x74c, 0x344, 2, 0x000, 0), /* MX51_PAD_DI2_PIN2__FEC_MDC */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN3, 0x750, 0x348, 0, 0x000, 0), /* MX51_PAD_DI2_PIN3__DI2_PIN3 */
+ IMX_PIN_REG(MX51_PAD_DI2_PIN3, 0x750, 0x348, 2, 0x954, 1), /* MX51_PAD_DI2_PIN3__FEC_MDIO */
+ IMX_PIN_REG(MX51_PAD_DI2_DISP_CLK, 0x754, 0x34c, 0, 0x000, 0), /* MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK */
+ IMX_PIN_REG(MX51_PAD_DI2_DISP_CLK, 0x754, 0x34c, 2, 0x95c, 1), /* MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 */
+ IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 4, 0x000, 0), /* MX51_PAD_DI_GP4__DI2_PIN15 */
+ IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 0, 0x9c0, 1), /* MX51_PAD_DI_GP4__DISP1_SER_DIN */
+ IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 3, 0x000, 0), /* MX51_PAD_DI_GP4__DISP2_PIN1 */
+ IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 2, 0x960, 1), /* MX51_PAD_DI_GP4__FEC_RDATA2 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT0__DISP2_DAT0 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 2, 0x964, 1), /* MX51_PAD_DISP2_DAT0__FEC_RDATA3 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 4, 0x9c8, 1), /* MX51_PAD_DISP2_DAT0__KEY_COL6 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 5, 0x9f4, 8), /* MX51_PAD_DISP2_DAT0__UART3_RXD */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 3, 0x9f8, 1), /* MX51_PAD_DISP2_DAT0__USBH3_CLK */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT1__DISP2_DAT1 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 2, 0x970, 1), /* MX51_PAD_DISP2_DAT1__FEC_RX_ER */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 4, 0x9cc, 1), /* MX51_PAD_DISP2_DAT1__KEY_COL7 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT1__UART3_TXD */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 3, 0xa1c, 1), /* MX51_PAD_DISP2_DAT1__USBH3_DIR */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT2, 0x764, 0x35c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT2__DISP2_DAT2 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT3, 0x768, 0x360, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT3__DISP2_DAT3 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT4, 0x76c, 0x364, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT4__DISP2_DAT4 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT5, 0x770, 0x368, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT5__DISP2_DAT5 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT6__DISP2_DAT6 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT6__FEC_TDATA1 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT6__GPIO1_19 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 4, 0x9d0, 1), /* MX51_PAD_DISP2_DAT6__KEY_ROW4 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 3, 0xa24, 1), /* MX51_PAD_DISP2_DAT6__USBH3_STP */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT7__DISP2_DAT7 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT7__FEC_TDATA2 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT7__GPIO1_29 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 4, 0x9d4, 1), /* MX51_PAD_DISP2_DAT7__KEY_ROW5 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 3, 0xa20, 1), /* MX51_PAD_DISP2_DAT7__USBH3_NXT */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT8__DISP2_DAT8 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT8__FEC_TDATA3 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT8__GPIO1_30 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 4, 0x9d8, 1), /* MX51_PAD_DISP2_DAT8__KEY_ROW6 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 3, 0x9fc, 1), /* MX51_PAD_DISP2_DAT8__USBH3_DATA0 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 4, 0x8f4, 1), /* MX51_PAD_DISP2_DAT9__AUD6_RXC */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT9__DISP2_DAT9 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT9__FEC_TX_EN */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT9__GPIO1_31 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 3, 0xa00, 1), /* MX51_PAD_DISP2_DAT9__USBH3_DATA1 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT10__DISP2_DAT10 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT10__DISP2_SER_CS */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 2, 0x94c, 1), /* MX51_PAD_DISP2_DAT10__FEC_COL */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 4, 0x9dc, 1), /* MX51_PAD_DISP2_DAT10__KEY_ROW7 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 3, 0xa04, 1), /* MX51_PAD_DISP2_DAT10__USBH3_DATA2 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 4, 0x8f0, 1), /* MX51_PAD_DISP2_DAT11__AUD6_TXD */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT11__DISP2_DAT11 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 2, 0x968, 1), /* MX51_PAD_DISP2_DAT11__FEC_RX_CLK */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 7, 0x000, 0), /* MX51_PAD_DISP2_DAT11__GPIO1_10 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 3, 0xa08, 1), /* MX51_PAD_DISP2_DAT11__USBH3_DATA3 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 4, 0x8ec, 1), /* MX51_PAD_DISP2_DAT12__AUD6_RXD */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT12__DISP2_DAT12 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 2, 0x96c, 1), /* MX51_PAD_DISP2_DAT12__FEC_RX_DV */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 3, 0xa0c, 1), /* MX51_PAD_DISP2_DAT12__USBH3_DATA4 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 4, 0x8fc, 1), /* MX51_PAD_DISP2_DAT13__AUD6_TXC */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT13__DISP2_DAT13 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 2, 0x974, 1), /* MX51_PAD_DISP2_DAT13__FEC_TX_CLK */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 3, 0xa10, 1), /* MX51_PAD_DISP2_DAT13__USBH3_DATA5 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 4, 0x900, 1), /* MX51_PAD_DISP2_DAT14__AUD6_TXFS */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT14__DISP2_DAT14 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 2, 0x958, 1), /* MX51_PAD_DISP2_DAT14__FEC_RDATA0 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 3, 0xa14, 1), /* MX51_PAD_DISP2_DAT14__USBH3_DATA6 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 4, 0x8f8, 1), /* MX51_PAD_DISP2_DAT15__AUD6_RXFS */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT15__DISP1_SER_CS */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT15__DISP2_DAT15 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT15__FEC_TDATA0 */
+ IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 3, 0xa18, 1), /* MX51_PAD_DISP2_DAT15__USBH3_DATA7 */
+ IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 1, 0x8e0, 1), /* MX51_PAD_SD1_CMD__AUD5_RXFS */
+ IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 2, 0x91c, 2), /* MX51_PAD_SD1_CMD__CSPI_MOSI */
+ IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 0, 0x000, 0), /* MX51_PAD_SD1_CMD__SD1_CMD */
+ IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 1, 0x8dc, 1), /* MX51_PAD_SD1_CLK__AUD5_RXC */
+ IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 2, 0x914, 2), /* MX51_PAD_SD1_CLK__CSPI_SCLK */
+ IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 0, 0x000, 0), /* MX51_PAD_SD1_CLK__SD1_CLK */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 1, 0x8d8, 2), /* MX51_PAD_SD1_DATA0__AUD5_TXD */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 2, 0x918, 1), /* MX51_PAD_SD1_DATA0__CSPI_MISO */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 0, 0x000, 0), /* MX51_PAD_SD1_DATA0__SD1_DATA0 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA0, NO_PAD, 0x01c, 0, 0x000, 0), /* MX51_PAD_EIM_DA0__EIM_DA0 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA1, NO_PAD, 0x020, 0, 0x000, 0), /* MX51_PAD_EIM_DA1__EIM_DA1 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA2, NO_PAD, 0x024, 0, 0x000, 0), /* MX51_PAD_EIM_DA2__EIM_DA2 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA3, NO_PAD, 0x028, 0, 0x000, 0), /* MX51_PAD_EIM_DA3__EIM_DA3 */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA1, 0x7a8, 0x3a0, 1, 0x8d4, 2), /* MX51_PAD_SD1_DATA1__AUD5_RXD */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA1, 0x7a8, 0x3a0, 0, 0x000, 0), /* MX51_PAD_SD1_DATA1__SD1_DATA1 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA4, NO_PAD, 0x02c, 0, 0x000, 0), /* MX51_PAD_EIM_DA4__EIM_DA4 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA5, NO_PAD, 0x030, 0, 0x000, 0), /* MX51_PAD_EIM_DA5__EIM_DA5 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA6, NO_PAD, 0x034, 0, 0x000, 0), /* MX51_PAD_EIM_DA6__EIM_DA6 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA7, NO_PAD, 0x038, 0, 0x000, 0), /* MX51_PAD_EIM_DA7__EIM_DA7 */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA2, 0x7ac, 0x3a4, 1, 0x8e4, 2), /* MX51_PAD_SD1_DATA2__AUD5_TXC */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA2, 0x7ac, 0x3a4, 0, 0x000, 0), /* MX51_PAD_SD1_DATA2__SD1_DATA2 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA10, NO_PAD, 0x044, 0, 0x000, 0), /* MX51_PAD_EIM_DA10__EIM_DA10 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA11, NO_PAD, 0x048, 0, 0x000, 0), /* MX51_PAD_EIM_DA11__EIM_DA11 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA8, NO_PAD, 0x03c, 0, 0x000, 0), /* MX51_PAD_EIM_DA8__EIM_DA8 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA9, NO_PAD, 0x040, 0, 0x000, 0), /* MX51_PAD_EIM_DA9__EIM_DA9 */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 1, 0x8e8, 2), /* MX51_PAD_SD1_DATA3__AUD5_TXFS */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 2, 0x920, 1), /* MX51_PAD_SD1_DATA3__CSPI_SS1 */
+ IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 0, 0x000, 0), /* MX51_PAD_SD1_DATA3__SD1_DATA3 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 2, 0x924, 0), /* MX51_PAD_GPIO1_0__CSPI_SS2 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 1, 0x000, 0), /* MX51_PAD_GPIO1_0__GPIO1_0 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 0, 0x000, 0), /* MX51_PAD_GPIO1_0__SD1_CD */
+ IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 2, 0x918, 2), /* MX51_PAD_GPIO1_1__CSPI_MISO */
+ IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 1, 0x000, 0), /* MX51_PAD_GPIO1_1__GPIO1_1 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 0, 0x000, 0), /* MX51_PAD_GPIO1_1__SD1_WP */
+ IMX_PIN_REG(MX51_PAD_EIM_DA12, NO_PAD, 0x04c, 0, 0x000, 0), /* MX51_PAD_EIM_DA12__EIM_DA12 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA13, NO_PAD, 0x050, 0, 0x000, 0), /* MX51_PAD_EIM_DA13__EIM_DA13 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA14, NO_PAD, 0x054, 0, 0x000, 0), /* MX51_PAD_EIM_DA14__EIM_DA14 */
+ IMX_PIN_REG(MX51_PAD_EIM_DA15, NO_PAD, 0x058, 0, 0x000, 0), /* MX51_PAD_EIM_DA15__EIM_DA15 */
+ IMX_PIN_REG(MX51_PAD_SD2_CMD, NO_PAD, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */
+ IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 1, 0x9b0, 2), /* MX51_PAD_SD2_CMD__I2C1_SCL */
+ IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 0, 0x000, 0), /* MX51_PAD_SD2_CMD__SD2_CMD */
+ IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 2, 0x914, 3), /* MX51_PAD_SD2_CLK__CSPI_SCLK */
+ IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 1, 0x9b4, 2), /* MX51_PAD_SD2_CLK__I2C1_SDA */
+ IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 0, 0x000, 0), /* MX51_PAD_SD2_CLK__SD2_CLK */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 2, 0x918, 3), /* MX51_PAD_SD2_DATA0__CSPI_MISO */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 1, 0x000, 0), /* MX51_PAD_SD2_DATA0__SD1_DAT4 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 0, 0x000, 0), /* MX51_PAD_SD2_DATA0__SD2_DATA0 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 1, 0x000, 0), /* MX51_PAD_SD2_DATA1__SD1_DAT5 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 0, 0x000, 0), /* MX51_PAD_SD2_DATA1__SD2_DATA1 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 2, 0x000, 0), /* MX51_PAD_SD2_DATA1__USBH3_H2_DP */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 1, 0x000, 0), /* MX51_PAD_SD2_DATA2__SD1_DAT6 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 0, 0x000, 0), /* MX51_PAD_SD2_DATA2__SD2_DATA2 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 2, 0x000, 0), /* MX51_PAD_SD2_DATA2__USBH3_H2_DM */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 2, 0x924, 1), /* MX51_PAD_SD2_DATA3__CSPI_SS2 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 1, 0x000, 0), /* MX51_PAD_SD2_DATA3__SD1_DAT7 */
+ IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 0, 0x000, 0), /* MX51_PAD_SD2_DATA3__SD2_DATA3 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 5, 0x000, 0), /* MX51_PAD_GPIO1_2__CCM_OUT_2 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 0, 0x000, 0), /* MX51_PAD_GPIO1_2__GPIO1_2 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 2, 0x9b8, 3), /* MX51_PAD_GPIO1_2__I2C2_SCL */
+ IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 7, 0x90c, 1), /* MX51_PAD_GPIO1_2__PLL1_BYP */
+ IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 1, 0x000, 0), /* MX51_PAD_GPIO1_2__PWM1_PWMO */
+ IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 0, 0x000, 0), /* MX51_PAD_GPIO1_3__GPIO1_3 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 2, 0x9bc, 3), /* MX51_PAD_GPIO1_3__I2C2_SDA */
+ IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 7, 0x910, 1), /* MX51_PAD_GPIO1_3__PLL2_BYP */
+ IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 1, 0x000, 0), /* MX51_PAD_GPIO1_3__PWM2_PWMO */
+ IMX_PIN_REG(MX51_PAD_PMIC_INT_REQ, 0x7fc, 0x3d4, 0, 0x000, 0), /* MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ */
+ IMX_PIN_REG(MX51_PAD_PMIC_INT_REQ, 0x7fc, 0x3d4, 1, 0x000, 0), /* MX51_PAD_PMIC_INT_REQ__PMIC_PMU_IRQ_B */
+ IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 4, 0x908, 1), /* MX51_PAD_GPIO1_4__DISP2_EXT_CLK */
+ IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 3, 0x938, 1), /* MX51_PAD_GPIO1_4__EIM_RDY */
+ IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 0, 0x000, 0), /* MX51_PAD_GPIO1_4__GPIO1_4 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 2, 0x000, 0), /* MX51_PAD_GPIO1_4__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 6, 0x000, 0), /* MX51_PAD_GPIO1_5__CSI2_MCLK */
+ IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 3, 0x000, 0), /* MX51_PAD_GPIO1_5__DISP2_PIN16 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 0, 0x000, 0), /* MX51_PAD_GPIO1_5__GPIO1_5 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 2, 0x000, 0), /* MX51_PAD_GPIO1_5__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 4, 0x000, 0), /* MX51_PAD_GPIO1_6__DISP2_PIN17 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 0, 0x000, 0), /* MX51_PAD_GPIO1_6__GPIO1_6 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 3, 0x000, 0), /* MX51_PAD_GPIO1_6__REF_EN_B */
+ IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 3, 0x000, 0), /* MX51_PAD_GPIO1_7__CCM_OUT_0 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 0, 0x000, 0), /* MX51_PAD_GPIO1_7__GPIO1_7 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 6, 0x000, 0), /* MX51_PAD_GPIO1_7__SD2_WP */
+ IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 2, 0x000, 0), /* MX51_PAD_GPIO1_7__SPDIF_OUT1 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 2, 0x99c, 2), /* MX51_PAD_GPIO1_8__CSI2_DATA_EN */
+ IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 0, 0x000, 0), /* MX51_PAD_GPIO1_8__GPIO1_8 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 6, 0x000, 0), /* MX51_PAD_GPIO1_8__SD2_CD */
+ IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 1, 0x000, 0), /* MX51_PAD_GPIO1_8__USBH3_PWR */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 3, 0x000, 0), /* MX51_PAD_GPIO1_9__CCM_OUT_1 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 2, 0x000, 0), /* MX51_PAD_GPIO1_9__DISP2_D1_CS */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 7, 0x000, 0), /* MX51_PAD_GPIO1_9__DISP2_SER_CS */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 0, 0x000, 0), /* MX51_PAD_GPIO1_9__GPIO1_9 */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 6, 0x000, 0), /* MX51_PAD_GPIO1_9__SD2_LCTL */
+ IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 1, 0x000, 0), /* MX51_PAD_GPIO1_9__USBH3_OC */
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx51_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D16),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D17),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D18),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D19),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D20),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D21),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D22),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D23),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D24),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D25),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D26),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D27),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D28),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D29),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D30),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_D31),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A16),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A17),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A18),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A19),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A20),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A21),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A22),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A23),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A24),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A25),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A26),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_A27),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_EB0),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_EB1),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_EB2),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_EB3),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_OE),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS0),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS1),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS2),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS3),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS4),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CS5),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DTACK),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_LBA),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_CRE),
+ IMX_PINCTRL_PIN(MX51_PAD_DRAM_CS1),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_WE_B),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RE_B),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB1),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB2),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB3),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO_NAND),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS4),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS5),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS6),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS7),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_RDY_INT),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D15),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D14),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D13),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D12),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D11),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D10),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D9),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D8),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D7),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D6),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D5),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D4),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D3),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D2),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D1),
+ IMX_PINCTRL_PIN(MX51_PAD_NANDF_D0),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D8),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D9),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D10),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D11),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D12),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D13),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D14),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D15),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D16),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D17),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D18),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_D19),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_VSYNC),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_HSYNC),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_PIXCLK),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI1_MCLK),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D12),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D13),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D14),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D15),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D16),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D17),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D18),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_D19),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_VSYNC),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_HSYNC),
+ IMX_PINCTRL_PIN(MX51_PAD_CSI2_PIXCLK),
+ IMX_PINCTRL_PIN(MX51_PAD_I2C1_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_I2C1_DAT),
+ IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_TXD),
+ IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_RXD),
+ IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_CK),
+ IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_FS),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_MISO),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SS0),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SS1),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_RDY),
+ IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX51_PAD_UART1_RXD),
+ IMX_PINCTRL_PIN(MX51_PAD_UART1_TXD),
+ IMX_PINCTRL_PIN(MX51_PAD_UART1_RTS),
+ IMX_PINCTRL_PIN(MX51_PAD_UART1_CTS),
+ IMX_PINCTRL_PIN(MX51_PAD_UART2_RXD),
+ IMX_PINCTRL_PIN(MX51_PAD_UART2_TXD),
+ IMX_PINCTRL_PIN(MX51_PAD_UART3_RXD),
+ IMX_PINCTRL_PIN(MX51_PAD_UART3_TXD),
+ IMX_PINCTRL_PIN(MX51_PAD_OWIRE_LINE),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL0),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL1),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL2),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL3),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL4),
+ IMX_PINCTRL_PIN(MX51_PAD_KEY_COL5),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DIR),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_STP),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_NXT),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA0),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA1),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA2),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA3),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA4),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA5),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA6),
+ IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA7),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN11),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN12),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN13),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_D0_CS),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_D1_CS),
+ IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_DIN),
+ IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_DIO),
+ IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_RS),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT0),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT1),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT2),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT3),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT4),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT5),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT6),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT7),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT8),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT9),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT10),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT11),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT12),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT13),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT14),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT15),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT16),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT17),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT18),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT19),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT20),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT21),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT22),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT23),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN3),
+ IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN2),
+ IMX_PINCTRL_PIN(MX51_PAD_DI_GP2),
+ IMX_PINCTRL_PIN(MX51_PAD_DI_GP3),
+ IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN4),
+ IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN2),
+ IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN3),
+ IMX_PINCTRL_PIN(MX51_PAD_DI2_DISP_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_DI_GP4),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT0),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT1),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT2),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT3),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT4),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT5),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT6),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT7),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT8),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT9),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT10),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT11),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT12),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT13),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT14),
+ IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT15),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_CMD),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA0),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA1),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA2),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA3),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA4),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA5),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA6),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA7),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA10),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA11),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA8),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA9),
+ IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_0),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_1),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA12),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA13),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA14),
+ IMX_PINCTRL_PIN(MX51_PAD_EIM_DA15),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_CMD),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_CLK),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_2),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_3),
+ IMX_PINCTRL_PIN(MX51_PAD_PMIC_INT_REQ),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_4),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_5),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_6),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_7),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_8),
+ IMX_PINCTRL_PIN(MX51_PAD_GPIO1_9),
+};
+
+static struct imx_pinctrl_soc_info imx51_pinctrl_info = {
+ .pins = imx51_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx51_pinctrl_pads),
+ .pin_regs = imx51_pin_regs,
+ .npin_regs = ARRAY_SIZE(imx51_pin_regs),
+};
+
+static struct of_device_id imx51_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "fsl,imx51-iomuxc", },
+ { /* sentinel */ }
+};
+
+static int __devinit imx51_pinctrl_probe(struct platform_device *pdev)
+{
+ return imx_pinctrl_probe(pdev, &imx51_pinctrl_info);
+}
+
+static struct platform_driver imx51_pinctrl_driver = {
+ .driver = {
+ .name = "imx51-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx51_pinctrl_of_match),
+ },
+ .probe = imx51_pinctrl_probe,
+ .remove = __devexit_p(imx_pinctrl_remove),
+};
+
+static int __init imx51_pinctrl_init(void)
+{
+ return platform_driver_register(&imx51_pinctrl_driver);
+}
+arch_initcall(imx51_pinctrl_init);
+
+static void __exit imx51_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx51_pinctrl_driver);
+}
+module_exit(imx51_pinctrl_exit);
+MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
+MODULE_DESCRIPTION("Freescale IMX51 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/pinctrl-imx53.c
new file mode 100644
index 0000000..1f49e16
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx53.c
@@ -0,0 +1,1649 @@
+/*
+ * imx53 pinctrl driver based on imx pinmux core
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx53_pads {
+ MX53_PAD_GPIO_19 = 1,
+ MX53_PAD_KEY_COL0 = 2,
+ MX53_PAD_KEY_ROW0 = 3,
+ MX53_PAD_KEY_COL1 = 4,
+ MX53_PAD_KEY_ROW1 = 5,
+ MX53_PAD_KEY_COL2 = 6,
+ MX53_PAD_KEY_ROW2 = 7,
+ MX53_PAD_KEY_COL3 = 8,
+ MX53_PAD_KEY_ROW3 = 9,
+ MX53_PAD_KEY_COL4 = 10,
+ MX53_PAD_KEY_ROW4 = 11,
+ MX53_PAD_DI0_DISP_CLK = 12,
+ MX53_PAD_DI0_PIN15 = 13,
+ MX53_PAD_DI0_PIN2 = 14,
+ MX53_PAD_DI0_PIN3 = 15,
+ MX53_PAD_DI0_PIN4 = 16,
+ MX53_PAD_DISP0_DAT0 = 17,
+ MX53_PAD_DISP0_DAT1 = 18,
+ MX53_PAD_DISP0_DAT2 = 19,
+ MX53_PAD_DISP0_DAT3 = 20,
+ MX53_PAD_DISP0_DAT4 = 21,
+ MX53_PAD_DISP0_DAT5 = 22,
+ MX53_PAD_DISP0_DAT6 = 23,
+ MX53_PAD_DISP0_DAT7 = 24,
+ MX53_PAD_DISP0_DAT8 = 25,
+ MX53_PAD_DISP0_DAT9 = 26,
+ MX53_PAD_DISP0_DAT10 = 27,
+ MX53_PAD_DISP0_DAT11 = 28,
+ MX53_PAD_DISP0_DAT12 = 29,
+ MX53_PAD_DISP0_DAT13 = 30,
+ MX53_PAD_DISP0_DAT14 = 31,
+ MX53_PAD_DISP0_DAT15 = 32,
+ MX53_PAD_DISP0_DAT16 = 33,
+ MX53_PAD_DISP0_DAT17 = 34,
+ MX53_PAD_DISP0_DAT18 = 35,
+ MX53_PAD_DISP0_DAT19 = 36,
+ MX53_PAD_DISP0_DAT20 = 37,
+ MX53_PAD_DISP0_DAT21 = 38,
+ MX53_PAD_DISP0_DAT22 = 39,
+ MX53_PAD_DISP0_DAT23 = 40,
+ MX53_PAD_CSI0_PIXCLK = 41,
+ MX53_PAD_CSI0_MCLK = 42,
+ MX53_PAD_CSI0_DATA_EN = 43,
+ MX53_PAD_CSI0_VSYNC = 44,
+ MX53_PAD_CSI0_DAT4 = 45,
+ MX53_PAD_CSI0_DAT5 = 46,
+ MX53_PAD_CSI0_DAT6 = 47,
+ MX53_PAD_CSI0_DAT7 = 48,
+ MX53_PAD_CSI0_DAT8 = 49,
+ MX53_PAD_CSI0_DAT9 = 50,
+ MX53_PAD_CSI0_DAT10 = 51,
+ MX53_PAD_CSI0_DAT11 = 52,
+ MX53_PAD_CSI0_DAT12 = 53,
+ MX53_PAD_CSI0_DAT13 = 54,
+ MX53_PAD_CSI0_DAT14 = 55,
+ MX53_PAD_CSI0_DAT15 = 56,
+ MX53_PAD_CSI0_DAT16 = 57,
+ MX53_PAD_CSI0_DAT17 = 58,
+ MX53_PAD_CSI0_DAT18 = 59,
+ MX53_PAD_CSI0_DAT19 = 60,
+ MX53_PAD_EIM_A25 = 61,
+ MX53_PAD_EIM_EB2 = 62,
+ MX53_PAD_EIM_D16 = 63,
+ MX53_PAD_EIM_D17 = 64,
+ MX53_PAD_EIM_D18 = 65,
+ MX53_PAD_EIM_D19 = 66,
+ MX53_PAD_EIM_D20 = 67,
+ MX53_PAD_EIM_D21 = 68,
+ MX53_PAD_EIM_D22 = 69,
+ MX53_PAD_EIM_D23 = 70,
+ MX53_PAD_EIM_EB3 = 71,
+ MX53_PAD_EIM_D24 = 72,
+ MX53_PAD_EIM_D25 = 73,
+ MX53_PAD_EIM_D26 = 74,
+ MX53_PAD_EIM_D27 = 75,
+ MX53_PAD_EIM_D28 = 76,
+ MX53_PAD_EIM_D29 = 77,
+ MX53_PAD_EIM_D30 = 78,
+ MX53_PAD_EIM_D31 = 79,
+ MX53_PAD_EIM_A24 = 80,
+ MX53_PAD_EIM_A23 = 81,
+ MX53_PAD_EIM_A22 = 82,
+ MX53_PAD_EIM_A21 = 83,
+ MX53_PAD_EIM_A20 = 84,
+ MX53_PAD_EIM_A19 = 85,
+ MX53_PAD_EIM_A18 = 86,
+ MX53_PAD_EIM_A17 = 87,
+ MX53_PAD_EIM_A16 = 88,
+ MX53_PAD_EIM_CS0 = 89,
+ MX53_PAD_EIM_CS1 = 90,
+ MX53_PAD_EIM_OE = 91,
+ MX53_PAD_EIM_RW = 92,
+ MX53_PAD_EIM_LBA = 93,
+ MX53_PAD_EIM_EB0 = 94,
+ MX53_PAD_EIM_EB1 = 95,
+ MX53_PAD_EIM_DA0 = 96,
+ MX53_PAD_EIM_DA1 = 97,
+ MX53_PAD_EIM_DA2 = 98,
+ MX53_PAD_EIM_DA3 = 99,
+ MX53_PAD_EIM_DA4 = 100,
+ MX53_PAD_EIM_DA5 = 101,
+ MX53_PAD_EIM_DA6 = 102,
+ MX53_PAD_EIM_DA7 = 103,
+ MX53_PAD_EIM_DA8 = 104,
+ MX53_PAD_EIM_DA9 = 105,
+ MX53_PAD_EIM_DA10 = 106,
+ MX53_PAD_EIM_DA11 = 107,
+ MX53_PAD_EIM_DA12 = 108,
+ MX53_PAD_EIM_DA13 = 109,
+ MX53_PAD_EIM_DA14 = 110,
+ MX53_PAD_EIM_DA15 = 111,
+ MX53_PAD_NANDF_WE_B = 112,
+ MX53_PAD_NANDF_RE_B = 113,
+ MX53_PAD_EIM_WAIT = 114,
+ MX53_PAD_LVDS1_TX3_P = 115,
+ MX53_PAD_LVDS1_TX2_P = 116,
+ MX53_PAD_LVDS1_CLK_P = 117,
+ MX53_PAD_LVDS1_TX1_P = 118,
+ MX53_PAD_LVDS1_TX0_P = 119,
+ MX53_PAD_LVDS0_TX3_P = 120,
+ MX53_PAD_LVDS0_CLK_P = 121,
+ MX53_PAD_LVDS0_TX2_P = 122,
+ MX53_PAD_LVDS0_TX1_P = 123,
+ MX53_PAD_LVDS0_TX0_P = 124,
+ MX53_PAD_GPIO_10 = 125,
+ MX53_PAD_GPIO_11 = 126,
+ MX53_PAD_GPIO_12 = 127,
+ MX53_PAD_GPIO_13 = 128,
+ MX53_PAD_GPIO_14 = 129,
+ MX53_PAD_NANDF_CLE = 130,
+ MX53_PAD_NANDF_ALE = 131,
+ MX53_PAD_NANDF_WP_B = 132,
+ MX53_PAD_NANDF_RB0 = 133,
+ MX53_PAD_NANDF_CS0 = 134,
+ MX53_PAD_NANDF_CS1 = 135,
+ MX53_PAD_NANDF_CS2 = 136,
+ MX53_PAD_NANDF_CS3 = 137,
+ MX53_PAD_FEC_MDIO = 138,
+ MX53_PAD_FEC_REF_CLK = 139,
+ MX53_PAD_FEC_RX_ER = 140,
+ MX53_PAD_FEC_CRS_DV = 141,
+ MX53_PAD_FEC_RXD1 = 142,
+ MX53_PAD_FEC_RXD0 = 143,
+ MX53_PAD_FEC_TX_EN = 144,
+ MX53_PAD_FEC_TXD1 = 145,
+ MX53_PAD_FEC_TXD0 = 146,
+ MX53_PAD_FEC_MDC = 147,
+ MX53_PAD_PATA_DIOW = 148,
+ MX53_PAD_PATA_DMACK = 149,
+ MX53_PAD_PATA_DMARQ = 150,
+ MX53_PAD_PATA_BUFFER_EN = 151,
+ MX53_PAD_PATA_INTRQ = 152,
+ MX53_PAD_PATA_DIOR = 153,
+ MX53_PAD_PATA_RESET_B = 154,
+ MX53_PAD_PATA_IORDY = 155,
+ MX53_PAD_PATA_DA_0 = 156,
+ MX53_PAD_PATA_DA_1 = 157,
+ MX53_PAD_PATA_DA_2 = 158,
+ MX53_PAD_PATA_CS_0 = 159,
+ MX53_PAD_PATA_CS_1 = 160,
+ MX53_PAD_PATA_DATA0 = 161,
+ MX53_PAD_PATA_DATA1 = 162,
+ MX53_PAD_PATA_DATA2 = 163,
+ MX53_PAD_PATA_DATA3 = 164,
+ MX53_PAD_PATA_DATA4 = 165,
+ MX53_PAD_PATA_DATA5 = 166,
+ MX53_PAD_PATA_DATA6 = 167,
+ MX53_PAD_PATA_DATA7 = 168,
+ MX53_PAD_PATA_DATA8 = 169,
+ MX53_PAD_PATA_DATA9 = 170,
+ MX53_PAD_PATA_DATA10 = 171,
+ MX53_PAD_PATA_DATA11 = 172,
+ MX53_PAD_PATA_DATA12 = 173,
+ MX53_PAD_PATA_DATA13 = 174,
+ MX53_PAD_PATA_DATA14 = 175,
+ MX53_PAD_PATA_DATA15 = 176,
+ MX53_PAD_SD1_DATA0 = 177,
+ MX53_PAD_SD1_DATA1 = 178,
+ MX53_PAD_SD1_CMD = 179,
+ MX53_PAD_SD1_DATA2 = 180,
+ MX53_PAD_SD1_CLK = 181,
+ MX53_PAD_SD1_DATA3 = 182,
+ MX53_PAD_SD2_CLK = 183,
+ MX53_PAD_SD2_CMD = 184,
+ MX53_PAD_SD2_DATA3 = 185,
+ MX53_PAD_SD2_DATA2 = 186,
+ MX53_PAD_SD2_DATA1 = 187,
+ MX53_PAD_SD2_DATA0 = 188,
+ MX53_PAD_GPIO_0 = 189,
+ MX53_PAD_GPIO_1 = 190,
+ MX53_PAD_GPIO_9 = 191,
+ MX53_PAD_GPIO_3 = 192,
+ MX53_PAD_GPIO_6 = 193,
+ MX53_PAD_GPIO_2 = 194,
+ MX53_PAD_GPIO_4 = 195,
+ MX53_PAD_GPIO_5 = 196,
+ MX53_PAD_GPIO_7 = 197,
+ MX53_PAD_GPIO_8 = 198,
+ MX53_PAD_GPIO_16 = 199,
+ MX53_PAD_GPIO_17 = 200,
+ MX53_PAD_GPIO_18 = 201,
+};
+
+/* imx53 register maps */
+static struct imx_pin_reg imx53_pin_regs[] = {
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 0, 0x840, 0), /* MX53_PAD_GPIO_19__KPP_COL_5 */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 1, 0x000, 0), /* MX53_PAD_GPIO_19__GPIO4_5 */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 2, 0x000, 0), /* MX53_PAD_GPIO_19__CCM_CLKO */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 3, 0x000, 0), /* MX53_PAD_GPIO_19__SPDIF_OUT1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 4, 0x000, 0), /* MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 5, 0x000, 0), /* MX53_PAD_GPIO_19__ECSPI1_RDY */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 6, 0x000, 0), /* MX53_PAD_GPIO_19__FEC_TDATA_3 */
+ IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 7, 0x000, 0), /* MX53_PAD_GPIO_19__SRC_INT_BOOT */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 0, 0x000, 0), /* MX53_PAD_KEY_COL0__KPP_COL_0 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 1, 0x000, 0), /* MX53_PAD_KEY_COL0__GPIO4_6 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 2, 0x758, 0), /* MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 4, 0x000, 0), /* MX53_PAD_KEY_COL0__UART4_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 5, 0x79C, 0), /* MX53_PAD_KEY_COL0__ECSPI1_SCLK */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 6, 0x000, 0), /* MX53_PAD_KEY_COL0__FEC_RDATA_3 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 7, 0x000, 0), /* MX53_PAD_KEY_COL0__SRC_ANY_PU_RST */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 0, 0x000, 0), /* MX53_PAD_KEY_ROW0__KPP_ROW_0 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 1, 0x000, 0), /* MX53_PAD_KEY_ROW0__GPIO4_7 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 2, 0x74C, 0), /* MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 4, 0x890, 1), /* MX53_PAD_KEY_ROW0__UART4_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 5, 0x7A4, 0), /* MX53_PAD_KEY_ROW0__ECSPI1_MOSI */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 6, 0x000, 0), /* MX53_PAD_KEY_ROW0__FEC_TX_ER */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 0, 0x000, 0), /* MX53_PAD_KEY_COL1__KPP_COL_1 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 1, 0x000, 0), /* MX53_PAD_KEY_COL1__GPIO4_8 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 2, 0x75C, 0), /* MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 4, 0x000, 0), /* MX53_PAD_KEY_COL1__UART5_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 5, 0x7A0, 0), /* MX53_PAD_KEY_COL1__ECSPI1_MISO */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 6, 0x808, 0), /* MX53_PAD_KEY_COL1__FEC_RX_CLK */
+ IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 7, 0x000, 0), /* MX53_PAD_KEY_COL1__USBPHY1_TXREADY */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 0, 0x000, 0), /* MX53_PAD_KEY_ROW1__KPP_ROW_1 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 1, 0x000, 0), /* MX53_PAD_KEY_ROW1__GPIO4_9 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 2, 0x748, 0), /* MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 4, 0x898, 1), /* MX53_PAD_KEY_ROW1__UART5_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 5, 0x7A8, 0), /* MX53_PAD_KEY_ROW1__ECSPI1_SS0 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 6, 0x800, 0), /* MX53_PAD_KEY_ROW1__FEC_COL */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 7, 0x000, 0), /* MX53_PAD_KEY_ROW1__USBPHY1_RXVALID */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 0, 0x000, 0), /* MX53_PAD_KEY_COL2__KPP_COL_2 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 1, 0x000, 0), /* MX53_PAD_KEY_COL2__GPIO4_10 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 2, 0x000, 0), /* MX53_PAD_KEY_COL2__CAN1_TXCAN */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 4, 0x804, 0), /* MX53_PAD_KEY_COL2__FEC_MDIO */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 5, 0x7AC, 0), /* MX53_PAD_KEY_COL2__ECSPI1_SS1 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 6, 0x000, 0), /* MX53_PAD_KEY_COL2__FEC_RDATA_2 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 7, 0x000, 0), /* MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 0, 0x000, 0), /* MX53_PAD_KEY_ROW2__KPP_ROW_2 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 1, 0x000, 0), /* MX53_PAD_KEY_ROW2__GPIO4_11 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 2, 0x760, 0), /* MX53_PAD_KEY_ROW2__CAN1_RXCAN */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 4, 0x000, 0), /* MX53_PAD_KEY_ROW2__FEC_MDC */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 5, 0x7B0, 0), /* MX53_PAD_KEY_ROW2__ECSPI1_SS2 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 6, 0x000, 0), /* MX53_PAD_KEY_ROW2__FEC_TDATA_2 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 7, 0x000, 0), /* MX53_PAD_KEY_ROW2__USBPHY1_RXERROR */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 0, 0x000, 0), /* MX53_PAD_KEY_COL3__KPP_COL_3 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 1, 0x000, 0), /* MX53_PAD_KEY_COL3__GPIO4_12 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 2, 0x000, 0), /* MX53_PAD_KEY_COL3__USBOH3_H2_DP */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 3, 0x870, 0), /* MX53_PAD_KEY_COL3__SPDIF_IN1 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 4, 0x81C, 0), /* MX53_PAD_KEY_COL3__I2C2_SCL */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 5, 0x7B4, 0), /* MX53_PAD_KEY_COL3__ECSPI1_SS3 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 6, 0x000, 0), /* MX53_PAD_KEY_COL3__FEC_CRS */
+ IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 7, 0x000, 0), /* MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 0, 0x000, 0), /* MX53_PAD_KEY_ROW3__KPP_ROW_3 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 1, 0x000, 0), /* MX53_PAD_KEY_ROW3__GPIO4_13 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 2, 0x000, 0), /* MX53_PAD_KEY_ROW3__USBOH3_H2_DM */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 3, 0x768, 0), /* MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 4, 0x820, 0), /* MX53_PAD_KEY_ROW3__I2C2_SDA */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 5, 0x000, 0), /* MX53_PAD_KEY_ROW3__OSC32K_32K_OUT */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 6, 0x77C, 0), /* MX53_PAD_KEY_ROW3__CCM_PLL4_BYP */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 7, 0x000, 0), /* MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 0, 0x000, 0), /* MX53_PAD_KEY_COL4__KPP_COL_4 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 1, 0x000, 0), /* MX53_PAD_KEY_COL4__GPIO4_14 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 2, 0x000, 0), /* MX53_PAD_KEY_COL4__CAN2_TXCAN */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 3, 0x000, 0), /* MX53_PAD_KEY_COL4__IPU_SISG_4 */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 4, 0x894, 0), /* MX53_PAD_KEY_COL4__UART5_RTS */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 5, 0x89C, 0), /* MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC */
+ IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 7, 0x000, 0), /* MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 0, 0x000, 0), /* MX53_PAD_KEY_ROW4__KPP_ROW_4 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 1, 0x000, 0), /* MX53_PAD_KEY_ROW4__GPIO4_15 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 2, 0x764, 0), /* MX53_PAD_KEY_ROW4__CAN2_RXCAN */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 3, 0x000, 0), /* MX53_PAD_KEY_ROW4__IPU_SISG_5 */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 4, 0x000, 0), /* MX53_PAD_KEY_ROW4__UART5_CTS */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 5, 0x000, 0), /* MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR */
+ IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 7, 0x000, 0), /* MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 0, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 1, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__GPIO4_16 */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 2, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 5, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 6, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 */
+ IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 7, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 0, 0x000, 0), /* MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 1, 0x000, 0), /* MX53_PAD_DI0_PIN15__GPIO4_17 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 2, 0x000, 0), /* MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 5, 0x000, 0), /* MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 6, 0x000, 0), /* MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 7, 0x000, 0), /* MX53_PAD_DI0_PIN15__USBPHY1_BVALID */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 0, 0x000, 0), /* MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 1, 0x000, 0), /* MX53_PAD_DI0_PIN2__GPIO4_18 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 2, 0x000, 0), /* MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 5, 0x000, 0), /* MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 6, 0x000, 0), /* MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 7, 0x000, 0), /* MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 0, 0x000, 0), /* MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 1, 0x000, 0), /* MX53_PAD_DI0_PIN3__GPIO4_19 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 2, 0x000, 0), /* MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 5, 0x000, 0), /* MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 6, 0x000, 0), /* MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 7, 0x000, 0), /* MX53_PAD_DI0_PIN3__USBPHY1_IDDIG */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 0, 0x000, 0), /* MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 1, 0x000, 0), /* MX53_PAD_DI0_PIN4__GPIO4_20 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 2, 0x000, 0), /* MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 3, 0x7FC, 0), /* MX53_PAD_DI0_PIN4__ESDHC1_WP */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 5, 0x000, 0), /* MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 6, 0x000, 0), /* MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 */
+ IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 7, 0x000, 0), /* MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT0__GPIO4_21 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 2, 0x780, 0), /* MX53_PAD_DISP0_DAT0__CSPI_SCLK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT1__GPIO4_22 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 2, 0x788, 0), /* MX53_PAD_DISP0_DAT1__CSPI_MOSI */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT2__GPIO4_23 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 2, 0x784, 0), /* MX53_PAD_DISP0_DAT2__CSPI_MISO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT3__GPIO4_24 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 2, 0x78C, 0), /* MX53_PAD_DISP0_DAT3__CSPI_SS0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT4__GPIO4_25 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 2, 0x790, 0), /* MX53_PAD_DISP0_DAT4__CSPI_SS1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT5__GPIO4_26 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 2, 0x794, 0), /* MX53_PAD_DISP0_DAT5__CSPI_SS2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT6__GPIO4_27 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 2, 0x798, 0), /* MX53_PAD_DISP0_DAT6__CSPI_SS3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT7__GPIO4_28 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT7__CSPI_RDY */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT8__GPIO4_29 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT8__PWM1_PWMO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT8__USBPHY2_AVALID */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT9__GPIO4_30 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT9__PWM2_PWMO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT10__GPIO4_31 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT11__GPIO5_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT12__GPIO5_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT13__GPIO5_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 3, 0x754, 0), /* MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT14__GPIO5_8 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 3, 0x750, 0), /* MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT15__GPIO5_9 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 2, 0x7AC, 1), /* MX53_PAD_DISP0_DAT15__ECSPI1_SS1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 3, 0x7C8, 0), /* MX53_PAD_DISP0_DAT15__ECSPI2_SS1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT16__GPIO5_10 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 2, 0x7C0, 0), /* MX53_PAD_DISP0_DAT16__ECSPI2_MOSI */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 3, 0x758, 1), /* MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 4, 0x868, 0), /* MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT17__GPIO5_11 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 2, 0x7BC, 0), /* MX53_PAD_DISP0_DAT17__ECSPI2_MISO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 3, 0x74C, 1), /* MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 4, 0x86C, 0), /* MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT18__GPIO5_12 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 2, 0x7C4, 0), /* MX53_PAD_DISP0_DAT18__ECSPI2_SS0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 3, 0x75C, 1), /* MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 4, 0x73C, 0), /* MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT19__GPIO5_13 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 2, 0x7B8, 0), /* MX53_PAD_DISP0_DAT19__ECSPI2_SCLK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 3, 0x748, 1), /* MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 4, 0x738, 0), /* MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT20__GPIO5_14 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 2, 0x79C, 1), /* MX53_PAD_DISP0_DAT20__ECSPI1_SCLK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 3, 0x740, 0), /* MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT20__SATA_PHY_TDI */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT21__GPIO5_15 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 2, 0x7A4, 1), /* MX53_PAD_DISP0_DAT21__ECSPI1_MOSI */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 3, 0x734, 0), /* MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT21__SATA_PHY_TDO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT22__GPIO5_16 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 2, 0x7A0, 1), /* MX53_PAD_DISP0_DAT22__ECSPI1_MISO */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 3, 0x744, 0), /* MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT22__SATA_PHY_TCK */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT23__GPIO5_17 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 2, 0x7A8, 1), /* MX53_PAD_DISP0_DAT23__ECSPI1_SS0 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 3, 0x730, 0), /* MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 */
+ IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT23__SATA_PHY_TMS */
+ IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 0, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 1, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__GPIO5_18 */
+ IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 5, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 6, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 0, 0x000, 0), /* MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 1, 0x000, 0), /* MX53_PAD_CSI0_MCLK__GPIO5_19 */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 2, 0x000, 0), /* MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 5, 0x000, 0), /* MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 6, 0x000, 0), /* MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 */
+ IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 7, 0x000, 0), /* MX53_PAD_CSI0_MCLK__TPIU_TRCTL */
+ IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 0, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN */
+ IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 1, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__GPIO5_20 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 5, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 6, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 7, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 0, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC */
+ IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 1, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__GPIO5_21 */
+ IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 5, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 */
+ IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 6, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 */
+ IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 7, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT4__GPIO5_22 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 2, 0x840, 1), /* MX53_PAD_CSI0_DAT4__KPP_COL_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 3, 0x79C, 2), /* MX53_PAD_CSI0_DAT4__ECSPI1_SCLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT5__GPIO5_23 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 2, 0x84C, 0), /* MX53_PAD_CSI0_DAT5__KPP_ROW_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 3, 0x7A4, 2), /* MX53_PAD_CSI0_DAT5__ECSPI1_MOSI */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT6__GPIO5_24 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 2, 0x844, 0), /* MX53_PAD_CSI0_DAT6__KPP_COL_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 3, 0x7A0, 2), /* MX53_PAD_CSI0_DAT6__ECSPI1_MISO */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT7__GPIO5_25 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 2, 0x850, 0), /* MX53_PAD_CSI0_DAT7__KPP_ROW_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 3, 0x7A8, 2), /* MX53_PAD_CSI0_DAT7__ECSPI1_SS0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT8__GPIO5_26 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 2, 0x848, 0), /* MX53_PAD_CSI0_DAT8__KPP_COL_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 3, 0x7B8, 1), /* MX53_PAD_CSI0_DAT8__ECSPI2_SCLK */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 5, 0x818, 0), /* MX53_PAD_CSI0_DAT8__I2C1_SDA */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT9__GPIO5_27 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 2, 0x854, 0), /* MX53_PAD_CSI0_DAT9__KPP_ROW_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 3, 0x7C0, 1), /* MX53_PAD_CSI0_DAT9__ECSPI2_MOSI */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 5, 0x814, 0), /* MX53_PAD_CSI0_DAT9__I2C1_SCL */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT10__GPIO5_28 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT10__UART1_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 3, 0x7BC, 1), /* MX53_PAD_CSI0_DAT10__ECSPI2_MISO */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT11__GPIO5_29 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 2, 0x878, 1), /* MX53_PAD_CSI0_DAT11__UART1_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 3, 0x7C4, 1), /* MX53_PAD_CSI0_DAT11__ECSPI2_SS0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT12__GPIO5_30 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT12__UART4_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT13__GPIO5_31 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 2, 0x890, 3), /* MX53_PAD_CSI0_DAT13__UART4_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT14__GPIO6_0 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT14__UART5_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT15__GPIO6_1 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 2, 0x898, 3), /* MX53_PAD_CSI0_DAT15__UART5_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT16__GPIO6_2 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 2, 0x88C, 0), /* MX53_PAD_CSI0_DAT16__UART4_RTS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT17__GPIO6_3 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT17__UART4_CTS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT18__GPIO6_4 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 2, 0x894, 2), /* MX53_PAD_CSI0_DAT18__UART5_RTS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT19__GPIO6_5 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT19__UART5_CTS */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 */
+ IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 0, 0x000, 0), /* MX53_PAD_EIM_A25__EMI_WEIM_A_25 */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 1, 0x000, 0), /* MX53_PAD_EIM_A25__GPIO5_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 2, 0x000, 0), /* MX53_PAD_EIM_A25__ECSPI2_RDY */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 3, 0x000, 0), /* MX53_PAD_EIM_A25__IPU_DI1_PIN12 */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 4, 0x790, 1), /* MX53_PAD_EIM_A25__CSPI_SS1 */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 6, 0x000, 0), /* MX53_PAD_EIM_A25__IPU_DI0_D1_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 7, 0x000, 0), /* MX53_PAD_EIM_A25__USBPHY1_BISTOK */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 0, 0x000, 0), /* MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 1, 0x000, 0), /* MX53_PAD_EIM_EB2__GPIO2_30 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 2, 0x76C, 0), /* MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 3, 0x000, 0), /* MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 4, 0x7A8, 3), /* MX53_PAD_EIM_EB2__ECSPI1_SS0 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 5, 0x81C, 1), /* MX53_PAD_EIM_EB2__I2C2_SCL */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 0, 0x000, 0), /* MX53_PAD_EIM_D16__EMI_WEIM_D_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 1, 0x000, 0), /* MX53_PAD_EIM_D16__GPIO3_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 2, 0x000, 0), /* MX53_PAD_EIM_D16__IPU_DI0_PIN5 */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 3, 0x000, 0), /* MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 4, 0x79C, 3), /* MX53_PAD_EIM_D16__ECSPI1_SCLK */
+ IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 5, 0x820, 1), /* MX53_PAD_EIM_D16__I2C2_SDA */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 0, 0x000, 0), /* MX53_PAD_EIM_D17__EMI_WEIM_D_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 1, 0x000, 0), /* MX53_PAD_EIM_D17__GPIO3_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 2, 0x000, 0), /* MX53_PAD_EIM_D17__IPU_DI0_PIN6 */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 3, 0x830, 0), /* MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 4, 0x7A0, 3), /* MX53_PAD_EIM_D17__ECSPI1_MISO */
+ IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 5, 0x824, 0), /* MX53_PAD_EIM_D17__I2C3_SCL */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 0, 0x000, 0), /* MX53_PAD_EIM_D18__EMI_WEIM_D_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 1, 0x000, 0), /* MX53_PAD_EIM_D18__GPIO3_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 2, 0x000, 0), /* MX53_PAD_EIM_D18__IPU_DI0_PIN7 */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 3, 0x830, 1), /* MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 4, 0x7A4, 3), /* MX53_PAD_EIM_D18__ECSPI1_MOSI */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 5, 0x828, 0), /* MX53_PAD_EIM_D18__I2C3_SDA */
+ IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 6, 0x000, 0), /* MX53_PAD_EIM_D18__IPU_DI1_D0_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 0, 0x000, 0), /* MX53_PAD_EIM_D19__EMI_WEIM_D_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 1, 0x000, 0), /* MX53_PAD_EIM_D19__GPIO3_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 2, 0x000, 0), /* MX53_PAD_EIM_D19__IPU_DI0_PIN8 */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 3, 0x000, 0), /* MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 4, 0x7AC, 2), /* MX53_PAD_EIM_D19__ECSPI1_SS1 */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 5, 0x000, 0), /* MX53_PAD_EIM_D19__EPIT1_EPITO */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 6, 0x000, 0), /* MX53_PAD_EIM_D19__UART1_CTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 7, 0x8A4, 0), /* MX53_PAD_EIM_D19__USBOH3_USBH2_OC */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 0, 0x000, 0), /* MX53_PAD_EIM_D20__EMI_WEIM_D_20 */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 1, 0x000, 0), /* MX53_PAD_EIM_D20__GPIO3_20 */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 2, 0x000, 0), /* MX53_PAD_EIM_D20__IPU_DI0_PIN16 */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 3, 0x000, 0), /* MX53_PAD_EIM_D20__IPU_SER_DISP0_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 4, 0x78C, 1), /* MX53_PAD_EIM_D20__CSPI_SS0 */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 5, 0x000, 0), /* MX53_PAD_EIM_D20__EPIT2_EPITO */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 6, 0x874, 1), /* MX53_PAD_EIM_D20__UART1_RTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 7, 0x000, 0), /* MX53_PAD_EIM_D20__USBOH3_USBH2_PWR */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 0, 0x000, 0), /* MX53_PAD_EIM_D21__EMI_WEIM_D_21 */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 1, 0x000, 0), /* MX53_PAD_EIM_D21__GPIO3_21 */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 2, 0x000, 0), /* MX53_PAD_EIM_D21__IPU_DI0_PIN17 */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 3, 0x000, 0), /* MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 4, 0x780, 1), /* MX53_PAD_EIM_D21__CSPI_SCLK */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 5, 0x814, 1), /* MX53_PAD_EIM_D21__I2C1_SCL */
+ IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 6, 0x89C, 1), /* MX53_PAD_EIM_D21__USBOH3_USBOTG_OC */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 0, 0x000, 0), /* MX53_PAD_EIM_D22__EMI_WEIM_D_22 */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 1, 0x000, 0), /* MX53_PAD_EIM_D22__GPIO3_22 */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 2, 0x000, 0), /* MX53_PAD_EIM_D22__IPU_DI0_PIN1 */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 3, 0x82C, 0), /* MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 4, 0x784, 1), /* MX53_PAD_EIM_D22__CSPI_MISO */
+ IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 6, 0x000, 0), /* MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 0, 0x000, 0), /* MX53_PAD_EIM_D23__EMI_WEIM_D_23 */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 1, 0x000, 0), /* MX53_PAD_EIM_D23__GPIO3_23 */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 2, 0x000, 0), /* MX53_PAD_EIM_D23__UART3_CTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 3, 0x000, 0), /* MX53_PAD_EIM_D23__UART1_DCD */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 4, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI0_D0_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 5, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI1_PIN2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 6, 0x834, 0), /* MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN */
+ IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 7, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI1_PIN14 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 0, 0x000, 0), /* MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 1, 0x000, 0), /* MX53_PAD_EIM_EB3__GPIO2_31 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 2, 0x884, 1), /* MX53_PAD_EIM_EB3__UART3_RTS */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 3, 0x000, 0), /* MX53_PAD_EIM_EB3__UART1_RI */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 5, 0x000, 0), /* MX53_PAD_EIM_EB3__IPU_DI1_PIN3 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 6, 0x838, 0), /* MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC */
+ IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 7, 0x000, 0), /* MX53_PAD_EIM_EB3__IPU_DI1_PIN16 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 0, 0x000, 0), /* MX53_PAD_EIM_D24__EMI_WEIM_D_24 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 1, 0x000, 0), /* MX53_PAD_EIM_D24__GPIO3_24 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 2, 0x000, 0), /* MX53_PAD_EIM_D24__UART3_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 3, 0x7B0, 1), /* MX53_PAD_EIM_D24__ECSPI1_SS2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 4, 0x794, 1), /* MX53_PAD_EIM_D24__CSPI_SS2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 5, 0x754, 1), /* MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 6, 0x000, 0), /* MX53_PAD_EIM_D24__ECSPI2_SS2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 7, 0x000, 0), /* MX53_PAD_EIM_D24__UART1_DTR */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 0, 0x000, 0), /* MX53_PAD_EIM_D25__EMI_WEIM_D_25 */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 1, 0x000, 0), /* MX53_PAD_EIM_D25__GPIO3_25 */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 2, 0x888, 1), /* MX53_PAD_EIM_D25__UART3_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 3, 0x7B4, 1), /* MX53_PAD_EIM_D25__ECSPI1_SS3 */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 4, 0x798, 1), /* MX53_PAD_EIM_D25__CSPI_SS3 */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 5, 0x750, 1), /* MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 6, 0x000, 0), /* MX53_PAD_EIM_D25__ECSPI2_SS3 */
+ IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 7, 0x000, 0), /* MX53_PAD_EIM_D25__UART1_DSR */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 0, 0x000, 0), /* MX53_PAD_EIM_D26__EMI_WEIM_D_26 */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 1, 0x000, 0), /* MX53_PAD_EIM_D26__GPIO3_26 */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 2, 0x000, 0), /* MX53_PAD_EIM_D26__UART2_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 3, 0x80C, 0), /* MX53_PAD_EIM_D26__FIRI_RXD */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 4, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_CSI0_D_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 5, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_DI1_PIN11 */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 6, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_SISG_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 7, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 0, 0x000, 0), /* MX53_PAD_EIM_D27__EMI_WEIM_D_27 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 1, 0x000, 0), /* MX53_PAD_EIM_D27__GPIO3_27 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 2, 0x880, 1), /* MX53_PAD_EIM_D27__UART2_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 3, 0x000, 0), /* MX53_PAD_EIM_D27__FIRI_TXD */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 4, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_CSI0_D_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 5, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_DI1_PIN13 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 6, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_SISG_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 7, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 0, 0x000, 0), /* MX53_PAD_EIM_D28__EMI_WEIM_D_28 */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 1, 0x000, 0), /* MX53_PAD_EIM_D28__GPIO3_28 */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 2, 0x000, 0), /* MX53_PAD_EIM_D28__UART2_CTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 3, 0x82C, 1), /* MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 4, 0x788, 1), /* MX53_PAD_EIM_D28__CSPI_MOSI */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 5, 0x818, 1), /* MX53_PAD_EIM_D28__I2C1_SDA */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 6, 0x000, 0), /* MX53_PAD_EIM_D28__IPU_EXT_TRIG */
+ IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 7, 0x000, 0), /* MX53_PAD_EIM_D28__IPU_DI0_PIN13 */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 0, 0x000, 0), /* MX53_PAD_EIM_D29__EMI_WEIM_D_29 */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 1, 0x000, 0), /* MX53_PAD_EIM_D29__GPIO3_29 */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 2, 0x87C, 1), /* MX53_PAD_EIM_D29__UART2_RTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 3, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 4, 0x78C, 2), /* MX53_PAD_EIM_D29__CSPI_SS0 */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 5, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DI1_PIN15 */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 6, 0x83C, 0), /* MX53_PAD_EIM_D29__IPU_CSI1_VSYNC */
+ IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 7, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DI0_PIN14 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 0, 0x000, 0), /* MX53_PAD_EIM_D30__EMI_WEIM_D_30 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 1, 0x000, 0), /* MX53_PAD_EIM_D30__GPIO3_30 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 2, 0x000, 0), /* MX53_PAD_EIM_D30__UART3_CTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 3, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_CSI0_D_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 4, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_DI0_PIN11 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 5, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 6, 0x8A0, 0), /* MX53_PAD_EIM_D30__USBOH3_USBH1_OC */
+ IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 7, 0x8A4, 1), /* MX53_PAD_EIM_D30__USBOH3_USBH2_OC */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 0, 0x000, 0), /* MX53_PAD_EIM_D31__EMI_WEIM_D_31 */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 1, 0x000, 0), /* MX53_PAD_EIM_D31__GPIO3_31 */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 2, 0x884, 3), /* MX53_PAD_EIM_D31__UART3_RTS */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 3, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_CSI0_D_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 4, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_DI0_PIN12 */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 5, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 6, 0x000, 0), /* MX53_PAD_EIM_D31__USBOH3_USBH1_PWR */
+ IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 7, 0x000, 0), /* MX53_PAD_EIM_D31__USBOH3_USBH2_PWR */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 0, 0x000, 0), /* MX53_PAD_EIM_A24__EMI_WEIM_A_24 */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 1, 0x000, 0), /* MX53_PAD_EIM_A24__GPIO5_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 2, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 3, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_CSI1_D_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 6, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_SISG_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 7, 0x000, 0), /* MX53_PAD_EIM_A24__USBPHY2_BVALID */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 0, 0x000, 0), /* MX53_PAD_EIM_A23__EMI_WEIM_A_23 */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 1, 0x000, 0), /* MX53_PAD_EIM_A23__GPIO6_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 2, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 3, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_CSI1_D_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 6, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_SISG_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 7, 0x000, 0), /* MX53_PAD_EIM_A23__USBPHY2_ENDSESSION */
+ IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 0, 0x000, 0), /* MX53_PAD_EIM_A22__EMI_WEIM_A_22 */
+ IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 1, 0x000, 0), /* MX53_PAD_EIM_A22__GPIO2_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 2, 0x000, 0), /* MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 3, 0x000, 0), /* MX53_PAD_EIM_A22__IPU_CSI1_D_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 7, 0x000, 0), /* MX53_PAD_EIM_A22__SRC_BT_CFG1_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 0, 0x000, 0), /* MX53_PAD_EIM_A21__EMI_WEIM_A_21 */
+ IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 1, 0x000, 0), /* MX53_PAD_EIM_A21__GPIO2_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 2, 0x000, 0), /* MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 3, 0x000, 0), /* MX53_PAD_EIM_A21__IPU_CSI1_D_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 7, 0x000, 0), /* MX53_PAD_EIM_A21__SRC_BT_CFG1_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 0, 0x000, 0), /* MX53_PAD_EIM_A20__EMI_WEIM_A_20 */
+ IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 1, 0x000, 0), /* MX53_PAD_EIM_A20__GPIO2_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 2, 0x000, 0), /* MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 */
+ IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 3, 0x000, 0), /* MX53_PAD_EIM_A20__IPU_CSI1_D_15 */
+ IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 7, 0x000, 0), /* MX53_PAD_EIM_A20__SRC_BT_CFG1_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 0, 0x000, 0), /* MX53_PAD_EIM_A19__EMI_WEIM_A_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 1, 0x000, 0), /* MX53_PAD_EIM_A19__GPIO2_19 */
+ IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 2, 0x000, 0), /* MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 */
+ IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 3, 0x000, 0), /* MX53_PAD_EIM_A19__IPU_CSI1_D_14 */
+ IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 7, 0x000, 0), /* MX53_PAD_EIM_A19__SRC_BT_CFG1_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 0, 0x000, 0), /* MX53_PAD_EIM_A18__EMI_WEIM_A_18 */
+ IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 1, 0x000, 0), /* MX53_PAD_EIM_A18__GPIO2_20 */
+ IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 2, 0x000, 0), /* MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 */
+ IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 3, 0x000, 0), /* MX53_PAD_EIM_A18__IPU_CSI1_D_13 */
+ IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 7, 0x000, 0), /* MX53_PAD_EIM_A18__SRC_BT_CFG1_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 0, 0x000, 0), /* MX53_PAD_EIM_A17__EMI_WEIM_A_17 */
+ IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 1, 0x000, 0), /* MX53_PAD_EIM_A17__GPIO2_21 */
+ IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 2, 0x000, 0), /* MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 */
+ IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 3, 0x000, 0), /* MX53_PAD_EIM_A17__IPU_CSI1_D_12 */
+ IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 7, 0x000, 0), /* MX53_PAD_EIM_A17__SRC_BT_CFG1_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 0, 0x000, 0), /* MX53_PAD_EIM_A16__EMI_WEIM_A_16 */
+ IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 1, 0x000, 0), /* MX53_PAD_EIM_A16__GPIO2_22 */
+ IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 2, 0x000, 0), /* MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 3, 0x000, 0), /* MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK */
+ IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 7, 0x000, 0), /* MX53_PAD_EIM_A16__SRC_BT_CFG1_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 0, 0x000, 0), /* MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 1, 0x000, 0), /* MX53_PAD_EIM_CS0__GPIO2_23 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 2, 0x7B8, 2), /* MX53_PAD_EIM_CS0__ECSPI2_SCLK */
+ IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 3, 0x000, 0), /* MX53_PAD_EIM_CS0__IPU_DI1_PIN5 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 0, 0x000, 0), /* MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 1, 0x000, 0), /* MX53_PAD_EIM_CS1__GPIO2_24 */
+ IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 2, 0x7C0, 2), /* MX53_PAD_EIM_CS1__ECSPI2_MOSI */
+ IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 3, 0x000, 0), /* MX53_PAD_EIM_CS1__IPU_DI1_PIN6 */
+ IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 0, 0x000, 0), /* MX53_PAD_EIM_OE__EMI_WEIM_OE */
+ IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 1, 0x000, 0), /* MX53_PAD_EIM_OE__GPIO2_25 */
+ IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 2, 0x7BC, 2), /* MX53_PAD_EIM_OE__ECSPI2_MISO */
+ IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 3, 0x000, 0), /* MX53_PAD_EIM_OE__IPU_DI1_PIN7 */
+ IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 7, 0x000, 0), /* MX53_PAD_EIM_OE__USBPHY2_IDDIG */
+ IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 0, 0x000, 0), /* MX53_PAD_EIM_RW__EMI_WEIM_RW */
+ IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 1, 0x000, 0), /* MX53_PAD_EIM_RW__GPIO2_26 */
+ IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 2, 0x7C4, 2), /* MX53_PAD_EIM_RW__ECSPI2_SS0 */
+ IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 3, 0x000, 0), /* MX53_PAD_EIM_RW__IPU_DI1_PIN8 */
+ IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 7, 0x000, 0), /* MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT */
+ IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 0, 0x000, 0), /* MX53_PAD_EIM_LBA__EMI_WEIM_LBA */
+ IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 1, 0x000, 0), /* MX53_PAD_EIM_LBA__GPIO2_27 */
+ IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 2, 0x7C8, 1), /* MX53_PAD_EIM_LBA__ECSPI2_SS1 */
+ IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 3, 0x000, 0), /* MX53_PAD_EIM_LBA__IPU_DI1_PIN17 */
+ IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 7, 0x000, 0), /* MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 0, 0x000, 0), /* MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 1, 0x000, 0), /* MX53_PAD_EIM_EB0__GPIO2_28 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 3, 0x000, 0), /* MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 4, 0x000, 0), /* MX53_PAD_EIM_EB0__IPU_CSI1_D_11 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 5, 0x810, 0), /* MX53_PAD_EIM_EB0__GPC_PMIC_RDY */
+ IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 7, 0x000, 0), /* MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 0, 0x000, 0), /* MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 1, 0x000, 0), /* MX53_PAD_EIM_EB1__GPIO2_29 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 3, 0x000, 0), /* MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 4, 0x000, 0), /* MX53_PAD_EIM_EB1__IPU_CSI1_D_10 */
+ IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 7, 0x000, 0), /* MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 0, 0x000, 0), /* MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 1, 0x000, 0), /* MX53_PAD_EIM_DA0__GPIO3_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 3, 0x000, 0), /* MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 4, 0x000, 0), /* MX53_PAD_EIM_DA0__IPU_CSI1_D_9 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 7, 0x000, 0), /* MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 0, 0x000, 0), /* MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 1, 0x000, 0), /* MX53_PAD_EIM_DA1__GPIO3_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 3, 0x000, 0), /* MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 4, 0x000, 0), /* MX53_PAD_EIM_DA1__IPU_CSI1_D_8 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 7, 0x000, 0), /* MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 0, 0x000, 0), /* MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 1, 0x000, 0), /* MX53_PAD_EIM_DA2__GPIO3_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 3, 0x000, 0), /* MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 4, 0x000, 0), /* MX53_PAD_EIM_DA2__IPU_CSI1_D_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 7, 0x000, 0), /* MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 0, 0x000, 0), /* MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 1, 0x000, 0), /* MX53_PAD_EIM_DA3__GPIO3_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 3, 0x000, 0), /* MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 4, 0x000, 0), /* MX53_PAD_EIM_DA3__IPU_CSI1_D_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 7, 0x000, 0), /* MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 0, 0x000, 0), /* MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 1, 0x000, 0), /* MX53_PAD_EIM_DA4__GPIO3_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 3, 0x000, 0), /* MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 4, 0x000, 0), /* MX53_PAD_EIM_DA4__IPU_CSI1_D_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 7, 0x000, 0), /* MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 0, 0x000, 0), /* MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 1, 0x000, 0), /* MX53_PAD_EIM_DA5__GPIO3_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 3, 0x000, 0), /* MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 4, 0x000, 0), /* MX53_PAD_EIM_DA5__IPU_CSI1_D_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 7, 0x000, 0), /* MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 0, 0x000, 0), /* MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 1, 0x000, 0), /* MX53_PAD_EIM_DA6__GPIO3_6 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 3, 0x000, 0), /* MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 4, 0x000, 0), /* MX53_PAD_EIM_DA6__IPU_CSI1_D_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 7, 0x000, 0), /* MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 0, 0x000, 0), /* MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 1, 0x000, 0), /* MX53_PAD_EIM_DA7__GPIO3_7 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 3, 0x000, 0), /* MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 4, 0x000, 0), /* MX53_PAD_EIM_DA7__IPU_CSI1_D_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 7, 0x000, 0), /* MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 0, 0x000, 0), /* MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 1, 0x000, 0), /* MX53_PAD_EIM_DA8__GPIO3_8 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 3, 0x000, 0), /* MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 4, 0x000, 0), /* MX53_PAD_EIM_DA8__IPU_CSI1_D_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 7, 0x000, 0), /* MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 0, 0x000, 0), /* MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 1, 0x000, 0), /* MX53_PAD_EIM_DA9__GPIO3_9 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 3, 0x000, 0), /* MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 4, 0x000, 0), /* MX53_PAD_EIM_DA9__IPU_CSI1_D_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 7, 0x000, 0), /* MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 0, 0x000, 0), /* MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 1, 0x000, 0), /* MX53_PAD_EIM_DA10__GPIO3_10 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 3, 0x000, 0), /* MX53_PAD_EIM_DA10__IPU_DI1_PIN15 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 4, 0x834, 1), /* MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN */
+ IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 7, 0x000, 0), /* MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 0, 0x000, 0), /* MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 1, 0x000, 0), /* MX53_PAD_EIM_DA11__GPIO3_11 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 3, 0x000, 0), /* MX53_PAD_EIM_DA11__IPU_DI1_PIN2 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 4, 0x838, 1), /* MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC */
+ IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 0, 0x000, 0), /* MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 1, 0x000, 0), /* MX53_PAD_EIM_DA12__GPIO3_12 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 3, 0x000, 0), /* MX53_PAD_EIM_DA12__IPU_DI1_PIN3 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 4, 0x83C, 1), /* MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC */
+ IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 0, 0x000, 0), /* MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 1, 0x000, 0), /* MX53_PAD_EIM_DA13__GPIO3_13 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 3, 0x000, 0), /* MX53_PAD_EIM_DA13__IPU_DI1_D0_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 4, 0x76C, 1), /* MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 0, 0x000, 0), /* MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 1, 0x000, 0), /* MX53_PAD_EIM_DA14__GPIO3_14 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 3, 0x000, 0), /* MX53_PAD_EIM_DA14__IPU_DI1_D1_CS */
+ IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 4, 0x000, 0), /* MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK */
+ IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 0, 0x000, 0), /* MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 1, 0x000, 0), /* MX53_PAD_EIM_DA15__GPIO3_15 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 3, 0x000, 0), /* MX53_PAD_EIM_DA15__IPU_DI1_PIN1 */
+ IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 4, 0x000, 0), /* MX53_PAD_EIM_DA15__IPU_DI1_PIN4 */
+ IMX_PIN_REG(MX53_PAD_NANDF_WE_B, 0x52C, 0x1DC, 0, 0x000, 0), /* MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B */
+ IMX_PIN_REG(MX53_PAD_NANDF_WE_B, 0x52C, 0x1DC, 1, 0x000, 0), /* MX53_PAD_NANDF_WE_B__GPIO6_12 */
+ IMX_PIN_REG(MX53_PAD_NANDF_RE_B, 0x530, 0x1E0, 0, 0x000, 0), /* MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B */
+ IMX_PIN_REG(MX53_PAD_NANDF_RE_B, 0x530, 0x1E0, 1, 0x000, 0), /* MX53_PAD_NANDF_RE_B__GPIO6_13 */
+ IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 0, 0x000, 0), /* MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT */
+ IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 1, 0x000, 0), /* MX53_PAD_EIM_WAIT__GPIO5_0 */
+ IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 2, 0x000, 0), /* MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX3_P, NO_PAD, 0x1EC, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX3_P__GPIO6_22 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX3_P, NO_PAD, 0x1EC, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX2_P, NO_PAD, 0x1F0, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX2_P__GPIO6_24 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX2_P, NO_PAD, 0x1F0, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_CLK_P, NO_PAD, 0x1F4, 0, 0x000, 0), /* MX53_PAD_LVDS1_CLK_P__GPIO6_26 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_CLK_P, NO_PAD, 0x1F4, 1, 0x000, 0), /* MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX1_P, NO_PAD, 0x1F8, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX1_P__GPIO6_28 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX1_P, NO_PAD, 0x1F8, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX0_P, NO_PAD, 0x1FC, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX0_P__GPIO6_30 */
+ IMX_PIN_REG(MX53_PAD_LVDS1_TX0_P, NO_PAD, 0x1FC, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX3_P, NO_PAD, 0x200, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX3_P__GPIO7_22 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX3_P, NO_PAD, 0x200, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_CLK_P, NO_PAD, 0x204, 0, 0x000, 0), /* MX53_PAD_LVDS0_CLK_P__GPIO7_24 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_CLK_P, NO_PAD, 0x204, 1, 0x000, 0), /* MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX2_P, NO_PAD, 0x208, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX2_P__GPIO7_26 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX2_P, NO_PAD, 0x208, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX1_P, NO_PAD, 0x20C, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX1_P__GPIO7_28 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX1_P, NO_PAD, 0x20C, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX0_P, NO_PAD, 0x210, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX0_P__GPIO7_30 */
+ IMX_PIN_REG(MX53_PAD_LVDS0_TX0_P, NO_PAD, 0x210, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_10, 0x540, 0x214, 0, 0x000, 0), /* MX53_PAD_GPIO_10__GPIO4_0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_10, 0x540, 0x214, 1, 0x000, 0), /* MX53_PAD_GPIO_10__OSC32k_32K_OUT */
+ IMX_PIN_REG(MX53_PAD_GPIO_11, 0x544, 0x218, 0, 0x000, 0), /* MX53_PAD_GPIO_11__GPIO4_1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_12, 0x548, 0x21C, 0, 0x000, 0), /* MX53_PAD_GPIO_12__GPIO4_2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_13, 0x54C, 0x220, 0, 0x000, 0), /* MX53_PAD_GPIO_13__GPIO4_3 */
+ IMX_PIN_REG(MX53_PAD_GPIO_14, 0x550, 0x224, 0, 0x000, 0), /* MX53_PAD_GPIO_14__GPIO4_4 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 0, 0x000, 0), /* MX53_PAD_NANDF_CLE__EMI_NANDF_CLE */
+ IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 1, 0x000, 0), /* MX53_PAD_NANDF_CLE__GPIO6_7 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 7, 0x000, 0), /* MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 */
+ IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 0, 0x000, 0), /* MX53_PAD_NANDF_ALE__EMI_NANDF_ALE */
+ IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 1, 0x000, 0), /* MX53_PAD_NANDF_ALE__GPIO6_8 */
+ IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 7, 0x000, 0), /* MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 */
+ IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 0, 0x000, 0), /* MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B */
+ IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 1, 0x000, 0), /* MX53_PAD_NANDF_WP_B__GPIO6_9 */
+ IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 7, 0x000, 0), /* MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 */
+ IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 0, 0x000, 0), /* MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 */
+ IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 1, 0x000, 0), /* MX53_PAD_NANDF_RB0__GPIO6_10 */
+ IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 7, 0x000, 0), /* MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 0, 0x000, 0), /* MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 1, 0x000, 0), /* MX53_PAD_NANDF_CS0__GPIO6_11 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 7, 0x000, 0), /* MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 0, 0x000, 0), /* MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 1, 0x000, 0), /* MX53_PAD_NANDF_CS1__GPIO6_14 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 6, 0x858, 0), /* MX53_PAD_NANDF_CS1__MLB_MLBCLK */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 7, 0x000, 0), /* MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 0, 0x000, 0), /* MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 1, 0x000, 0), /* MX53_PAD_NANDF_CS2__GPIO6_15 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 2, 0x000, 0), /* MX53_PAD_NANDF_CS2__IPU_SISG_0 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 3, 0x7E4, 0), /* MX53_PAD_NANDF_CS2__ESAI1_TX0 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 4, 0x000, 0), /* MX53_PAD_NANDF_CS2__EMI_WEIM_CRE */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 5, 0x000, 0), /* MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 6, 0x860, 0), /* MX53_PAD_NANDF_CS2__MLB_MLBSIG */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 7, 0x000, 0), /* MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 0, 0x000, 0), /* MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 1, 0x000, 0), /* MX53_PAD_NANDF_CS3__GPIO6_16 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 2, 0x000, 0), /* MX53_PAD_NANDF_CS3__IPU_SISG_1 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 3, 0x7E8, 0), /* MX53_PAD_NANDF_CS3__ESAI1_TX1 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 4, 0x000, 0), /* MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 6, 0x85C, 0), /* MX53_PAD_NANDF_CS3__MLB_MLBDAT */
+ IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 7, 0x000, 0), /* MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 0, 0x804, 1), /* MX53_PAD_FEC_MDIO__FEC_MDIO */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 1, 0x000, 0), /* MX53_PAD_FEC_MDIO__GPIO1_22 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 2, 0x7DC, 0), /* MX53_PAD_FEC_MDIO__ESAI1_SCKR */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 3, 0x800, 1), /* MX53_PAD_FEC_MDIO__FEC_COL */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 4, 0x000, 0), /* MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 5, 0x000, 0), /* MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 6, 0x000, 0), /* MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 */
+ IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 0, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__FEC_TX_CLK */
+ IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 1, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__GPIO1_23 */
+ IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 2, 0x7CC, 0), /* MX53_PAD_FEC_REF_CLK__ESAI1_FSR */
+ IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 5, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 */
+ IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 6, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 */
+ IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 0, 0x000, 0), /* MX53_PAD_FEC_RX_ER__FEC_RX_ER */
+ IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 1, 0x000, 0), /* MX53_PAD_FEC_RX_ER__GPIO1_24 */
+ IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 2, 0x7D4, 0), /* MX53_PAD_FEC_RX_ER__ESAI1_HCKR */
+ IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 3, 0x808, 1), /* MX53_PAD_FEC_RX_ER__FEC_RX_CLK */
+ IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 4, 0x000, 0), /* MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 */
+ IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 0, 0x000, 0), /* MX53_PAD_FEC_CRS_DV__FEC_RX_DV */
+ IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 1, 0x000, 0), /* MX53_PAD_FEC_CRS_DV__GPIO1_25 */
+ IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 2, 0x7E0, 0), /* MX53_PAD_FEC_CRS_DV__ESAI1_SCKT */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 0, 0x000, 0), /* MX53_PAD_FEC_RXD1__FEC_RDATA_1 */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 1, 0x000, 0), /* MX53_PAD_FEC_RXD1__GPIO1_26 */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 2, 0x7D0, 0), /* MX53_PAD_FEC_RXD1__ESAI1_FST */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 3, 0x860, 1), /* MX53_PAD_FEC_RXD1__MLB_MLBSIG */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 4, 0x000, 0), /* MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 0, 0x000, 0), /* MX53_PAD_FEC_RXD0__FEC_RDATA_0 */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 1, 0x000, 0), /* MX53_PAD_FEC_RXD0__GPIO1_27 */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 2, 0x7D8, 0), /* MX53_PAD_FEC_RXD0__ESAI1_HCKT */
+ IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 3, 0x000, 0), /* MX53_PAD_FEC_RXD0__OSC32k_32K_OUT */
+ IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 0, 0x000, 0), /* MX53_PAD_FEC_TX_EN__FEC_TX_EN */
+ IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 1, 0x000, 0), /* MX53_PAD_FEC_TX_EN__GPIO1_28 */
+ IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 2, 0x7F0, 0), /* MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 0, 0x000, 0), /* MX53_PAD_FEC_TXD1__FEC_TDATA_1 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 1, 0x000, 0), /* MX53_PAD_FEC_TXD1__GPIO1_29 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 2, 0x7EC, 0), /* MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 3, 0x858, 1), /* MX53_PAD_FEC_TXD1__MLB_MLBCLK */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 4, 0x000, 0), /* MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 0, 0x000, 0), /* MX53_PAD_FEC_TXD0__FEC_TDATA_0 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 1, 0x000, 0), /* MX53_PAD_FEC_TXD0__GPIO1_30 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 2, 0x7F4, 0), /* MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 */
+ IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 7, 0x000, 0), /* MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 0, 0x000, 0), /* MX53_PAD_FEC_MDC__FEC_MDC */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 1, 0x000, 0), /* MX53_PAD_FEC_MDC__GPIO1_31 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 2, 0x7F8, 0), /* MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 3, 0x85C, 1), /* MX53_PAD_FEC_MDC__MLB_MLBDAT */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 4, 0x000, 0), /* MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG */
+ IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 7, 0x000, 0), /* MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 0, 0x000, 0), /* MX53_PAD_PATA_DIOW__PATA_DIOW */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 1, 0x000, 0), /* MX53_PAD_PATA_DIOW__GPIO6_17 */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 3, 0x000, 0), /* MX53_PAD_PATA_DIOW__UART1_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 7, 0x000, 0), /* MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 0, 0x000, 0), /* MX53_PAD_PATA_DMACK__PATA_DMACK */
+ IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 1, 0x000, 0), /* MX53_PAD_PATA_DMACK__GPIO6_18 */
+ IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 3, 0x878, 3), /* MX53_PAD_PATA_DMACK__UART1_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 7, 0x000, 0), /* MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 0, 0x000, 0), /* MX53_PAD_PATA_DMARQ__PATA_DMARQ */
+ IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 1, 0x000, 0), /* MX53_PAD_PATA_DMARQ__GPIO7_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 3, 0x000, 0), /* MX53_PAD_PATA_DMARQ__UART2_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 5, 0x000, 0), /* MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 7, 0x000, 0), /* MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 0, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN */
+ IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 1, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__GPIO7_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 3, 0x880, 3), /* MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 5, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 7, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 0, 0x000, 0), /* MX53_PAD_PATA_INTRQ__PATA_INTRQ */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 1, 0x000, 0), /* MX53_PAD_PATA_INTRQ__GPIO7_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 3, 0x000, 0), /* MX53_PAD_PATA_INTRQ__UART2_CTS */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 4, 0x000, 0), /* MX53_PAD_PATA_INTRQ__CAN1_TXCAN */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 5, 0x000, 0), /* MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 7, 0x000, 0), /* MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 0, 0x000, 0), /* MX53_PAD_PATA_DIOR__PATA_DIOR */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 1, 0x000, 0), /* MX53_PAD_PATA_DIOR__GPIO7_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 3, 0x87C, 3), /* MX53_PAD_PATA_DIOR__UART2_RTS */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 4, 0x760, 1), /* MX53_PAD_PATA_DIOR__CAN1_RXCAN */
+ IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 7, 0x000, 0), /* MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 0, 0x000, 0), /* MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 1, 0x000, 0), /* MX53_PAD_PATA_RESET_B__GPIO7_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 2, 0x000, 0), /* MX53_PAD_PATA_RESET_B__ESDHC3_CMD */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 3, 0x000, 0), /* MX53_PAD_PATA_RESET_B__UART1_CTS */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 4, 0x000, 0), /* MX53_PAD_PATA_RESET_B__CAN2_TXCAN */
+ IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 7, 0x000, 0), /* MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 0, 0x000, 0), /* MX53_PAD_PATA_IORDY__PATA_IORDY */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 1, 0x000, 0), /* MX53_PAD_PATA_IORDY__GPIO7_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 2, 0x000, 0), /* MX53_PAD_PATA_IORDY__ESDHC3_CLK */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 3, 0x874, 3), /* MX53_PAD_PATA_IORDY__UART1_RTS */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 4, 0x764, 1), /* MX53_PAD_PATA_IORDY__CAN2_RXCAN */
+ IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 7, 0x000, 0), /* MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 0, 0x000, 0), /* MX53_PAD_PATA_DA_0__PATA_DA_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 1, 0x000, 0), /* MX53_PAD_PATA_DA_0__GPIO7_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 2, 0x000, 0), /* MX53_PAD_PATA_DA_0__ESDHC3_RST */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 4, 0x864, 0), /* MX53_PAD_PATA_DA_0__OWIRE_LINE */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 7, 0x000, 0), /* MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 0, 0x000, 0), /* MX53_PAD_PATA_DA_1__PATA_DA_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 1, 0x000, 0), /* MX53_PAD_PATA_DA_1__GPIO7_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 2, 0x000, 0), /* MX53_PAD_PATA_DA_1__ESDHC4_CMD */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 4, 0x000, 0), /* MX53_PAD_PATA_DA_1__UART3_CTS */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 7, 0x000, 0), /* MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 0, 0x000, 0), /* MX53_PAD_PATA_DA_2__PATA_DA_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 1, 0x000, 0), /* MX53_PAD_PATA_DA_2__GPIO7_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 2, 0x000, 0), /* MX53_PAD_PATA_DA_2__ESDHC4_CLK */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 4, 0x884, 5), /* MX53_PAD_PATA_DA_2__UART3_RTS */
+ IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 7, 0x000, 0), /* MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 0, 0x000, 0), /* MX53_PAD_PATA_CS_0__PATA_CS_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 1, 0x000, 0), /* MX53_PAD_PATA_CS_0__GPIO7_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 4, 0x000, 0), /* MX53_PAD_PATA_CS_0__UART3_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 7, 0x000, 0), /* MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 0, 0x000, 0), /* MX53_PAD_PATA_CS_1__PATA_CS_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 1, 0x000, 0), /* MX53_PAD_PATA_CS_1__GPIO7_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 4, 0x888, 3), /* MX53_PAD_PATA_CS_1__UART3_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 7, 0x000, 0), /* MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA0__PATA_DATA_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA0__GPIO2_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA0__ESDHC3_DAT4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 7, 0x000, 0), /* MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA1__PATA_DATA_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA1__GPIO2_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA1__ESDHC3_DAT5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA2__PATA_DATA_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA2__GPIO2_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA2__ESDHC3_DAT6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA3__PATA_DATA_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA3__GPIO2_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA3__ESDHC3_DAT7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA4__PATA_DATA_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA4__GPIO2_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA4__ESDHC4_DAT4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA5__PATA_DATA_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA5__GPIO2_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA5__ESDHC4_DAT5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA6__PATA_DATA_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA6__GPIO2_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA6__ESDHC4_DAT6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA7__PATA_DATA_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA7__GPIO2_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA7__ESDHC4_DAT7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA8__PATA_DATA_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA8__GPIO2_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 2, 0x000, 0), /* MX53_PAD_PATA_DATA8__ESDHC1_DAT4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA8__ESDHC3_DAT0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA9__PATA_DATA_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA9__GPIO2_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 2, 0x000, 0), /* MX53_PAD_PATA_DATA9__ESDHC1_DAT5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA9__ESDHC3_DAT1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA10__PATA_DATA_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA10__GPIO2_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 2, 0x000, 0), /* MX53_PAD_PATA_DATA10__ESDHC1_DAT6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA10__ESDHC3_DAT2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA11__PATA_DATA_11 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA11__GPIO2_11 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 2, 0x000, 0), /* MX53_PAD_PATA_DATA11__ESDHC1_DAT7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA11__ESDHC3_DAT3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA12__PATA_DATA_12 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA12__GPIO2_12 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 2, 0x000, 0), /* MX53_PAD_PATA_DATA12__ESDHC2_DAT4 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA12__ESDHC4_DAT0 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA13__PATA_DATA_13 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA13__GPIO2_13 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 2, 0x000, 0), /* MX53_PAD_PATA_DATA13__ESDHC2_DAT5 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA13__ESDHC4_DAT1 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA14__PATA_DATA_14 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA14__GPIO2_14 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 2, 0x000, 0), /* MX53_PAD_PATA_DATA14__ESDHC2_DAT6 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA14__ESDHC4_DAT2 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA15__PATA_DATA_15 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA15__GPIO2_15 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 2, 0x000, 0), /* MX53_PAD_PATA_DATA15__ESDHC2_DAT7 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA15__ESDHC4_DAT3 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 */
+ IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 0, 0x000, 0), /* MX53_PAD_SD1_DATA0__ESDHC1_DAT0 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 1, 0x000, 0), /* MX53_PAD_SD1_DATA0__GPIO1_16 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 3, 0x000, 0), /* MX53_PAD_SD1_DATA0__GPT_CAPIN1 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 5, 0x784, 2), /* MX53_PAD_SD1_DATA0__CSPI_MISO */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 7, 0x778, 0), /* MX53_PAD_SD1_DATA0__CCM_PLL3_BYP */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 0, 0x000, 0), /* MX53_PAD_SD1_DATA1__ESDHC1_DAT1 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 1, 0x000, 0), /* MX53_PAD_SD1_DATA1__GPIO1_17 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 3, 0x000, 0), /* MX53_PAD_SD1_DATA1__GPT_CAPIN2 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 5, 0x78C, 3), /* MX53_PAD_SD1_DATA1__CSPI_SS0 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 7, 0x77C, 1), /* MX53_PAD_SD1_DATA1__CCM_PLL4_BYP */
+ IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 0, 0x000, 0), /* MX53_PAD_SD1_CMD__ESDHC1_CMD */
+ IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 1, 0x000, 0), /* MX53_PAD_SD1_CMD__GPIO1_18 */
+ IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 3, 0x000, 0), /* MX53_PAD_SD1_CMD__GPT_CMPOUT1 */
+ IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 5, 0x788, 2), /* MX53_PAD_SD1_CMD__CSPI_MOSI */
+ IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 7, 0x770, 0), /* MX53_PAD_SD1_CMD__CCM_PLL1_BYP */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 0, 0x000, 0), /* MX53_PAD_SD1_DATA2__ESDHC1_DAT2 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 1, 0x000, 0), /* MX53_PAD_SD1_DATA2__GPIO1_19 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 2, 0x000, 0), /* MX53_PAD_SD1_DATA2__GPT_CMPOUT2 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 3, 0x000, 0), /* MX53_PAD_SD1_DATA2__PWM2_PWMO */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 4, 0x000, 0), /* MX53_PAD_SD1_DATA2__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 5, 0x790, 2), /* MX53_PAD_SD1_DATA2__CSPI_SS1 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 6, 0x000, 0), /* MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 7, 0x774, 0), /* MX53_PAD_SD1_DATA2__CCM_PLL2_BYP */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 0, 0x000, 0), /* MX53_PAD_SD1_CLK__ESDHC1_CLK */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 1, 0x000, 0), /* MX53_PAD_SD1_CLK__GPIO1_20 */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 2, 0x000, 0), /* MX53_PAD_SD1_CLK__OSC32k_32K_OUT */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 3, 0x000, 0), /* MX53_PAD_SD1_CLK__GPT_CLKIN */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 5, 0x780, 2), /* MX53_PAD_SD1_CLK__CSPI_SCLK */
+ IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 7, 0x000, 0), /* MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 0, 0x000, 0), /* MX53_PAD_SD1_DATA3__ESDHC1_DAT3 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 1, 0x000, 0), /* MX53_PAD_SD1_DATA3__GPIO1_21 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 2, 0x000, 0), /* MX53_PAD_SD1_DATA3__GPT_CMPOUT3 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 3, 0x000, 0), /* MX53_PAD_SD1_DATA3__PWM1_PWMO */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 4, 0x000, 0), /* MX53_PAD_SD1_DATA3__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 5, 0x794, 2), /* MX53_PAD_SD1_DATA3__CSPI_SS2 */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 6, 0x000, 0), /* MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB */
+ IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 7, 0x000, 0), /* MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 0, 0x000, 0), /* MX53_PAD_SD2_CLK__ESDHC2_CLK */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 1, 0x000, 0), /* MX53_PAD_SD2_CLK__GPIO1_10 */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 2, 0x840, 2), /* MX53_PAD_SD2_CLK__KPP_COL_5 */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 3, 0x73C, 1), /* MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 5, 0x780, 3), /* MX53_PAD_SD2_CLK__CSPI_SCLK */
+ IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 7, 0x000, 0), /* MX53_PAD_SD2_CLK__SCC_RANDOM_V */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 0, 0x000, 0), /* MX53_PAD_SD2_CMD__ESDHC2_CMD */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 1, 0x000, 0), /* MX53_PAD_SD2_CMD__GPIO1_11 */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 2, 0x84C, 1), /* MX53_PAD_SD2_CMD__KPP_ROW_5 */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 3, 0x738, 1), /* MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 5, 0x788, 3), /* MX53_PAD_SD2_CMD__CSPI_MOSI */
+ IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 7, 0x000, 0), /* MX53_PAD_SD2_CMD__SCC_RANDOM */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 0, 0x000, 0), /* MX53_PAD_SD2_DATA3__ESDHC2_DAT3 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 1, 0x000, 0), /* MX53_PAD_SD2_DATA3__GPIO1_12 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 2, 0x844, 1), /* MX53_PAD_SD2_DATA3__KPP_COL_6 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 3, 0x740, 1), /* MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 5, 0x794, 3), /* MX53_PAD_SD2_DATA3__CSPI_SS2 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 7, 0x000, 0), /* MX53_PAD_SD2_DATA3__SJC_DONE */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 0, 0x000, 0), /* MX53_PAD_SD2_DATA2__ESDHC2_DAT2 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 1, 0x000, 0), /* MX53_PAD_SD2_DATA2__GPIO1_13 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 2, 0x850, 1), /* MX53_PAD_SD2_DATA2__KPP_ROW_6 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 3, 0x734, 1), /* MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 5, 0x790, 3), /* MX53_PAD_SD2_DATA2__CSPI_SS1 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 7, 0x000, 0), /* MX53_PAD_SD2_DATA2__SJC_FAIL */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 0, 0x000, 0), /* MX53_PAD_SD2_DATA1__ESDHC2_DAT1 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 1, 0x000, 0), /* MX53_PAD_SD2_DATA1__GPIO1_14 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 2, 0x848, 1), /* MX53_PAD_SD2_DATA1__KPP_COL_7 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 3, 0x744, 0), /* MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 5, 0x78C, 4), /* MX53_PAD_SD2_DATA1__CSPI_SS0 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 7, 0x000, 0), /* MX53_PAD_SD2_DATA1__RTIC_SEC_VIO */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 0, 0x000, 0), /* MX53_PAD_SD2_DATA0__ESDHC2_DAT0 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 1, 0x000, 0), /* MX53_PAD_SD2_DATA0__GPIO1_15 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 2, 0x854, 1), /* MX53_PAD_SD2_DATA0__KPP_ROW_7 */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 3, 0x730, 1), /* MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 5, 0x784, 3), /* MX53_PAD_SD2_DATA0__CSPI_MISO */
+ IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 7, 0x000, 0), /* MX53_PAD_SD2_DATA0__RTIC_DONE_INT */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 0, 0x000, 0), /* MX53_PAD_GPIO_0__CCM_CLKO */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 1, 0x000, 0), /* MX53_PAD_GPIO_0__GPIO1_0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 2, 0x840, 3), /* MX53_PAD_GPIO_0__KPP_COL_5 */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 3, 0x000, 0), /* MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 4, 0x000, 0), /* MX53_PAD_GPIO_0__EPIT1_EPITO */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 5, 0x000, 0), /* MX53_PAD_GPIO_0__SRTC_ALARM_DEB */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 6, 0x000, 0), /* MX53_PAD_GPIO_0__USBOH3_USBH1_PWR */
+ IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 7, 0x000, 0), /* MX53_PAD_GPIO_0__CSU_TD */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 0, 0x7DC, 1), /* MX53_PAD_GPIO_1__ESAI1_SCKR */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 1, 0x000, 0), /* MX53_PAD_GPIO_1__GPIO1_1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 2, 0x84C, 2), /* MX53_PAD_GPIO_1__KPP_ROW_5 */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 3, 0x000, 0), /* MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 4, 0x000, 0), /* MX53_PAD_GPIO_1__PWM2_PWMO */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 5, 0x000, 0), /* MX53_PAD_GPIO_1__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 6, 0x000, 0), /* MX53_PAD_GPIO_1__ESDHC1_CD */
+ IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 7, 0x000, 0), /* MX53_PAD_GPIO_1__SRC_TESTER_ACK */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 0, 0x7CC, 1), /* MX53_PAD_GPIO_9__ESAI1_FSR */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 1, 0x000, 0), /* MX53_PAD_GPIO_9__GPIO1_9 */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 2, 0x844, 2), /* MX53_PAD_GPIO_9__KPP_COL_6 */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 3, 0x000, 0), /* MX53_PAD_GPIO_9__CCM_REF_EN_B */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 4, 0x000, 0), /* MX53_PAD_GPIO_9__PWM1_PWMO */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 5, 0x000, 0), /* MX53_PAD_GPIO_9__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 6, 0x7FC, 1), /* MX53_PAD_GPIO_9__ESDHC1_WP */
+ IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 7, 0x000, 0), /* MX53_PAD_GPIO_9__SCC_FAIL_STATE */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 0, 0x7D4, 1), /* MX53_PAD_GPIO_3__ESAI1_HCKR */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 1, 0x000, 0), /* MX53_PAD_GPIO_3__GPIO1_3 */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 2, 0x824, 1), /* MX53_PAD_GPIO_3__I2C3_SCL */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 3, 0x000, 0), /* MX53_PAD_GPIO_3__DPLLIP1_TOG_EN */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 4, 0x000, 0), /* MX53_PAD_GPIO_3__CCM_CLKO2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 5, 0x000, 0), /* MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 6, 0x8A0, 1), /* MX53_PAD_GPIO_3__USBOH3_USBH1_OC */
+ IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 7, 0x858, 2), /* MX53_PAD_GPIO_3__MLB_MLBCLK */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 0, 0x7E0, 1), /* MX53_PAD_GPIO_6__ESAI1_SCKT */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 1, 0x000, 0), /* MX53_PAD_GPIO_6__GPIO1_6 */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 2, 0x828, 1), /* MX53_PAD_GPIO_6__I2C3_SDA */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 3, 0x000, 0), /* MX53_PAD_GPIO_6__CCM_CCM_OUT_0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 4, 0x000, 0), /* MX53_PAD_GPIO_6__CSU_CSU_INT_DEB */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 5, 0x000, 0), /* MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 6, 0x000, 0), /* MX53_PAD_GPIO_6__ESDHC2_LCTL */
+ IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 7, 0x860, 2), /* MX53_PAD_GPIO_6__MLB_MLBSIG */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 0, 0x7D0, 1), /* MX53_PAD_GPIO_2__ESAI1_FST */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 1, 0x000, 0), /* MX53_PAD_GPIO_2__GPIO1_2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 2, 0x850, 2), /* MX53_PAD_GPIO_2__KPP_ROW_6 */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 3, 0x000, 0), /* MX53_PAD_GPIO_2__CCM_CCM_OUT_1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 4, 0x000, 0), /* MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 5, 0x000, 0), /* MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 6, 0x000, 0), /* MX53_PAD_GPIO_2__ESDHC2_WP */
+ IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 7, 0x85C, 2), /* MX53_PAD_GPIO_2__MLB_MLBDAT */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 0, 0x7D8, 1), /* MX53_PAD_GPIO_4__ESAI1_HCKT */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 1, 0x000, 0), /* MX53_PAD_GPIO_4__GPIO1_4 */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 2, 0x848, 2), /* MX53_PAD_GPIO_4__KPP_COL_7 */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 3, 0x000, 0), /* MX53_PAD_GPIO_4__CCM_CCM_OUT_2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 4, 0x000, 0), /* MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 5, 0x000, 0), /* MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 6, 0x000, 0), /* MX53_PAD_GPIO_4__ESDHC2_CD */
+ IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 7, 0x000, 0), /* MX53_PAD_GPIO_4__SCC_SEC_STATE */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 0, 0x7EC, 1), /* MX53_PAD_GPIO_5__ESAI1_TX2_RX3 */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 1, 0x000, 0), /* MX53_PAD_GPIO_5__GPIO1_5 */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 2, 0x854, 2), /* MX53_PAD_GPIO_5__KPP_ROW_7 */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 3, 0x000, 0), /* MX53_PAD_GPIO_5__CCM_CLKO */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 4, 0x000, 0), /* MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 5, 0x000, 0), /* MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 6, 0x824, 2), /* MX53_PAD_GPIO_5__I2C3_SCL */
+ IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 7, 0x770, 1), /* MX53_PAD_GPIO_5__CCM_PLL1_BYP */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 0, 0x7F4, 1), /* MX53_PAD_GPIO_7__ESAI1_TX4_RX1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 1, 0x000, 0), /* MX53_PAD_GPIO_7__GPIO1_7 */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 2, 0x000, 0), /* MX53_PAD_GPIO_7__EPIT1_EPITO */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 3, 0x000, 0), /* MX53_PAD_GPIO_7__CAN1_TXCAN */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 4, 0x000, 0), /* MX53_PAD_GPIO_7__UART2_TXD_MUX */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 5, 0x80C, 1), /* MX53_PAD_GPIO_7__FIRI_RXD */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 6, 0x000, 0), /* MX53_PAD_GPIO_7__SPDIF_PLOCK */
+ IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 7, 0x774, 1), /* MX53_PAD_GPIO_7__CCM_PLL2_BYP */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 0, 0x7F8, 1), /* MX53_PAD_GPIO_8__ESAI1_TX5_RX0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 1, 0x000, 0), /* MX53_PAD_GPIO_8__GPIO1_8 */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 2, 0x000, 0), /* MX53_PAD_GPIO_8__EPIT2_EPITO */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 3, 0x760, 3), /* MX53_PAD_GPIO_8__CAN1_RXCAN */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 4, 0x880, 5), /* MX53_PAD_GPIO_8__UART2_RXD_MUX */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 5, 0x000, 0), /* MX53_PAD_GPIO_8__FIRI_TXD */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 6, 0x000, 0), /* MX53_PAD_GPIO_8__SPDIF_SRCLK */
+ IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 7, 0x778, 1), /* MX53_PAD_GPIO_8__CCM_PLL3_BYP */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 0, 0x7F0, 1), /* MX53_PAD_GPIO_16__ESAI1_TX3_RX2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 1, 0x000, 0), /* MX53_PAD_GPIO_16__GPIO7_11 */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 2, 0x000, 0), /* MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 4, 0x000, 0), /* MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 5, 0x870, 1), /* MX53_PAD_GPIO_16__SPDIF_IN1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 6, 0x828, 2), /* MX53_PAD_GPIO_16__I2C3_SDA */
+ IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 7, 0x000, 0), /* MX53_PAD_GPIO_16__SJC_DE_B */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 0, 0x7E4, 1), /* MX53_PAD_GPIO_17__ESAI1_TX0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 1, 0x000, 0), /* MX53_PAD_GPIO_17__GPIO7_12 */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 2, 0x868, 1), /* MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 3, 0x810, 1), /* MX53_PAD_GPIO_17__GPC_PMIC_RDY */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 4, 0x000, 0), /* MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 5, 0x000, 0), /* MX53_PAD_GPIO_17__SPDIF_OUT1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 6, 0x000, 0), /* MX53_PAD_GPIO_17__IPU_SNOOP2 */
+ IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 7, 0x000, 0), /* MX53_PAD_GPIO_17__SJC_JTAG_ACT */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 0, 0x7E8, 1), /* MX53_PAD_GPIO_18__ESAI1_TX1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 1, 0x000, 0), /* MX53_PAD_GPIO_18__GPIO7_13 */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 2, 0x86C, 1), /* MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 3, 0x864, 1), /* MX53_PAD_GPIO_18__OWIRE_LINE */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 4, 0x000, 0), /* MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 5, 0x768, 1), /* MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 6, 0x000, 0), /* MX53_PAD_GPIO_18__ESDHC1_LCTL */
+ IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 7, 0x000, 0), /* MX53_PAD_GPIO_18__SRC_SYSTEM_RST */
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_19),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_COL0),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_COL1),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_COL2),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_COL3),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_COL4),
+ IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX53_PAD_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A25),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_EB2),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D16),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D17),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D18),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D19),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D20),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D21),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D22),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D23),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_EB3),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D24),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D25),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D26),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D27),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D28),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D29),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D30),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_D31),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A24),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A23),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A22),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A21),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A20),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A19),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A18),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A17),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_A16),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_CS0),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_CS1),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_OE),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_RW),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_LBA),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_EB0),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_EB1),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA0),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA1),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA2),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA3),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA4),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA5),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA6),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA7),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA8),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA9),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA10),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA11),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA12),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA13),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA14),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_DA15),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_WE_B),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_RE_B),
+ IMX_PINCTRL_PIN(MX53_PAD_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX3_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX2_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS1_CLK_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX1_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX0_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX3_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS0_CLK_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX2_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX1_P),
+ IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX0_P),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_10),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_11),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_12),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_13),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_14),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_MDIO),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_REF_CLK),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_RX_ER),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_CRS_DV),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_RXD1),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_RXD0),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_TX_EN),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_TXD1),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_TXD0),
+ IMX_PINCTRL_PIN(MX53_PAD_FEC_MDC),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DIOW),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DMACK),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DMARQ),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_BUFFER_EN),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_INTRQ),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DIOR),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_RESET_B),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_IORDY),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_0),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_1),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_2),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_CS_0),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_CS_1),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA0),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA1),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA2),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA3),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA4),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA5),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA6),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA7),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA8),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA9),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA10),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA11),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA12),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA13),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA14),
+ IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA15),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_CMD),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_CLK),
+ IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_CLK),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_CMD),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_0),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_1),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_9),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_3),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_6),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_2),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_4),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_5),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_7),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_8),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_16),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_17),
+ IMX_PINCTRL_PIN(MX53_PAD_GPIO_18),
+};
+
+static struct imx_pinctrl_soc_info imx53_pinctrl_info = {
+ .pins = imx53_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx53_pinctrl_pads),
+ .pin_regs = imx53_pin_regs,
+ .npin_regs = ARRAY_SIZE(imx53_pin_regs),
+};
+
+static struct of_device_id imx53_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "fsl,imx53-iomuxc", },
+ { /* sentinel */ }
+};
+
+static int __devinit imx53_pinctrl_probe(struct platform_device *pdev)
+{
+ return imx_pinctrl_probe(pdev, &imx53_pinctrl_info);
+}
+
+static struct platform_driver imx53_pinctrl_driver = {
+ .driver = {
+ .name = "imx53-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx53_pinctrl_of_match),
+ },
+ .probe = imx53_pinctrl_probe,
+ .remove = __devexit_p(imx_pinctrl_remove),
+};
+
+static int __init imx53_pinctrl_init(void)
+{
+ return platform_driver_register(&imx53_pinctrl_driver);
+}
+arch_initcall(imx53_pinctrl_init);
+
+static void __exit imx53_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx53_pinctrl_driver);
+}
+module_exit(imx53_pinctrl_exit);
+MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
+MODULE_DESCRIPTION("Freescale IMX53 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c
new file mode 100644
index 0000000..7737d4d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-imx6q.c
@@ -0,0 +1,2331 @@
+/*
+ * imx6q pinctrl driver based on imx pinmux core
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx6q_pads {
+ MX6Q_PAD_SD2_DAT1 = 0,
+ MX6Q_PAD_SD2_DAT2 = 1,
+ MX6Q_PAD_SD2_DAT0 = 2,
+ MX6Q_PAD_RGMII_TXC = 3,
+ MX6Q_PAD_RGMII_TD0 = 4,
+ MX6Q_PAD_RGMII_TD1 = 5,
+ MX6Q_PAD_RGMII_TD2 = 6,
+ MX6Q_PAD_RGMII_TD3 = 7,
+ MX6Q_PAD_RGMII_RX_CTL = 8,
+ MX6Q_PAD_RGMII_RD0 = 9,
+ MX6Q_PAD_RGMII_TX_CTL = 10,
+ MX6Q_PAD_RGMII_RD1 = 11,
+ MX6Q_PAD_RGMII_RD2 = 12,
+ MX6Q_PAD_RGMII_RD3 = 13,
+ MX6Q_PAD_RGMII_RXC = 14,
+ MX6Q_PAD_EIM_A25 = 15,
+ MX6Q_PAD_EIM_EB2 = 16,
+ MX6Q_PAD_EIM_D16 = 17,
+ MX6Q_PAD_EIM_D17 = 18,
+ MX6Q_PAD_EIM_D18 = 19,
+ MX6Q_PAD_EIM_D19 = 20,
+ MX6Q_PAD_EIM_D20 = 21,
+ MX6Q_PAD_EIM_D21 = 22,
+ MX6Q_PAD_EIM_D22 = 23,
+ MX6Q_PAD_EIM_D23 = 24,
+ MX6Q_PAD_EIM_EB3 = 25,
+ MX6Q_PAD_EIM_D24 = 26,
+ MX6Q_PAD_EIM_D25 = 27,
+ MX6Q_PAD_EIM_D26 = 28,
+ MX6Q_PAD_EIM_D27 = 29,
+ MX6Q_PAD_EIM_D28 = 30,
+ MX6Q_PAD_EIM_D29 = 31,
+ MX6Q_PAD_EIM_D30 = 32,
+ MX6Q_PAD_EIM_D31 = 33,
+ MX6Q_PAD_EIM_A24 = 34,
+ MX6Q_PAD_EIM_A23 = 35,
+ MX6Q_PAD_EIM_A22 = 36,
+ MX6Q_PAD_EIM_A21 = 37,
+ MX6Q_PAD_EIM_A20 = 38,
+ MX6Q_PAD_EIM_A19 = 39,
+ MX6Q_PAD_EIM_A18 = 40,
+ MX6Q_PAD_EIM_A17 = 41,
+ MX6Q_PAD_EIM_A16 = 42,
+ MX6Q_PAD_EIM_CS0 = 43,
+ MX6Q_PAD_EIM_CS1 = 44,
+ MX6Q_PAD_EIM_OE = 45,
+ MX6Q_PAD_EIM_RW = 46,
+ MX6Q_PAD_EIM_LBA = 47,
+ MX6Q_PAD_EIM_EB0 = 48,
+ MX6Q_PAD_EIM_EB1 = 49,
+ MX6Q_PAD_EIM_DA0 = 50,
+ MX6Q_PAD_EIM_DA1 = 51,
+ MX6Q_PAD_EIM_DA2 = 52,
+ MX6Q_PAD_EIM_DA3 = 53,
+ MX6Q_PAD_EIM_DA4 = 54,
+ MX6Q_PAD_EIM_DA5 = 55,
+ MX6Q_PAD_EIM_DA6 = 56,
+ MX6Q_PAD_EIM_DA7 = 57,
+ MX6Q_PAD_EIM_DA8 = 58,
+ MX6Q_PAD_EIM_DA9 = 59,
+ MX6Q_PAD_EIM_DA10 = 60,
+ MX6Q_PAD_EIM_DA11 = 61,
+ MX6Q_PAD_EIM_DA12 = 62,
+ MX6Q_PAD_EIM_DA13 = 63,
+ MX6Q_PAD_EIM_DA14 = 64,
+ MX6Q_PAD_EIM_DA15 = 65,
+ MX6Q_PAD_EIM_WAIT = 66,
+ MX6Q_PAD_EIM_BCLK = 67,
+ MX6Q_PAD_DI0_DISP_CLK = 68,
+ MX6Q_PAD_DI0_PIN15 = 69,
+ MX6Q_PAD_DI0_PIN2 = 70,
+ MX6Q_PAD_DI0_PIN3 = 71,
+ MX6Q_PAD_DI0_PIN4 = 72,
+ MX6Q_PAD_DISP0_DAT0 = 73,
+ MX6Q_PAD_DISP0_DAT1 = 74,
+ MX6Q_PAD_DISP0_DAT2 = 75,
+ MX6Q_PAD_DISP0_DAT3 = 76,
+ MX6Q_PAD_DISP0_DAT4 = 77,
+ MX6Q_PAD_DISP0_DAT5 = 78,
+ MX6Q_PAD_DISP0_DAT6 = 79,
+ MX6Q_PAD_DISP0_DAT7 = 80,
+ MX6Q_PAD_DISP0_DAT8 = 81,
+ MX6Q_PAD_DISP0_DAT9 = 82,
+ MX6Q_PAD_DISP0_DAT10 = 83,
+ MX6Q_PAD_DISP0_DAT11 = 84,
+ MX6Q_PAD_DISP0_DAT12 = 85,
+ MX6Q_PAD_DISP0_DAT13 = 86,
+ MX6Q_PAD_DISP0_DAT14 = 87,
+ MX6Q_PAD_DISP0_DAT15 = 88,
+ MX6Q_PAD_DISP0_DAT16 = 89,
+ MX6Q_PAD_DISP0_DAT17 = 90,
+ MX6Q_PAD_DISP0_DAT18 = 91,
+ MX6Q_PAD_DISP0_DAT19 = 92,
+ MX6Q_PAD_DISP0_DAT20 = 93,
+ MX6Q_PAD_DISP0_DAT21 = 94,
+ MX6Q_PAD_DISP0_DAT22 = 95,
+ MX6Q_PAD_DISP0_DAT23 = 96,
+ MX6Q_PAD_ENET_MDIO = 97,
+ MX6Q_PAD_ENET_REF_CLK = 98,
+ MX6Q_PAD_ENET_RX_ER = 99,
+ MX6Q_PAD_ENET_CRS_DV = 100,
+ MX6Q_PAD_ENET_RXD1 = 101,
+ MX6Q_PAD_ENET_RXD0 = 102,
+ MX6Q_PAD_ENET_TX_EN = 103,
+ MX6Q_PAD_ENET_TXD1 = 104,
+ MX6Q_PAD_ENET_TXD0 = 105,
+ MX6Q_PAD_ENET_MDC = 106,
+ MX6Q_PAD_DRAM_D40 = 107,
+ MX6Q_PAD_DRAM_D41 = 108,
+ MX6Q_PAD_DRAM_D42 = 109,
+ MX6Q_PAD_DRAM_D43 = 110,
+ MX6Q_PAD_DRAM_D44 = 111,
+ MX6Q_PAD_DRAM_D45 = 112,
+ MX6Q_PAD_DRAM_D46 = 113,
+ MX6Q_PAD_DRAM_D47 = 114,
+ MX6Q_PAD_DRAM_SDQS5 = 115,
+ MX6Q_PAD_DRAM_DQM5 = 116,
+ MX6Q_PAD_DRAM_D32 = 117,
+ MX6Q_PAD_DRAM_D33 = 118,
+ MX6Q_PAD_DRAM_D34 = 119,
+ MX6Q_PAD_DRAM_D35 = 120,
+ MX6Q_PAD_DRAM_D36 = 121,
+ MX6Q_PAD_DRAM_D37 = 122,
+ MX6Q_PAD_DRAM_D38 = 123,
+ MX6Q_PAD_DRAM_D39 = 124,
+ MX6Q_PAD_DRAM_DQM4 = 125,
+ MX6Q_PAD_DRAM_SDQS4 = 126,
+ MX6Q_PAD_DRAM_D24 = 127,
+ MX6Q_PAD_DRAM_D25 = 128,
+ MX6Q_PAD_DRAM_D26 = 129,
+ MX6Q_PAD_DRAM_D27 = 130,
+ MX6Q_PAD_DRAM_D28 = 131,
+ MX6Q_PAD_DRAM_D29 = 132,
+ MX6Q_PAD_DRAM_SDQS3 = 133,
+ MX6Q_PAD_DRAM_D30 = 134,
+ MX6Q_PAD_DRAM_D31 = 135,
+ MX6Q_PAD_DRAM_DQM3 = 136,
+ MX6Q_PAD_DRAM_D16 = 137,
+ MX6Q_PAD_DRAM_D17 = 138,
+ MX6Q_PAD_DRAM_D18 = 139,
+ MX6Q_PAD_DRAM_D19 = 140,
+ MX6Q_PAD_DRAM_D20 = 141,
+ MX6Q_PAD_DRAM_D21 = 142,
+ MX6Q_PAD_DRAM_D22 = 143,
+ MX6Q_PAD_DRAM_SDQS2 = 144,
+ MX6Q_PAD_DRAM_D23 = 145,
+ MX6Q_PAD_DRAM_DQM2 = 146,
+ MX6Q_PAD_DRAM_A0 = 147,
+ MX6Q_PAD_DRAM_A1 = 148,
+ MX6Q_PAD_DRAM_A2 = 149,
+ MX6Q_PAD_DRAM_A3 = 150,
+ MX6Q_PAD_DRAM_A4 = 151,
+ MX6Q_PAD_DRAM_A5 = 152,
+ MX6Q_PAD_DRAM_A6 = 153,
+ MX6Q_PAD_DRAM_A7 = 154,
+ MX6Q_PAD_DRAM_A8 = 155,
+ MX6Q_PAD_DRAM_A9 = 156,
+ MX6Q_PAD_DRAM_A10 = 157,
+ MX6Q_PAD_DRAM_A11 = 158,
+ MX6Q_PAD_DRAM_A12 = 159,
+ MX6Q_PAD_DRAM_A13 = 160,
+ MX6Q_PAD_DRAM_A14 = 161,
+ MX6Q_PAD_DRAM_A15 = 162,
+ MX6Q_PAD_DRAM_CAS = 163,
+ MX6Q_PAD_DRAM_CS0 = 164,
+ MX6Q_PAD_DRAM_CS1 = 165,
+ MX6Q_PAD_DRAM_RAS = 166,
+ MX6Q_PAD_DRAM_RESET = 167,
+ MX6Q_PAD_DRAM_SDBA0 = 168,
+ MX6Q_PAD_DRAM_SDBA1 = 169,
+ MX6Q_PAD_DRAM_SDCLK_0 = 170,
+ MX6Q_PAD_DRAM_SDBA2 = 171,
+ MX6Q_PAD_DRAM_SDCKE0 = 172,
+ MX6Q_PAD_DRAM_SDCLK_1 = 173,
+ MX6Q_PAD_DRAM_SDCKE1 = 174,
+ MX6Q_PAD_DRAM_SDODT0 = 175,
+ MX6Q_PAD_DRAM_SDODT1 = 176,
+ MX6Q_PAD_DRAM_SDWE = 177,
+ MX6Q_PAD_DRAM_D0 = 178,
+ MX6Q_PAD_DRAM_D1 = 179,
+ MX6Q_PAD_DRAM_D2 = 180,
+ MX6Q_PAD_DRAM_D3 = 181,
+ MX6Q_PAD_DRAM_D4 = 182,
+ MX6Q_PAD_DRAM_D5 = 183,
+ MX6Q_PAD_DRAM_SDQS0 = 184,
+ MX6Q_PAD_DRAM_D6 = 185,
+ MX6Q_PAD_DRAM_D7 = 186,
+ MX6Q_PAD_DRAM_DQM0 = 187,
+ MX6Q_PAD_DRAM_D8 = 188,
+ MX6Q_PAD_DRAM_D9 = 189,
+ MX6Q_PAD_DRAM_D10 = 190,
+ MX6Q_PAD_DRAM_D11 = 191,
+ MX6Q_PAD_DRAM_D12 = 192,
+ MX6Q_PAD_DRAM_D13 = 193,
+ MX6Q_PAD_DRAM_D14 = 194,
+ MX6Q_PAD_DRAM_SDQS1 = 195,
+ MX6Q_PAD_DRAM_D15 = 196,
+ MX6Q_PAD_DRAM_DQM1 = 197,
+ MX6Q_PAD_DRAM_D48 = 198,
+ MX6Q_PAD_DRAM_D49 = 199,
+ MX6Q_PAD_DRAM_D50 = 200,
+ MX6Q_PAD_DRAM_D51 = 201,
+ MX6Q_PAD_DRAM_D52 = 202,
+ MX6Q_PAD_DRAM_D53 = 203,
+ MX6Q_PAD_DRAM_D54 = 204,
+ MX6Q_PAD_DRAM_D55 = 205,
+ MX6Q_PAD_DRAM_SDQS6 = 206,
+ MX6Q_PAD_DRAM_DQM6 = 207,
+ MX6Q_PAD_DRAM_D56 = 208,
+ MX6Q_PAD_DRAM_SDQS7 = 209,
+ MX6Q_PAD_DRAM_D57 = 210,
+ MX6Q_PAD_DRAM_D58 = 211,
+ MX6Q_PAD_DRAM_D59 = 212,
+ MX6Q_PAD_DRAM_D60 = 213,
+ MX6Q_PAD_DRAM_DQM7 = 214,
+ MX6Q_PAD_DRAM_D61 = 215,
+ MX6Q_PAD_DRAM_D62 = 216,
+ MX6Q_PAD_DRAM_D63 = 217,
+ MX6Q_PAD_KEY_COL0 = 218,
+ MX6Q_PAD_KEY_ROW0 = 219,
+ MX6Q_PAD_KEY_COL1 = 220,
+ MX6Q_PAD_KEY_ROW1 = 221,
+ MX6Q_PAD_KEY_COL2 = 222,
+ MX6Q_PAD_KEY_ROW2 = 223,
+ MX6Q_PAD_KEY_COL3 = 224,
+ MX6Q_PAD_KEY_ROW3 = 225,
+ MX6Q_PAD_KEY_COL4 = 226,
+ MX6Q_PAD_KEY_ROW4 = 227,
+ MX6Q_PAD_GPIO_0 = 228,
+ MX6Q_PAD_GPIO_1 = 229,
+ MX6Q_PAD_GPIO_9 = 230,
+ MX6Q_PAD_GPIO_3 = 231,
+ MX6Q_PAD_GPIO_6 = 232,
+ MX6Q_PAD_GPIO_2 = 233,
+ MX6Q_PAD_GPIO_4 = 234,
+ MX6Q_PAD_GPIO_5 = 235,
+ MX6Q_PAD_GPIO_7 = 236,
+ MX6Q_PAD_GPIO_8 = 237,
+ MX6Q_PAD_GPIO_16 = 238,
+ MX6Q_PAD_GPIO_17 = 239,
+ MX6Q_PAD_GPIO_18 = 240,
+ MX6Q_PAD_GPIO_19 = 241,
+ MX6Q_PAD_CSI0_PIXCLK = 242,
+ MX6Q_PAD_CSI0_MCLK = 243,
+ MX6Q_PAD_CSI0_DATA_EN = 244,
+ MX6Q_PAD_CSI0_VSYNC = 245,
+ MX6Q_PAD_CSI0_DAT4 = 246,
+ MX6Q_PAD_CSI0_DAT5 = 247,
+ MX6Q_PAD_CSI0_DAT6 = 248,
+ MX6Q_PAD_CSI0_DAT7 = 249,
+ MX6Q_PAD_CSI0_DAT8 = 250,
+ MX6Q_PAD_CSI0_DAT9 = 251,
+ MX6Q_PAD_CSI0_DAT10 = 252,
+ MX6Q_PAD_CSI0_DAT11 = 253,
+ MX6Q_PAD_CSI0_DAT12 = 254,
+ MX6Q_PAD_CSI0_DAT13 = 255,
+ MX6Q_PAD_CSI0_DAT14 = 256,
+ MX6Q_PAD_CSI0_DAT15 = 257,
+ MX6Q_PAD_CSI0_DAT16 = 258,
+ MX6Q_PAD_CSI0_DAT17 = 259,
+ MX6Q_PAD_CSI0_DAT18 = 260,
+ MX6Q_PAD_CSI0_DAT19 = 261,
+ MX6Q_PAD_JTAG_TMS = 262,
+ MX6Q_PAD_JTAG_MOD = 263,
+ MX6Q_PAD_JTAG_TRSTB = 264,
+ MX6Q_PAD_JTAG_TDI = 265,
+ MX6Q_PAD_JTAG_TCK = 266,
+ MX6Q_PAD_JTAG_TDO = 267,
+ MX6Q_PAD_LVDS1_TX3_P = 268,
+ MX6Q_PAD_LVDS1_TX2_P = 269,
+ MX6Q_PAD_LVDS1_CLK_P = 270,
+ MX6Q_PAD_LVDS1_TX1_P = 271,
+ MX6Q_PAD_LVDS1_TX0_P = 272,
+ MX6Q_PAD_LVDS0_TX3_P = 273,
+ MX6Q_PAD_LVDS0_CLK_P = 274,
+ MX6Q_PAD_LVDS0_TX2_P = 275,
+ MX6Q_PAD_LVDS0_TX1_P = 276,
+ MX6Q_PAD_LVDS0_TX0_P = 277,
+ MX6Q_PAD_TAMPER = 278,
+ MX6Q_PAD_PMIC_ON_REQ = 279,
+ MX6Q_PAD_PMIC_STBY_REQ = 280,
+ MX6Q_PAD_POR_B = 281,
+ MX6Q_PAD_BOOT_MODE1 = 282,
+ MX6Q_PAD_RESET_IN_B = 283,
+ MX6Q_PAD_BOOT_MODE0 = 284,
+ MX6Q_PAD_TEST_MODE = 285,
+ MX6Q_PAD_SD3_DAT7 = 286,
+ MX6Q_PAD_SD3_DAT6 = 287,
+ MX6Q_PAD_SD3_DAT5 = 288,
+ MX6Q_PAD_SD3_DAT4 = 289,
+ MX6Q_PAD_SD3_CMD = 290,
+ MX6Q_PAD_SD3_CLK = 291,
+ MX6Q_PAD_SD3_DAT0 = 292,
+ MX6Q_PAD_SD3_DAT1 = 293,
+ MX6Q_PAD_SD3_DAT2 = 294,
+ MX6Q_PAD_SD3_DAT3 = 295,
+ MX6Q_PAD_SD3_RST = 296,
+ MX6Q_PAD_NANDF_CLE = 297,
+ MX6Q_PAD_NANDF_ALE = 298,
+ MX6Q_PAD_NANDF_WP_B = 299,
+ MX6Q_PAD_NANDF_RB0 = 300,
+ MX6Q_PAD_NANDF_CS0 = 301,
+ MX6Q_PAD_NANDF_CS1 = 302,
+ MX6Q_PAD_NANDF_CS2 = 303,
+ MX6Q_PAD_NANDF_CS3 = 304,
+ MX6Q_PAD_SD4_CMD = 305,
+ MX6Q_PAD_SD4_CLK = 306,
+ MX6Q_PAD_NANDF_D0 = 307,
+ MX6Q_PAD_NANDF_D1 = 308,
+ MX6Q_PAD_NANDF_D2 = 309,
+ MX6Q_PAD_NANDF_D3 = 310,
+ MX6Q_PAD_NANDF_D4 = 311,
+ MX6Q_PAD_NANDF_D5 = 312,
+ MX6Q_PAD_NANDF_D6 = 313,
+ MX6Q_PAD_NANDF_D7 = 314,
+ MX6Q_PAD_SD4_DAT0 = 315,
+ MX6Q_PAD_SD4_DAT1 = 316,
+ MX6Q_PAD_SD4_DAT2 = 317,
+ MX6Q_PAD_SD4_DAT3 = 318,
+ MX6Q_PAD_SD4_DAT4 = 319,
+ MX6Q_PAD_SD4_DAT5 = 320,
+ MX6Q_PAD_SD4_DAT6 = 321,
+ MX6Q_PAD_SD4_DAT7 = 322,
+ MX6Q_PAD_SD1_DAT1 = 323,
+ MX6Q_PAD_SD1_DAT0 = 324,
+ MX6Q_PAD_SD1_DAT3 = 325,
+ MX6Q_PAD_SD1_CMD = 326,
+ MX6Q_PAD_SD1_DAT2 = 327,
+ MX6Q_PAD_SD1_CLK = 328,
+ MX6Q_PAD_SD2_CLK = 329,
+ MX6Q_PAD_SD2_CMD = 330,
+ MX6Q_PAD_SD2_DAT3 = 331,
+};
+
+/* imx6q register maps */
+static struct imx_pin_reg imx6q_pin_regs[] = {
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__USDHC2_DAT1 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 1, 0x0834, 0), /* MX6Q_PAD_SD2_DAT1__ECSPI5_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 2, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__WEIM_WEIM_CS_2 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 3, 0x07C8, 0), /* MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 4, 0x08F0, 0), /* MX6Q_PAD_SD2_DAT1__KPP_COL_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__GPIO_1_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__CCM_WAIT */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__ANATOP_TESTO_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__USDHC2_DAT2 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 1, 0x0838, 0), /* MX6Q_PAD_SD2_DAT2__ECSPI5_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 2, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__WEIM_WEIM_CS_3 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 3, 0x07B8, 0), /* MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 4, 0x08F8, 0), /* MX6Q_PAD_SD2_DAT2__KPP_ROW_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__GPIO_1_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__CCM_STOP */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__ANATOP_TESTO_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__USDHC2_DAT0 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 1, 0x082C, 0), /* MX6Q_PAD_SD2_DAT0__ECSPI5_MISO */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 3, 0x07B4, 0), /* MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 4, 0x08FC, 0), /* MX6Q_PAD_SD2_DAT0__KPP_ROW_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__GPIO_1_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__DCIC2_DCIC_OUT */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__TESTO_2 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__USBOH3_H2_DATA */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 2, 0x0918, 0), /* MX6Q_PAD_RGMII_TXC__SPDIF_SPDIF_EXTCLK */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__GPIO_6_19 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__MIPI_CORE_DPHY_IN_0 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__ANATOP_24M_OUT */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__MIPI_HSI_CRL_TX_RDY */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__GPIO_6_20 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__MIPI_CORE_DPHY_IN_1 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__MIPI_HSI_CRL_RX_FLG */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__GPIO_6_21 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__MIPI_CORE_DPHY_IN_2 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__CCM_PLL3_BYP */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__MIPI_HSI_CRL_RX_DTA */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__GPIO_6_22 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__MIPI_CORE_DPHY_IN_3 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__CCM_PLL2_BYP */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__MIPI_HSI_CRL_RX_WAK */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__GPIO_6_23 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__MIPI_CORE_DPHY_IN_4 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__USBOH3_H3_DATA */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 1, 0x0858, 0), /* MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__GPIO_6_24 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__MIPI_DPHY_IN_5 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__MIPI_HSI_CRL_RX_RDY */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 1, 0x0848, 0), /* MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__GPIO_6_25 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__MIPI_CORE_DPHY_IN_6 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__GPIO_6_26 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__CORE_DPHY_IN_7 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 7, 0x083C, 0), /* MX6Q_PAD_RGMII_TX_CTL__ANATOP_REF_OUT */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__MIPI_HSI_CTRL_TX_FL */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 1, 0x084C, 0), /* MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__GPIO_6_27 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__CORE_DPHY_TEST_IN_8 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__SJC_FAIL */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__MIPI_HSI_CRL_TX_DTA */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 1, 0x0850, 0), /* MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__GPIO_6_28 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__MIPI_CORE_DPHY_IN_9 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__MIPI_HSI_CRL_TX_WAK */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 1, 0x0854, 0), /* MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__GPIO_6_29 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__MIPI_CORE_DPHY_IN10 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 1, 0x0844, 0), /* MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__GPIO_6_30 */
+ IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__MIPI_CORE_DPHY_IN11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A25__WEIM_WEIM_A_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A25__ECSPI4_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 2, 0x0000, 0), /* MX6Q_PAD_EIM_A25__ECSPI2_RDY */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A25__IPU1_DI1_PIN12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A25__IPU1_DI0_D1_CS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A25__GPIO_5_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 6, 0x088C, 0), /* MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A25__PL301_PER1_HBURST_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__WEIM_WEIM_EB_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 1, 0x0800, 0), /* MX6Q_PAD_EIM_EB2__ECSPI1_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 2, 0x07EC, 0), /* MX6Q_PAD_EIM_EB2__CCM_DI1_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 3, 0x08D4, 0), /* MX6Q_PAD_EIM_EB2__IPU2_CSI1_D_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 4, 0x0890, 0), /* MX6Q_PAD_EIM_EB2__HDMI_TX_DDC_SCL */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__GPIO_2_30 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 6, 0x08A0, 0), /* MX6Q_PAD_EIM_EB2__I2C2_SCL */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__SRC_BT_CFG_30 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D16__WEIM_WEIM_D_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 1, 0x07F4, 0), /* MX6Q_PAD_EIM_D16__ECSPI1_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D16__IPU1_DI0_PIN5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 3, 0x08D0, 0), /* MX6Q_PAD_EIM_D16__IPU2_CSI1_D_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 4, 0x0894, 0), /* MX6Q_PAD_EIM_D16__HDMI_TX_DDC_SDA */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D16__GPIO_3_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 6, 0x08A4, 0), /* MX6Q_PAD_EIM_D16__I2C2_SDA */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D17__WEIM_WEIM_D_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 1, 0x07F8, 0), /* MX6Q_PAD_EIM_D17__ECSPI1_MISO */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D17__IPU1_DI0_PIN6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 3, 0x08E0, 0), /* MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D17__DCIC1_DCIC_OUT */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D17__GPIO_3_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 6, 0x08A8, 0), /* MX6Q_PAD_EIM_D17__I2C3_SCL */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D17__PL301_PER1_HBURST_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D18__WEIM_WEIM_D_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 1, 0x07FC, 0), /* MX6Q_PAD_EIM_D18__ECSPI1_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D18__IPU1_DI0_PIN7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 3, 0x08CC, 0), /* MX6Q_PAD_EIM_D18__IPU2_CSI1_D_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D18__IPU1_DI1_D0_CS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D18__GPIO_3_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 6, 0x08AC, 0), /* MX6Q_PAD_EIM_D18__I2C3_SDA */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D18__PL301_PER1_HBURST_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D19__WEIM_WEIM_D_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 1, 0x0804, 0), /* MX6Q_PAD_EIM_D19__ECSPI1_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D19__IPU1_DI0_PIN8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 3, 0x08C8, 0), /* MX6Q_PAD_EIM_D19__IPU2_CSI1_D_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 4, 0x091C, 0), /* MX6Q_PAD_EIM_D19__UART1_CTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D19__GPIO_3_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D19__EPIT1_EPITO */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D19__PL301_PER1_HRESP */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D20__WEIM_WEIM_D_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 1, 0x0824, 0), /* MX6Q_PAD_EIM_D20__ECSPI4_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D20__IPU1_DI0_PIN16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 3, 0x08C4, 0), /* MX6Q_PAD_EIM_D20__IPU2_CSI1_D_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 4, 0x091C, 1), /* MX6Q_PAD_EIM_D20__UART1_RTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D20__GPIO_3_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D20__EPIT2_EPITO */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D21__WEIM_WEIM_D_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D21__ECSPI4_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D21__IPU1_DI0_PIN17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 3, 0x08B4, 0), /* MX6Q_PAD_EIM_D21__IPU2_CSI1_D_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 4, 0x0944, 0), /* MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D21__GPIO_3_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 6, 0x0898, 0), /* MX6Q_PAD_EIM_D21__I2C1_SCL */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 7, 0x0914, 0), /* MX6Q_PAD_EIM_D21__SPDIF_IN1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D22__WEIM_WEIM_D_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D22__ECSPI4_MISO */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D22__IPU1_DI0_PIN1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 3, 0x08B0, 0), /* MX6Q_PAD_EIM_D22__IPU2_CSI1_D_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D22__USBOH3_USBOTG_PWR */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D22__GPIO_3_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D22__SPDIF_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D22__PL301_PER1_HWRITE */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D23__WEIM_WEIM_D_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI0_D0_CS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 2, 0x092C, 0), /* MX6Q_PAD_EIM_D23__UART3_CTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D23__UART1_DCD */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 4, 0x08D8, 0), /* MX6Q_PAD_EIM_D23__IPU2_CSI1_DATA_EN */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D23__GPIO_3_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI1_PIN2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI1_PIN14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__WEIM_WEIM_EB_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__ECSPI4_RDY */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 2, 0x092C, 1), /* MX6Q_PAD_EIM_EB3__UART3_RTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__UART1_RI */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 4, 0x08DC, 0), /* MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__GPIO_2_31 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__IPU1_DI1_PIN3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__SRC_BT_CFG_31 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D24__WEIM_WEIM_D_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D24__ECSPI4_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D24__UART3_TXD */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 3, 0x0808, 0), /* MX6Q_PAD_EIM_D24__ECSPI1_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D24__ECSPI2_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D24__GPIO_3_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 6, 0x07D8, 0), /* MX6Q_PAD_EIM_D24__AUDMUX_AUD5_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D24__UART1_DTR */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D25__WEIM_WEIM_D_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D25__ECSPI4_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 2, 0x0930, 1), /* MX6Q_PAD_EIM_D25__UART3_RXD */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 3, 0x080C, 0), /* MX6Q_PAD_EIM_D25__ECSPI1_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D25__ECSPI2_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D25__GPIO_3_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 6, 0x07D4, 0), /* MX6Q_PAD_EIM_D25__AUDMUX_AUD5_RXC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D25__UART1_DSR */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D26__WEIM_WEIM_D_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_DI1_PIN11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_CSI0_D_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 3, 0x08C0, 0), /* MX6Q_PAD_EIM_D26__IPU2_CSI1_D_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D26__UART2_TXD */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D26__GPIO_3_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_SISG_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_DISP1_DAT_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D27__WEIM_WEIM_D_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_DI1_PIN13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_CSI0_D_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 3, 0x08BC, 0), /* MX6Q_PAD_EIM_D27__IPU2_CSI1_D_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 4, 0x0928, 1), /* MX6Q_PAD_EIM_D27__UART2_RXD */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D27__GPIO_3_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_SISG_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_DISP1_DAT_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D28__WEIM_WEIM_D_28 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 1, 0x089C, 0), /* MX6Q_PAD_EIM_D28__I2C1_SDA */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D28__ECSPI4_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 3, 0x08B8, 0), /* MX6Q_PAD_EIM_D28__IPU2_CSI1_D_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 4, 0x0924, 0), /* MX6Q_PAD_EIM_D28__UART2_CTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D28__GPIO_3_28 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D29__WEIM_WEIM_D_29 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D29__IPU1_DI1_PIN15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 2, 0x0824, 1), /* MX6Q_PAD_EIM_D29__ECSPI4_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 4, 0x0924, 1), /* MX6Q_PAD_EIM_D29__UART2_RTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D29__GPIO_3_29 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 6, 0x08E4, 0), /* MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D30__WEIM_WEIM_D_30 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_DISP1_DAT_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_DI0_PIN11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_CSI0_D_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 4, 0x092C, 2), /* MX6Q_PAD_EIM_D30__UART3_CTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D30__GPIO_3_30 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 6, 0x0948, 0), /* MX6Q_PAD_EIM_D30__USBOH3_USBH1_OC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D30__PL301_PER1_HPROT_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D31__WEIM_WEIM_D_31 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_DISP1_DAT_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_DI0_PIN12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_CSI0_D_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 4, 0x092C, 3), /* MX6Q_PAD_EIM_D31__UART3_RTS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D31__GPIO_3_31 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D31__USBOH3_USBH1_PWR */
+ IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D31__PL301_PER1_HPROT_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A24__WEIM_WEIM_A_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU1_DISP1_DAT_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 2, 0x08D4, 1), /* MX6Q_PAD_EIM_A24__IPU2_CSI1_D_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU2_SISG_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU1_SISG_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A24__GPIO_5_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A24__PL301_PER1_HPROT_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A24__SRC_BT_CFG_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A23__WEIM_WEIM_A_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU1_DISP1_DAT_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 2, 0x08D0, 1), /* MX6Q_PAD_EIM_A23__IPU2_CSI1_D_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU2_SISG_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU1_SISG_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A23__GPIO_6_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A23__PL301_PER1_HPROT_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A23__SRC_BT_CFG_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A22__WEIM_WEIM_A_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A22__IPU1_DISP1_DAT_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 2, 0x08CC, 1), /* MX6Q_PAD_EIM_A22__IPU2_CSI1_D_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A22__GPIO_2_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A22__TPSMP_HDATA_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A22__SRC_BT_CFG_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A21__WEIM_WEIM_A_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A21__IPU1_DISP1_DAT_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 2, 0x08C8, 1), /* MX6Q_PAD_EIM_A21__IPU2_CSI1_D_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A21__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A21__MIPI_CORE_DPHY_OUT_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A21__GPIO_2_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A21__TPSMP_HDATA_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A21__SRC_BT_CFG_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A20__WEIM_WEIM_A_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A20__IPU1_DISP1_DAT_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 2, 0x08C4, 1), /* MX6Q_PAD_EIM_A20__IPU2_CSI1_D_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A20__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A20__MIPI_CORE_DPHY_OUT_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A20__GPIO_2_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A20__TPSMP_HDATA_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A20__SRC_BT_CFG_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A19__WEIM_WEIM_A_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A19__IPU1_DISP1_DAT_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 2, 0x08C0, 1), /* MX6Q_PAD_EIM_A19__IPU2_CSI1_D_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A19__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A19__MIPI_CORE_DPHY_OUT_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A19__GPIO_2_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A19__TPSMP_HDATA_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A19__SRC_BT_CFG_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A18__WEIM_WEIM_A_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A18__IPU1_DISP1_DAT_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 2, 0x08BC, 1), /* MX6Q_PAD_EIM_A18__IPU2_CSI1_D_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A18__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A18__MIPI_CORE_DPHY_OUT_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A18__GPIO_2_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A18__TPSMP_HDATA_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A18__SRC_BT_CFG_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A17__WEIM_WEIM_A_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A17__IPU1_DISP1_DAT_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 2, 0x08B8, 1), /* MX6Q_PAD_EIM_A17__IPU2_CSI1_D_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A17__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A17__MIPI_CORE_DPHY_OUT_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A17__GPIO_2_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A17__TPSMP_HDATA_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A17__SRC_BT_CFG_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A16__WEIM_WEIM_A_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A16__IPU1_DI1_DISP_CLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 2, 0x08E0, 1), /* MX6Q_PAD_EIM_A16__IPU2_CSI1_PIXCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A16__MIPI_CORE_DPHY_OUT_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A16__GPIO_2_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A16__TPSMP_HDATA_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A16__SRC_BT_CFG_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__WEIM_WEIM_CS_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__IPU1_DI1_PIN5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 2, 0x0810, 0), /* MX6Q_PAD_EIM_CS0__ECSPI2_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__MIPI_CORE_DPHY_OUT_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__GPIO_2_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__TPSMP_HDATA_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__WEIM_WEIM_CS_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__IPU1_DI1_PIN6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 2, 0x0818, 0), /* MX6Q_PAD_EIM_CS1__ECSPI2_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__MIPI_CORE_DPHY_OUT_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__GPIO_2_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__TPSMP_HDATA_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 0, 0x0000, 0), /* MX6Q_PAD_EIM_OE__WEIM_WEIM_OE */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 1, 0x0000, 0), /* MX6Q_PAD_EIM_OE__IPU1_DI1_PIN7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 2, 0x0814, 0), /* MX6Q_PAD_EIM_OE__ECSPI2_MISO */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 4, 0x0000, 0), /* MX6Q_PAD_EIM_OE__MIPI_CORE_DPHY_OUT_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 5, 0x0000, 0), /* MX6Q_PAD_EIM_OE__GPIO_2_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 6, 0x0000, 0), /* MX6Q_PAD_EIM_OE__TPSMP_HDATA_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 0, 0x0000, 0), /* MX6Q_PAD_EIM_RW__WEIM_WEIM_RW */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 1, 0x0000, 0), /* MX6Q_PAD_EIM_RW__IPU1_DI1_PIN8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 2, 0x081C, 0), /* MX6Q_PAD_EIM_RW__ECSPI2_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 4, 0x0000, 0), /* MX6Q_PAD_EIM_RW__MIPI_CORE_DPHY_OUT_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 5, 0x0000, 0), /* MX6Q_PAD_EIM_RW__GPIO_2_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 6, 0x0000, 0), /* MX6Q_PAD_EIM_RW__TPSMP_HDATA_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 7, 0x0000, 0), /* MX6Q_PAD_EIM_RW__SRC_BT_CFG_29 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 0, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__WEIM_WEIM_LBA */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 1, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__IPU1_DI1_PIN17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 2, 0x0820, 0), /* MX6Q_PAD_EIM_LBA__ECSPI2_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 5, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__GPIO_2_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 6, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__TPSMP_HDATA_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 7, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__SRC_BT_CFG_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__WEIM_WEIM_EB_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__IPU1_DISP1_DAT_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 2, 0x08B4, 1), /* MX6Q_PAD_EIM_EB0__IPU2_CSI1_D_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__MIPI_CORE_DPHY_OUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 4, 0x07F0, 0), /* MX6Q_PAD_EIM_EB0__CCM_PMIC_RDY */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__GPIO_2_28 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__TPSMP_HDATA_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__SRC_BT_CFG_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__WEIM_WEIM_EB_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__IPU1_DISP1_DAT_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 2, 0x08B0, 1), /* MX6Q_PAD_EIM_EB1__IPU2_CSI1_D_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__MIPI_CORE_DPHY__OUT_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__GPIO_2_29 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__TPSMP_HDATA_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__SRC_BT_CFG_28 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__WEIM_WEIM_DA_A_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__IPU1_DISP1_DAT_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__IPU2_CSI1_D_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__MIPI_CORE_DPHY__OUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__GPIO_3_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__TPSMP_HDATA_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__SRC_BT_CFG_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__WEIM_WEIM_DA_A_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__IPU1_DISP1_DAT_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__IPU2_CSI1_D_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__MIPI_CORE_DPHY_OUT_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__USBPHY1_TX_LS_MODE */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__GPIO_3_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__TPSMP_HDATA_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__SRC_BT_CFG_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__WEIM_WEIM_DA_A_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__IPU1_DISP1_DAT_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__IPU2_CSI1_D_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__MIPI_CORE_DPHY_OUT_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__USBPHY1_TX_HS_MODE */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__GPIO_3_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__TPSMP_HDATA_16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__SRC_BT_CFG_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__WEIM_WEIM_DA_A_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__IPU1_DISP1_DAT_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__IPU2_CSI1_D_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__MIPI_CORE_DPHY_OUT_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__USBPHY1_TX_HIZ */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__GPIO_3_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__TPSMP_HDATA_17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__SRC_BT_CFG_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__WEIM_WEIM_DA_A_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__IPU1_DISP1_DAT_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__IPU2_CSI1_D_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__MIPI_CORE_DPHY_OUT_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__ANATOP_USBPHY1_TX_EN */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__GPIO_3_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__TPSMP_HDATA_18 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__SRC_BT_CFG_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__WEIM_WEIM_DA_A_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__IPU1_DISP1_DAT_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__IPU2_CSI1_D_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__MIPI_CORE_DPHY_OUT_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__ANATOP_USBPHY1_TX_DP */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__GPIO_3_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__TPSMP_HDATA_19 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__SRC_BT_CFG_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__WEIM_WEIM_DA_A_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__IPU1_DISP1_DAT_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__IPU2_CSI1_D_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__MIPI_CORE_DPHY_OUT_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__ANATOP_USBPHY1_TX_DN */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__GPIO_3_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__TPSMP_HDATA_20 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__SRC_BT_CFG_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__WEIM_WEIM_DA_A_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__IPU1_DISP1_DAT_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__IPU2_CSI1_D_2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__MIPI_CORE_DPHY_OUT_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__GPIO_3_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__TPSMP_HDATA_21 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__SRC_BT_CFG_7 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__WEIM_WEIM_DA_A_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__IPU1_DISP1_DAT_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__IPU2_CSI1_D_1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__MIPI_CORE_DPHY_OUT_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__GPIO_3_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__TPSMP_HDATA_22 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__SRC_BT_CFG_8 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__WEIM_WEIM_DA_A_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__IPU1_DISP1_DAT_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__IPU2_CSI1_D_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__MIPI_CORE_DPHY_OUT_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__GPIO_3_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__TPSMP_HDATA_23 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__SRC_BT_CFG_9 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__WEIM_WEIM_DA_A_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__IPU1_DI1_PIN15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 2, 0x08D8, 1), /* MX6Q_PAD_EIM_DA10__IPU2_CSI1_DATA_EN */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__MIPI_CORE_DPHY_OUT12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__GPIO_3_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__TPSMP_HDATA_24 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__SRC_BT_CFG_10 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__WEIM_WEIM_DA_A_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__IPU1_DI1_PIN2 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 2, 0x08DC, 1), /* MX6Q_PAD_EIM_DA11__IPU2_CSI1_HSYNC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__MIPI_CORE_DPHY_OUT13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__SDMA_DBG_EVT_CHN_6 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__GPIO_3_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__TPSMP_HDATA_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__SRC_BT_CFG_11 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__WEIM_WEIM_DA_A_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__IPU1_DI1_PIN3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 2, 0x08E4, 1), /* MX6Q_PAD_EIM_DA12__IPU2_CSI1_VSYNC */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__MIPI_CORE_DPHY_OUT14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__SDMA_DEBUG_EVT_CHN_3 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__GPIO_3_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__TPSMP_HDATA_26 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__SRC_BT_CFG_12 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__WEIM_WEIM_DA_A_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__IPU1_DI1_D0_CS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 2, 0x07EC, 1), /* MX6Q_PAD_EIM_DA13__CCM_DI1_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__MIPI_CORE_DPHY_OUT15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__SDMA_DEBUG_EVT_CHN_4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__GPIO_3_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__TPSMP_HDATA_27 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__SRC_BT_CFG_13 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__WEIM_WEIM_DA_A_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__IPU1_DI1_D1_CS */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__CCM_DI0_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__MIPI_CORE_DPHY_OUT16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__SDMA_DEBUG_EVT_CHN_5 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__GPIO_3_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__TPSMP_HDATA_28 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__SRC_BT_CFG_14 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__WEIM_WEIM_DA_A_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN1 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN4 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__MIPI_CORE_DPHY_OUT17 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__GPIO_3_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__TPSMP_HDATA_29 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__SRC_BT_CFG_15 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 0, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__WEIM_WEIM_WAIT */
+ IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 1, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__WEIM_WEIM_DTACK_B */
+ IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 5, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__GPIO_5_0 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 6, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__TPSMP_HDATA_30 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 7, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__SRC_BT_CFG_25 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 0, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__WEIM_WEIM_BCLK */
+ IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 1, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__IPU1_DI1_PIN16 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 5, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__GPIO_6_31 */
+ IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 6, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__TPSMP_HDATA_31 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 0, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DSP_CLK */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 1, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__IPU2_DI0_DSP_CLK */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 3, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__MIPI_CR_DPY_OT28 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 4, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__SDMA_DBG_CR_STA0 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 5, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__GPIO_4_16 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 6, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__MMDC_DEBUG_0 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__IPU2_DI0_PIN15 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__AUDMUX_AUD6_TXC */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__MIPI_CR_DPHY_OUT_29 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__SDMA_DBG_CORE_STA_1 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__GPIO_4_17 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__MMDC_MMDC_DEBUG_1 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__IPU2_DI0_PIN2 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__AUDMUX_AUD6_TXD */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__MIPI_CR_DPHY_OUT_30 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__SDMA_DBG_CORE_STA_2 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__GPIO_4_18 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__MMDC_DEBUG_2 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__PL301_PER1_HADDR_9 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__IPU2_DI0_PIN3 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__MIPI_CORE_DPHY_OUT31 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__SDMA_DBG_CORE_STA_3 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__GPIO_4_19 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__MMDC_MMDC_DEBUG_3 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__PL301_PER1_HADDR_10 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN4 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__IPU2_DI0_PIN4 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__AUDMUX_AUD6_RXD */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 3, 0x094C, 0), /* MX6Q_PAD_DI0_PIN4__USDHC1_WP */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__SDMA_DEBUG_YIELD */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__GPIO_4_20 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__MMDC_MMDC_DEBUG_4 */
+ IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__PL301_PER1_HADDR_11 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__IPU2_DISP0_DAT_0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__ECSPI3_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__USDHC1_USDHC_DBG_0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__SDMA_DBG_CORE_RUN */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__GPIO_4_21 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__MMDC_MMDC_DEBUG_5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__IPU2_DISP0_DAT_1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__ECSPI3_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__USDHC1_USDHC_DBG_1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__SDMA_DBG_EVT_CHNSL */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__GPIO_4_22 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__MMDC_DEBUG_6 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__PL301_PER1_HADR_12 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__IPU2_DISP0_DAT_2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__ECSPI3_MISO */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__USDHC1_USDHC_DBG_2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__SDMA_DEBUG_MODE */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__GPIO_4_23 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__MMDC_DEBUG_7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__PL301_PER1_HADR_13 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__IPU2_DISP0_DAT_3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__ECSPI3_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__USDHC1_USDHC_DBG_3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__SDMA_DBG_BUS_ERROR */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__GPIO_4_24 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__MMDC_MMDC_DBG_8 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__PL301_PER1_HADR_14 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__IPU2_DISP0_DAT_4 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__ECSPI3_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__USDHC1_USDHC_DBG_4 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__GPIO_4_25 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__MMDC_MMDC_DEBUG_9 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__PL301_PER1_HADR_15 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__IPU2_DISP0_DAT_5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__ECSPI3_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__AUDMUX_AUD6_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__SDMA_DBG_MCH_DMBUS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__GPIO_4_26 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__MMDC_DEBUG_10 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__PL301_PER1_HADR_16 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__IPU2_DISP0_DAT_6 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__ECSPI3_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__AUDMUX_AUD6_RXC */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__SDMA_DBG_RTBUF_WRT */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__GPIO_4_27 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__MMDC_DEBUG_11 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__PL301_PER1_HADR_17 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__IPU2_DISP0_DAT_7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__ECSPI3_RDY */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__USDHC1_USDHC_DBG_5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__SDMA_DBG_EVT_CHN_0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__GPIO_4_28 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__MMDC_DEBUG_12 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__PL301_PER1_HADR_18 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__IPU2_DISP0_DAT_8 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__PWM1_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__SDMA_DBG_EVT_CHN_1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__GPIO_4_29 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__MMDC_DEBUG_13 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__PL301_PER1_HADR_19 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__IPU2_DISP0_DAT_9 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__PWM2_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__SDMA_DBG_EVT_CHN_2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__GPIO_4_30 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__MMDC_DEBUG_14 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__PL301_PER1_HADR_20 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__IPU2_DISP0_DAT_10 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__USDHC1_DBG_6 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__SDMA_DBG_EVT_CHN3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__GPIO_4_31 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__MMDC_DEBUG_15 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__PL301_PER1_HADR21 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__IPU2_DISP0_DAT_11 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__USDHC1_USDHC_DBG7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__SDMA_DBG_EVT_CHN4 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__GPIO_5_5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__MMDC_DEBUG_16 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__PL301_PER1_HADR22 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__IPU2_DISP0_DAT_12 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__SDMA_DBG_EVT_CHN5 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__GPIO_5_6 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__MMDC_DEBUG_17 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__PL301_PER1_HADR23 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__IPU2_DISP0_DAT_13 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 3, 0x07D8, 1), /* MX6Q_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__SDMA_DBG_EVT_CHN0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__GPIO_5_7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__MMDC_DEBUG_18 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__PL301_PER1_HADR24 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__IPU2_DISP0_DAT_14 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 3, 0x07D4, 1), /* MX6Q_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__SDMA_DBG_EVT_CHN1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__GPIO_5_8 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__MMDC_DEBUG_19 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__IPU2_DISP0_DAT_15 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 2, 0x0804, 1), /* MX6Q_PAD_DISP0_DAT15__ECSPI1_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 3, 0x0820, 1), /* MX6Q_PAD_DISP0_DAT15__ECSPI2_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__SDMA_DBG_EVT_CHN2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__GPIO_5_9 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__MMDC_DEBUG_20 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__PL301_PER1_HADR25 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__IPU2_DISP0_DAT_16 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 2, 0x0818, 1), /* MX6Q_PAD_DISP0_DAT16__ECSPI2_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 3, 0x07DC, 0), /* MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 4, 0x090C, 0), /* MX6Q_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__GPIO_5_10 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__MMDC_DEBUG_21 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__PL301_PER1_HADR26 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__IPU2_DISP0_DAT_17 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 2, 0x0814, 1), /* MX6Q_PAD_DISP0_DAT17__ECSPI2_MISO */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 3, 0x07D0, 0), /* MX6Q_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 4, 0x0910, 0), /* MX6Q_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__GPIO_5_11 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__MMDC_DEBUG_22 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__PL301_PER1_HADR27 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__IPU2_DISP0_DAT_18 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 2, 0x081C, 1), /* MX6Q_PAD_DISP0_DAT18__ECSPI2_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 3, 0x07E0, 0), /* MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 4, 0x07C0, 0), /* MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__GPIO_5_12 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__MMDC_DEBUG_23 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__WEIM_WEIM_CS_2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__IPU2_DISP0_DAT_19 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 2, 0x0810, 1), /* MX6Q_PAD_DISP0_DAT19__ECSPI2_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 3, 0x07CC, 0), /* MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 4, 0x07BC, 0), /* MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__GPIO_5_13 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__MMDC_DEBUG_24 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__WEIM_WEIM_CS_3 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__IPU2_DISP0_DAT_20 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 2, 0x07F4, 1), /* MX6Q_PAD_DISP0_DAT20__ECSPI1_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 3, 0x07C4, 0), /* MX6Q_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__SDMA_DBG_EVT_CHN7 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__GPIO_5_14 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__MMDC_DEBUG_25 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__PL301_PER1_HADR28 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__IPU2_DISP0_DAT_21 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 2, 0x07FC, 1), /* MX6Q_PAD_DISP0_DAT21__ECSPI1_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 3, 0x07B8, 1), /* MX6Q_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__SDMA_DBG_BUS_DEV0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__GPIO_5_15 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__MMDC_DEBUG_26 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__PL301_PER1_HADR29 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__IPU2_DISP0_DAT_22 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 2, 0x07F8, 1), /* MX6Q_PAD_DISP0_DAT22__ECSPI1_MISO */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 3, 0x07C8, 1), /* MX6Q_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__SDMA_DBG_BUS_DEV1 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__GPIO_5_16 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__MMDC_DEBUG_27 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__PL301_PER1_HADR30 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__IPU2_DISP0_DAT_23 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 2, 0x0800, 1), /* MX6Q_PAD_DISP0_DAT23__ECSPI1_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 3, 0x07B4, 1), /* MX6Q_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__SDMA_DBG_BUS_DEV2 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__GPIO_5_17 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__MMDC_DEBUG_28 */
+ IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__PL301_PER1_HADR31 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 0, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__RESERVED_RESERVED */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 1, 0x0840, 0), /* MX6Q_PAD_ENET_MDIO__ENET_MDIO */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 2, 0x086C, 0), /* MX6Q_PAD_ENET_MDIO__ESAI1_SCKR */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 3, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__SDMA_DEBUG_BUS_DEV3 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 4, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__ENET_1588_EVT1_OUT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__GPIO_1_22 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__SPDIF_PLOCK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 0, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__RESERVED_RSRVED */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 1, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 2, 0x085C, 0), /* MX6Q_PAD_ENET_REF_CLK__ESAI1_FSR */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 3, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__SDMA_DBGBUS_DEV4 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__GPIO_1_23 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__SPDIF_SRCLK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__USBPHY1_RX_SQH */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 1, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ENET_RX_ER */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 2, 0x0864, 0), /* MX6Q_PAD_ENET_RX_ER__ESAI1_HCKR */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 3, 0x0914, 1), /* MX6Q_PAD_ENET_RX_ER__SPDIF_IN1 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 4, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ENET_1588_EVT2_OUT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__GPIO_1_24 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__PHY_TDI */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__USBPHY1_RX_HS_RXD */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 0, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__RESERVED_RSRVED */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 1, 0x0858, 1), /* MX6Q_PAD_ENET_CRS_DV__ENET_RX_EN */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 2, 0x0870, 0), /* MX6Q_PAD_ENET_CRS_DV__ESAI1_SCKT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 3, 0x0918, 1), /* MX6Q_PAD_ENET_CRS_DV__SPDIF_EXTCLK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 5, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__GPIO_1_25 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 6, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__PHY_TDO */
+ IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 7, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__USBPHY1_RX_FS_RXD */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 0, 0x0908, 0), /* MX6Q_PAD_ENET_RXD1__MLB_MLBSIG */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 1, 0x084C, 1), /* MX6Q_PAD_ENET_RXD1__ENET_RDATA_1 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 2, 0x0860, 0), /* MX6Q_PAD_ENET_RXD1__ESAI1_FST */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 4, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__ENET_1588_EVT3_OUT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__GPIO_1_26 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__PHY_TCK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__USBPHY1_RX_DISCON */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 0, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__OSC32K_32K_OUT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 1, 0x0848, 1), /* MX6Q_PAD_ENET_RXD0__ENET_RDATA_0 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 2, 0x0868, 0), /* MX6Q_PAD_ENET_RXD0__ESAI1_HCKT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 3, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__SPDIF_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__GPIO_1_27 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__PHY_TMS */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__USBPHY1_PLL_CK20DIV */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 0, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__RESERVED_RSRVED */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__ENET_TX_EN */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 2, 0x0880, 0), /* MX6Q_PAD_ENET_TX_EN__ESAI1_TX3_RX2 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__GPIO_1_28 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__SATA_PHY_TDI */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__USBPHY2_RX_SQH */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 0, 0x0900, 0), /* MX6Q_PAD_ENET_TXD1__MLB_MLBCLK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__ENET_TDATA_1 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 2, 0x087C, 0), /* MX6Q_PAD_ENET_TXD1__ESAI1_TX2_RX3 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 4, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__ENET_1588_EVENT0_IN */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__GPIO_1_29 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__SATA_PHY_TDO */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__USBPHY2_RX_HS_RXD */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 0, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__RESERVED_RSRVED */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__ENET_TDATA_0 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 2, 0x0884, 0), /* MX6Q_PAD_ENET_TXD0__ESAI1_TX4_RX1 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__GPIO_1_30 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__SATA_PHY_TCK */
+ IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__USBPHY2_RX_FS_RXD */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 0, 0x0904, 0), /* MX6Q_PAD_ENET_MDC__MLB_MLBDAT */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 1, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__ENET_MDC */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 2, 0x0888, 0), /* MX6Q_PAD_ENET_MDC__ESAI1_TX5_RX0 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 4, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__ENET_1588_EVENT1_IN */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__GPIO_1_31 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__SATA_PHY_TMS */
+ IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__USBPHY2_RX_DISCON */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D40, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D40__MMDC_DRAM_D_40 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D41, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D41__MMDC_DRAM_D_41 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D42, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D42__MMDC_DRAM_D_42 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D43, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D43__MMDC_DRAM_D_43 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D44, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D44__MMDC_DRAM_D_44 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D45, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D45__MMDC_DRAM_D_45 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D46, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D46__MMDC_DRAM_D_46 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D47, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D47__MMDC_DRAM_D_47 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS5, 0x050C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS5__MMDC_DRAM_SDQS_5 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM5, 0x0510, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM5__MMDC_DRAM_DQM_5 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D32, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D32__MMDC_DRAM_D_32 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D33, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D33__MMDC_DRAM_D_33 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D34, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D34__MMDC_DRAM_D_34 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D35, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D35__MMDC_DRAM_D_35 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D36, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D36__MMDC_DRAM_D_36 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D37, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D37__MMDC_DRAM_D_37 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D38, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D38__MMDC_DRAM_D_38 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D39, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D39__MMDC_DRAM_D_39 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM4, 0x0514, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM4__MMDC_DRAM_DQM_4 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS4, 0x0518, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS4__MMDC_DRAM_SDQS_4 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D24, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D24__MMDC_DRAM_D_24 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D25, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D25__MMDC_DRAM_D_25 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D26, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D26__MMDC_DRAM_D_26 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D27, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D27__MMDC_DRAM_D_27 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D28, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D28__MMDC_DRAM_D_28 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D29, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D29__MMDC_DRAM_D_29 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS3, 0x051C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS3__MMDC_DRAM_SDQS_3 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D30, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D30__MMDC_DRAM_D_30 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D31, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D31__MMDC_DRAM_D_31 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM3, 0x0520, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM3__MMDC_DRAM_DQM_3 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D16, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D16__MMDC_DRAM_D_16 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D17, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D17__MMDC_DRAM_D_17 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D18, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D18__MMDC_DRAM_D_18 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D19, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D19__MMDC_DRAM_D_19 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D20, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D20__MMDC_DRAM_D_20 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D21, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D21__MMDC_DRAM_D_21 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D22, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D22__MMDC_DRAM_D_22 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS2, 0x0524, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS2__MMDC_DRAM_SDQS_2 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D23, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D23__MMDC_DRAM_D_23 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM2, 0x0528, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM2__MMDC_DRAM_DQM_2 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A0, 0x052C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A0__MMDC_DRAM_A_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A1, 0x0530, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A1__MMDC_DRAM_A_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A2, 0x0534, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A2__MMDC_DRAM_A_2 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A3, 0x0538, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A3__MMDC_DRAM_A_3 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A4, 0x053C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A4__MMDC_DRAM_A_4 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A5, 0x0540, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A5__MMDC_DRAM_A_5 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A6, 0x0544, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A6__MMDC_DRAM_A_6 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A7, 0x0548, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A7__MMDC_DRAM_A_7 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A8, 0x054C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A8__MMDC_DRAM_A_8 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A9, 0x0550, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A9__MMDC_DRAM_A_9 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A10, 0x0554, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A10__MMDC_DRAM_A_10 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A11, 0x0558, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A11__MMDC_DRAM_A_11 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A12, 0x055C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A12__MMDC_DRAM_A_12 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A13, 0x0560, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A13__MMDC_DRAM_A_13 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A14, 0x0564, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A14__MMDC_DRAM_A_14 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_A15, 0x0568, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A15__MMDC_DRAM_A_15 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_CAS, 0x056C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CAS__MMDC_DRAM_CAS */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_CS0, 0x0570, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CS0__MMDC_DRAM_CS_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_CS1, 0x0574, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CS1__MMDC_DRAM_CS_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_RAS, 0x0578, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_RAS__MMDC_DRAM_RAS */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_RESET, 0x057C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_RESET__MMDC_DRAM_RESET */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA0, 0x0580, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA0__MMDC_DRAM_SDBA_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA1, 0x0584, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA1__MMDC_DRAM_SDBA_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDCLK_0, 0x0588, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCLK_0__MMDC_DRAM_SDCLK0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA2, 0x058C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA2__MMDC_DRAM_SDBA_2 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDCKE0, 0x0590, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCKE0__MMDC_DRAM_SDCKE_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDCLK_1, 0x0594, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCLK_1__MMDC_DRAM_SDCLK1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDCKE1, 0x0598, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCKE1__MMDC_DRAM_SDCKE_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDODT0, 0x059C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDODT0__MMDC_DRAM_ODT_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDODT1, 0x05A0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDODT1__MMDC_DRAM_ODT_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDWE, 0x05A4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDWE__MMDC_DRAM_SDWE */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D0, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D0__MMDC_DRAM_D_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D1, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D1__MMDC_DRAM_D_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D2, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D2__MMDC_DRAM_D_2 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D3, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D3__MMDC_DRAM_D_3 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D4, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D4__MMDC_DRAM_D_4 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D5, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D5__MMDC_DRAM_D_5 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS0, 0x05A8, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS0__MMDC_DRAM_SDQS_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D6, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D6__MMDC_DRAM_D_6 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D7, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D7__MMDC_DRAM_D_7 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM0, 0x05AC, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM0__MMDC_DRAM_DQM_0 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D8, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D8__MMDC_DRAM_D_8 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D9, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D9__MMDC_DRAM_D_9 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D10, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D10__MMDC_DRAM_D_10 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D11, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D11__MMDC_DRAM_D_11 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D12, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D12__MMDC_DRAM_D_12 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D13, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D13__MMDC_DRAM_D_13 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D14, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D14__MMDC_DRAM_D_14 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS1, 0x05B0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS1__MMDC_DRAM_SDQS_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D15, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D15__MMDC_DRAM_D_15 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM1, 0x05B4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM1__MMDC_DRAM_DQM_1 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D48, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D48__MMDC_DRAM_D_48 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D49, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D49__MMDC_DRAM_D_49 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D50, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D50__MMDC_DRAM_D_50 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D51, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D51__MMDC_DRAM_D_51 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D52, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D52__MMDC_DRAM_D_52 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D53, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D53__MMDC_DRAM_D_53 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D54, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D54__MMDC_DRAM_D_54 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D55, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D55__MMDC_DRAM_D_55 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS6, 0x05B8, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS6__MMDC_DRAM_SDQS_6 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM6, 0x05BC, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM6__MMDC_DRAM_DQM_6 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D56, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D56__MMDC_DRAM_D_56 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS7, 0x05C0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS7__MMDC_DRAM_SDQS_7 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D57, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D57__MMDC_DRAM_D_57 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D58, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D58__MMDC_DRAM_D_58 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D59, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D59__MMDC_DRAM_D_59 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D60, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D60__MMDC_DRAM_D_60 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_DQM7, 0x05C4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM7__MMDC_DRAM_DQM_7 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D61, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D61__MMDC_DRAM_D_61 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D62, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D62__MMDC_DRAM_D_62 */
+ IMX_PIN_REG(MX6Q_PAD_DRAM_D63, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D63__MMDC_DRAM_D_63 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 0, 0x07F4, 2), /* MX6Q_PAD_KEY_COL0__ECSPI1_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 1, 0x0854, 1), /* MX6Q_PAD_KEY_COL0__ENET_RDATA_3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 2, 0x07DC, 1), /* MX6Q_PAD_KEY_COL0__AUDMUX_AUD5_TXC */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__KPP_COL_0 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__UART4_TXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__GPIO_4_6 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__DCIC1_DCIC_OUT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__SRC_ANY_PU_RST */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 0, 0x07FC, 2), /* MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__ENET_TDATA_3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 2, 0x07D0, 1), /* MX6Q_PAD_KEY_ROW0__AUDMUX_AUD5_TXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__KPP_ROW_0 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 4, 0x0938, 1), /* MX6Q_PAD_KEY_ROW0__UART4_RXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__GPIO_4_7 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__DCIC2_DCIC_OUT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__PL301_PER1_HADR_0 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 0, 0x07F8, 2), /* MX6Q_PAD_KEY_COL1__ECSPI1_MISO */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 1, 0x0840, 1), /* MX6Q_PAD_KEY_COL1__ENET_MDIO */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 2, 0x07E0, 1), /* MX6Q_PAD_KEY_COL1__AUDMUX_AUD5_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__KPP_COL_1 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__UART5_TXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__GPIO_4_8 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__USDHC1_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__PL301MX_PER1_HADR_1 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 0, 0x0800, 2), /* MX6Q_PAD_KEY_ROW1__ECSPI1_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__ENET_COL */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 2, 0x07CC, 1), /* MX6Q_PAD_KEY_ROW1__AUDMUX_AUD5_RXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__KPP_ROW_1 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 4, 0x0940, 1), /* MX6Q_PAD_KEY_ROW1__UART5_RXD */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__GPIO_4_9 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__USDHC2_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__PL301_PER1_HADDR_2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 0, 0x0804, 2), /* MX6Q_PAD_KEY_COL2__ECSPI1_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 1, 0x0850, 1), /* MX6Q_PAD_KEY_COL2__ENET_RDATA_2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 2, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__CAN1_TXCAN */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__KPP_COL_2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__ENET_MDC */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__GPIO_4_10 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__USBOH3_H1_PWRCTL_WKP */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__PL301_PER1_HADDR_3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 0, 0x0808, 1), /* MX6Q_PAD_KEY_ROW2__ECSPI1_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__ENET_TDATA_2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 2, 0x07E4, 0), /* MX6Q_PAD_KEY_ROW2__CAN1_RXCAN */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__KPP_ROW_2 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 4, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__USDHC2_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__GPIO_4_11 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 6, 0x088C, 1), /* MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__PL301_PER1_HADR_4 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 0, 0x080C, 1), /* MX6Q_PAD_KEY_COL3__ECSPI1_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 1, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__ENET_CRS */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 2, 0x0890, 1), /* MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__KPP_COL_3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 4, 0x08A0, 1), /* MX6Q_PAD_KEY_COL3__I2C2_SCL */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__GPIO_4_12 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 6, 0x0914, 2), /* MX6Q_PAD_KEY_COL3__SPDIF_IN1 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__PL301_PER1_HADR_5 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 0, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__OSC32K_32K_OUT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 1, 0x07B0, 0), /* MX6Q_PAD_KEY_ROW3__ASRC_ASRC_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 2, 0x0894, 1), /* MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__KPP_ROW_3 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 4, 0x08A4, 1), /* MX6Q_PAD_KEY_ROW3__I2C2_SDA */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__GPIO_4_13 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__USDHC1_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__PL301_PER1_HADR_6 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 0, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__CAN2_TXCAN */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 1, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__IPU1_SISG_4 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 2, 0x0944, 1), /* MX6Q_PAD_KEY_COL4__USBOH3_USBOTG_OC */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__KPP_COL_4 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 4, 0x093C, 0), /* MX6Q_PAD_KEY_COL4__UART5_RTS */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__GPIO_4_14 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__MMDC_DEBUG_49 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__PL301_PER1_HADDR_7 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 0, 0x07E8, 0), /* MX6Q_PAD_KEY_ROW4__CAN2_RXCAN */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__IPU1_SISG_5 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 2, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__USBOH3_USBOTG_PWR */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__KPP_ROW_4 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 4, 0x093C, 1), /* MX6Q_PAD_KEY_ROW4__UART5_CTS */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__GPIO_4_15 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__MMDC_DEBUG_50 */
+ IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__PL301_PER1_HADR_8 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 0, 0x0000, 0), /* MX6Q_PAD_GPIO_0__CCM_CLKO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 2, 0x08E8, 0), /* MX6Q_PAD_GPIO_0__KPP_COL_5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 3, 0x07B0, 1), /* MX6Q_PAD_GPIO_0__ASRC_ASRC_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_0__EPIT1_EPITO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_0__GPIO_1_0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_0__USBOH3_USBH1_PWR */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_0__SNVS_HP_WRAP_SNVS_VIO5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 0, 0x086C, 1), /* MX6Q_PAD_GPIO_1__ESAI1_SCKR */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_1__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 2, 0x08F4, 0), /* MX6Q_PAD_GPIO_1__KPP_ROW_5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_1__PWM2_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_1__GPIO_1_1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_1__USDHC1_CD */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_1__SRC_TESTER_ACK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 0, 0x085C, 1), /* MX6Q_PAD_GPIO_9__ESAI1_FSR */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_9__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 2, 0x08EC, 0), /* MX6Q_PAD_GPIO_9__KPP_COL_6 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_9__CCM_REF_EN_B */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_9__PWM1_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_9__GPIO_1_9 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 6, 0x094C, 1), /* MX6Q_PAD_GPIO_9__USDHC1_WP */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_9__SRC_EARLY_RST */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 0, 0x0864, 1), /* MX6Q_PAD_GPIO_3__ESAI1_HCKR */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_3__OBSERVE_MUX_INT_OUT0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 2, 0x08A8, 1), /* MX6Q_PAD_GPIO_3__I2C3_SCL */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_3__ANATOP_24M_OUT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_3__CCM_CLKO2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_3__GPIO_1_3 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 6, 0x0948, 1), /* MX6Q_PAD_GPIO_3__USBOH3_USBH1_OC */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 7, 0x0900, 1), /* MX6Q_PAD_GPIO_3__MLB_MLBCLK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 0, 0x0870, 1), /* MX6Q_PAD_GPIO_6__ESAI1_SCKT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_6__OBSERVE_MUX_INT_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 2, 0x08AC, 1), /* MX6Q_PAD_GPIO_6__I2C3_SDA */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_6__CCM_CCM_OUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_6__CSU_CSU_INT_DEB */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_6__GPIO_1_6 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_6__USDHC2_LCTL */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 7, 0x0908, 1), /* MX6Q_PAD_GPIO_6__MLB_MLBSIG */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 0, 0x0860, 1), /* MX6Q_PAD_GPIO_2__ESAI1_FST */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_2__OBSERVE_MUX_INT_OUT2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 2, 0x08F8, 1), /* MX6Q_PAD_GPIO_2__KPP_ROW_6 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_2__CCM_CCM_OUT_1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_2__GPIO_1_2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_2__USDHC2_WP */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 7, 0x0904, 1), /* MX6Q_PAD_GPIO_2__MLB_MLBDAT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 0, 0x0868, 1), /* MX6Q_PAD_GPIO_4__ESAI1_HCKT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_4__OBSERVE_MUX_INT_OUT3 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 2, 0x08F0, 1), /* MX6Q_PAD_GPIO_4__KPP_COL_7 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_4__CCM_CCM_OUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_4__GPIO_1_4 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_4__USDHC2_CD */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_4__OCOTP_CRL_WRAR_FUSE_LA */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 0, 0x087C, 1), /* MX6Q_PAD_GPIO_5__ESAI1_TX2_RX3 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_5__OBSERVE_MUX_INT_OUT4 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 2, 0x08FC, 1), /* MX6Q_PAD_GPIO_5__KPP_ROW_7 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CCM_CLKO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_5__GPIO_1_5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 6, 0x08A8, 2), /* MX6Q_PAD_GPIO_5__I2C3_SCL */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CHEETAH_EVENTI */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 0, 0x0884, 1), /* MX6Q_PAD_GPIO_7__ESAI1_TX4_RX1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_7__ECSPI5_RDY */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_7__EPIT1_EPITO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_7__CAN1_TXCAN */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_7__UART2_TXD */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_7__GPIO_1_7 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_7__SPDIF_PLOCK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_7__USBOH3_OTGUSB_HST_MODE */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 0, 0x0888, 1), /* MX6Q_PAD_GPIO_8__ESAI1_TX5_RX0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_8__ANATOP_ANATOP_32K_OUT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_8__EPIT2_EPITO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 3, 0x07E4, 1), /* MX6Q_PAD_GPIO_8__CAN1_RXCAN */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 4, 0x0928, 3), /* MX6Q_PAD_GPIO_8__UART2_RXD */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_8__GPIO_1_8 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_8__SPDIF_SRCLK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_8__USBOH3_OTG_PWRCTL_WAK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 0, 0x0880, 1), /* MX6Q_PAD_GPIO_16__ESAI1_TX3_RX2 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_16__ENET_1588_EVENT2_IN */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 2, 0x083C, 1), /* MX6Q_PAD_GPIO_16__ENET_ETHERNET_REF_OUT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_16__USDHC1_LCTL */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 4, 0x0914, 3), /* MX6Q_PAD_GPIO_16__SPDIF_IN1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_16__GPIO_7_11 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 6, 0x08AC, 2), /* MX6Q_PAD_GPIO_16__I2C3_SDA */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_16__SJC_DE_B */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 0, 0x0874, 0), /* MX6Q_PAD_GPIO_17__ESAI1_TX0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_17__ENET_1588_EVENT3_IN */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 2, 0x07F0, 1), /* MX6Q_PAD_GPIO_17__CCM_PMIC_RDY */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 3, 0x090C, 1), /* MX6Q_PAD_GPIO_17__SDMA_SDMA_EXT_EVENT_0 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_17__SPDIF_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_17__GPIO_7_12 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_17__SJC_JTAG_ACT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 0, 0x0878, 0), /* MX6Q_PAD_GPIO_18__ESAI1_TX1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 1, 0x0844, 1), /* MX6Q_PAD_GPIO_18__ENET_RX_CLK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_18__USDHC3_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 3, 0x0910, 1), /* MX6Q_PAD_GPIO_18__SDMA_SDMA_EXT_EVENT_1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 4, 0x07B0, 2), /* MX6Q_PAD_GPIO_18__ASRC_ASRC_EXT_CLK */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_18__GPIO_7_13 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_18__SNVS_HP_WRA_SNVS_VIO5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_18__SRC_SYSTEM_RST */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 0, 0x08E8, 1), /* MX6Q_PAD_GPIO_19__KPP_COL_5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ENET_1588_EVENT0_OUT */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_19__SPDIF_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_19__CCM_CLKO */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ECSPI1_RDY */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_19__GPIO_4_5 */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ENET_TX_ER */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_19__SRC_INT_BOOT */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__PCIE_CTRL_MUX_12 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__GPIO_5_18 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK___MMDC_DEBUG_29 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__CHEETAH_EVENTO */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__PCIE_CTRL_MUX_13 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__CCM_CLKO */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__GPIO_5_19 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__MMDC_MMDC_DEBUG_30 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__CHEETAH_TRCTL */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DA_EN */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__WEIM_WEIM_D_0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__PCIE_CTRL_MUX_14 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__GPIO_5_20 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__MMDC_DEBUG_31 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__CHEETAH_TRCLK */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__WEIM_WEIM_D_1 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__PCIE_CTRL_MUX_15 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__GPIO_5_21 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__MMDC_DEBUG_32 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__CHEETAH_TRACE_0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__IPU1_CSI0_D_4 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__WEIM_WEIM_D_2 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 2, 0x07F4, 3), /* MX6Q_PAD_CSI0_DAT4__ECSPI1_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 3, 0x08E8, 2), /* MX6Q_PAD_CSI0_DAT4__KPP_COL_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__GPIO_5_22 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__MMDC_DEBUG_43 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__CHEETAH_TRACE_1 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__IPU1_CSI0_D_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__WEIM_WEIM_D_3 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 2, 0x07FC, 3), /* MX6Q_PAD_CSI0_DAT5__ECSPI1_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 3, 0x08F4, 1), /* MX6Q_PAD_CSI0_DAT5__KPP_ROW_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__GPIO_5_23 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__MMDC_MMDC_DEBUG_44 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__CHEETAH_TRACE_2 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__IPU1_CSI0_D_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__WEIM_WEIM_D_4 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 2, 0x07F8, 3), /* MX6Q_PAD_CSI0_DAT6__ECSPI1_MISO */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 3, 0x08EC, 1), /* MX6Q_PAD_CSI0_DAT6__KPP_COL_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__GPIO_5_24 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__MMDC_MMDC_DEBUG_45 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__CHEETAH_TRACE_3 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__IPU1_CSI0_D_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__WEIM_WEIM_D_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 2, 0x0800, 3), /* MX6Q_PAD_CSI0_DAT7__ECSPI1_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 3, 0x08F8, 2), /* MX6Q_PAD_CSI0_DAT7__KPP_ROW_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__GPIO_5_25 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__MMDC_MMDC_DEBUG_46 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__CHEETAH_TRACE_4 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__WEIM_WEIM_D_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 2, 0x0810, 2), /* MX6Q_PAD_CSI0_DAT8__ECSPI2_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 3, 0x08F0, 2), /* MX6Q_PAD_CSI0_DAT8__KPP_COL_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 4, 0x089C, 1), /* MX6Q_PAD_CSI0_DAT8__I2C1_SDA */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__GPIO_5_26 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__MMDC_MMDC_DEBUG_47 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__CHEETAH_TRACE_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__WEIM_WEIM_D_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 2, 0x0818, 2), /* MX6Q_PAD_CSI0_DAT9__ECSPI2_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 3, 0x08FC, 2), /* MX6Q_PAD_CSI0_DAT9__KPP_ROW_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 4, 0x0898, 1), /* MX6Q_PAD_CSI0_DAT9__I2C1_SCL */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__GPIO_5_27 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__MMDC_MMDC_DEBUG_48 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__CHEETAH_TRACE_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 2, 0x0814, 2), /* MX6Q_PAD_CSI0_DAT10__ECSPI2_MISO */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__UART1_TXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__GPIO_5_28 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__MMDC_MMDC_DEBUG_33 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__CHEETAH_TRACE_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 2, 0x081C, 2), /* MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 3, 0x0920, 1), /* MX6Q_PAD_CSI0_DAT11__UART1_RXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__GPIO_5_29 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__MMDC_MMDC_DEBUG_34 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__CHEETAH_TRACE_8 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__WEIM_WEIM_D_8 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__PCIE_CTRL_MUX_16 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__UART4_TXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__GPIO_5_30 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__MMDC_MMDC_DEBUG_35 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__CHEETAH_TRACE_9 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__WEIM_WEIM_D_9 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__PCIE_CTRL_MUX_17 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 3, 0x0938, 3), /* MX6Q_PAD_CSI0_DAT13__UART4_RXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__GPIO_5_31 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__MMDC_MMDC_DEBUG_36 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__CHEETAH_TRACE_10 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__WEIM_WEIM_D_10 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__PCIE_CTRL_MUX_18 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__UART5_TXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__GPIO_6_0 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__MMDC_MMDC_DEBUG_37 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__CHEETAH_TRACE_11 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__WEIM_WEIM_D_11 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__PCIE_CTRL_MUX_19 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 3, 0x0940, 3), /* MX6Q_PAD_CSI0_DAT15__UART5_RXD */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__GPIO_6_1 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__MMDC_MMDC_DEBUG_38 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__CHEETAH_TRACE_12 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__WEIM_WEIM_D_12 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__PCIE_CTRL_MUX_20 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 3, 0x0934, 0), /* MX6Q_PAD_CSI0_DAT16__UART4_RTS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__GPIO_6_2 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__MMDC_MMDC_DEBUG_39 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__CHEETAH_TRACE_13 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__WEIM_WEIM_D_13 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__PCIE_CTRL_MUX_21 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 3, 0x0934, 1), /* MX6Q_PAD_CSI0_DAT17__UART4_CTS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__GPIO_6_3 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__MMDC_MMDC_DEBUG_40 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__CHEETAH_TRACE_14 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__WEIM_WEIM_D_14 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__PCIE_CTRL_MUX_22 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 3, 0x093C, 2), /* MX6Q_PAD_CSI0_DAT18__UART5_RTS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__GPIO_6_4 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__MMDC_MMDC_DEBUG_41 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__CHEETAH_TRACE_15 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__WEIM_WEIM_D_15 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__PCIE_CTRL_MUX_23 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 3, 0x093C, 3), /* MX6Q_PAD_CSI0_DAT19__UART5_CTS */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__GPIO_6_5 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__MMDC_MMDC_DEBUG_42 */
+ IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__ANATOP_TESTO_9 */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_TMS, 0x0678, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TMS__SJC_TMS */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_MOD, 0x067C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_MOD__SJC_MOD */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_TRSTB, 0x0680, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TRSTB__SJC_TRSTB */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_TDI, 0x0684, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TDI__SJC_TDI */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_TCK, 0x0688, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TCK__SJC_TCK */
+ IMX_PIN_REG(MX6Q_PAD_JTAG_TDO, 0x068C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TDO__SJC_TDO */
+ IMX_PIN_REG(MX6Q_PAD_LVDS1_TX3_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS1_TX2_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS1_CLK_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK */
+ IMX_PIN_REG(MX6Q_PAD_LVDS1_TX1_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS1_TX0_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS0_TX3_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS0_CLK_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK */
+ IMX_PIN_REG(MX6Q_PAD_LVDS0_TX2_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS0_TX1_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 */
+ IMX_PIN_REG(MX6Q_PAD_LVDS0_TX0_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 */
+ IMX_PIN_REG(MX6Q_PAD_TAMPER, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_TAMPER__SNVS_LP_WRAP_SNVS_TD1 */
+ IMX_PIN_REG(MX6Q_PAD_PMIC_ON_REQ, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_PMIC_ON_REQ__SNVS_LPWRAP_WKALM */
+ IMX_PIN_REG(MX6Q_PAD_PMIC_STBY_REQ, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_PMIC_STBY_REQ__CCM_PMIC_STBYRQ */
+ IMX_PIN_REG(MX6Q_PAD_POR_B, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_POR_B__SRC_POR_B */
+ IMX_PIN_REG(MX6Q_PAD_BOOT_MODE1, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_BOOT_MODE1__SRC_BOOT_MODE_1 */
+ IMX_PIN_REG(MX6Q_PAD_RESET_IN_B, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_RESET_IN_B__SRC_RESET_B */
+ IMX_PIN_REG(MX6Q_PAD_BOOT_MODE0, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_BOOT_MODE0__SRC_BOOT_MODE_0 */
+ IMX_PIN_REG(MX6Q_PAD_TEST_MODE, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_TEST_MODE__TCU_TEST_MODE */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USDHC3_DAT7 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 1, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__UART1_TXD */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__PCIE_CTRL_MUX_24 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBOH3_UH3_DFD_OUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBOH3_UH2_DFD_OUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__GPIO_6_17 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__MIPI_CORE_DPHY_IN_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBPHY2_CLK20DIV */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USDHC3_DAT6 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 1, 0x0920, 3), /* MX6Q_PAD_SD3_DAT6__UART1_RXD */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__PCIE_CTRL_MUX_25 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USBOH3_UH3_DFD_OUT_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USBOH3_UH2_DFD_OUT_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__GPIO_6_18 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__MIPI_CORE_DPHY_IN_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__ANATOP_TESTO_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USDHC3_DAT5 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 1, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__UART2_TXD */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__PCIE_CTRL_MUX_26 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USBOH3_UH3_DFD_OUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USBOH3_UH2_DFD_OUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__GPIO_7_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__MIPI_CORE_DPHY_IN_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__ANATOP_TESTO_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USDHC3_DAT4 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 1, 0x0928, 5), /* MX6Q_PAD_SD3_DAT4__UART2_RXD */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__PCIE_CTRL_MUX_27 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USBOH3_UH3_DFD_OUT_3 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USBOH3_UH2_DFD_OUT_3 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__GPIO_7_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__MIPI_CORE_DPHY_IN_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__ANATOP_TESTO_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USDHC3_CMD */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 1, 0x0924, 2), /* MX6Q_PAD_SD3_CMD__UART2_CTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__CAN1_TXCAN */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USBOH3_UH3_DFD_OUT_4 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USBOH3_UH2_DFD_OUT_4 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__GPIO_7_2 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__MIPI_CORE_DPHY_IN_16 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__ANATOP_TESTO_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USDHC3_CLK */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 1, 0x0924, 3), /* MX6Q_PAD_SD3_CLK__UART2_RTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 2, 0x07E4, 2), /* MX6Q_PAD_SD3_CLK__CAN1_RXCAN */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USBOH3_UH3_DFD_OUT_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USBOH3_UH2_DFD_OUT_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__GPIO_7_3 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__MIPI_CORE_DPHY_IN_17 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__ANATOP_TESTO_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USDHC3_DAT0 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 1, 0x091C, 2), /* MX6Q_PAD_SD3_DAT0__UART1_CTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__CAN2_TXCAN */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USBOH3_UH3_DFD_OUT_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USBOH3_UH2_DFD_OUT_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__GPIO_7_4 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__MIPI_CORE_DPHY_IN_18 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__ANATOP_TESTO_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USDHC3_DAT1 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 1, 0x091C, 3), /* MX6Q_PAD_SD3_DAT1__UART1_RTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 2, 0x07E8, 1), /* MX6Q_PAD_SD3_DAT1__CAN2_RXCAN */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USBOH3_UH3_DFD_OUT_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USBOH3_UH2_DFD_OUT_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__GPIO_7_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__MIPI_CORE_DPHY_IN_19 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__ANATOP_TESTI_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USDHC3_DAT2 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__PCIE_CTRL_MUX_28 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USBOH3_UH3_DFD_OUT_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USBOH3_UH2_DFD_OUT_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__GPIO_7_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__MIPI_CORE_DPHY_IN_20 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__ANATOP_TESTI_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USDHC3_DAT3 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 1, 0x092C, 4), /* MX6Q_PAD_SD3_DAT3__UART3_CTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__PCIE_CTRL_MUX_29 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USBOH3_UH3_DFD_OUT_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USBOH3_UH2_DFD_OUT_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__GPIO_7_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__MIPI_CORE_DPHY_IN_21 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__ANATOP_TESTI_2 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USDHC3_RST */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 1, 0x092C, 5), /* MX6Q_PAD_SD3_RST__UART3_RTS */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_RST__PCIE_CTRL_MUX_30 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USBOH3_UH3_DFD_OUT_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USBOH3_UH2_DFD_OUT_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_RST__GPIO_7_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_RST__MIPI_CORE_DPHY_IN_22 */
+ IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_RST__ANATOP_ANATOP_TESTI_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__RAWNAND_CLE */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__IPU2_SISG_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__PCIE_CTRL_MUX_31 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__USBOH3_UH3_DFD_OT11 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__USBOH3_UH2_DFD_OT11 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__GPIO_6_7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__MIPI_CORE_DPHY_IN23 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__TPSMP_HTRANS_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__RAWNAND_ALE */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USDHC4_RST */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__PCIE_CTRL_MUX_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USBOH3_UH3_DFD_OT12 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USBOH3_UH2_DFD_OT12 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__GPIO_6_8 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__MIPI_CR_DPHY_IN_24 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__TPSMP_HTRANS_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__IPU2_SISG_5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__PCIE_CTRL__MUX_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__USBOH3_UH3_DFDOT13 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__USBOH3_UH2_DFDOT13 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__GPIO_6_9 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__MIPI_CR_DPHY_OUT32 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__PL301_PER1_HSIZE_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__RAWNAND_READY0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__IPU2_DI0_PIN1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__PCIE_CTRL_MUX_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__USBOH3_UH3_DFD_OT14 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__USBOH3_UH2_DFD_OT14 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__GPIO_6_10 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__MIPI_CR_DPHY_OUT_33 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__PL301_PER1_HSIZE_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__USBOH3_UH3_DFD_OT15 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__USBOH3_UH2_DFD_OT15 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__GPIO_6_11 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__PL301_PER1_HSIZE_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__USDHC4_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__USDHC3_VSELECT */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__PCIE_CTRL_MUX_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__GPIO_6_14 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__PL301_PER1_HRDYOUT */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__IPU1_SISG_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 2, 0x0874, 1), /* MX6Q_PAD_NANDF_CS2__ESAI1_TX0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__WEIM_WEIM_CRE */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__CCM_CLKO2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__GPIO_6_15 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__IPU2_SISG_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__IPU1_SISG_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 2, 0x0878, 1), /* MX6Q_PAD_NANDF_CS3__ESAI1_TX1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__WEIM_WEIM_A_26 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__PCIE_CTRL_MUX_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__GPIO_6_16 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__IPU2_SISG_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__TPSMP_CLK */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 0, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__USDHC4_CMD */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 1, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__RAWNAND_RDN */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 2, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__UART3_TXD */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 4, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__PCIE_CTRL_MUX_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 5, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__GPIO_7_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 7, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__TPSMP_HDATA_DIR */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 0, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__USDHC4_CLK */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 1, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__RAWNAND_WRN */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 2, 0x0930, 3), /* MX6Q_PAD_SD4_CLK__UART3_RXD */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 4, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__PCIE_CTRL_MUX_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 5, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__GPIO_7_10 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__RAWNAND_D0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USDHC1_DAT4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__GPU3D_GPU_DBG_OUT_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USBOH3_UH2_DFD_OUT16 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USBOH3_UH3_DFD_OUT16 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__GPIO_2_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__IPU1_IPU_DIAG_BUS_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__IPU2_IPU_DIAG_BUS_0 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__RAWNAND_D1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USDHC1_DAT5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__GPU3D_GPU_DEBUG_OUT1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USBOH3_UH2_DFD_OUT17 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USBOH3_UH3_DFD_OUT17 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__GPIO_2_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__IPU1_IPU_DIAG_BUS_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__IPU2_IPU_DIAG_BUS_1 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__RAWNAND_D2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USDHC1_DAT6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__GPU3D_GPU_DBG_OUT_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USBOH3_UH2_DFD_OUT18 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USBOH3_UH3_DFD_OUT18 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__GPIO_2_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__IPU1_IPU_DIAG_BUS_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__IPU2_IPU_DIAG_BUS_2 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__RAWNAND_D3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USDHC1_DAT7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__GPU3D_GPU_DBG_OUT_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USBOH3_UH2_DFD_OUT19 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USBOH3_UH3_DFD_OUT19 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__GPIO_2_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__IPU1_IPU_DIAG_BUS_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__IPU2_IPU_DIAG_BUS_3 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__RAWNAND_D4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USDHC2_DAT4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__GPU3D_GPU_DBG_OUT_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USBOH3_UH2_DFD_OUT20 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USBOH3_UH3_DFD_OUT20 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__GPIO_2_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__IPU1_IPU_DIAG_BUS_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__IPU2_IPU_DIAG_BUS_4 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__RAWNAND_D5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USDHC2_DAT5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__GPU3D_GPU_DBG_OUT_5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USBOH3_UH2_DFD_OUT21 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USBOH3_UH3_DFD_OUT21 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__GPIO_2_5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__IPU1_IPU_DIAG_BUS_5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__IPU2_IPU_DIAG_BUS_5 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__RAWNAND_D6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USDHC2_DAT6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__GPU3D_GPU_DBG_OUT_6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USBOH3_UH2_DFD_OUT22 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USBOH3_UH3_DFD_OUT22 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__GPIO_2_6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__IPU1_IPU_DIAG_BUS_6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__IPU2_IPU_DIAG_BUS_6 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__RAWNAND_D7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USDHC2_DAT7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__GPU3D_GPU_DBG_OUT_7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USBOH3_UH2_DFD_OUT23 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USBOH3_UH3_DFD_OUT23 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__GPIO_2_7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__IPU1_IPU_DIAG_BUS_7 */
+ IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__IPU2_IPU_DIAG_BUS_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__RAWNAND_D8 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USDHC4_DAT0 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__RAWNAND_DQS */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USBOH3_UH2_DFD_OUT24 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USBOH3_UH3_DFD_OUT24 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__GPIO_2_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__IPU1_IPU_DIAG_BUS_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__IPU2_IPU_DIAG_BUS_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__RAWNAND_D9 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USDHC4_DAT1 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__PWM3_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USBOH3_UH2_DFD_OUT25 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USBOH3_UH3_DFD_OUT25 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__GPIO_2_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__IPU1_IPU_DIAG_BUS_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__IPU2_IPU_DIAG_BUS_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__RAWNAND_D10 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USDHC4_DAT2 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__PWM4_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USBOH3_UH2_DFD_OUT26 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USBOH3_UH3_DFD_OUT26 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__GPIO_2_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__IPU1_IPU_DIAG_BUS_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__IPU2_IPU_DIAG_BUS_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__RAWNAND_D11 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USDHC4_DAT3 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USBOH3_UH2_DFD_OUT27 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USBOH3_UH3_DFD_OUT27 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__GPIO_2_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__IPU1_IPU_DIAG_BUS_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__IPU2_IPU_DIAG_BUS_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__RAWNAND_D12 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USDHC4_DAT4 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 2, 0x0928, 6), /* MX6Q_PAD_SD4_DAT4__UART2_RXD */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USBOH3_UH2_DFD_OUT28 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USBOH3_UH3_DFD_OUT28 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__GPIO_2_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__IPU1_IPU_DIAG_BUS_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__IPU2_IPU_DIAG_BUS_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__RAWNAND_D13 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USDHC4_DAT5 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 2, 0x0924, 4), /* MX6Q_PAD_SD4_DAT5__UART2_RTS */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USBOH3_UH2_DFD_OUT29 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USBOH3_UH3_DFD_OUT29 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__GPIO_2_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__IPU1_IPU_DIAG_BUS_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__IPU2_IPU_DIAG_BUS_13 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__RAWNAND_D14 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USDHC4_DAT6 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 2, 0x0924, 5), /* MX6Q_PAD_SD4_DAT6__UART2_CTS */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USBOH3_UH2_DFD_OUT30 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USBOH3_UH3_DFD_OUT30 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__GPIO_2_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__IPU1_IPU_DIAG_BUS_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__IPU2_IPU_DIAG_BUS_14 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__RAWNAND_D15 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__UART2_TXD */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USBOH3_UH2_DFD_OUT31 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USBOH3_UH3_DFD_OUT31 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__GPIO_2_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__IPU1_IPU_DIAG_BUS_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__IPU2_IPU_DIAG_BUS_15 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__USDHC1_DAT1 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 1, 0x0834, 1), /* MX6Q_PAD_SD1_DAT1__ECSPI5_SS0 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__PWM3_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__GPT_CAPIN2 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__PCIE_CTRL_MUX_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__GPIO_1_17 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__HDMI_TX_OPHYDTB_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__ANATOP_TESTO_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__USDHC1_DAT0 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 1, 0x082C, 1), /* MX6Q_PAD_SD1_DAT0__ECSPI5_MISO */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__CAAM_WRAP_RNG_OSCOBS */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__GPT_CAPIN1 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__PCIE_CTRL_MUX_8 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__GPIO_1_16 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__HDMI_TX_OPHYDTB_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__ANATOP_TESTO_7 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__USDHC1_DAT3 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 1, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__ECSPI5_SS2 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__GPT_CMPOUT3 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__PWM1_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__GPIO_1_21 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_RST_B_DEB */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__ANATOP_TESTO_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 0, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__USDHC1_CMD */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 1, 0x0830, 0), /* MX6Q_PAD_SD1_CMD__ECSPI5_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 2, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__PWM4_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 3, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__GPT_CMPOUT1 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 5, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__GPIO_1_18 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 7, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__ANATOP_TESTO_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__USDHC1_DAT2 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 1, 0x0838, 1), /* MX6Q_PAD_SD1_DAT2__ECSPI5_SS1 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__GPT_CMPOUT2 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__PWM2_PWMO */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_B */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__GPIO_1_19 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_RST_B_DEB */
+ IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__ANATOP_TESTO_4 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 0, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__USDHC1_CLK */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 1, 0x0828, 0), /* MX6Q_PAD_SD1_CLK__ECSPI5_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 2, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__OSC32K_32K_OUT */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 3, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__GPT_CLKIN */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 5, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__GPIO_1_20 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 6, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__PHY_DTB_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 7, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__SATA_PHY_DTB_0 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 0, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__USDHC2_CLK */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 1, 0x0828, 1), /* MX6Q_PAD_SD2_CLK__ECSPI5_SCLK */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 2, 0x08E8, 3), /* MX6Q_PAD_SD2_CLK__KPP_COL_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 3, 0x07C0, 1), /* MX6Q_PAD_SD2_CLK__AUDMUX_AUD4_RXFS */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 4, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__PCIE_CTRL_MUX_9 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 5, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__GPIO_1_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 6, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__PHY_DTB_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 7, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__SATA_PHY_DTB_1 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 0, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__USDHC2_CMD */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 1, 0x0830, 1), /* MX6Q_PAD_SD2_CMD__ECSPI5_MOSI */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 2, 0x08F4, 2), /* MX6Q_PAD_SD2_CMD__KPP_ROW_5 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 3, 0x07BC, 1), /* MX6Q_PAD_SD2_CMD__AUDMUX_AUD4_RXC */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 4, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__PCIE_CTRL_MUX_10 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 5, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__GPIO_1_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__USDHC2_DAT3 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 1, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ECSPI5_SS3 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 2, 0x08EC, 2), /* MX6Q_PAD_SD2_DAT3__KPP_COL_6 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 3, 0x07C4, 1), /* MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 4, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__PCIE_CTRL_MUX_11 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__GPIO_1_12 */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__SJC_DONE */
+ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 */
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TXC),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RXC),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A25),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D20),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D21),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D22),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D23),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D24),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D25),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D26),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D27),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D28),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D29),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D30),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D31),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A24),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A23),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A22),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A21),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A20),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_CS0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_CS1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_OE),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_RW),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_LBA),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA10),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA11),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA12),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA13),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA14),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_WAIT),
+ IMX_PINCTRL_PIN(MX6Q_PAD_EIM_BCLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DI0_DISP_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT20),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT21),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT22),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT23),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_REF_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RX_ER),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_CRS_DV),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RXD1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RXD0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TX_EN),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TXD1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TXD0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_ENET_MDC),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D40),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D41),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D42),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D43),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D44),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D45),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D46),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D47),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D32),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D33),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D34),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D35),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D36),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D37),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D38),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D39),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D24),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D25),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D26),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D27),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D28),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D29),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D30),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D31),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D20),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D21),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D22),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D23),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A10),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A11),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A12),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A13),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A14),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CAS),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CS0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CS1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_RAS),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_RESET),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCLK_0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCKE0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCLK_1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCKE1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDODT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDODT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDWE),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D10),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D11),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D12),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D13),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D14),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D48),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D49),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D50),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D51),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D52),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D53),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D54),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D55),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D56),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D57),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D58),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D59),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D60),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D61),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D62),
+ IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D63),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_PIXCLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_MCLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DATA_EN),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_VSYNC),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT8),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT9),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT10),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT11),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT12),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT13),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT14),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT15),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT16),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT17),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT18),
+ IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT19),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TMS),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_MOD),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TRSTB),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TDI),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TCK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TDO),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX3_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX2_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_CLK_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX1_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX0_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX3_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_CLK_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX2_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX1_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX0_P),
+ IMX_PINCTRL_PIN(MX6Q_PAD_TAMPER),
+ IMX_PINCTRL_PIN(MX6Q_PAD_PMIC_ON_REQ),
+ IMX_PINCTRL_PIN(MX6Q_PAD_PMIC_STBY_REQ),
+ IMX_PINCTRL_PIN(MX6Q_PAD_POR_B),
+ IMX_PINCTRL_PIN(MX6Q_PAD_BOOT_MODE1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_RESET_IN_B),
+ IMX_PINCTRL_PIN(MX6Q_PAD_BOOT_MODE0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_TEST_MODE),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_CMD),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD3_RST),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CLE),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_ALE),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_WP_B),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_RB0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_CMD),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT4),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT5),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT6),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT7),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT1),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT0),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT3),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_CMD),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT2),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD1_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_CLK),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_CMD),
+ IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT3),
+};
+
+static struct imx_pinctrl_soc_info imx6q_pinctrl_info = {
+ .pins = imx6q_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx6q_pinctrl_pads),
+ .pin_regs = imx6q_pin_regs,
+ .npin_regs = ARRAY_SIZE(imx6q_pin_regs),
+};
+
+static struct of_device_id imx6q_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "fsl,imx6q-iomuxc", },
+ { /* sentinel */ }
+};
+
+static int __devinit imx6q_pinctrl_probe(struct platform_device *pdev)
+{
+ return imx_pinctrl_probe(pdev, &imx6q_pinctrl_info);
+}
+
+static struct platform_driver imx6q_pinctrl_driver = {
+ .driver = {
+ .name = "imx6q-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx6q_pinctrl_of_match),
+ },
+ .probe = imx6q_pinctrl_probe,
+ .remove = __devexit_p(imx_pinctrl_remove),
+};
+
+static int __init imx6q_pinctrl_init(void)
+{
+ return platform_driver_register(&imx6q_pinctrl_driver);
+}
+arch_initcall(imx6q_pinctrl_init);
+
+static void __exit imx6q_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx6q_pinctrl_driver);
+}
+module_exit(imx6q_pinctrl_exit);
+MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
+MODULE_DESCRIPTION("Freescale IMX6Q pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
new file mode 100644
index 0000000..556e45a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "core.h"
+#include "pinctrl-mxs.h"
+
+#define SUFFIX_LEN 4
+
+struct mxs_pinctrl_data {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *base;
+ struct mxs_pinctrl_soc_data *soc;
+};
+
+static int mxs_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ return d->soc->ngroups;
+}
+
+static const char *mxs_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ return d->soc->groups[group].name;
+}
+
+static int mxs_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
+ const unsigned **pins, unsigned *num_pins)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = d->soc->groups[group].pins;
+ *num_pins = d->soc->groups[group].npins;
+
+ return 0;
+}
+
+static void mxs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+
+static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct pinctrl_map *new_map;
+ char *group = NULL;
+ unsigned new_num = 1;
+ unsigned long config = 0;
+ unsigned long *pconfig;
+ int length = strlen(np->name) + SUFFIX_LEN;
+ bool purecfg = false;
+ u32 val, reg;
+ int ret, i = 0;
+
+ /* Check for pin config node which has no 'reg' property */
+ if (of_property_read_u32(np, "reg", &reg))
+ purecfg = true;
+
+ ret = of_property_read_u32(np, "fsl,drive-strength", &val);
+ if (!ret)
+ config = val | MA_PRESENT;
+ ret = of_property_read_u32(np, "fsl,voltage", &val);
+ if (!ret)
+ config |= val << VOL_SHIFT | VOL_PRESENT;
+ ret = of_property_read_u32(np, "fsl,pull-up", &val);
+ if (!ret)
+ config |= val << PULL_SHIFT | PULL_PRESENT;
+
+ /* Check for group node which has both mux and config settings */
+ if (!purecfg && config)
+ new_num = 2;
+
+ new_map = kzalloc(sizeof(*new_map) * new_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ if (!purecfg) {
+ new_map[i].type = PIN_MAP_TYPE_MUX_GROUP;
+ new_map[i].data.mux.function = np->name;
+
+ /* Compose group name */
+ group = kzalloc(length, GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+ snprintf(group, length, "%s.%d", np->name, reg);
+ new_map[i].data.mux.group = group;
+ i++;
+ }
+
+ if (config) {
+ pconfig = kmemdup(&config, sizeof(config), GFP_KERNEL);
+ if (!pconfig) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ new_map[i].data.configs.group_or_pin = purecfg ? np->name :
+ group;
+ new_map[i].data.configs.configs = pconfig;
+ new_map[i].data.configs.num_configs = 1;
+ }
+
+ *map = new_map;
+ *num_maps = new_num;
+
+ return 0;
+
+free:
+ kfree(new_map);
+ return ret;
+}
+
+static void mxs_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++) {
+ if (map[i].type == PIN_MAP_TYPE_MUX_GROUP)
+ kfree(map[i].data.mux.group);
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+ kfree(map[i].data.configs.configs);
+ }
+
+ kfree(map);
+}
+
+static struct pinctrl_ops mxs_pinctrl_ops = {
+ .get_groups_count = mxs_get_groups_count,
+ .get_group_name = mxs_get_group_name,
+ .get_group_pins = mxs_get_group_pins,
+ .pin_dbg_show = mxs_pin_dbg_show,
+ .dt_node_to_map = mxs_dt_node_to_map,
+ .dt_free_map = mxs_dt_free_map,
+};
+
+static int mxs_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ return d->soc->nfunctions;
+}
+
+static const char *mxs_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ return d->soc->functions[function].name;
+}
+
+static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = d->soc->functions[group].groups;
+ *num_groups = d->soc->functions[group].ngroups;
+
+ return 0;
+}
+
+static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+ struct mxs_group *g = &d->soc->groups[group];
+ void __iomem *reg;
+ u8 bank, shift;
+ u16 pin;
+ int i;
+
+ for (i = 0; i < g->npins; i++) {
+ bank = PINID_TO_BANK(g->pins[i]);
+ pin = PINID_TO_PIN(g->pins[i]);
+ reg = d->base + d->soc->regs->muxsel;
+ reg += bank * 0x20 + pin / 16 * 0x10;
+ shift = pin % 16 * 2;
+
+ writel(0x3 << shift, reg + CLR);
+ writel(g->muxsel[i] << shift, reg + SET);
+ }
+
+ return 0;
+}
+
+static struct pinmux_ops mxs_pinmux_ops = {
+ .get_functions_count = mxs_pinctrl_get_funcs_count,
+ .get_function_name = mxs_pinctrl_get_func_name,
+ .get_function_groups = mxs_pinctrl_get_func_groups,
+ .enable = mxs_pinctrl_enable,
+};
+
+static int mxs_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin, unsigned long *config)
+{
+ return -ENOTSUPP;
+}
+
+static int mxs_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned pin, unsigned long config)
+{
+ return -ENOTSUPP;
+}
+
+static int mxs_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned group, unsigned long *config)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+ *config = d->soc->groups[group].config;
+
+ return 0;
+}
+
+static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned group, unsigned long config)
+{
+ struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+ struct mxs_group *g = &d->soc->groups[group];
+ void __iomem *reg;
+ u8 ma, vol, pull, bank, shift;
+ u16 pin;
+ int i;
+
+ ma = CONFIG_TO_MA(config);
+ vol = CONFIG_TO_VOL(config);
+ pull = CONFIG_TO_PULL(config);
+
+ for (i = 0; i < g->npins; i++) {
+ bank = PINID_TO_BANK(g->pins[i]);
+ pin = PINID_TO_PIN(g->pins[i]);
+
+ /* drive */
+ reg = d->base + d->soc->regs->drive;
+ reg += bank * 0x40 + pin / 8 * 0x10;
+
+ /* mA */
+ if (config & MA_PRESENT) {
+ shift = pin % 8 * 4;
+ writel(0x3 << shift, reg + CLR);
+ writel(ma << shift, reg + SET);
+ }
+
+ /* vol */
+ if (config & VOL_PRESENT) {
+ shift = pin % 8 * 4 + 2;
+ if (vol)
+ writel(1 << shift, reg + SET);
+ else
+ writel(1 << shift, reg + CLR);
+ }
+
+ /* pull */
+ if (config & PULL_PRESENT) {
+ reg = d->base + d->soc->regs->pull;
+ reg += bank * 0x10;
+ shift = pin;
+ if (pull)
+ writel(1 << shift, reg + SET);
+ else
+ writel(1 << shift, reg + CLR);
+ }
+ }
+
+ /* cache the config value for mxs_pinconf_group_get() */
+ g->config = config;
+
+ return 0;
+}
+
+static void mxs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin)
+{
+ /* Not support */
+}
+
+static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned group)
+{
+ unsigned long config;
+
+ if (!mxs_pinconf_group_get(pctldev, group, &config))
+ seq_printf(s, "0x%lx", config);
+}
+
+struct pinconf_ops mxs_pinconf_ops = {
+ .pin_config_get = mxs_pinconf_get,
+ .pin_config_set = mxs_pinconf_set,
+ .pin_config_group_get = mxs_pinconf_group_get,
+ .pin_config_group_set = mxs_pinconf_group_set,
+ .pin_config_dbg_show = mxs_pinconf_dbg_show,
+ .pin_config_group_dbg_show = mxs_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc mxs_pinctrl_desc = {
+ .pctlops = &mxs_pinctrl_ops,
+ .pmxops = &mxs_pinmux_ops,
+ .confops = &mxs_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit mxs_pinctrl_parse_group(struct platform_device *pdev,
+ struct device_node *np, int idx,
+ const char **out_name)
+{
+ struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
+ struct mxs_group *g = &d->soc->groups[idx];
+ struct property *prop;
+ const char *propname = "fsl,pinmux-ids";
+ char *group;
+ int length = strlen(np->name) + SUFFIX_LEN;
+ int i;
+ u32 val;
+
+ group = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+ if (of_property_read_u32(np, "reg", &val))
+ snprintf(group, length, "%s", np->name);
+ else
+ snprintf(group, length, "%s.%d", np->name, val);
+ g->name = group;
+
+ prop = of_find_property(np, propname, &length);
+ if (!prop)
+ return -EINVAL;
+ g->npins = length / sizeof(u32);
+
+ g->pins = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->pins),
+ GFP_KERNEL);
+ if (!g->pins)
+ return -ENOMEM;
+
+ g->muxsel = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->muxsel),
+ GFP_KERNEL);
+ if (!g->muxsel)
+ return -ENOMEM;
+
+ of_property_read_u32_array(np, propname, g->pins, g->npins);
+ for (i = 0; i < g->npins; i++) {
+ g->muxsel[i] = MUXID_TO_MUXSEL(g->pins[i]);
+ g->pins[i] = MUXID_TO_PINID(g->pins[i]);
+ }
+
+ if (out_name)
+ *out_name = g->name;
+
+ return 0;
+}
+
+static int __devinit mxs_pinctrl_probe_dt(struct platform_device *pdev,
+ struct mxs_pinctrl_data *d)
+{
+ struct mxs_pinctrl_soc_data *soc = d->soc;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ struct mxs_function *f;
+ const char *gpio_compat = "fsl,mxs-gpio";
+ const char *fn, *fnull = "";
+ int i = 0, idxf = 0, idxg = 0;
+ int ret;
+ u32 val;
+
+ child = of_get_next_child(np, NULL);
+ if (!child) {
+ dev_err(&pdev->dev, "no group is defined\n");
+ return -ENOENT;
+ }
+
+ /* Count total functions and groups */
+ fn = fnull;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat))
+ continue;
+ soc->ngroups++;
+ /* Skip pure pinconf node */
+ if (of_property_read_u32(child, "reg", &val))
+ continue;
+ if (strcmp(fn, child->name)) {
+ fn = child->name;
+ soc->nfunctions++;
+ }
+ }
+
+ soc->functions = devm_kzalloc(&pdev->dev, soc->nfunctions *
+ sizeof(*soc->functions), GFP_KERNEL);
+ if (!soc->functions)
+ return -ENOMEM;
+
+ soc->groups = devm_kzalloc(&pdev->dev, soc->ngroups *
+ sizeof(*soc->groups), GFP_KERNEL);
+ if (!soc->groups)
+ return -ENOMEM;
+
+ /* Count groups for each function */
+ fn = fnull;
+ f = &soc->functions[idxf];
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat))
+ continue;
+ if (of_property_read_u32(child, "reg", &val))
+ continue;
+ if (strcmp(fn, child->name)) {
+ f = &soc->functions[idxf++];
+ f->name = fn = child->name;
+ }
+ f->ngroups++;
+ };
+
+ /* Get groups for each function */
+ idxf = 0;
+ fn = fnull;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat))
+ continue;
+ if (of_property_read_u32(child, "reg", &val)) {
+ ret = mxs_pinctrl_parse_group(pdev, child,
+ idxg++, NULL);
+ if (ret)
+ return ret;
+ continue;
+ }
+
+ if (strcmp(fn, child->name)) {
+ f = &soc->functions[idxf++];
+ f->groups = devm_kzalloc(&pdev->dev, f->ngroups *
+ sizeof(*f->groups),
+ GFP_KERNEL);
+ if (!f->groups)
+ return -ENOMEM;
+ fn = child->name;
+ i = 0;
+ }
+ ret = mxs_pinctrl_parse_group(pdev, child, idxg++,
+ &f->groups[i++]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int __devinit mxs_pinctrl_probe(struct platform_device *pdev,
+ struct mxs_pinctrl_soc_data *soc)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mxs_pinctrl_data *d;
+ int ret;
+
+ d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ d->dev = &pdev->dev;
+ d->soc = soc;
+
+ d->base = of_iomap(np, 0);
+ if (!d->base)
+ return -EADDRNOTAVAIL;
+
+ mxs_pinctrl_desc.pins = d->soc->pins;
+ mxs_pinctrl_desc.npins = d->soc->npins;
+ mxs_pinctrl_desc.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, d);
+
+ ret = mxs_pinctrl_probe_dt(pdev, d);
+ if (ret) {
+ dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+ goto err;
+ }
+
+ d->pctl = pinctrl_register(&mxs_pinctrl_desc, &pdev->dev, d);
+ if (!d->pctl) {
+ dev_err(&pdev->dev, "Couldn't register MXS pinctrl driver\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ iounmap(d->base);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mxs_pinctrl_probe);
+
+int __devexit mxs_pinctrl_remove(struct platform_device *pdev)
+{
+ struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(d->pctl);
+ iounmap(d->base);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mxs_pinctrl_remove);
diff --git a/drivers/pinctrl/pinctrl-mxs.h b/drivers/pinctrl/pinctrl-mxs.h
new file mode 100644
index 0000000..fdd88d0b
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-mxs.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __PINCTRL_MXS_H
+#define __PINCTRL_MXS_H
+
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define MXS_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+#define PINID(bank, pin) ((bank) * 32 + (pin))
+
+/*
+ * pinmux-id bit field definitions
+ *
+ * bank: 15..12 (4)
+ * pin: 11..4 (8)
+ * muxsel: 3..0 (4)
+ */
+#define MUXID_TO_PINID(m) PINID((m) >> 12 & 0xf, (m) >> 4 & 0xff)
+#define MUXID_TO_MUXSEL(m) ((m) & 0xf)
+
+#define PINID_TO_BANK(p) ((p) >> 5)
+#define PINID_TO_PIN(p) ((p) % 32)
+
+/*
+ * pin config bit field definitions
+ *
+ * pull-up: 6..5 (2)
+ * voltage: 4..3 (2)
+ * mA: 2..0 (3)
+ *
+ * MSB of each field is presence bit for the config.
+ */
+#define PULL_PRESENT (1 << 6)
+#define PULL_SHIFT 5
+#define VOL_PRESENT (1 << 4)
+#define VOL_SHIFT 3
+#define MA_PRESENT (1 << 2)
+#define MA_SHIFT 0
+#define CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1)
+#define CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1)
+#define CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3)
+
+struct mxs_function {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct mxs_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned npins;
+ u8 *muxsel;
+ u8 config;
+};
+
+struct mxs_regs {
+ u16 muxsel;
+ u16 drive;
+ u16 pull;
+};
+
+struct mxs_pinctrl_soc_data {
+ const struct mxs_regs *regs;
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ struct mxs_function *functions;
+ unsigned nfunctions;
+ struct mxs_group *groups;
+ unsigned ngroups;
+};
+
+int mxs_pinctrl_probe(struct platform_device *pdev,
+ struct mxs_pinctrl_soc_data *soc);
+int mxs_pinctrl_remove(struct platform_device *pdev);
+
+#endif /* __PINCTRL_MXS_H */
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c
new file mode 100644
index 0000000..8b20222
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -0,0 +1,857 @@
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-nomadik.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define _GPIO(offset) (offset)
+
+#define DB8500_PIN_AJ5 _GPIO(0)
+#define DB8500_PIN_AJ3 _GPIO(1)
+#define DB8500_PIN_AH4 _GPIO(2)
+#define DB8500_PIN_AH3 _GPIO(3)
+#define DB8500_PIN_AH6 _GPIO(4)
+#define DB8500_PIN_AG6 _GPIO(5)
+#define DB8500_PIN_AF6 _GPIO(6)
+#define DB8500_PIN_AG5 _GPIO(7)
+#define DB8500_PIN_AD5 _GPIO(8)
+#define DB8500_PIN_AE4 _GPIO(9)
+#define DB8500_PIN_AF5 _GPIO(10)
+#define DB8500_PIN_AG4 _GPIO(11)
+#define DB8500_PIN_AC4 _GPIO(12)
+#define DB8500_PIN_AF3 _GPIO(13)
+#define DB8500_PIN_AE3 _GPIO(14)
+#define DB8500_PIN_AC3 _GPIO(15)
+#define DB8500_PIN_AD3 _GPIO(16)
+#define DB8500_PIN_AD4 _GPIO(17)
+#define DB8500_PIN_AC2 _GPIO(18)
+#define DB8500_PIN_AC1 _GPIO(19)
+#define DB8500_PIN_AB4 _GPIO(20)
+#define DB8500_PIN_AB3 _GPIO(21)
+#define DB8500_PIN_AA3 _GPIO(22)
+#define DB8500_PIN_AA4 _GPIO(23)
+#define DB8500_PIN_AB2 _GPIO(24)
+#define DB8500_PIN_Y4 _GPIO(25)
+#define DB8500_PIN_Y2 _GPIO(26)
+#define DB8500_PIN_AA2 _GPIO(27)
+#define DB8500_PIN_AA1 _GPIO(28)
+#define DB8500_PIN_W2 _GPIO(29)
+#define DB8500_PIN_W3 _GPIO(30)
+#define DB8500_PIN_V3 _GPIO(31)
+#define DB8500_PIN_V2 _GPIO(32)
+#define DB8500_PIN_AF2 _GPIO(33)
+#define DB8500_PIN_AE1 _GPIO(34)
+#define DB8500_PIN_AE2 _GPIO(35)
+#define DB8500_PIN_AG2 _GPIO(36)
+/* Hole */
+#define DB8500_PIN_F3 _GPIO(64)
+#define DB8500_PIN_F1 _GPIO(65)
+#define DB8500_PIN_G3 _GPIO(66)
+#define DB8500_PIN_G2 _GPIO(67)
+#define DB8500_PIN_E1 _GPIO(68)
+#define DB8500_PIN_E2 _GPIO(69)
+#define DB8500_PIN_G5 _GPIO(70)
+#define DB8500_PIN_G4 _GPIO(71)
+#define DB8500_PIN_H4 _GPIO(72)
+#define DB8500_PIN_H3 _GPIO(73)
+#define DB8500_PIN_J3 _GPIO(74)
+#define DB8500_PIN_H2 _GPIO(75)
+#define DB8500_PIN_J2 _GPIO(76)
+#define DB8500_PIN_H1 _GPIO(77)
+#define DB8500_PIN_F4 _GPIO(78)
+#define DB8500_PIN_E3 _GPIO(79)
+#define DB8500_PIN_E4 _GPIO(80)
+#define DB8500_PIN_D2 _GPIO(81)
+#define DB8500_PIN_C1 _GPIO(82)
+#define DB8500_PIN_D3 _GPIO(83)
+#define DB8500_PIN_C2 _GPIO(84)
+#define DB8500_PIN_D5 _GPIO(85)
+#define DB8500_PIN_C6 _GPIO(86)
+#define DB8500_PIN_B3 _GPIO(87)
+#define DB8500_PIN_C4 _GPIO(88)
+#define DB8500_PIN_E6 _GPIO(89)
+#define DB8500_PIN_A3 _GPIO(90)
+#define DB8500_PIN_B6 _GPIO(91)
+#define DB8500_PIN_D6 _GPIO(92)
+#define DB8500_PIN_B7 _GPIO(93)
+#define DB8500_PIN_D7 _GPIO(94)
+#define DB8500_PIN_E8 _GPIO(95)
+#define DB8500_PIN_D8 _GPIO(96)
+#define DB8500_PIN_D9 _GPIO(97)
+/* Hole */
+#define DB8500_PIN_A5 _GPIO(128)
+#define DB8500_PIN_B4 _GPIO(129)
+#define DB8500_PIN_C8 _GPIO(130)
+#define DB8500_PIN_A12 _GPIO(131)
+#define DB8500_PIN_C10 _GPIO(132)
+#define DB8500_PIN_B10 _GPIO(133)
+#define DB8500_PIN_B9 _GPIO(134)
+#define DB8500_PIN_A9 _GPIO(135)
+#define DB8500_PIN_C7 _GPIO(136)
+#define DB8500_PIN_A7 _GPIO(137)
+#define DB8500_PIN_C5 _GPIO(138)
+#define DB8500_PIN_C9 _GPIO(139)
+#define DB8500_PIN_B11 _GPIO(140)
+#define DB8500_PIN_C12 _GPIO(141)
+#define DB8500_PIN_C11 _GPIO(142)
+#define DB8500_PIN_D12 _GPIO(143)
+#define DB8500_PIN_B13 _GPIO(144)
+#define DB8500_PIN_C13 _GPIO(145)
+#define DB8500_PIN_D13 _GPIO(146)
+#define DB8500_PIN_C15 _GPIO(147)
+#define DB8500_PIN_B16 _GPIO(148)
+#define DB8500_PIN_B14 _GPIO(149)
+#define DB8500_PIN_C14 _GPIO(150)
+#define DB8500_PIN_D17 _GPIO(151)
+#define DB8500_PIN_D16 _GPIO(152)
+#define DB8500_PIN_B17 _GPIO(153)
+#define DB8500_PIN_C16 _GPIO(154)
+#define DB8500_PIN_C19 _GPIO(155)
+#define DB8500_PIN_C17 _GPIO(156)
+#define DB8500_PIN_A18 _GPIO(157)
+#define DB8500_PIN_C18 _GPIO(158)
+#define DB8500_PIN_B19 _GPIO(159)
+#define DB8500_PIN_B20 _GPIO(160)
+#define DB8500_PIN_D21 _GPIO(161)
+#define DB8500_PIN_D20 _GPIO(162)
+#define DB8500_PIN_C20 _GPIO(163)
+#define DB8500_PIN_B21 _GPIO(164)
+#define DB8500_PIN_C21 _GPIO(165)
+#define DB8500_PIN_A22 _GPIO(166)
+#define DB8500_PIN_B24 _GPIO(167)
+#define DB8500_PIN_C22 _GPIO(168)
+#define DB8500_PIN_D22 _GPIO(169)
+#define DB8500_PIN_C23 _GPIO(170)
+#define DB8500_PIN_D23 _GPIO(171)
+/* Hole */
+#define DB8500_PIN_AJ27 _GPIO(192)
+#define DB8500_PIN_AH27 _GPIO(193)
+#define DB8500_PIN_AF27 _GPIO(194)
+#define DB8500_PIN_AG28 _GPIO(195)
+#define DB8500_PIN_AG26 _GPIO(196)
+#define DB8500_PIN_AH24 _GPIO(197)
+#define DB8500_PIN_AG25 _GPIO(198)
+#define DB8500_PIN_AH23 _GPIO(199)
+#define DB8500_PIN_AH26 _GPIO(200)
+#define DB8500_PIN_AF24 _GPIO(201)
+#define DB8500_PIN_AF25 _GPIO(202)
+#define DB8500_PIN_AE23 _GPIO(203)
+#define DB8500_PIN_AF23 _GPIO(204)
+#define DB8500_PIN_AG23 _GPIO(205)
+#define DB8500_PIN_AG24 _GPIO(206)
+#define DB8500_PIN_AJ23 _GPIO(207)
+#define DB8500_PIN_AH16 _GPIO(208)
+#define DB8500_PIN_AG15 _GPIO(209)
+#define DB8500_PIN_AJ15 _GPIO(210)
+#define DB8500_PIN_AG14 _GPIO(211)
+#define DB8500_PIN_AF13 _GPIO(212)
+#define DB8500_PIN_AG13 _GPIO(213)
+#define DB8500_PIN_AH15 _GPIO(214)
+#define DB8500_PIN_AH13 _GPIO(215)
+#define DB8500_PIN_AG12 _GPIO(216)
+#define DB8500_PIN_AH12 _GPIO(217)
+#define DB8500_PIN_AH11 _GPIO(218)
+#define DB8500_PIN_AG10 _GPIO(219)
+#define DB8500_PIN_AH10 _GPIO(220)
+#define DB8500_PIN_AJ11 _GPIO(221)
+#define DB8500_PIN_AJ9 _GPIO(222)
+#define DB8500_PIN_AH9 _GPIO(223)
+#define DB8500_PIN_AG9 _GPIO(224)
+#define DB8500_PIN_AG8 _GPIO(225)
+#define DB8500_PIN_AF8 _GPIO(226)
+#define DB8500_PIN_AH7 _GPIO(227)
+#define DB8500_PIN_AJ6 _GPIO(228)
+#define DB8500_PIN_AG7 _GPIO(229)
+#define DB8500_PIN_AF7 _GPIO(230)
+/* Hole */
+#define DB8500_PIN_AF28 _GPIO(256)
+#define DB8500_PIN_AE29 _GPIO(257)
+#define DB8500_PIN_AD29 _GPIO(258)
+#define DB8500_PIN_AC29 _GPIO(259)
+#define DB8500_PIN_AD28 _GPIO(260)
+#define DB8500_PIN_AD26 _GPIO(261)
+#define DB8500_PIN_AE26 _GPIO(262)
+#define DB8500_PIN_AG29 _GPIO(263)
+#define DB8500_PIN_AE27 _GPIO(264)
+#define DB8500_PIN_AD27 _GPIO(265)
+#define DB8500_PIN_AC28 _GPIO(266)
+#define DB8500_PIN_AC27 _GPIO(267)
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc nmk_db8500_pins[] = {
+ PINCTRL_PIN(DB8500_PIN_AJ5, "GPIO0_AJ5"),
+ PINCTRL_PIN(DB8500_PIN_AJ3, "GPIO1_AJ3"),
+ PINCTRL_PIN(DB8500_PIN_AH4, "GPIO2_AH4"),
+ PINCTRL_PIN(DB8500_PIN_AH3, "GPIO3_AH3"),
+ PINCTRL_PIN(DB8500_PIN_AH6, "GPIO4_AH6"),
+ PINCTRL_PIN(DB8500_PIN_AG6, "GPIO5_AG6"),
+ PINCTRL_PIN(DB8500_PIN_AF6, "GPIO6_AF6"),
+ PINCTRL_PIN(DB8500_PIN_AG5, "GPIO7_AG5"),
+ PINCTRL_PIN(DB8500_PIN_AD5, "GPIO8_AD5"),
+ PINCTRL_PIN(DB8500_PIN_AE4, "GPIO9_AE4"),
+ PINCTRL_PIN(DB8500_PIN_AF5, "GPIO10_AF5"),
+ PINCTRL_PIN(DB8500_PIN_AG4, "GPIO11_AG4"),
+ PINCTRL_PIN(DB8500_PIN_AC4, "GPIO12_AC4"),
+ PINCTRL_PIN(DB8500_PIN_AF3, "GPIO13_AF3"),
+ PINCTRL_PIN(DB8500_PIN_AE3, "GPIO14_AE3"),
+ PINCTRL_PIN(DB8500_PIN_AC3, "GPIO15_AC3"),
+ PINCTRL_PIN(DB8500_PIN_AD3, "GPIO16_AD3"),
+ PINCTRL_PIN(DB8500_PIN_AD4, "GPIO17_AD4"),
+ PINCTRL_PIN(DB8500_PIN_AC2, "GPIO18_AC2"),
+ PINCTRL_PIN(DB8500_PIN_AC1, "GPIO19_AC1"),
+ PINCTRL_PIN(DB8500_PIN_AB4, "GPIO20_AB4"),
+ PINCTRL_PIN(DB8500_PIN_AB3, "GPIO21_AB3"),
+ PINCTRL_PIN(DB8500_PIN_AA3, "GPIO22_AA3"),
+ PINCTRL_PIN(DB8500_PIN_AA4, "GPIO23_AA4"),
+ PINCTRL_PIN(DB8500_PIN_AB2, "GPIO24_AB2"),
+ PINCTRL_PIN(DB8500_PIN_Y4, "GPIO25_Y4"),
+ PINCTRL_PIN(DB8500_PIN_Y2, "GPIO26_Y2"),
+ PINCTRL_PIN(DB8500_PIN_AA2, "GPIO27_AA2"),
+ PINCTRL_PIN(DB8500_PIN_AA1, "GPIO28_AA1"),
+ PINCTRL_PIN(DB8500_PIN_W2, "GPIO29_W2"),
+ PINCTRL_PIN(DB8500_PIN_W3, "GPIO30_W3"),
+ PINCTRL_PIN(DB8500_PIN_V3, "GPIO31_V3"),
+ PINCTRL_PIN(DB8500_PIN_V2, "GPIO32_V2"),
+ PINCTRL_PIN(DB8500_PIN_AF2, "GPIO33_AF2"),
+ PINCTRL_PIN(DB8500_PIN_AE1, "GPIO34_AE1"),
+ PINCTRL_PIN(DB8500_PIN_AE2, "GPIO35_AE2"),
+ PINCTRL_PIN(DB8500_PIN_AG2, "GPIO36_AG2"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_F3, "GPIO64_F3"),
+ PINCTRL_PIN(DB8500_PIN_F1, "GPIO65_F1"),
+ PINCTRL_PIN(DB8500_PIN_G3, "GPIO66_G3"),
+ PINCTRL_PIN(DB8500_PIN_G2, "GPIO67_G2"),
+ PINCTRL_PIN(DB8500_PIN_E1, "GPIO68_E1"),
+ PINCTRL_PIN(DB8500_PIN_E2, "GPIO69_E2"),
+ PINCTRL_PIN(DB8500_PIN_G5, "GPIO70_G5"),
+ PINCTRL_PIN(DB8500_PIN_G4, "GPIO71_G4"),
+ PINCTRL_PIN(DB8500_PIN_H4, "GPIO72_H4"),
+ PINCTRL_PIN(DB8500_PIN_H3, "GPIO73_H3"),
+ PINCTRL_PIN(DB8500_PIN_J3, "GPIO74_J3"),
+ PINCTRL_PIN(DB8500_PIN_H2, "GPIO75_H2"),
+ PINCTRL_PIN(DB8500_PIN_J2, "GPIO76_J2"),
+ PINCTRL_PIN(DB8500_PIN_H1, "GPIO77_H1"),
+ PINCTRL_PIN(DB8500_PIN_F4, "GPIO78_F4"),
+ PINCTRL_PIN(DB8500_PIN_E3, "GPIO79_E3"),
+ PINCTRL_PIN(DB8500_PIN_E4, "GPIO80_E4"),
+ PINCTRL_PIN(DB8500_PIN_D2, "GPIO81_D2"),
+ PINCTRL_PIN(DB8500_PIN_C1, "GPIO82_C1"),
+ PINCTRL_PIN(DB8500_PIN_D3, "GPIO83_D3"),
+ PINCTRL_PIN(DB8500_PIN_C2, "GPIO84_C2"),
+ PINCTRL_PIN(DB8500_PIN_D5, "GPIO85_D5"),
+ PINCTRL_PIN(DB8500_PIN_C6, "GPIO86_C6"),
+ PINCTRL_PIN(DB8500_PIN_B3, "GPIO87_B3"),
+ PINCTRL_PIN(DB8500_PIN_C4, "GPIO88_C4"),
+ PINCTRL_PIN(DB8500_PIN_E6, "GPIO89_E6"),
+ PINCTRL_PIN(DB8500_PIN_A3, "GPIO90_A3"),
+ PINCTRL_PIN(DB8500_PIN_B6, "GPIO91_B6"),
+ PINCTRL_PIN(DB8500_PIN_D6, "GPIO92_D6"),
+ PINCTRL_PIN(DB8500_PIN_B7, "GPIO93_B7"),
+ PINCTRL_PIN(DB8500_PIN_D7, "GPIO94_D7"),
+ PINCTRL_PIN(DB8500_PIN_E8, "GPIO95_E8"),
+ PINCTRL_PIN(DB8500_PIN_D8, "GPIO96_D8"),
+ PINCTRL_PIN(DB8500_PIN_D9, "GPIO97_D9"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_A5, "GPIO128_A5"),
+ PINCTRL_PIN(DB8500_PIN_B4, "GPIO129_B4"),
+ PINCTRL_PIN(DB8500_PIN_C8, "GPIO130_C8"),
+ PINCTRL_PIN(DB8500_PIN_A12, "GPIO131_A12"),
+ PINCTRL_PIN(DB8500_PIN_C10, "GPIO132_C10"),
+ PINCTRL_PIN(DB8500_PIN_B10, "GPIO133_B10"),
+ PINCTRL_PIN(DB8500_PIN_B9, "GPIO134_B9"),
+ PINCTRL_PIN(DB8500_PIN_A9, "GPIO135_A9"),
+ PINCTRL_PIN(DB8500_PIN_C7, "GPIO136_C7"),
+ PINCTRL_PIN(DB8500_PIN_A7, "GPIO137_A7"),
+ PINCTRL_PIN(DB8500_PIN_C5, "GPIO138_C5"),
+ PINCTRL_PIN(DB8500_PIN_C9, "GPIO139_C9"),
+ PINCTRL_PIN(DB8500_PIN_B11, "GPIO140_B11"),
+ PINCTRL_PIN(DB8500_PIN_C12, "GPIO141_C12"),
+ PINCTRL_PIN(DB8500_PIN_C11, "GPIO142_C11"),
+ PINCTRL_PIN(DB8500_PIN_D12, "GPIO143_D12"),
+ PINCTRL_PIN(DB8500_PIN_B13, "GPIO144_B13"),
+ PINCTRL_PIN(DB8500_PIN_C13, "GPIO145_C13"),
+ PINCTRL_PIN(DB8500_PIN_D13, "GPIO146_D13"),
+ PINCTRL_PIN(DB8500_PIN_C15, "GPIO147_C15"),
+ PINCTRL_PIN(DB8500_PIN_B16, "GPIO148_B16"),
+ PINCTRL_PIN(DB8500_PIN_B14, "GPIO149_B14"),
+ PINCTRL_PIN(DB8500_PIN_C14, "GPIO150_C14"),
+ PINCTRL_PIN(DB8500_PIN_D17, "GPIO151_D17"),
+ PINCTRL_PIN(DB8500_PIN_D16, "GPIO152_D16"),
+ PINCTRL_PIN(DB8500_PIN_B17, "GPIO153_B17"),
+ PINCTRL_PIN(DB8500_PIN_C16, "GPIO154_C16"),
+ PINCTRL_PIN(DB8500_PIN_C19, "GPIO155_C19"),
+ PINCTRL_PIN(DB8500_PIN_C17, "GPIO156_C17"),
+ PINCTRL_PIN(DB8500_PIN_A18, "GPIO157_A18"),
+ PINCTRL_PIN(DB8500_PIN_C18, "GPIO158_C18"),
+ PINCTRL_PIN(DB8500_PIN_B19, "GPIO159_B19"),
+ PINCTRL_PIN(DB8500_PIN_B20, "GPIO160_B20"),
+ PINCTRL_PIN(DB8500_PIN_D21, "GPIO161_D21"),
+ PINCTRL_PIN(DB8500_PIN_D20, "GPIO162_D20"),
+ PINCTRL_PIN(DB8500_PIN_C20, "GPIO163_C20"),
+ PINCTRL_PIN(DB8500_PIN_B21, "GPIO164_B21"),
+ PINCTRL_PIN(DB8500_PIN_C21, "GPIO165_C21"),
+ PINCTRL_PIN(DB8500_PIN_A22, "GPIO166_A22"),
+ PINCTRL_PIN(DB8500_PIN_B24, "GPIO167_B24"),
+ PINCTRL_PIN(DB8500_PIN_C22, "GPIO168_C22"),
+ PINCTRL_PIN(DB8500_PIN_D22, "GPIO169_D22"),
+ PINCTRL_PIN(DB8500_PIN_C23, "GPIO170_C23"),
+ PINCTRL_PIN(DB8500_PIN_D23, "GPIO171_D23"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_AJ27, "GPIO192_AJ27"),
+ PINCTRL_PIN(DB8500_PIN_AH27, "GPIO193_AH27"),
+ PINCTRL_PIN(DB8500_PIN_AF27, "GPIO194_AF27"),
+ PINCTRL_PIN(DB8500_PIN_AG28, "GPIO195_AG28"),
+ PINCTRL_PIN(DB8500_PIN_AG26, "GPIO196_AG26"),
+ PINCTRL_PIN(DB8500_PIN_AH24, "GPIO197_AH24"),
+ PINCTRL_PIN(DB8500_PIN_AG25, "GPIO198_AG25"),
+ PINCTRL_PIN(DB8500_PIN_AH23, "GPIO199_AH23"),
+ PINCTRL_PIN(DB8500_PIN_AH26, "GPIO200_AH26"),
+ PINCTRL_PIN(DB8500_PIN_AF24, "GPIO201_AF24"),
+ PINCTRL_PIN(DB8500_PIN_AF25, "GPIO202_AF25"),
+ PINCTRL_PIN(DB8500_PIN_AE23, "GPIO203_AE23"),
+ PINCTRL_PIN(DB8500_PIN_AF23, "GPIO204_AF23"),
+ PINCTRL_PIN(DB8500_PIN_AG23, "GPIO205_AG23"),
+ PINCTRL_PIN(DB8500_PIN_AG24, "GPIO206_AG24"),
+ PINCTRL_PIN(DB8500_PIN_AJ23, "GPIO207_AJ23"),
+ PINCTRL_PIN(DB8500_PIN_AH16, "GPIO208_AH16"),
+ PINCTRL_PIN(DB8500_PIN_AG15, "GPIO209_AG15"),
+ PINCTRL_PIN(DB8500_PIN_AJ15, "GPIO210_AJ15"),
+ PINCTRL_PIN(DB8500_PIN_AG14, "GPIO211_AG14"),
+ PINCTRL_PIN(DB8500_PIN_AF13, "GPIO212_AF13"),
+ PINCTRL_PIN(DB8500_PIN_AG13, "GPIO213_AG13"),
+ PINCTRL_PIN(DB8500_PIN_AH15, "GPIO214_AH15"),
+ PINCTRL_PIN(DB8500_PIN_AH13, "GPIO215_AH13"),
+ PINCTRL_PIN(DB8500_PIN_AG12, "GPIO216_AG12"),
+ PINCTRL_PIN(DB8500_PIN_AH12, "GPIO217_AH12"),
+ PINCTRL_PIN(DB8500_PIN_AH11, "GPIO218_AH11"),
+ PINCTRL_PIN(DB8500_PIN_AG10, "GPIO219_AG10"),
+ PINCTRL_PIN(DB8500_PIN_AH10, "GPIO220_AH10"),
+ PINCTRL_PIN(DB8500_PIN_AJ11, "GPIO221_AJ11"),
+ PINCTRL_PIN(DB8500_PIN_AJ9, "GPIO222_AJ9"),
+ PINCTRL_PIN(DB8500_PIN_AH9, "GPIO223_AH9"),
+ PINCTRL_PIN(DB8500_PIN_AG9, "GPIO224_AG9"),
+ PINCTRL_PIN(DB8500_PIN_AG8, "GPIO225_AG8"),
+ PINCTRL_PIN(DB8500_PIN_AF8, "GPIO226_AF8"),
+ PINCTRL_PIN(DB8500_PIN_AH7, "GPIO227_AH7"),
+ PINCTRL_PIN(DB8500_PIN_AJ6, "GPIO228_AJ6"),
+ PINCTRL_PIN(DB8500_PIN_AG7, "GPIO229_AG7"),
+ PINCTRL_PIN(DB8500_PIN_AF7, "GPIO230_AF7"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_AF28, "GPIO256_AF28"),
+ PINCTRL_PIN(DB8500_PIN_AE29, "GPIO257_AE29"),
+ PINCTRL_PIN(DB8500_PIN_AD29, "GPIO258_AD29"),
+ PINCTRL_PIN(DB8500_PIN_AC29, "GPIO259_AC29"),
+ PINCTRL_PIN(DB8500_PIN_AD28, "GPIO260_AD28"),
+ PINCTRL_PIN(DB8500_PIN_AD26, "GPIO261_AD26"),
+ PINCTRL_PIN(DB8500_PIN_AE26, "GPIO262_AE26"),
+ PINCTRL_PIN(DB8500_PIN_AG29, "GPIO263_AG29"),
+ PINCTRL_PIN(DB8500_PIN_AE27, "GPIO264_AE27"),
+ PINCTRL_PIN(DB8500_PIN_AD27, "GPIO265_AD27"),
+ PINCTRL_PIN(DB8500_PIN_AC28, "GPIO266_AC28"),
+ PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"),
+};
+
+#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \
+ .pin_base = b, .npins = c }
+
+/*
+ * This matches the 32-pin gpio chips registered by the GPIO portion. This
+ * cannot be const since we assign the struct gpio_chip * pointer at runtime.
+ */
+static struct pinctrl_gpio_range nmk_db8500_ranges[] = {
+ DB8500_GPIO_RANGE(0, 0, 32),
+ DB8500_GPIO_RANGE(1, 32, 5),
+ DB8500_GPIO_RANGE(2, 64, 32),
+ DB8500_GPIO_RANGE(3, 96, 2),
+ DB8500_GPIO_RANGE(4, 128, 32),
+ DB8500_GPIO_RANGE(5, 160, 12),
+ DB8500_GPIO_RANGE(6, 192, 32),
+ DB8500_GPIO_RANGE(7, 224, 7),
+ DB8500_GPIO_RANGE(8, 256, 12),
+};
+
+/*
+ * Read the pin group names like this:
+ * u0_a_1 = first groups of pins for uart0 on alt function a
+ * i2c2_b_2 = second group of pins for i2c2 on alt function b
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* Altfunction A column */
+static const unsigned u0_a_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+ DB8500_PIN_AH4, DB8500_PIN_AH3 };
+static const unsigned u1rxtx_a_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned u1ctsrts_a_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+/* Image processor I2C line, this is driven by image processor firmware */
+static const unsigned ipi2c_a_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned ipi2c_a_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+/* MSP0 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp0txrx_a_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned msp0tfstck_a_1_pins[] = { DB8500_PIN_AF3, DB8500_PIN_AE3 };
+static const unsigned msp0rfsrck_a_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Basic pins of the MMC/SD card 0 interface */
+static const unsigned mc0_a_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+ DB8500_PIN_AB4, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+/* Often only 4 bits are used, then these are not needed (only used for MMC) */
+static const unsigned mc0_dat47_a_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+ DB8500_PIN_V3, DB8500_PIN_V2};
+static const unsigned mc0dat31dir_a_1_pins[] = { DB8500_PIN_AB3 };
+/* MSP1 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp1txrx_a_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned msp1_a_1_pins[] = { DB8500_PIN_AE1, DB8500_PIN_AE2 };
+/* LCD interface */
+static const unsigned lcdb_a_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+ DB8500_PIN_G3, DB8500_PIN_G2 };
+static const unsigned lcdvsi0_a_1_pins[] = { DB8500_PIN_E1 };
+static const unsigned lcdvsi1_a_1_pins[] = { DB8500_PIN_E2 };
+static const unsigned lcd_d0_d7_a_1_pins[] = {
+ DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+ DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1 };
+/* D8 thru D11 often used as TVOUT lines */
+static const unsigned lcd_d8_d11_a_1_pins[] = { DB8500_PIN_F4,
+ DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2 };
+static const unsigned lcd_d12_d23_a_1_pins[] = {
+ DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5,
+ DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6,
+ DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned kp_a_1_pins[] = { DB8500_PIN_D7, DB8500_PIN_E8,
+ DB8500_PIN_D8, DB8500_PIN_D9 };
+static const unsigned kpskaskb_a_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16 };
+static const unsigned kp_a_2_pins[] = {
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+/* MC2 has 8 data lines and no direction control, so only for (e)MMC */
+static const unsigned mc2_a_1_pins[] = { DB8500_PIN_A5, DB8500_PIN_B4,
+ DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10,
+ DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7,
+ DB8500_PIN_C5 };
+static const unsigned ssp1_a_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+ DB8500_PIN_C12, DB8500_PIN_C11 };
+static const unsigned ssp0_a_1_pins[] = { DB8500_PIN_D12, DB8500_PIN_B13,
+ DB8500_PIN_C13, DB8500_PIN_D13 };
+static const unsigned i2c0_a_1_pins[] = { DB8500_PIN_C15, DB8500_PIN_B16 };
+/*
+ * Image processor GPIO pins are named "ipgpio" and have their own
+ * numberspace
+ */
+static const unsigned ipgpio0_a_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned ipgpio1_a_1_pins[] = { DB8500_PIN_C14 };
+/* Three modem pins named RF_PURn, MODEM_STATE and MODEM_PWREN */
+static const unsigned modem_a_1_pins[] = { DB8500_PIN_D22, DB8500_PIN_C23,
+ DB8500_PIN_D23 };
+/*
+ * This MSP cannot switch RX and TX, SCK in a separate group since this
+ * seems to be optional.
+ */
+static const unsigned msp2sck_a_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned msp2_a_1_pins[] = { DB8500_PIN_AH27, DB8500_PIN_AF27,
+ DB8500_PIN_AG28, DB8500_PIN_AG26 };
+static const unsigned mc4_a_1_pins[] = { DB8500_PIN_AH24, DB8500_PIN_AG25,
+ DB8500_PIN_AH23, DB8500_PIN_AH26, DB8500_PIN_AF24, DB8500_PIN_AF25,
+ DB8500_PIN_AE23, DB8500_PIN_AF23, DB8500_PIN_AG23, DB8500_PIN_AG24,
+ DB8500_PIN_AJ23 };
+/* MC1 has only 4 data pins, designed for SD or SDIO exclusively */
+static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15,
+ DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,
+ DB8500_PIN_AH15 };
+static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11 };
+static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10 };
+static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ11, DB8500_PIN_AJ9,
+ DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 };
+static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 };
+static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29,
+ DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26,
+ DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27,
+ DB8500_PIN_AC28, DB8500_PIN_AC27 };
+
+/* Altfunction B column */
+static const unsigned trig_b_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3 };
+static const unsigned i2c4_b_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned i2c1_b_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+static const unsigned i2c2_b_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned i2c2_b_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+static const unsigned msp0txrx_b_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned i2c1_b_2_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Just RX and TX for UART2 */
+static const unsigned u2rxtx_b_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1 };
+static const unsigned uartmodtx_b_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned msp0sck_b_1_pins[] = { DB8500_PIN_AB3 };
+static const unsigned uartmodrx_b_1_pins[] = { DB8500_PIN_AA3 };
+static const unsigned stmmod_b_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4,
+ DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned uartmodrx_b_2_pins[] = { DB8500_PIN_AB2 };
+static const unsigned spi3_b_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+ DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned msp1txrx_b_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+ DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_E1, DB8500_PIN_E2,
+ DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+ DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1,
+ DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2,
+ DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 };
+static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+ DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8,
+ DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9,
+ DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5,
+ DB8500_PIN_C9, DB8500_PIN_B14 };
+/* This chip select pin can be "ps0" in alt B so have it separately */
+static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 };
+static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 };
+static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 };
+static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 };
+static const unsigned lcdaclk_b_1_pins[] = { DB8500_PIN_C14 };
+static const unsigned lcda_b_1_pins[] = { DB8500_PIN_D22,
+ DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned lcd_b_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+static const unsigned ddrtrig_b_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned pwl_b_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned spi1_b_1_pins[] = { DB8500_PIN_AG15, DB8500_PIN_AF13,
+ DB8500_PIN_AG13, DB8500_PIN_AH15 };
+static const unsigned mc3_b_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11, DB8500_PIN_AG10, DB8500_PIN_AH10,
+ DB8500_PIN_AJ11, DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9,
+ DB8500_PIN_AG8 };
+static const unsigned pwl_b_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned pwl_b_3_pins[] = { DB8500_PIN_AG7 };
+static const unsigned pwl_b_4_pins[] = { DB8500_PIN_AF7 };
+
+/* Altfunction C column */
+static const unsigned ipjtag_c_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+ DB8500_PIN_AH4, DB8500_PIN_AH3, DB8500_PIN_AH6 };
+static const unsigned ipgpio6_c_1_pins[] = { DB8500_PIN_AG6 };
+static const unsigned ipgpio0_c_1_pins[] = { DB8500_PIN_AF6 };
+static const unsigned ipgpio1_c_1_pins[] = { DB8500_PIN_AG5 };
+static const unsigned ipgpio3_c_1_pins[] = { DB8500_PIN_AF5 };
+static const unsigned ipgpio2_c_1_pins[] = { DB8500_PIN_AG4 };
+static const unsigned slim0_c_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Optional 4-bit Memory Stick interface */
+static const unsigned ms_c_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+ DB8500_PIN_AB3, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned iptrigout_c_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned u2rxtx_c_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3 };
+static const unsigned u2ctsrts_c_1_pins[] = { DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned u0_c_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AE1,
+ DB8500_PIN_AE2, DB8500_PIN_AG2 };
+static const unsigned ipgpio4_c_1_pins[] = { DB8500_PIN_F3 };
+static const unsigned ipgpio5_c_1_pins[] = { DB8500_PIN_F1 };
+static const unsigned ipgpio6_c_2_pins[] = { DB8500_PIN_G3 };
+static const unsigned ipgpio7_c_1_pins[] = { DB8500_PIN_G2 };
+static const unsigned smcleale_c_1_pins[] = { DB8500_PIN_E1, DB8500_PIN_E2 };
+static const unsigned stmape_c_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 };
+static const unsigned u2rxtx_c_2_pins[] = { DB8500_PIN_H2, DB8500_PIN_J2 };
+static const unsigned ipgpio2_c_2_pins[] = { DB8500_PIN_F4 };
+static const unsigned ipgpio3_c_2_pins[] = { DB8500_PIN_E3 };
+static const unsigned ipgpio4_c_2_pins[] = { DB8500_PIN_E4 };
+static const unsigned ipgpio5_c_2_pins[] = { DB8500_PIN_D2 };
+static const unsigned mc5_c_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+ DB8500_PIN_D9 };
+static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 };
+static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+ DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 };
+static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 };
+static const unsigned uartmodrx_c_1_pins[] = { DB8500_PIN_D21 };
+static const unsigned uartmodtx_c_1_pins[] = { DB8500_PIN_D20 };
+static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 };
+static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 };
+static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 };
+static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 };
+static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9,
+ DB8500_PIN_AG9, DB8500_PIN_AG8 };
+static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+
+/* Other C1 column */
+static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11 };
+
+#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct nmk_pingroup nmk_db8500_groups[] = {
+ /* Altfunction A column */
+ DB8500_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
+ /* Altfunction B column */
+ DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(u2rxtx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodtx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp0sck_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodrx_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcdaclk_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcda_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcd_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B),
+ /* Altfunction C column */
+ DB8500_PIN_GROUP(ipjtag_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(slim0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ms_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(iptrigout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2ctsrts_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(uartmodrx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(uartmodtx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C),
+ /* Other alt C1 column, these are still configured as alt C */
+ DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define DB8500_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+DB8500_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1");
+DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1");
+/*
+ * UART2 can be muxed out with just RX/TX in four places, CTS+RTS is however
+ * only available on two pins in alternative function C
+ */
+DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1",
+ "u2rxtx_c_2", "u2rxtx_c_3");
+DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
+/*
+ * MSP0 can only be on a certain set of pins, but the TX/RX pins can be
+ * switched around by selecting the altfunction A or B. The SCK pin is
+ * only available on the altfunction B.
+ */
+DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1",
+ "msp0txrx_b_1", "msp0sck_b_1");
+DB8500_FUNC_GROUPS(mc0, "mc0_a_1");
+/* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */
+DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
+DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
+DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
+ "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
+DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
+DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
+DB8500_FUNC_GROUPS(i2c0, "i2c0_a_1");
+/* The image processor has 8 GPIO pins that can be muxed out */
+DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1",
+ "ipgpio2_b_1", "ipgpio3_b_1", "ipgpio6_c_1", "ipgpio0_c_1",
+ "ipgpio1_c_1", "ipgpio3_c_1", "ipgpio2_c_1", "ipgpio4_c_1",
+ "ipgpio5_c_1", "ipgpio6_c_2", "ipgpio7_c_1", "ipgpio2_c_2",
+ "ipgpio3_c_2", "ipgpio4_c_2", "ipgpio5_c_2");
+/* MSP2 can not invert the RX/TX pins but has the optional SCK pin */
+DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
+DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
+DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1");
+DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1");
+DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
+DB8500_FUNC_GROUPS(usb, "usb_a_1");
+DB8500_FUNC_GROUPS(trig, "trig_b_1");
+DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1");
+DB8500_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2");
+DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
+/*
+ * The modem UART can output its RX and TX pins in some different places,
+ * so select one of each.
+ */
+DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2",
+ "uartmodrx_c_1", "uartmod_tx_c_1");
+DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1");
+DB8500_FUNC_GROUPS(spi3, "spi3_b_1");
+/* Select between CS0 on alt B or PS1 on alt C */
+DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcleale_c_1", "smps1_c_1");
+DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1");
+DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
+DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4");
+DB8500_FUNC_GROUPS(spi1, "spi1_b_1");
+DB8500_FUNC_GROUPS(mc3, "mc3_b_1");
+DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1");
+DB8500_FUNC_GROUPS(slim0, "slim0_c_1");
+DB8500_FUNC_GROUPS(ms, "ms_c_1");
+DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1");
+DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2");
+DB8500_FUNC_GROUPS(mc5, "mc5_c_1");
+DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2");
+DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2");
+DB8500_FUNC_GROUPS(spi0, "spi0_c_1");
+DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct nmk_function nmk_db8500_functions[] = {
+ FUNCTION(u0),
+ FUNCTION(u1),
+ FUNCTION(u2),
+ FUNCTION(ipi2c),
+ FUNCTION(msp0),
+ FUNCTION(mc0),
+ FUNCTION(msp1),
+ FUNCTION(lcdb),
+ FUNCTION(lcd),
+ FUNCTION(kp),
+ FUNCTION(mc2),
+ FUNCTION(ssp1),
+ FUNCTION(ssp0),
+ FUNCTION(i2c0),
+ FUNCTION(ipgpio),
+ FUNCTION(msp2),
+ FUNCTION(mc4),
+ FUNCTION(mc1),
+ FUNCTION(hsi),
+ FUNCTION(clkout),
+ FUNCTION(usb),
+ FUNCTION(trig),
+ FUNCTION(i2c4),
+ FUNCTION(i2c1),
+ FUNCTION(i2c2),
+ FUNCTION(uartmod),
+ FUNCTION(stmmod),
+ FUNCTION(spi3),
+ FUNCTION(sm),
+ FUNCTION(lcda),
+ FUNCTION(ddrtrig),
+ FUNCTION(pwl),
+ FUNCTION(spi1),
+ FUNCTION(mc3),
+ FUNCTION(ipjtag),
+ FUNCTION(slim0),
+ FUNCTION(ms),
+ FUNCTION(iptrigout),
+ FUNCTION(stmape),
+ FUNCTION(mc5),
+ FUNCTION(usbsim),
+ FUNCTION(i2c3),
+ FUNCTION(spi0),
+ FUNCTION(spi2),
+};
+
+static const struct nmk_pinctrl_soc_data nmk_db8500_soc = {
+ .gpio_ranges = nmk_db8500_ranges,
+ .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges),
+ .pins = nmk_db8500_pins,
+ .npins = ARRAY_SIZE(nmk_db8500_pins),
+ .functions = nmk_db8500_functions,
+ .nfunctions = ARRAY_SIZE(nmk_db8500_functions),
+ .groups = nmk_db8500_groups,
+ .ngroups = ARRAY_SIZE(nmk_db8500_groups),
+};
+
+void __devinit
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+ *soc = &nmk_db8500_soc;
+}
diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 839624f..b8e01c3 100644
--- a/drivers/gpio/gpio-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -22,14 +22,20 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
#include <asm/mach/irq.h>
#include <plat/pincfg.h>
#include <plat/gpio-nomadik.h>
-#include <mach/hardware.h>
-#include <asm/gpio.h>
+
+#include "pinctrl-nomadik.h"
/*
* The GPIO module in the Nomadik family of Systems-on-Chip is an
@@ -43,6 +49,7 @@
struct nmk_gpio_chip {
struct gpio_chip chip;
+ struct irq_domain *domain;
void __iomem *addr;
struct clk *clk;
unsigned int bank;
@@ -58,8 +65,16 @@ struct nmk_gpio_chip {
u32 real_wake;
u32 rwimsc;
u32 fwimsc;
- u32 slpm;
+ u32 rimsc;
+ u32 fimsc;
u32 pull_up;
+ u32 lowemi;
+};
+
+struct nmk_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ const struct nmk_pinctrl_soc_data *soc;
};
static struct nmk_gpio_chip *
@@ -124,6 +139,24 @@ static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
}
}
+static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, bool lowemi)
+{
+ u32 bit = BIT(offset);
+ bool enabled = nmk_chip->lowemi & bit;
+
+ if (lowemi == enabled)
+ return;
+
+ if (lowemi)
+ nmk_chip->lowemi |= bit;
+ else
+ nmk_chip->lowemi &= ~bit;
+
+ writel_relaxed(nmk_chip->lowemi,
+ nmk_chip->addr + NMK_GPIO_LOWEMI);
+}
+
static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
unsigned offset)
{
@@ -150,8 +183,8 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
unsigned offset, int gpio_mode,
bool glitch)
{
- u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
- u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
+ u32 rwimsc = nmk_chip->rwimsc;
+ u32 fwimsc = nmk_chip->fwimsc;
if (glitch && nmk_chip->set_ioforce) {
u32 bit = BIT(offset);
@@ -173,6 +206,36 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
}
}
+static void
+nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
+{
+ u32 falling = nmk_chip->fimsc & BIT(offset);
+ u32 rising = nmk_chip->rimsc & BIT(offset);
+ int gpio = nmk_chip->chip.base + offset;
+ int irq = NOMADIK_GPIO_TO_IRQ(gpio);
+ struct irq_data *d = irq_get_irq_data(irq);
+
+ if (!rising && !falling)
+ return;
+
+ if (!d || !irqd_irq_disabled(d))
+ return;
+
+ if (rising) {
+ nmk_chip->rimsc &= ~BIT(offset);
+ writel_relaxed(nmk_chip->rimsc,
+ nmk_chip->addr + NMK_GPIO_RIMSC);
+ }
+
+ if (falling) {
+ nmk_chip->fimsc &= ~BIT(offset);
+ writel_relaxed(nmk_chip->fimsc,
+ nmk_chip->addr + NMK_GPIO_FIMSC);
+ }
+
+ dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
+}
+
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
{
@@ -238,6 +301,17 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
__nmk_gpio_set_pull(nmk_chip, offset, pull);
}
+ __nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg));
+
+ /*
+ * If the pin is switching to altfunc, and there was an interrupt
+ * installed on it which has been lazy disabled, actually mask the
+ * interrupt to prevent spurious interrupts that would occur while the
+ * pin is under control of the peripheral. Only SKE does this.
+ */
+ if (af != NMK_GPIO_ALT_GPIO)
+ nmk_gpio_disable_lazy_irq(nmk_chip, offset);
+
/*
* If we've backed up the SLPM registers (glitch workaround), modify
* the backups since they will be restored.
@@ -334,7 +408,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
struct nmk_gpio_chip *nmk_chip;
int pin = PIN_NUM(cfgs[i]);
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(pin));
+ nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP];
if (!nmk_chip) {
ret = -EINVAL;
break;
@@ -342,7 +416,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
clk_enable(nmk_chip->clk);
spin_lock(&nmk_chip->lock);
- __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
+ __nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP,
cfgs[i], sleep, glitch ? slpm : NULL);
spin_unlock(&nmk_chip->lock);
clk_disable(nmk_chip->clk);
@@ -426,7 +500,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
@@ -434,7 +508,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
- __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
+ __nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode);
spin_unlock(&nmk_chip->lock);
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
@@ -461,13 +535,13 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
+ __nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -489,13 +563,13 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
+ __nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -508,11 +582,11 @@ int nmk_gpio_get_mode(int gpio)
struct nmk_gpio_chip *nmk_chip;
u32 afunc, bfunc, bit;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
- bit = 1 << (gpio - nmk_chip->chip.base);
+ bit = 1 << (gpio % NMK_GPIO_PER_CHIP);
clk_enable(nmk_chip->clk);
@@ -529,21 +603,19 @@ EXPORT_SYMBOL(nmk_gpio_get_mode);
/* IRQ functions */
static inline int nmk_gpio_get_bitmask(int gpio)
{
- return 1 << (gpio % 32);
+ return 1 << (gpio % NMK_GPIO_PER_CHIP);
}
static void nmk_gpio_irq_ack(struct irq_data *d)
{
- int gpio;
struct nmk_gpio_chip *nmk_chip;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return;
clk_enable(nmk_chip->clk);
- writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
+ writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
clk_disable(nmk_chip->clk);
}
@@ -556,37 +628,52 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
int gpio, enum nmk_gpio_irq_type which,
bool enable)
{
- u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
- u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
u32 bitmask = nmk_gpio_get_bitmask(gpio);
- u32 reg;
+ u32 *rimscval;
+ u32 *fimscval;
+ u32 rimscreg;
+ u32 fimscreg;
+
+ if (which == NORMAL) {
+ rimscreg = NMK_GPIO_RIMSC;
+ fimscreg = NMK_GPIO_FIMSC;
+ rimscval = &nmk_chip->rimsc;
+ fimscval = &nmk_chip->fimsc;
+ } else {
+ rimscreg = NMK_GPIO_RWIMSC;
+ fimscreg = NMK_GPIO_FWIMSC;
+ rimscval = &nmk_chip->rwimsc;
+ fimscval = &nmk_chip->fwimsc;
+ }
/* we must individually set/clear the two edges */
if (nmk_chip->edge_rising & bitmask) {
- reg = readl(nmk_chip->addr + rimsc);
if (enable)
- reg |= bitmask;
+ *rimscval |= bitmask;
else
- reg &= ~bitmask;
- writel(reg, nmk_chip->addr + rimsc);
+ *rimscval &= ~bitmask;
+ writel(*rimscval, nmk_chip->addr + rimscreg);
}
if (nmk_chip->edge_falling & bitmask) {
- reg = readl(nmk_chip->addr + fimsc);
if (enable)
- reg |= bitmask;
+ *fimscval |= bitmask;
else
- reg &= ~bitmask;
- writel(reg, nmk_chip->addr + fimsc);
+ *fimscval &= ~bitmask;
+ writel(*fimscval, nmk_chip->addr + fimscreg);
}
}
static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
int gpio, bool on)
{
- if (nmk_chip->sleepmode) {
- __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
- on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
- : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+ /*
+ * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is
+ * disabled, since setting SLPM to 1 increases power consumption, and
+ * wakeup is anyhow controlled by the RIMSC and FIMSC registers.
+ */
+ if (nmk_chip->sleepmode && on) {
+ __nmk_gpio_set_slpm(nmk_chip, gpio % nmk_chip->chip.base,
+ NMK_GPIO_SLPM_WAKEUP_ENABLE);
}
__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
@@ -594,14 +681,12 @@ static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
{
- int gpio;
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
if (!nmk_chip)
return -EINVAL;
@@ -609,10 +694,10 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable);
if (!(nmk_chip->real_wake & bitmask))
- __nmk_gpio_set_wake(nmk_chip, gpio, enable);
+ __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable);
spin_unlock(&nmk_chip->lock);
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
@@ -636,20 +721,18 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- int gpio;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return -EINVAL;
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
if (irqd_irq_disabled(d))
- __nmk_gpio_set_wake(nmk_chip, gpio, on);
+ __nmk_gpio_set_wake(nmk_chip, d->hwirq, on);
if (on)
nmk_chip->real_wake |= bitmask;
@@ -667,17 +750,14 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
bool enabled = !irqd_irq_disabled(d);
bool wake = irqd_is_wakeup_set(d);
- int gpio;
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
if (!nmk_chip)
return -EINVAL;
-
if (type & IRQ_TYPE_LEVEL_HIGH)
return -EINVAL;
if (type & IRQ_TYPE_LEVEL_LOW)
@@ -687,10 +767,10 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_lock_irqsave(&nmk_chip->lock, flags);
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false);
if (enabled || wake)
- __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false);
nmk_chip->edge_rising &= ~bitmask;
if (type & IRQ_TYPE_EDGE_RISING)
@@ -701,10 +781,10 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
nmk_chip->edge_falling |= bitmask;
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true);
if (enabled || wake)
- __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -750,7 +830,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
chained_irq_enter(host_chip, desc);
nmk_chip = irq_get_handler_data(irq);
- first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
+ first_irq = nmk_chip->domain->revmap_data.legacy.first_irq;
while (status) {
int bit = __ffs(status);
@@ -784,18 +864,6 @@ static void nmk_gpio_secondary_irq_handler(unsigned int irq,
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
{
- unsigned int first_irq;
- int i;
-
- first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
- for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
- irq_set_chip_and_handler(i, &nmk_gpio_irq_chip,
- handle_edge_irq);
- set_irq_flags(i, IRQF_VALID);
- irq_set_chip_data(i, nmk_chip);
- irq_set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
- }
-
irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
@@ -809,6 +877,25 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
}
/* I/O Functions */
+
+static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void nmk_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
{
struct nmk_gpio_chip *nmk_chip =
@@ -872,21 +959,23 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
- return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
+ return irq_find_mapping(nmk_chip->domain, offset);
}
#ifdef CONFIG_DEBUG_FS
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
- int mode;
- unsigned i;
- unsigned gpio = chip->base;
- int is_out;
+ const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
+ int mode;
+ bool is_out;
+ bool pull;
+ u32 bit = 1 << offset;
const char *modes[] = {
[NMK_GPIO_ALT_GPIO] = "gpio",
[NMK_GPIO_ALT_A] = "altA",
@@ -895,61 +984,70 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
};
clk_enable(nmk_chip->clk);
-
- for (i = 0; i < chip->ngpio; i++, gpio++) {
- const char *label = gpiochip_is_requested(chip, i);
- bool pull;
- u32 bit = 1 << i;
-
- is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
- pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
- mode = nmk_gpio_get_mode(gpio);
- seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
- gpio, label ?: "(none)",
- is_out ? "out" : "in ",
- chip->get
- ? (chip->get(chip, i) ? "hi" : "lo")
- : "? ",
- (mode < 0) ? "unknown" : modes[mode],
- pull ? "pull" : "none");
-
- if (label && !is_out) {
- int irq = gpio_to_irq(gpio);
- struct irq_desc *desc = irq_to_desc(irq);
-
- /* This races with request_irq(), set_irq_type(),
- * and set_irq_wake() ... but those are "rare".
- */
- if (irq >= 0 && desc->action) {
- char *trigger;
- u32 bitmask = nmk_gpio_get_bitmask(gpio);
-
- if (nmk_chip->edge_rising & bitmask)
- trigger = "edge-rising";
- else if (nmk_chip->edge_falling & bitmask)
- trigger = "edge-falling";
- else
- trigger = "edge-undefined";
-
- seq_printf(s, " irq-%d %s%s",
- irq, trigger,
- irqd_is_wakeup_set(&desc->irq_data)
- ? " wakeup" : "");
- }
+ is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
+ pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
+ mode = nmk_gpio_get_mode(gpio);
+
+ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
+ gpio, label ?: "(none)",
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, offset) ? "hi" : "lo")
+ : "? ",
+ (mode < 0) ? "unknown" : modes[mode],
+ pull ? "pull" : "none");
+
+ if (label && !is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+ u32 bitmask = nmk_gpio_get_bitmask(gpio);
+
+ if (nmk_chip->edge_rising & bitmask)
+ trigger = "edge-rising";
+ else if (nmk_chip->edge_falling & bitmask)
+ trigger = "edge-falling";
+ else
+ trigger = "edge-undefined";
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ irqd_is_wakeup_set(&desc->irq_data)
+ ? " wakeup" : "");
}
+ }
+ clk_disable(nmk_chip->clk);
+}
+static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned i;
+ unsigned gpio = chip->base;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ nmk_gpio_dbg_show_one(s, chip, i, gpio);
seq_printf(s, "\n");
}
-
- clk_disable(nmk_chip->clk);
}
#else
+static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
+{
+}
#define nmk_gpio_dbg_show NULL
#endif
/* This structure is replicated for each GPIO block allocated at probe time */
static struct gpio_chip nmk_gpio_template = {
+ .request = nmk_gpio_request,
+ .free = nmk_gpio_free,
.direction_input = nmk_gpio_make_input,
.get = nmk_gpio_get_input,
.direction_output = nmk_gpio_make_output,
@@ -1008,21 +1106,11 @@ void nmk_gpio_wakeups_suspend(void)
clk_enable(chip->clk);
- chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
- chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
-
writel(chip->rwimsc & chip->real_wake,
chip->addr + NMK_GPIO_RWIMSC);
writel(chip->fwimsc & chip->real_wake,
chip->addr + NMK_GPIO_FWIMSC);
- if (chip->sleepmode) {
- chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
-
- /* 0 -> wakeup enable */
- writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
- }
-
clk_disable(chip->clk);
}
}
@@ -1042,9 +1130,6 @@ void nmk_gpio_wakeups_resume(void)
writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
- if (chip->sleepmode)
- writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
-
clk_disable(chip->clk);
}
}
@@ -1068,19 +1153,62 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
+int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct nmk_gpio_chip *nmk_chip = d->host_data;
+
+ if (!nmk_chip)
+ return -EINVAL;
+
+ irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ irq_set_chip_data(irq, nmk_chip);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
+}
+
+const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
+ .map = nmk_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
static int __devinit nmk_gpio_probe(struct platform_device *dev)
{
struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
+ struct device_node *np = dev->dev.of_node;
struct nmk_gpio_chip *nmk_chip;
struct gpio_chip *chip;
struct resource *res;
struct clk *clk;
int secondary_irq;
+ void __iomem *base;
int irq;
int ret;
- if (!pdata)
+ if (!pdata && !np) {
+ dev_err(&dev->dev, "No platform data or device tree found\n");
return -ENODEV;
+ }
+
+ if (np) {
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_get_property(np, "supports-sleepmode", NULL))
+ pdata->supports_sleepmode = true;
+
+ if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
+ dev_err(&dev->dev, "gpio-bank property not found\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
+ pdata->num_gpio = NMK_GPIO_PER_CHIP;
+ }
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1106,10 +1234,16 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
goto out;
}
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
clk = clk_get(&dev->dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- goto out_release;
+ goto out_unmap;
}
nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
@@ -1117,13 +1251,14 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
ret = -ENOMEM;
goto out_clk;
}
+
/*
* The virt address in nmk_chip->addr is in the nomadik register space,
* so we can simply convert the resource address, without remapping
*/
nmk_chip->bank = dev->id;
nmk_chip->clk = clk;
- nmk_chip->addr = io_p2v(res->start);
+ nmk_chip->addr = base;
nmk_chip->chip = nmk_gpio_template;
nmk_chip->parent_irq = irq;
nmk_chip->secondary_parent_irq = secondary_irq;
@@ -1139,6 +1274,14 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
+ clk_enable(nmk_chip->clk);
+ nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI);
+ clk_disable(nmk_chip->clk);
+
+#ifdef CONFIG_OF_GPIO
+ chip->of_node = np;
+#endif
+
ret = gpiochip_add(&nmk_chip->chip);
if (ret)
goto out_free;
@@ -1146,12 +1289,22 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
+
platform_set_drvdata(dev, nmk_chip);
+ nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP,
+ NOMADIK_GPIO_TO_IRQ(pdata->first_gpio),
+ 0, &nmk_gpio_irq_simple_ops, nmk_chip);
+ if (!nmk_chip->domain) {
+ pr_err("%s: Failed to create irqdomain\n", np->full_name);
+ ret = -ENOSYS;
+ goto out_free;
+ }
+
nmk_gpio_init_irq(nmk_chip);
- dev_info(&dev->dev, "at address %p\n",
- nmk_chip->addr);
+ dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
+
return 0;
out_free:
@@ -1159,25 +1312,465 @@ out_free:
out_clk:
clk_disable(clk);
clk_put(clk);
+out_unmap:
+ iounmap(base);
out_release:
release_mem_region(res->start, resource_size(res));
out:
dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
pdata->first_gpio, pdata->first_gpio+31);
+ if (np)
+ kfree(pdata);
+
return ret;
}
+static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->ngroups;
+}
+
+static const char *nmk_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->groups[selector].name;
+}
+
+static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = npct->soc->groups[selector].pins;
+ *num_pins = npct->soc->groups[selector].npins;
+ return 0;
+}
+
+static struct pinctrl_gpio_range *
+nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ int i;
+
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+ struct pinctrl_gpio_range *range;
+
+ range = &npct->soc->gpio_ranges[i];
+ if (offset >= range->pin_base &&
+ offset <= (range->pin_base + range->npins - 1))
+ return range;
+ }
+ return NULL;
+}
+
+static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ struct pinctrl_gpio_range *range;
+ struct gpio_chip *chip;
+
+ range = nmk_match_gpio_range(pctldev, offset);
+ if (!range || !range->gc) {
+ seq_printf(s, "invalid pin offset");
+ return;
+ }
+ chip = range->gc;
+ nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+}
+
+static struct pinctrl_ops nmk_pinctrl_ops = {
+ .get_groups_count = nmk_get_groups_cnt,
+ .get_group_name = nmk_get_group_name,
+ .get_group_pins = nmk_get_group_pins,
+ .pin_dbg_show = nmk_pin_dbg_show,
+};
+
+static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->nfunctions;
+}
+
+static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->functions[function].name;
+}
+
+static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = npct->soc->functions[function].groups;
+ *num_groups = npct->soc->functions[function].ngroups;
+
+ return 0;
+}
+
+static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct nmk_pingroup *g;
+ static unsigned int slpm[NUM_BANKS];
+ unsigned long flags;
+ bool glitch;
+ int ret = -EINVAL;
+ int i;
+
+ g = &npct->soc->groups[group];
+
+ if (g->altsetting < 0)
+ return -EINVAL;
+
+ dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+ /* Handle this special glitch on altfunction C */
+ glitch = (g->altsetting == NMK_GPIO_ALT_C);
+
+ if (glitch) {
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+
+ /* Initially don't put any pins to sleep when switching */
+ memset(slpm, 0xff, sizeof(slpm));
+
+ /*
+ * Then mask the pins that need to be sleeping now when we're
+ * switching to the ALT C function.
+ */
+ for (i = 0; i < g->npins; i++)
+ slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]);
+ nmk_gpio_glitch_slpm_init(slpm);
+ }
+
+ for (i = 0; i < g->npins; i++) {
+ struct pinctrl_gpio_range *range;
+ struct nmk_gpio_chip *nmk_chip;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ range = nmk_match_gpio_range(pctldev, g->pins[i]);
+ if (!range) {
+ dev_err(npct->dev,
+ "invalid pin offset %d in group %s at index %d\n",
+ g->pins[i], g->name, i);
+ goto out_glitch;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n",
+ g->pins[i], g->name, i);
+ goto out_glitch;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting);
+
+ clk_enable(nmk_chip->clk);
+ bit = g->pins[i] % NMK_GPIO_PER_CHIP;
+ /*
+ * If the pin is switching to altfunc, and there was an
+ * interrupt installed on it which has been lazy disabled,
+ * actually mask the interrupt to prevent spurious interrupts
+ * that would occur while the pin is under control of the
+ * peripheral. Only SKE does this.
+ */
+ nmk_gpio_disable_lazy_irq(nmk_chip, bit);
+
+ __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch);
+ clk_disable(nmk_chip->clk);
+ }
+
+ /* When all pins are successfully reconfigured we get here */
+ ret = 0;
+
+out_glitch:
+ if (glitch) {
+ nmk_gpio_glitch_slpm_restore(slpm);
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+ }
+
+ return ret;
+}
+
+static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct nmk_pingroup *g;
+
+ g = &npct->soc->groups[group];
+
+ if (g->altsetting < 0)
+ return;
+
+ /* Poke out the mux, set the pin to some default state? */
+ dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct nmk_gpio_chip *nmk_chip;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ if (!range) {
+ dev_err(npct->dev, "invalid range\n");
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "missing GPIO chip in range\n");
+ return -EINVAL;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+ clk_enable(nmk_chip->clk);
+ bit = offset % NMK_GPIO_PER_CHIP;
+ /* There is no glitch when converting any pin to GPIO */
+ __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+ clk_disable(nmk_chip->clk);
+
+ return 0;
+}
+
+void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+ /* Set the pin to some default state, GPIO is usually default */
+}
+
+static struct pinmux_ops nmk_pinmux_ops = {
+ .get_functions_count = nmk_pmx_get_funcs_cnt,
+ .get_function_name = nmk_pmx_get_func_name,
+ .get_function_groups = nmk_pmx_get_func_groups,
+ .enable = nmk_pmx_enable,
+ .disable = nmk_pmx_disable,
+ .gpio_request_enable = nmk_gpio_request_enable,
+ .gpio_disable_free = nmk_gpio_disable_free,
+};
+
+int nmk_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config)
+{
+ /* Not implemented */
+ return -EINVAL;
+}
+
+int nmk_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long config)
+{
+ static const char *pullnames[] = {
+ [NMK_GPIO_PULL_NONE] = "none",
+ [NMK_GPIO_PULL_UP] = "up",
+ [NMK_GPIO_PULL_DOWN] = "down",
+ [3] /* illegal */ = "??"
+ };
+ static const char *slpmnames[] = {
+ [NMK_GPIO_SLPM_INPUT] = "input/wakeup",
+ [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup",
+ };
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct nmk_gpio_chip *nmk_chip;
+ struct pinctrl_gpio_range *range;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ /*
+ * The pin config contains pin number and altfunction fields, here
+ * we just ignore that part. It's being handled by the framework and
+ * pinmux callback respectively.
+ */
+ pin_cfg_t cfg = (pin_cfg_t) config;
+ int pull = PIN_PULL(cfg);
+ int slpm = PIN_SLPM(cfg);
+ int output = PIN_DIR(cfg);
+ int val = PIN_VAL(cfg);
+ bool lowemi = PIN_LOWEMI(cfg);
+ bool gpiomode = PIN_GPIOMODE(cfg);
+ bool sleep = PIN_SLEEPMODE(cfg);
+
+ range = nmk_match_gpio_range(pctldev, pin);
+ if (!range) {
+ dev_err(npct->dev, "invalid pin offset %d\n", pin);
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "GPIO chip missing in range for pin %d\n",
+ pin);
+ return -EINVAL;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+ if (sleep) {
+ int slpm_pull = PIN_SLPM_PULL(cfg);
+ int slpm_output = PIN_SLPM_DIR(cfg);
+ int slpm_val = PIN_SLPM_VAL(cfg);
+
+ /* All pins go into GPIO mode at sleep */
+ gpiomode = true;
+
+ /*
+ * The SLPM_* values are normal values + 1 to allow zero to
+ * mean "same as normal".
+ */
+ if (slpm_pull)
+ pull = slpm_pull - 1;
+ if (slpm_output)
+ output = slpm_output - 1;
+ if (slpm_val)
+ val = slpm_val - 1;
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
+ pin,
+ slpm_pull ? pullnames[pull] : "same",
+ slpm_output ? (output ? "output" : "input") : "same",
+ slpm_val ? (val ? "high" : "low") : "same");
+ }
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
+ pin, cfg, pullnames[pull], slpmnames[slpm],
+ output ? "output " : "input",
+ output ? (val ? "high" : "low") : "",
+ lowemi ? "on" : "off" );
+
+ clk_enable(nmk_chip->clk);
+ bit = pin % NMK_GPIO_PER_CHIP;
+ if (gpiomode)
+ /* No glitch when going to GPIO mode */
+ __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+ if (output)
+ __nmk_gpio_make_output(nmk_chip, bit, val);
+ else {
+ __nmk_gpio_make_input(nmk_chip, bit);
+ __nmk_gpio_set_pull(nmk_chip, bit, pull);
+ }
+ /* TODO: isn't this only applicable on output pins? */
+ __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+
+ __nmk_gpio_set_slpm(nmk_chip, bit, slpm);
+ clk_disable(nmk_chip->clk);
+ return 0;
+}
+
+static struct pinconf_ops nmk_pinconf_ops = {
+ .pin_config_get = nmk_pin_config_get,
+ .pin_config_set = nmk_pin_config_set,
+};
+
+static struct pinctrl_desc nmk_pinctrl_desc = {
+ .name = "pinctrl-nomadik",
+ .pctlops = &nmk_pinctrl_ops,
+ .pmxops = &nmk_pinmux_ops,
+ .confops = &nmk_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
+ struct nmk_pinctrl *npct;
+ int i;
+
+ npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL);
+ if (!npct)
+ return -ENOMEM;
+
+ /* Poke in other ASIC variants here */
+ if (platid->driver_data == PINCTRL_NMK_DB8500)
+ nmk_pinctrl_db8500_init(&npct->soc);
+
+ /*
+ * We need all the GPIO drivers to probe FIRST, or we will not be able
+ * to obtain references to the struct gpio_chip * for them, and we
+ * need this to proceed.
+ */
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+ if (!nmk_gpio_chips[i]) {
+ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+ devm_kfree(&pdev->dev, npct);
+ return -EPROBE_DEFER;
+ }
+ npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+ }
+
+ nmk_pinctrl_desc.pins = npct->soc->pins;
+ nmk_pinctrl_desc.npins = npct->soc->npins;
+ npct->dev = &pdev->dev;
+ npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
+ if (!npct->pctl) {
+ dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
+ return -EINVAL;
+ }
+
+ /* We will handle a range of GPIO pins */
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++)
+ pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]);
+
+ platform_set_drvdata(pdev, npct);
+ dev_info(&pdev->dev, "initialized Nomadik pin control driver\n");
+
+ return 0;
+}
+
+static const struct of_device_id nmk_gpio_match[] = {
+ { .compatible = "st,nomadik-gpio", },
+ {}
+};
+
static struct platform_driver nmk_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gpio",
+ .of_match_table = nmk_gpio_match,
},
.probe = nmk_gpio_probe,
};
+static const struct platform_device_id nmk_pinctrl_id[] = {
+ { "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
+ { "pinctrl-db8500", PINCTRL_NMK_DB8500 },
+};
+
+static struct platform_driver nmk_pinctrl_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pinctrl-nomadik",
+ },
+ .probe = nmk_pinctrl_probe,
+ .id_table = nmk_pinctrl_id,
+};
+
static int __init nmk_gpio_init(void)
{
- return platform_driver_register(&nmk_gpio_driver);
+ int ret;
+
+ ret = platform_driver_register(&nmk_gpio_driver);
+ if (ret)
+ return ret;
+ return platform_driver_register(&nmk_pinctrl_driver);
}
core_initcall(nmk_gpio_init);
diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h
new file mode 100644
index 0000000..bc91aed
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik.h
@@ -0,0 +1,77 @@
+#ifndef PINCTRL_PINCTRL_NOMADIK_H
+#define PINCTRL_PINCTRL_NOMADIK_H
+
+#include <plat/gpio-nomadik.h>
+
+/* Package definitions */
+#define PINCTRL_NMK_STN8815 0
+#define PINCTRL_NMK_DB8500 1
+
+/**
+ * struct nmk_function - Nomadik pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct nmk_function {
+ const char *name;
+ const char * const *groups;
+ unsigned ngroups;
+};
+
+/**
+ * struct nmk_pingroup - describes a Nomadik pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ * configure them to be used by a function
+ */
+struct nmk_pingroup {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned npins;
+ int altsetting;
+};
+
+/**
+ * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration
+ * @gpio_ranges: An array of GPIO ranges for this SoC
+ * @gpio_num_ranges: The number of GPIO ranges for this SoC
+ * @pins: An array describing all pins the pin controller affects.
+ * All pins which are also GPIOs must be listed first within the
+ * array, and be numbered identically to the GPIO controller's
+ * numbering.
+ * @npins: The number of entries in @pins.
+ * @functions: The functions supported on this SoC.
+ * @nfunction: The number of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The number of entries in @groups.
+ */
+struct nmk_pinctrl_soc_data {
+ struct pinctrl_gpio_range *gpio_ranges;
+ unsigned gpio_num_ranges;
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ const struct nmk_function *functions;
+ unsigned nfunctions;
+ const struct nmk_pingroup *groups;
+ unsigned ngroups;
+};
+
+#ifdef CONFIG_PINCTRL_DB8500
+
+void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_NOMADIK_H */
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
index 079dce0..f14cd6b 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.c
+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
@@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
.pin_base = 0,
};
-static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
+static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
{
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- if (selector >= info->num_grps)
- return -EINVAL;
- return 0;
+
+ return info->num_grps;
}
static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
unsigned selector)
{
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- if (selector >= info->num_grps)
- return NULL;
+
return info->grps[selector].name;
}
@@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
unsigned *num_pins)
{
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- if (selector >= info->num_grps)
- return -EINVAL;
+
*pins = info->grps[selector].pins;
*num_pins = info->grps[selector].npins;
return 0;
}
static struct pinctrl_ops pxa3xx_pctrl_ops = {
- .list_groups = pxa3xx_list_groups,
+ .get_groups_count = pxa3xx_get_groups_count,
.get_group_name = pxa3xx_get_group_name,
.get_group_pins = pxa3xx_get_group_pins,
};
-static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
+static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
{
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- if (func >= info->num_funcs)
- return -EINVAL;
- return 0;
+
+ return info->num_funcs;
}
static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
@@ -142,11 +138,6 @@ static int pxa3xx_pmx_enable(struct pinctrl_dev *pctrldev, unsigned func,
return 0;
}
-static void pxa3xx_pmx_disable(struct pinctrl_dev *pctrldev, unsigned func,
- unsigned group)
-{
-}
-
static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
struct pinctrl_gpio_range *range,
unsigned pin)
@@ -170,11 +161,10 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
}
static struct pinmux_ops pxa3xx_pmx_ops = {
- .list_functions = pxa3xx_pmx_list_func,
+ .get_functions_count = pxa3xx_pmx_get_funcs_count,
.get_function_name = pxa3xx_pmx_get_func_name,
.get_function_groups = pxa3xx_pmx_get_groups,
.enable = pxa3xx_pmx_enable,
- .disable = pxa3xx_pmx_disable,
.gpio_request_enable = pxa3xx_pmx_request_gpio,
};
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index 6b3534c..ba15b1a 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
};
-static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
{
- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
- return -EINVAL;
- return 0;
+ return ARRAY_SIZE(sirfsoc_pin_groups);
}
static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
- return NULL;
return sirfsoc_pin_groups[selector].name;
}
@@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
const unsigned **pins,
unsigned *num_pins)
{
- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
- return -EINVAL;
*pins = sirfsoc_pin_groups[selector].pins;
*num_pins = sirfsoc_pin_groups[selector].num_pins;
return 0;
@@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
}
static struct pinctrl_ops sirfsoc_pctrl_ops = {
- .list_groups = sirfsoc_list_groups,
+ .get_groups_count = sirfsoc_get_groups_count,
.get_group_name = sirfsoc_get_group_name,
.get_group_pins = sirfsoc_get_group_pins,
.pin_dbg_show = sirfsoc_pin_dbg_show,
@@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
sirfsoc_pinmux_endisable(spmx, selector, false);
}
-static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
+static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
{
- if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
- return -EINVAL;
- return 0;
+ return ARRAY_SIZE(sirfsoc_pmx_functions);
}
static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
@@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
}
static struct pinmux_ops sirfsoc_pinmux_ops = {
- .list_functions = sirfsoc_pinmux_list_funcs,
.enable = sirfsoc_pinmux_enable,
.disable = sirfsoc_pinmux_disable,
+ .get_functions_count = sirfsoc_pinmux_get_funcs_count,
.get_function_name = sirfsoc_pinmux_get_func_name,
.get_function_groups = sirfsoc_pinmux_get_groups,
.gpio_request_enable = sirfsoc_pinmux_request_gpio,
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 9b32968..b693486 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -1,7 +1,7 @@
/*
* Driver for the NVIDIA Tegra pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* Derived from code:
* Copyright (C) 2010 Google, Inc.
@@ -22,17 +22,19 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
+#include <linux/slab.h>
#include <mach/pinconf-tegra.h>
+#include "core.h"
#include "pinctrl-tegra.h"
-#define DRIVER_NAME "tegra-pinmux-disabled"
-
struct tegra_pmx {
struct device *dev;
struct pinctrl_dev *pctl;
@@ -53,15 +55,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
writel(val, pmx->regs[bank] + reg);
}
-static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
- unsigned group)
+static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (group >= pmx->soc->ngroups)
- return -EINVAL;
-
- return 0;
+ return pmx->soc->ngroups;
}
static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
@@ -69,9 +67,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (group >= pmx->soc->ngroups)
- return NULL;
-
return pmx->soc->groups[group].name;
}
@@ -82,38 +77,259 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (group >= pmx->soc->ngroups)
- return -EINVAL;
-
*pins = pmx->soc->groups[group].pins;
*num_pins = pmx->soc->groups[group].npins;
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned offset)
{
- seq_printf(s, " " DRIVER_NAME);
+ seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+#endif
+
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+ unsigned *reserved_maps, unsigned *num_maps,
+ unsigned reserve)
+{
+ unsigned old_num = *reserved_maps;
+ unsigned new_num = *num_maps + reserve;
+ struct pinctrl_map *new_map;
+
+ if (old_num >= new_num)
+ return 0;
+
+ new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+ if (!new_map) {
+ dev_err(dev, "krealloc(map) failed\n");
+ return -ENOMEM;
+ }
+
+ memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+ *map = new_map;
+ *reserved_maps = new_num;
+
+ return 0;
+}
+
+static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
+ unsigned *num_maps, const char *group,
+ const char *function)
+{
+ if (WARN_ON(*num_maps == *reserved_maps))
+ return -ENOSPC;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[*num_maps].data.mux.group = group;
+ (*map)[*num_maps].data.mux.function = function;
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int add_map_configs(struct device *dev, struct pinctrl_map **map,
+ unsigned *reserved_maps, unsigned *num_maps,
+ const char *group, unsigned long *configs,
+ unsigned num_configs)
+{
+ unsigned long *dup_configs;
+
+ if (WARN_ON(*num_maps == *reserved_maps))
+ return -ENOSPC;
+
+ dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+ GFP_KERNEL);
+ if (!dup_configs) {
+ dev_err(dev, "kmemdup(configs) failed\n");
+ return -ENOMEM;
+ }
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ (*map)[*num_maps].data.configs.group_or_pin = group;
+ (*map)[*num_maps].data.configs.configs = dup_configs;
+ (*map)[*num_maps].data.configs.num_configs = num_configs;
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int add_config(struct device *dev, unsigned long **configs,
+ unsigned *num_configs, unsigned long config)
+{
+ unsigned old_num = *num_configs;
+ unsigned new_num = old_num + 1;
+ unsigned long *new_configs;
+
+ new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
+ GFP_KERNEL);
+ if (!new_configs) {
+ dev_err(dev, "krealloc(configs) failed\n");
+ return -ENOMEM;
+ }
+
+ new_configs[old_num] = config;
+
+ *configs = new_configs;
+ *num_configs = new_num;
+
+ return 0;
+}
+
+void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+ kfree(map[i].data.configs.configs);
+
+ kfree(map);
+}
+
+static const struct cfg_param {
+ const char *property;
+ enum tegra_pinconf_param param;
+} cfg_params[] = {
+ {"nvidia,pull", TEGRA_PINCONF_PARAM_PULL},
+ {"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE},
+ {"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT},
+ {"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN},
+ {"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK},
+ {"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET},
+ {"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
+ {"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT},
+ {"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
+ {"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH},
+ {"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
+ {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
+ {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
+};
+
+int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ int ret, i;
+ const char *function;
+ u32 val;
+ unsigned long config;
+ unsigned long *configs = NULL;
+ unsigned num_configs = 0;
+ unsigned reserve;
+ struct property *prop;
+ const char *group;
+
+ ret = of_property_read_string(np, "nvidia,function", &function);
+ if (ret < 0) {
+ /* EINVAL=missing, which is fine since it's optional */
+ if (ret != -EINVAL)
+ dev_err(dev,
+ "could not parse property nvidia,function\n");
+ function = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+ ret = of_property_read_u32(np, cfg_params[i].property, &val);
+ if (!ret) {
+ config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
+ ret = add_config(dev, &configs, &num_configs, config);
+ if (ret < 0)
+ goto exit;
+ /* EINVAL=missing, which is fine since it's optional */
+ } else if (ret != -EINVAL) {
+ dev_err(dev, "could not parse property %s\n",
+ cfg_params[i].property);
+ }
+ }
+
+ reserve = 0;
+ if (function != NULL)
+ reserve++;
+ if (num_configs)
+ reserve++;
+ ret = of_property_count_strings(np, "nvidia,pins");
+ if (ret < 0) {
+ dev_err(dev, "could not parse property nvidia,pins\n");
+ goto exit;
+ }
+ reserve *= ret;
+
+ ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+ if (ret < 0)
+ goto exit;
+
+ of_property_for_each_string(np, "nvidia,pins", prop, group) {
+ if (function) {
+ ret = add_map_mux(map, reserved_maps, num_maps,
+ group, function);
+ if (ret < 0)
+ goto exit;
+ }
+
+ if (num_configs) {
+ ret = add_map_configs(dev, map, reserved_maps,
+ num_maps, group, configs,
+ num_configs);
+ if (ret < 0)
+ goto exit;
+ }
+ }
+
+ ret = 0;
+
+exit:
+ kfree(configs);
+ return ret;
+}
+
+int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ unsigned reserved_maps;
+ struct device_node *np;
+ int ret;
+
+ reserved_maps = 0;
+ *map = NULL;
+ *num_maps = 0;
+
+ for_each_child_of_node(np_config, np) {
+ ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+ &reserved_maps, num_maps);
+ if (ret < 0) {
+ tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+ return ret;
+ }
+ }
+
+ return 0;
}
static struct pinctrl_ops tegra_pinctrl_ops = {
- .list_groups = tegra_pinctrl_list_groups,
+ .get_groups_count = tegra_pinctrl_get_groups_count,
.get_group_name = tegra_pinctrl_get_group_name,
.get_group_pins = tegra_pinctrl_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+#endif
+ .dt_node_to_map = tegra_pinctrl_dt_node_to_map,
+ .dt_free_map = tegra_pinctrl_dt_free_map,
};
-static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
- unsigned function)
+static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (function >= pmx->soc->nfunctions)
- return -EINVAL;
-
- return 0;
+ return pmx->soc->nfunctions;
}
static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
@@ -121,9 +337,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (function >= pmx->soc->nfunctions)
- return NULL;
-
return pmx->soc->functions[function].name;
}
@@ -134,9 +347,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
- if (function >= pmx->soc->nfunctions)
- return -EINVAL;
-
*groups = pmx->soc->functions[function].groups;
*num_groups = pmx->soc->functions[function].ngroups;
@@ -151,18 +361,16 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
int i;
u32 val;
- if (group >= pmx->soc->ngroups)
- return -EINVAL;
g = &pmx->soc->groups[group];
- if (g->mux_reg < 0)
+ if (WARN_ON(g->mux_reg < 0))
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
if (g->funcs[i] == function)
break;
}
- if (i == ARRAY_SIZE(g->funcs))
+ if (WARN_ON(i == ARRAY_SIZE(g->funcs)))
return -EINVAL;
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -180,11 +388,9 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
const struct tegra_pingroup *g;
u32 val;
- if (group >= pmx->soc->ngroups)
- return;
g = &pmx->soc->groups[group];
- if (g->mux_reg < 0)
+ if (WARN_ON(g->mux_reg < 0))
return;
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -194,7 +400,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
}
static struct pinmux_ops tegra_pinmux_ops = {
- .list_functions = tegra_pinctrl_list_funcs,
+ .get_functions_count = tegra_pinctrl_get_funcs_count,
.get_function_name = tegra_pinctrl_get_func_name,
.get_function_groups = tegra_pinctrl_get_func_groups,
.enable = tegra_pinctrl_enable,
@@ -204,6 +410,7 @@ static struct pinmux_ops tegra_pinmux_ops = {
static int tegra_pinconf_reg(struct tegra_pmx *pmx,
const struct tegra_pingroup *g,
enum tegra_pinconf_param param,
+ bool report_err,
s8 *bank, s16 *reg, s8 *bit, s8 *width)
{
switch (param) {
@@ -291,9 +498,10 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
}
if (*reg < 0) {
- dev_err(pmx->dev,
- "Config param %04x not supported on group %s\n",
- param, g->name);
+ if (report_err)
+ dev_err(pmx->dev,
+ "Config param %04x not supported on group %s\n",
+ param, g->name);
return -ENOTSUPP;
}
@@ -303,12 +511,14 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
+ dev_err(pctldev->dev, "pin_config_get op not supported\n");
return -ENOTSUPP;
}
static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{
+ dev_err(pctldev->dev, "pin_config_set op not supported\n");
return -ENOTSUPP;
}
@@ -324,11 +534,10 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
s16 reg;
u32 val, mask;
- if (group >= pmx->soc->ngroups)
- return -EINVAL;
g = &pmx->soc->groups[group];
- ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+ ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+ &width);
if (ret < 0)
return ret;
@@ -353,11 +562,10 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
s16 reg;
u32 val, mask;
- if (group >= pmx->soc->ngroups)
- return -EINVAL;
g = &pmx->soc->groups[group];
- ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+ ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+ &width);
if (ret < 0)
return ret;
@@ -365,8 +573,10 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
/* LOCK can't be cleared */
if (param == TEGRA_PINCONF_PARAM_LOCK) {
- if ((val & BIT(bit)) && !arg)
+ if ((val & BIT(bit)) && !arg) {
+ dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
return -EINVAL;
+ }
}
/* Special-case Boolean values; allow any non-zero as true */
@@ -375,8 +585,12 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
/* Range-check user-supplied value */
mask = (1 << width) - 1;
- if (arg & ~mask)
+ if (arg & ~mask) {
+ dev_err(pctldev->dev,
+ "config %lx: %x too big for %d bit register\n",
+ config, arg, width);
return -EINVAL;
+ }
/* Update register */
val &= ~(mask << bit);
@@ -386,23 +600,78 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned offset)
{
}
+static const char *strip_prefix(const char *s)
+{
+ const char *comma = strchr(s, ',');
+ if (!comma)
+ return s;
+
+ return comma + 1;
+}
+
static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned selector)
+ struct seq_file *s, unsigned group)
{
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct tegra_pingroup *g;
+ int i, ret;
+ s8 bank, bit, width;
+ s16 reg;
+ u32 val;
+
+ g = &pmx->soc->groups[group];
+
+ for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+ ret = tegra_pinconf_reg(pmx, g, cfg_params[i].param, false,
+ &bank, &reg, &bit, &width);
+ if (ret < 0)
+ continue;
+
+ val = pmx_readl(pmx, bank, reg);
+ val >>= bit;
+ val &= (1 << width) - 1;
+
+ seq_printf(s, "\n\t%s=%u",
+ strip_prefix(cfg_params[i].property), val);
+ }
}
+static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ unsigned long config)
+{
+ enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
+ u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
+ const char *pname = "unknown";
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+ if (cfg_params[i].param == param) {
+ pname = cfg_params[i].property;
+ break;
+ }
+ }
+
+ seq_printf(s, "%s=%d", strip_prefix(pname), arg);
+}
+#endif
+
struct pinconf_ops tegra_pinconf_ops = {
.pin_config_get = tegra_pinconf_get,
.pin_config_set = tegra_pinconf_set,
.pin_config_group_get = tegra_pinconf_group_get,
.pin_config_group_set = tegra_pinconf_group_set,
+#ifdef CONFIG_DEBUG_FS
.pin_config_dbg_show = tegra_pinconf_dbg_show,
.pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
+ .pin_config_config_dbg_show = tegra_pinconf_config_dbg_show,
+#endif
};
static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
@@ -412,60 +681,29 @@ static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
};
static struct pinctrl_desc tegra_pinctrl_desc = {
- .name = DRIVER_NAME,
.pctlops = &tegra_pinctrl_ops,
.pmxops = &tegra_pinmux_ops,
.confops = &tegra_pinconf_ops,
.owner = THIS_MODULE,
};
-static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
-#ifdef CONFIG_PINCTRL_TEGRA20
- {
- .compatible = "nvidia,tegra20-pinmux-disabled",
- .data = tegra20_pinctrl_init,
- },
-#endif
-#ifdef CONFIG_PINCTRL_TEGRA30
- {
- .compatible = "nvidia,tegra30-pinmux-disabled",
- .data = tegra30_pinctrl_init,
- },
-#endif
- {},
-};
-
-static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
+int __devinit tegra_pinctrl_probe(struct platform_device *pdev,
+ const struct tegra_pinctrl_soc_data *soc_data)
{
- const struct of_device_id *match;
- tegra_pinctrl_soc_initf initf = NULL;
struct tegra_pmx *pmx;
struct resource *res;
int i;
- match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
- if (match)
- initf = (tegra_pinctrl_soc_initf)match->data;
-#ifdef CONFIG_PINCTRL_TEGRA20
- if (!initf)
- initf = tegra20_pinctrl_init;
-#endif
- if (!initf) {
- dev_err(&pdev->dev,
- "Could not determine SoC-specific init func\n");
- return -EINVAL;
- }
-
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx) {
dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
return -ENOMEM;
}
pmx->dev = &pdev->dev;
-
- (*initf)(&pmx->soc);
+ pmx->soc = soc_data;
tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
+ tegra_pinctrl_desc.name = dev_name(&pdev->dev);
tegra_pinctrl_desc.pins = pmx->soc->pins;
tegra_pinctrl_desc.npins = pmx->soc->npins;
@@ -520,8 +758,9 @@ static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
return 0;
}
+EXPORT_SYMBOL_GPL(tegra_pinctrl_probe);
-static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
{
struct tegra_pmx *pmx = platform_get_drvdata(pdev);
@@ -530,30 +769,4 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
return 0;
}
-
-static struct platform_driver tegra_pinctrl_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = tegra_pinctrl_of_match,
- },
- .probe = tegra_pinctrl_probe,
- .remove = __devexit_p(tegra_pinctrl_remove),
-};
-
-static int __init tegra_pinctrl_init(void)
-{
- return platform_driver_register(&tegra_pinctrl_driver);
-}
-arch_initcall(tegra_pinctrl_init);
-
-static void __exit tegra_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra_pinctrl_driver);
-}
-module_exit(tegra_pinctrl_exit);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);
+EXPORT_SYMBOL_GPL(tegra_pinctrl_remove);
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 782c795..705c007 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -139,25 +139,8 @@ struct tegra_pinctrl_soc_data {
unsigned ngroups;
};
-/**
- * tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC.
- * @soc_data: This pointer must be updated to point at a struct containing
- * details of the SoC.
- */
-typedef void (*tegra_pinctrl_soc_initf)(
- const struct tegra_pinctrl_soc_data **soc_data);
-
-/**
- * tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data: This pointer will be updated to point at a struct containing
- * details of Tegra20's pin controller.
- */
-void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
-/**
- * tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data: This pointer will be updated to point at a struct containing
- * details of Tegra30's pin controller.
- */
-void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
+int tegra_pinctrl_probe(struct platform_device *pdev,
+ const struct tegra_pinctrl_soc_data *soc_data);
+int tegra_pinctrl_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index f69ff96..a74f9a5 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra20 pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* Derived from code:
* Copyright (C) 2010 Google, Inc.
@@ -17,6 +17,8 @@
* more details.
*/
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -2854,7 +2856,39 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
.ngroups = ARRAY_SIZE(tegra20_groups),
};
-void __devinit tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev)
{
- *soc = &tegra20_pinctrl;
+ return tegra_pinctrl_probe(pdev, &tegra20_pinctrl);
}
+
+static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "nvidia,tegra20-pinmux", },
+ { },
+};
+
+static struct platform_driver tegra20_pinctrl_driver = {
+ .driver = {
+ .name = "tegra20-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_pinctrl_of_match,
+ },
+ .probe = tegra20_pinctrl_probe,
+ .remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra20_pinctrl_init(void)
+{
+ return platform_driver_register(&tegra20_pinctrl_driver);
+}
+arch_initcall(tegra20_pinctrl_init);
+
+static void __exit tegra20_pinctrl_exit(void)
+{
+ platform_driver_unregister(&tegra20_pinctrl_driver);
+}
+module_exit(tegra20_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra20_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 4d7571d..0386fdf 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra30 pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -13,6 +13,8 @@
* more details.
*/
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -3720,7 +3722,39 @@ static const struct tegra_pinctrl_soc_data tegra30_pinctrl = {
.ngroups = ARRAY_SIZE(tegra30_groups),
};
-void __devinit tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev)
{
- *soc = &tegra30_pinctrl;
+ return tegra_pinctrl_probe(pdev, &tegra30_pinctrl);
}
+
+static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "nvidia,tegra30-pinmux", },
+ { },
+};
+
+static struct platform_driver tegra30_pinctrl_driver = {
+ .driver = {
+ .name = "tegra30-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_pinctrl_of_match,
+ },
+ .probe = tegra30_pinctrl_probe,
+ .remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra30_pinctrl_init(void)
+{
+ return platform_driver_register(&tegra30_pinctrl_driver);
+}
+arch_initcall(tegra30_pinctrl_init);
+
+static void __exit tegra30_pinctrl_exit(void)
+{
+ platform_driver_unregister(&tegra30_pinctrl_driver);
+}
+module_exit(tegra30_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 26eb8cc..05d0299 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
},
};
-static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+static int u300_get_groups_count(struct pinctrl_dev *pctldev)
{
- if (selector >= ARRAY_SIZE(u300_pin_groups))
- return -EINVAL;
- return 0;
+ return ARRAY_SIZE(u300_pin_groups);
}
static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
- if (selector >= ARRAY_SIZE(u300_pin_groups))
- return NULL;
return u300_pin_groups[selector].name;
}
@@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
const unsigned **pins,
unsigned *num_pins)
{
- if (selector >= ARRAY_SIZE(u300_pin_groups))
- return -EINVAL;
*pins = u300_pin_groups[selector].pins;
*num_pins = u300_pin_groups[selector].num_pins;
return 0;
@@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
}
static struct pinctrl_ops u300_pctrl_ops = {
- .list_groups = u300_list_groups,
+ .get_groups_count = u300_get_groups_count,
.get_group_name = u300_get_group_name,
.get_group_pins = u300_get_group_pins,
.pin_dbg_show = u300_pin_dbg_show,
@@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
u300_pmx_endisable(upmx, selector, false);
}
-static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
{
- if (selector >= ARRAY_SIZE(u300_pmx_functions))
- return -EINVAL;
- return 0;
+ return ARRAY_SIZE(u300_pmx_functions);
}
static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
@@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
}
static struct pinmux_ops u300_pmx_ops = {
- .list_functions = u300_pmx_list_funcs,
+ .get_functions_count = u300_pmx_get_funcs_count,
.get_function_name = u300_pmx_get_func_name,
.get_function_groups = u300_pmx_get_groups,
.enable = u300_pmx_enable,
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 4e62783..3d5ac73 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -33,22 +33,25 @@
int pinmux_check_ops(struct pinctrl_dev *pctldev)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ unsigned nfuncs;
unsigned selector = 0;
/* Check that we implement required operations */
- if (!ops->list_functions ||
+ if (!ops ||
+ !ops->get_functions_count ||
!ops->get_function_name ||
!ops->get_function_groups ||
- !ops->enable ||
- !ops->disable)
+ !ops->enable) {
+ dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n");
return -EINVAL;
-
+ }
/* Check that all functions registered have names */
- while (ops->list_functions(pctldev, selector) >= 0) {
+ nfuncs = ops->get_functions_count(pctldev);
+ while (selector < nfuncs) {
const char *fname = ops->get_function_name(pctldev,
selector);
if (!fname) {
- pr_err("pinmux ops has no name for function%u\n",
+ dev_err(pctldev->dev, "pinmux ops has no name for function%u\n",
selector);
return -EINVAL;
}
@@ -85,20 +88,23 @@ static int pin_request(struct pinctrl_dev *pctldev,
const struct pinmux_ops *ops = pctldev->desc->pmxops;
int status = -EINVAL;
- dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
-
desc = pin_desc_get(pctldev, pin);
if (desc == NULL) {
dev_err(pctldev->dev,
- "pin is not registered so it cannot be requested\n");
+ "pin %d is not registered so it cannot be requested\n",
+ pin);
goto out;
}
+ dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
+ pin, desc->name, owner);
+
if (gpio_range) {
/* There's no need to support multiple GPIO requests */
if (desc->gpio_owner) {
dev_err(pctldev->dev,
- "pin already requested\n");
+ "pin %s already requested by %s; cannot claim for %s\n",
+ desc->name, desc->gpio_owner, owner);
goto out;
}
@@ -106,7 +112,8 @@ static int pin_request(struct pinctrl_dev *pctldev,
} else {
if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
dev_err(pctldev->dev,
- "pin already requested\n");
+ "pin %s already requested by %s; cannot claim for %s\n",
+ desc->name, desc->mux_owner, owner);
goto out;
}
@@ -139,8 +146,7 @@ static int pin_request(struct pinctrl_dev *pctldev,
status = 0;
if (status) {
- dev_err(pctldev->dev, "->request on device %s failed for pin %d\n",
- pctldev->desc->name, pin);
+ dev_err(pctldev->dev, "request() failed for pin %d\n", pin);
module_put(pctldev->owner);
}
@@ -157,7 +163,7 @@ out_free_pin:
out:
if (status)
dev_err(pctldev->dev, "pin-%d (%s) status %d\n",
- pin, owner, status);
+ pin, owner, status);
return status;
}
@@ -287,10 +293,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ unsigned nfuncs = ops->get_functions_count(pctldev);
unsigned selector = 0;
/* See if this pctldev has this function */
- while (ops->list_functions(pctldev, selector) >= 0) {
+ while (selector < nfuncs) {
const char *fname = ops->get_function_name(pctldev,
selector);
@@ -319,18 +326,32 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
const unsigned *pins;
unsigned num_pins;
- setting->data.mux.func =
- pinmux_func_name_to_selector(pctldev, map->data.mux.function);
- if (setting->data.mux.func < 0)
- return setting->data.mux.func;
+ if (!pmxops) {
+ dev_err(pctldev->dev, "does not support mux function\n");
+ return -EINVAL;
+ }
+
+ ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
+ if (ret < 0) {
+ dev_err(pctldev->dev, "invalid function %s in map table\n",
+ map->data.mux.function);
+ return ret;
+ }
+ setting->data.mux.func = ret;
ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,
&groups, &num_groups);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(pctldev->dev, "can't query groups for function %s\n",
+ map->data.mux.function);
return ret;
- if (!num_groups)
+ }
+ if (!num_groups) {
+ dev_err(pctldev->dev,
+ "function %s can't be selected on any group\n",
+ map->data.mux.function);
return -EINVAL;
-
+ }
if (map->data.mux.group) {
bool found = false;
group = map->data.mux.group;
@@ -340,15 +361,23 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
break;
}
}
- if (!found)
+ if (!found) {
+ dev_err(pctldev->dev,
+ "invalid group \"%s\" for function \"%s\"\n",
+ group, map->data.mux.function);
return -EINVAL;
+ }
} else {
group = groups[0];
}
- setting->data.mux.group = pinctrl_get_group_selector(pctldev, group);
- if (setting->data.mux.group < 0)
- return setting->data.mux.group;
+ ret = pinctrl_get_group_selector(pctldev, group);
+ if (ret < 0) {
+ dev_err(pctldev->dev, "invalid group %s in map table\n",
+ map->data.mux.group);
+ return ret;
+ }
+ setting->data.mux.group = ret;
ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
&num_pins);
@@ -364,7 +393,7 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
if (ret) {
dev_err(pctldev->dev,
- "could not get request pin %d on device %s\n",
+ "could not request pin %d on device %s\n",
pins[i], pinctrl_dev_get_name(pctldev));
/* On error release all taken pins */
i--; /* this pin just failed */
@@ -467,7 +496,8 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
desc->mux_setting = NULL;
}
- ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
+ if (ops->disable)
+ ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
}
#ifdef CONFIG_DEBUG_FS
@@ -477,11 +507,15 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+ unsigned nfuncs;
unsigned func_selector = 0;
- mutex_lock(&pinctrl_mutex);
+ if (!pmxops)
+ return 0;
- while (pmxops->list_functions(pctldev, func_selector) >= 0) {
+ mutex_lock(&pinctrl_mutex);
+ nfuncs = pmxops->get_functions_count(pctldev);
+ while (func_selector < nfuncs) {
const char *func = pmxops->get_function_name(pctldev,
func_selector);
const char * const *groups;
@@ -515,6 +549,9 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
unsigned i, pin;
+ if (!pmxops)
+ return 0;
+
seq_puts(s, "Pinmux settings per pin\n");
seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
index 6fc4700..d1a98b1c 100644
--- a/drivers/pinctrl/pinmux.h
+++ b/drivers/pinctrl/pinmux.h
@@ -31,12 +31,6 @@ void pinmux_free_setting(struct pinctrl_setting const *setting);
int pinmux_enable_setting(struct pinctrl_setting const *setting);
void pinmux_disable_setting(struct pinctrl_setting const *setting);
-void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
-void pinmux_show_setting(struct seq_file *s,
- struct pinctrl_setting const *setting);
-void pinmux_init_device_debugfs(struct dentry *devroot,
- struct pinctrl_dev *pctldev);
-
#else
static inline int pinmux_check_ops(struct pinctrl_dev *pctldev)
@@ -89,6 +83,18 @@ static inline void pinmux_disable_setting(
{
}
+#endif
+
+#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS)
+
+void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
+void pinmux_show_setting(struct seq_file *s,
+ struct pinctrl_setting const *setting);
+void pinmux_init_device_debugfs(struct dentry *devroot,
+ struct pinctrl_dev *pctldev);
+
+#else
+
static inline void pinmux_show_map(struct seq_file *s,
struct pinctrl_map const *map)
{
diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig
new file mode 100644
index 0000000..6a2596b
--- /dev/null
+++ b/drivers/pinctrl/spear/Kconfig
@@ -0,0 +1,34 @@
+#
+# ST Microelectronics SPEAr PINCTRL drivers
+#
+
+if PLAT_SPEAR
+
+config PINCTRL_SPEAR
+ bool
+ depends on OF
+ select PINMUX
+ help
+ This enables pin control drivers for SPEAr Platform
+
+config PINCTRL_SPEAR3XX
+ bool
+ depends on ARCH_SPEAR3XX
+ select PINCTRL_SPEAR
+
+config PINCTRL_SPEAR300
+ bool "ST Microelectronics SPEAr300 SoC pin controller driver"
+ depends on MACH_SPEAR300
+ select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR310
+ bool "ST Microelectronics SPEAr310 SoC pin controller driver"
+ depends on MACH_SPEAR310
+ select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR320
+ bool "ST Microelectronics SPEAr320 SoC pin controller driver"
+ depends on MACH_SPEAR320
+ select PINCTRL_SPEAR3XX
+
+endif
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
new file mode 100644
index 0000000..15dcb85
--- /dev/null
+++ b/drivers/pinctrl/spear/Makefile
@@ -0,0 +1,7 @@
+# SPEAr pinmux support
+
+obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
+obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
+obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
+obj-$(CONFIG_PINCTRL_SPEAR310) += pinctrl-spear310.o
+obj-$(CONFIG_PINCTRL_SPEAR320) += pinctrl-spear320.o
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
new file mode 100644
index 0000000..5ae50aa
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * Inspired from:
+ * - U300 Pinctl drivers
+ * - Tegra Pinctl drivers
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-spear.h"
+
+#define DRIVER_NAME "spear-pinmux"
+
+static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+{
+ return readl_relaxed(pmx->vbase + reg);
+}
+
+static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
+{
+ writel_relaxed(val, pmx->vbase + reg);
+}
+
+static int set_mode(struct spear_pmx *pmx, int mode)
+{
+ struct spear_pmx_mode *pmx_mode = NULL;
+ int i;
+ u32 val;
+
+ if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes)
+ return -EINVAL;
+
+ for (i = 0; i < pmx->machdata->npmx_modes; i++) {
+ if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) {
+ pmx_mode = pmx->machdata->pmx_modes[i];
+ break;
+ }
+ }
+
+ if (!pmx_mode)
+ return -EINVAL;
+
+ val = pmx_readl(pmx, pmx_mode->reg);
+ val &= ~pmx_mode->mask;
+ val |= pmx_mode->val;
+ pmx_writel(pmx, val, pmx_mode->reg);
+
+ pmx->machdata->mode = pmx_mode->mode;
+ dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n",
+ pmx_mode->name ? pmx_mode->name : "no_name",
+ pmx_mode->reg);
+
+ return 0;
+}
+
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
+{
+ struct spear_pingroup *pgroup;
+ struct spear_modemux *modemux;
+ int i, j, group;
+
+ for (group = 0; group < machdata->ngroups; group++) {
+ pgroup = machdata->groups[group];
+
+ for (i = 0; i < pgroup->nmodemuxs; i++) {
+ modemux = &pgroup->modemuxs[i];
+
+ for (j = 0; j < modemux->nmuxregs; j++)
+ if (modemux->muxregs[j].reg == 0xFFFF)
+ modemux->muxregs[j].reg = reg;
+ }
+ }
+}
+
+static int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->ngroups;
+}
+
+static const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->groups[group]->name;
+}
+
+static int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group, const unsigned **pins, unsigned *num_pins)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = pmx->machdata->groups[group]->pins;
+ *num_pins = pmx->machdata->groups[group]->npins;
+
+ return 0;
+}
+
+static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct device_node *np;
+ struct property *prop;
+ const char *function, *group;
+ int ret, index = 0, count = 0;
+
+ /* calculate number of maps required */
+ for_each_child_of_node(np_config, np) {
+ ret = of_property_read_string(np, "st,function", &function);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_count_strings(np, "st,pins");
+ if (ret < 0)
+ return ret;
+
+ count += ret;
+ }
+
+ if (!count) {
+ dev_err(pmx->dev, "No child nodes passed via DT\n");
+ return -ENODEV;
+ }
+
+ *map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
+
+ for_each_child_of_node(np_config, np) {
+ of_property_read_string(np, "st,function", &function);
+ of_property_for_each_string(np, "st,pins", prop, group) {
+ (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[index].data.mux.group = group;
+ (*map)[index].data.mux.function = function;
+ index++;
+ }
+ }
+
+ *num_maps = count;
+
+ return 0;
+}
+
+void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ kfree(map);
+}
+
+static struct pinctrl_ops spear_pinctrl_ops = {
+ .get_groups_count = spear_pinctrl_get_groups_cnt,
+ .get_group_name = spear_pinctrl_get_group_name,
+ .get_group_pins = spear_pinctrl_get_group_pins,
+ .pin_dbg_show = spear_pinctrl_pin_dbg_show,
+ .dt_node_to_map = spear_pinctrl_dt_node_to_map,
+ .dt_free_map = spear_pinctrl_dt_free_map,
+};
+
+static int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->nfunctions;
+}
+
+static const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->functions[function]->name;
+}
+
+static int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function, const char *const **groups,
+ unsigned * const ngroups)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pmx->machdata->functions[function]->groups;
+ *ngroups = pmx->machdata->functions[function]->ngroups;
+
+ return 0;
+}
+
+static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group, bool enable)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct spear_pingroup *pgroup;
+ const struct spear_modemux *modemux;
+ struct spear_muxreg *muxreg;
+ u32 val, temp;
+ int i, j;
+ bool found = false;
+
+ pgroup = pmx->machdata->groups[group];
+
+ for (i = 0; i < pgroup->nmodemuxs; i++) {
+ modemux = &pgroup->modemuxs[i];
+
+ /* SoC have any modes */
+ if (pmx->machdata->modes_supported) {
+ if (!(pmx->machdata->mode & modemux->modes))
+ continue;
+ }
+
+ found = true;
+ for (j = 0; j < modemux->nmuxregs; j++) {
+ muxreg = &modemux->muxregs[j];
+
+ val = pmx_readl(pmx, muxreg->reg);
+ val &= ~muxreg->mask;
+
+ if (enable)
+ temp = muxreg->val;
+ else
+ temp = ~muxreg->val;
+
+ val |= temp;
+ pmx_writel(pmx, val, muxreg->reg);
+ }
+ }
+
+ if (!found) {
+ dev_err(pmx->dev, "pinmux group: %s not supported\n",
+ pgroup->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int spear_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ return spear_pinctrl_endisable(pctldev, function, group, true);
+}
+
+static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group)
+{
+ spear_pinctrl_endisable(pctldev, function, group, false);
+}
+
+static struct pinmux_ops spear_pinmux_ops = {
+ .get_functions_count = spear_pinctrl_get_funcs_count,
+ .get_function_name = spear_pinctrl_get_func_name,
+ .get_function_groups = spear_pinctrl_get_func_groups,
+ .enable = spear_pinctrl_enable,
+ .disable = spear_pinctrl_disable,
+};
+
+static struct pinctrl_desc spear_pinctrl_desc = {
+ .name = DRIVER_NAME,
+ .pctlops = &spear_pinctrl_ops,
+ .pmxops = &spear_pinmux_ops,
+ .owner = THIS_MODULE,
+};
+
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+ struct spear_pinctrl_machdata *machdata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct spear_pmx *pmx;
+
+ if (!machdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+ if (!pmx) {
+ dev_err(&pdev->dev, "Can't alloc spear_pmx\n");
+ return -ENOMEM;
+ }
+
+ pmx->vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!pmx->vbase) {
+ dev_err(&pdev->dev, "Couldn't ioremap at index 0\n");
+ return -ENODEV;
+ }
+
+ pmx->dev = &pdev->dev;
+ pmx->machdata = machdata;
+
+ /* configure mode, if supported by SoC */
+ if (machdata->modes_supported) {
+ int mode = 0;
+
+ if (of_property_read_u32(np, "st,pinmux-mode", &mode)) {
+ dev_err(&pdev->dev, "OF: pinmux mode not passed\n");
+ return -EINVAL;
+ }
+
+ if (set_mode(pmx, mode)) {
+ dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n",
+ mode);
+ return -EINVAL;
+ }
+ }
+
+ platform_set_drvdata(pdev, pmx);
+
+ spear_pinctrl_desc.pins = machdata->pins;
+ spear_pinctrl_desc.npins = machdata->npins;
+
+ pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx);
+ if (IS_ERR(pmx->pctl)) {
+ dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+ return PTR_ERR(pmx->pctl);
+ }
+
+ return 0;
+}
+
+int __devexit spear_pinctrl_remove(struct platform_device *pdev)
+{
+ struct spear_pmx *pmx = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(pmx->pctl);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
new file mode 100644
index 0000000..47a6b5b
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -0,0 +1,142 @@
+/*
+ * Driver header file for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINMUX_SPEAR_H__
+#define __PINMUX_SPEAR_H__
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/types.h>
+
+struct platform_device;
+struct device;
+
+/**
+ * struct spear_pmx_mode - SPEAr pmx mode
+ * @name: name of pmx mode
+ * @mode: mode id
+ * @reg: register for configuring this mode
+ * @mask: mask of this mode in reg
+ * @val: val to be configured at reg after doing (val & mask)
+ */
+struct spear_pmx_mode {
+ const char *const name;
+ u16 mode;
+ u16 reg;
+ u16 mask;
+ u32 val;
+};
+
+/**
+ * struct spear_muxreg - SPEAr mux reg configuration
+ * @reg: register offset
+ * @mask: mask bits
+ * @val: val to be written on mask bits
+ */
+struct spear_muxreg {
+ u16 reg;
+ u32 mask;
+ u32 val;
+};
+
+/**
+ * struct spear_modemux - SPEAr mode mux configuration
+ * @modes: mode ids supported by this group of muxregs
+ * @nmuxregs: number of muxreg configurations to be done for modes
+ * @muxregs: array of muxreg configurations to be done for modes
+ */
+struct spear_modemux {
+ u16 modes;
+ u8 nmuxregs;
+ struct spear_muxreg *muxregs;
+};
+
+/**
+ * struct spear_pingroup - SPEAr pin group configurations
+ * @name: name of pin group
+ * @pins: array containing pin numbers
+ * @npins: size of pins array
+ * @modemuxs: array of modemux configurations for this pin group
+ * @nmodemuxs: size of array modemuxs
+ *
+ * A representation of a group of pins in the SPEAr pin controller. Each group
+ * allows some parameter or parameters to be configured.
+ */
+struct spear_pingroup {
+ const char *name;
+ const unsigned *pins;
+ unsigned npins;
+ struct spear_modemux *modemuxs;
+ unsigned nmodemuxs;
+};
+
+/**
+ * struct spear_function - SPEAr pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct spear_function {
+ const char *name;
+ const char *const *groups;
+ unsigned ngroups;
+};
+
+/**
+ * struct spear_pinctrl_machdata - SPEAr pin controller machine driver
+ * configuration
+ * @pins: An array describing all pins the pin controller affects.
+ * All pins which are also GPIOs must be listed first within the *array,
+ * and be numbered identically to the GPIO controller's *numbering.
+ * @npins: The numbmer of entries in @pins.
+ * @functions: An array describing all mux functions the SoC supports.
+ * @nfunctions: The numbmer of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The numbmer of entries in @groups.
+ *
+ * @modes_supported: Does SoC support modes
+ * @mode: mode configured from probe
+ * @pmx_modes: array of modes supported by SoC
+ * @npmx_modes: number of entries in pmx_modes.
+ */
+struct spear_pinctrl_machdata {
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ struct spear_function **functions;
+ unsigned nfunctions;
+ struct spear_pingroup **groups;
+ unsigned ngroups;
+
+ bool modes_supported;
+ u16 mode;
+ struct spear_pmx_mode **pmx_modes;
+ unsigned npmx_modes;
+};
+
+/**
+ * struct spear_pmx - SPEAr pinctrl mux
+ * @dev: pointer to struct dev of platform_device registered
+ * @pctl: pointer to struct pinctrl_dev
+ * @machdata: pointer to SoC or machine specific structure
+ * @vbase: virtual base address of pinmux controller
+ */
+struct spear_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ struct spear_pinctrl_machdata *machdata;
+ void __iomem *vbase;
+};
+
+/* exported routines */
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+ struct spear_pinctrl_machdata *machdata);
+int __devexit spear_pinctrl_remove(struct platform_device *pdev);
+#endif /* __PINMUX_SPEAR_H__ */
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
new file mode 100644
index 0000000..9c82a35
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -0,0 +1,708 @@
+/*
+ * Driver for the ST Microelectronics SPEAr300 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear300-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x00
+#define MODE_CONFIG_REG 0x04
+
+/* modes */
+#define NAND_MODE (1 << 0)
+#define NOR_MODE (1 << 1)
+#define PHOTO_FRAME_MODE (1 << 2)
+#define LEND_IP_PHONE_MODE (1 << 3)
+#define HEND_IP_PHONE_MODE (1 << 4)
+#define LEND_WIFI_PHONE_MODE (1 << 5)
+#define HEND_WIFI_PHONE_MODE (1 << 6)
+#define ATA_PABX_WI2S_MODE (1 << 7)
+#define ATA_PABX_I2S_MODE (1 << 8)
+#define CAML_LCDW_MODE (1 << 9)
+#define CAMU_LCD_MODE (1 << 10)
+#define CAMU_WLCD_MODE (1 << 11)
+#define CAML_LCD_MODE (1 << 12)
+
+static struct spear_pmx_mode pmx_mode_nand = {
+ .name = "nand",
+ .mode = NAND_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x00,
+};
+
+static struct spear_pmx_mode pmx_mode_nor = {
+ .name = "nor",
+ .mode = NOR_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x01,
+};
+
+static struct spear_pmx_mode pmx_mode_photo_frame = {
+ .name = "photo frame mode",
+ .mode = PHOTO_FRAME_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x02,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_ip_phone = {
+ .name = "lend ip phone mode",
+ .mode = LEND_IP_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x03,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_ip_phone = {
+ .name = "hend ip phone mode",
+ .mode = HEND_IP_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x04,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_wifi_phone = {
+ .name = "lend wifi phone mode",
+ .mode = LEND_WIFI_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x05,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_wifi_phone = {
+ .name = "hend wifi phone mode",
+ .mode = HEND_WIFI_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x06,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_wi2s = {
+ .name = "ata pabx wi2s mode",
+ .mode = ATA_PABX_WI2S_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x07,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_i2s = {
+ .name = "ata pabx i2s mode",
+ .mode = ATA_PABX_I2S_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x08,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcdw = {
+ .name = "caml lcdw mode",
+ .mode = CAML_LCDW_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0C,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_lcd = {
+ .name = "camu lcd mode",
+ .mode = CAMU_LCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0D,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_wlcd = {
+ .name = "camu wlcd mode",
+ .mode = CAMU_WLCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0xE,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcd = {
+ .name = "caml lcd mode",
+ .mode = CAML_LCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0F,
+};
+
+static struct spear_pmx_mode *spear300_pmx_modes[] = {
+ &pmx_mode_nand,
+ &pmx_mode_nor,
+ &pmx_mode_photo_frame,
+ &pmx_mode_lend_ip_phone,
+ &pmx_mode_hend_ip_phone,
+ &pmx_mode_lend_wifi_phone,
+ &pmx_mode_hend_wifi_phone,
+ &pmx_mode_ata_pabx_wi2s,
+ &pmx_mode_ata_pabx_i2s,
+ &pmx_mode_caml_lcdw,
+ &pmx_mode_camu_lcd,
+ &pmx_mode_camu_wlcd,
+ &pmx_mode_caml_lcd,
+};
+
+/* fsmc_2chips_pins */
+static const unsigned fsmc_2chips_pins[] = { 1, 97 };
+static struct spear_muxreg fsmc_2chips_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_2chips_modemux[] = {
+ {
+ .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+ .muxregs = fsmc_2chips_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_2chips_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_2chips_pingroup = {
+ .name = "fsmc_2chips_grp",
+ .pins = fsmc_2chips_pins,
+ .npins = ARRAY_SIZE(fsmc_2chips_pins),
+ .modemuxs = fsmc_2chips_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_2chips_modemux),
+};
+
+/* fsmc_4chips_pins */
+static const unsigned fsmc_4chips_pins[] = { 1, 2, 3, 97 };
+static struct spear_muxreg fsmc_4chips_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK | PMX_UART0_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_4chips_modemux[] = {
+ {
+ .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+ .muxregs = fsmc_4chips_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_4chips_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_4chips_pingroup = {
+ .name = "fsmc_4chips_grp",
+ .pins = fsmc_4chips_pins,
+ .npins = ARRAY_SIZE(fsmc_4chips_pins),
+ .modemuxs = fsmc_4chips_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_4chips_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_2chips_grp", "fsmc_4chips_grp"
+};
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* clcd_lcdmode_pins */
+static const unsigned clcd_lcdmode_pins[] = { 49, 50 };
+static struct spear_muxreg clcd_lcdmode_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux clcd_lcdmode_modemux[] = {
+ {
+ .modes = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ CAMU_LCD_MODE | CAML_LCD_MODE,
+ .muxregs = clcd_lcdmode_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_lcdmode_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_lcdmode_pingroup = {
+ .name = "clcd_lcdmode_grp",
+ .pins = clcd_lcdmode_pins,
+ .npins = ARRAY_SIZE(clcd_lcdmode_pins),
+ .modemuxs = clcd_lcdmode_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_lcdmode_modemux),
+};
+
+/* clcd_pfmode_pins */
+static const unsigned clcd_pfmode_pins[] = { 47, 48, 49, 50 };
+static struct spear_muxreg clcd_pfmode_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux clcd_pfmode_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = clcd_pfmode_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_pfmode_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_pfmode_pingroup = {
+ .name = "clcd_pfmode_grp",
+ .pins = clcd_pfmode_pins,
+ .npins = ARRAY_SIZE(clcd_pfmode_pins),
+ .modemuxs = clcd_pfmode_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_pfmode_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_lcdmode_grp", "clcd_pfmode_grp"
+};
+static struct spear_function clcd_function = {
+ .name = "clcd",
+ .groups = clcd_grps,
+ .ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 34, 35, 36, 37, 38 };
+static struct spear_muxreg tdm_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux tdm_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
+ | HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE
+ | ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = tdm_muxreg,
+ .nmuxregs = ARRAY_SIZE(tdm_muxreg),
+ },
+};
+
+static struct spear_pingroup tdm_pingroup = {
+ .name = "tdm_grp",
+ .pins = tdm_pins,
+ .npins = ARRAY_SIZE(tdm_pins),
+ .modemuxs = tdm_modemux,
+ .nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+ .name = "tdm",
+ .groups = tdm_grps,
+ .ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* i2c_clk_pins */
+static const unsigned i2c_clk_pins[] = { 45, 46, 47, 48 };
+static struct spear_muxreg i2c_clk_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux i2c_clk_modemux[] = {
+ {
+ .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
+ LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE | CAML_LCDW_MODE
+ | CAML_LCD_MODE,
+ .muxregs = i2c_clk_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c_clk_muxreg),
+ },
+};
+
+static struct spear_pingroup i2c_clk_pingroup = {
+ .name = "i2c_clk_grp_grp",
+ .pins = i2c_clk_pins,
+ .npins = ARRAY_SIZE(i2c_clk_pins),
+ .modemuxs = i2c_clk_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2c_clk_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c_clk_grp" };
+static struct spear_function i2c_function = {
+ .name = "i2c1",
+ .groups = i2c_grps,
+ .ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* caml_pins */
+static const unsigned caml_pins[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
+static struct spear_muxreg caml_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux caml_modemux[] = {
+ {
+ .modes = CAML_LCDW_MODE | CAML_LCD_MODE,
+ .muxregs = caml_muxreg,
+ .nmuxregs = ARRAY_SIZE(caml_muxreg),
+ },
+};
+
+static struct spear_pingroup caml_pingroup = {
+ .name = "caml_grp",
+ .pins = caml_pins,
+ .npins = ARRAY_SIZE(caml_pins),
+ .modemuxs = caml_modemux,
+ .nmodemuxs = ARRAY_SIZE(caml_modemux),
+};
+
+/* camu_pins */
+static const unsigned camu_pins[] = { 16, 17, 18, 19, 20, 21, 45, 46, 47, 48 };
+static struct spear_muxreg camu_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK | PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux camu_modemux[] = {
+ {
+ .modes = CAMU_LCD_MODE | CAMU_WLCD_MODE,
+ .muxregs = camu_muxreg,
+ .nmuxregs = ARRAY_SIZE(camu_muxreg),
+ },
+};
+
+static struct spear_pingroup camu_pingroup = {
+ .name = "camu_grp",
+ .pins = camu_pins,
+ .npins = ARRAY_SIZE(camu_pins),
+ .modemuxs = camu_modemux,
+ .nmodemuxs = ARRAY_SIZE(camu_modemux),
+};
+
+static const char *const cam_grps[] = { "caml_grp", "camu_grp" };
+static struct spear_function cam_function = {
+ .name = "cam",
+ .groups = cam_grps,
+ .ngroups = ARRAY_SIZE(cam_grps),
+};
+
+/* dac_pins */
+static const unsigned dac_pins[] = { 43, 44 };
+static struct spear_muxreg dac_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux dac_modemux[] = {
+ {
+ .modes = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = dac_muxreg,
+ .nmuxregs = ARRAY_SIZE(dac_muxreg),
+ },
+};
+
+static struct spear_pingroup dac_pingroup = {
+ .name = "dac_grp",
+ .pins = dac_pins,
+ .npins = ARRAY_SIZE(dac_pins),
+ .modemuxs = dac_modemux,
+ .nmodemuxs = ARRAY_SIZE(dac_modemux),
+};
+
+static const char *const dac_grps[] = { "dac_grp" };
+static struct spear_function dac_function = {
+ .name = "dac",
+ .groups = dac_grps,
+ .ngroups = ARRAY_SIZE(dac_grps),
+};
+
+/* i2s_pins */
+static const unsigned i2s_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux i2s_modemux[] = {
+ {
+ .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
+ | LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = i2s_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_muxreg),
+ },
+};
+
+static struct spear_pingroup i2s_pingroup = {
+ .name = "i2s_grp",
+ .pins = i2s_pins,
+ .npins = ARRAY_SIZE(i2s_pins),
+ .modemuxs = i2s_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+ .name = "i2s",
+ .groups = i2s_grps,
+ .ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* sdhci_4bit_pins */
+static const unsigned sdhci_4bit_pins[] = { 28, 29, 30, 31, 32, 33 };
+static struct spear_muxreg sdhci_4bit_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+ PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+ PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux sdhci_4bit_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+ HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+ CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE,
+ .muxregs = sdhci_4bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_4bit_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_4bit_pingroup = {
+ .name = "sdhci_4bit_grp",
+ .pins = sdhci_4bit_pins,
+ .npins = ARRAY_SIZE(sdhci_4bit_pins),
+ .modemuxs = sdhci_4bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_4bit_modemux),
+};
+
+/* sdhci_8bit_pins */
+static const unsigned sdhci_8bit_pins[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33 };
+static struct spear_muxreg sdhci_8bit_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+ PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+ PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux sdhci_8bit_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+ HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+ CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = sdhci_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_8bit_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_8bit_pingroup = {
+ .name = "sdhci_8bit_grp",
+ .pins = sdhci_8bit_pins,
+ .npins = ARRAY_SIZE(sdhci_8bit_pins),
+ .modemuxs = sdhci_8bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_8bit_modemux),
+};
+
+static const char *const sdhci_grps[] = { "sdhci_4bit_grp", "sdhci_8bit_grp" };
+static struct spear_function sdhci_function = {
+ .name = "sdhci",
+ .groups = sdhci_grps,
+ .ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* gpio1_0_to_3_pins */
+static const unsigned gpio1_0_to_3_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg gpio1_0_to_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux gpio1_0_to_3_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = gpio1_0_to_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio1_0_to_3_muxreg),
+ },
+};
+
+static struct spear_pingroup gpio1_0_to_3_pingroup = {
+ .name = "gpio1_0_to_3_grp",
+ .pins = gpio1_0_to_3_pins,
+ .npins = ARRAY_SIZE(gpio1_0_to_3_pins),
+ .modemuxs = gpio1_0_to_3_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio1_0_to_3_modemux),
+};
+
+/* gpio1_4_to_7_pins */
+static const unsigned gpio1_4_to_7_pins[] = { 43, 44, 45, 46 };
+
+static struct spear_muxreg gpio1_4_to_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux gpio1_4_to_7_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = gpio1_4_to_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio1_4_to_7_muxreg),
+ },
+};
+
+static struct spear_pingroup gpio1_4_to_7_pingroup = {
+ .name = "gpio1_4_to_7_grp",
+ .pins = gpio1_4_to_7_pins,
+ .npins = ARRAY_SIZE(gpio1_4_to_7_pins),
+ .modemuxs = gpio1_4_to_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio1_4_to_7_modemux),
+};
+
+static const char *const gpio1_grps[] = { "gpio1_0_to_3_grp", "gpio1_4_to_7_grp"
+};
+static struct spear_function gpio1_function = {
+ .name = "gpio1",
+ .groups = gpio1_grps,
+ .ngroups = ARRAY_SIZE(gpio1_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear300_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &fsmc_2chips_pingroup,
+ &fsmc_4chips_pingroup,
+ &clcd_lcdmode_pingroup,
+ &clcd_pfmode_pingroup,
+ &tdm_pingroup,
+ &i2c_clk_pingroup,
+ &caml_pingroup,
+ &camu_pingroup,
+ &dac_pingroup,
+ &i2s_pingroup,
+ &sdhci_4bit_pingroup,
+ &sdhci_8bit_pingroup,
+ &gpio1_0_to_3_pingroup,
+ &gpio1_4_to_7_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear300_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &fsmc_function,
+ &clcd_function,
+ &tdm_function,
+ &i2c_function,
+ &cam_function,
+ &dac_function,
+ &i2s_function,
+ &sdhci_function,
+ &gpio1_function,
+};
+
+static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear300-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear300_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
+ spear3xx_machdata.functions = spear300_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+
+ spear3xx_machdata.modes_supported = true;
+ spear3xx_machdata.pmx_modes = spear300_pmx_modes;
+ spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear300_pmx_modes);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear300_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear300_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear300_pinctrl_of_match,
+ },
+ .probe = spear300_pinctrl_probe,
+ .remove = __devexit_p(spear300_pinctrl_remove),
+};
+
+static int __init spear300_pinctrl_init(void)
+{
+ return platform_driver_register(&spear300_pinctrl_driver);
+}
+arch_initcall(spear300_pinctrl_init);
+
+static void __exit spear300_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear300_pinctrl_driver);
+}
+module_exit(spear300_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
new file mode 100644
index 0000000..1a97076
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -0,0 +1,431 @@
+/*
+ * Driver for the ST Microelectronics SPEAr310 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear310-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x08
+
+/* emi_cs_0_to_5_pins */
+static const unsigned emi_cs_0_to_5_pins[] = { 45, 46, 47, 48, 49, 50 };
+static struct spear_muxreg emi_cs_0_to_5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux emi_cs_0_to_5_modemux[] = {
+ {
+ .muxregs = emi_cs_0_to_5_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_cs_0_to_5_muxreg),
+ },
+};
+
+static struct spear_pingroup emi_cs_0_to_5_pingroup = {
+ .name = "emi_cs_0_to_5_grp",
+ .pins = emi_cs_0_to_5_pins,
+ .npins = ARRAY_SIZE(emi_cs_0_to_5_pins),
+ .modemuxs = emi_cs_0_to_5_modemux,
+ .nmodemuxs = ARRAY_SIZE(emi_cs_0_to_5_modemux),
+};
+
+static const char *const emi_cs_0_to_5_grps[] = { "emi_cs_0_to_5_grp" };
+static struct spear_function emi_cs_0_to_5_function = {
+ .name = "emi",
+ .groups = emi_cs_0_to_5_grps,
+ .ngroups = ARRAY_SIZE(emi_cs_0_to_5_grps),
+};
+
+/* uart1_pins */
+static const unsigned uart1_pins[] = { 0, 1 };
+static struct spear_muxreg uart1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart1_modemux[] = {
+ {
+ .muxregs = uart1_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_pingroup = {
+ .name = "uart1_grp",
+ .pins = uart1_pins,
+ .npins = ARRAY_SIZE(uart1_pins),
+ .modemuxs = uart1_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+ .name = "uart1",
+ .groups = uart1_grps,
+ .ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* uart2_pins */
+static const unsigned uart2_pins[] = { 43, 44 };
+static struct spear_muxreg uart2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart2_modemux[] = {
+ {
+ .muxregs = uart2_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_muxreg),
+ },
+};
+
+static struct spear_pingroup uart2_pingroup = {
+ .name = "uart2_grp",
+ .pins = uart2_pins,
+ .npins = ARRAY_SIZE(uart2_pins),
+ .modemuxs = uart2_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+ .name = "uart2",
+ .groups = uart2_grps,
+ .ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* uart3_pins */
+static const unsigned uart3_pins[] = { 37, 38 };
+static struct spear_muxreg uart3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart3_modemux[] = {
+ {
+ .muxregs = uart3_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_muxreg),
+ },
+};
+
+static struct spear_pingroup uart3_pingroup = {
+ .name = "uart3_grp",
+ .pins = uart3_pins,
+ .npins = ARRAY_SIZE(uart3_pins),
+ .modemuxs = uart3_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux),
+};
+
+static const char *const uart3_grps[] = { "uart3_grp" };
+static struct spear_function uart3_function = {
+ .name = "uart3",
+ .groups = uart3_grps,
+ .ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* uart4_pins */
+static const unsigned uart4_pins[] = { 39, 40 };
+static struct spear_muxreg uart4_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart4_modemux[] = {
+ {
+ .muxregs = uart4_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_muxreg),
+ },
+};
+
+static struct spear_pingroup uart4_pingroup = {
+ .name = "uart4_grp",
+ .pins = uart4_pins,
+ .npins = ARRAY_SIZE(uart4_pins),
+ .modemuxs = uart4_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux),
+};
+
+static const char *const uart4_grps[] = { "uart4_grp" };
+static struct spear_function uart4_function = {
+ .name = "uart4",
+ .groups = uart4_grps,
+ .ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* uart5_pins */
+static const unsigned uart5_pins[] = { 41, 42 };
+static struct spear_muxreg uart5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart5_modemux[] = {
+ {
+ .muxregs = uart5_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_muxreg),
+ },
+};
+
+static struct spear_pingroup uart5_pingroup = {
+ .name = "uart5_grp",
+ .pins = uart5_pins,
+ .npins = ARRAY_SIZE(uart5_pins),
+ .modemuxs = uart5_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux),
+};
+
+static const char *const uart5_grps[] = { "uart5_grp" };
+static struct spear_function uart5_function = {
+ .name = "uart5",
+ .groups = uart5_grps,
+ .ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* fsmc_pins */
+static const unsigned fsmc_pins[] = { 34, 35, 36 };
+static struct spear_muxreg fsmc_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_modemux[] = {
+ {
+ .muxregs = fsmc_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_pingroup = {
+ .name = "fsmc_grp",
+ .pins = fsmc_pins,
+ .npins = ARRAY_SIZE(fsmc_pins),
+ .modemuxs = fsmc_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_grp" };
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* rs485_0_pins */
+static const unsigned rs485_0_pins[] = { 19, 20, 21, 22, 23 };
+static struct spear_muxreg rs485_0_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux rs485_0_modemux[] = {
+ {
+ .muxregs = rs485_0_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_0_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_0_pingroup = {
+ .name = "rs485_0_grp",
+ .pins = rs485_0_pins,
+ .npins = ARRAY_SIZE(rs485_0_pins),
+ .modemuxs = rs485_0_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_0_modemux),
+};
+
+static const char *const rs485_0_grps[] = { "rs485_0" };
+static struct spear_function rs485_0_function = {
+ .name = "rs485_0",
+ .groups = rs485_0_grps,
+ .ngroups = ARRAY_SIZE(rs485_0_grps),
+};
+
+/* rs485_1_pins */
+static const unsigned rs485_1_pins[] = { 14, 15, 16, 17, 18 };
+static struct spear_muxreg rs485_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux rs485_1_modemux[] = {
+ {
+ .muxregs = rs485_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_1_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_1_pingroup = {
+ .name = "rs485_1_grp",
+ .pins = rs485_1_pins,
+ .npins = ARRAY_SIZE(rs485_1_pins),
+ .modemuxs = rs485_1_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_1_modemux),
+};
+
+static const char *const rs485_1_grps[] = { "rs485_1" };
+static struct spear_function rs485_1_function = {
+ .name = "rs485_1",
+ .groups = rs485_1_grps,
+ .ngroups = ARRAY_SIZE(rs485_1_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 10, 11, 12, 13 };
+static struct spear_muxreg tdm_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux tdm_modemux[] = {
+ {
+ .muxregs = tdm_muxreg,
+ .nmuxregs = ARRAY_SIZE(tdm_muxreg),
+ },
+};
+
+static struct spear_pingroup tdm_pingroup = {
+ .name = "tdm_grp",
+ .pins = tdm_pins,
+ .npins = ARRAY_SIZE(tdm_pins),
+ .modemuxs = tdm_modemux,
+ .nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+ .name = "tdm",
+ .groups = tdm_grps,
+ .ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear310_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &emi_cs_0_to_5_pingroup,
+ &uart1_pingroup,
+ &uart2_pingroup,
+ &uart3_pingroup,
+ &uart4_pingroup,
+ &uart5_pingroup,
+ &fsmc_pingroup,
+ &rs485_0_pingroup,
+ &rs485_1_pingroup,
+ &tdm_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear310_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &emi_cs_0_to_5_function,
+ &uart1_function,
+ &uart2_function,
+ &uart3_function,
+ &uart4_function,
+ &uart5_function,
+ &fsmc_function,
+ &rs485_0_function,
+ &rs485_1_function,
+ &tdm_function,
+};
+
+static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear310-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear310_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear310_pingroups);
+ spear3xx_machdata.functions = spear310_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ spear3xx_machdata.modes_supported = false;
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear310_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear310_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear310_pinctrl_of_match,
+ },
+ .probe = spear310_pinctrl_probe,
+ .remove = __devexit_p(spear310_pinctrl_remove),
+};
+
+static int __init spear310_pinctrl_init(void)
+{
+ return platform_driver_register(&spear310_pinctrl_driver);
+}
+arch_initcall(spear310_pinctrl_init);
+
+static void __exit spear310_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear310_pinctrl_driver);
+}
+module_exit(spear310_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
new file mode 100644
index 0000000..de726e6
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -0,0 +1,3468 @@
+/*
+ * Driver for the ST Microelectronics SPEAr320 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear320-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x0C
+#define MODE_CONFIG_REG 0x10
+#define MODE_EXT_CONFIG_REG 0x18
+
+/* modes */
+#define AUTO_NET_SMII_MODE (1 << 0)
+#define AUTO_NET_MII_MODE (1 << 1)
+#define AUTO_EXP_MODE (1 << 2)
+#define SMALL_PRINTERS_MODE (1 << 3)
+#define EXTENDED_MODE (1 << 4)
+
+static struct spear_pmx_mode pmx_mode_auto_net_smii = {
+ .name = "Automation Networking SMII mode",
+ .mode = AUTO_NET_SMII_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x0,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_net_mii = {
+ .name = "Automation Networking MII mode",
+ .mode = AUTO_NET_MII_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x1,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_exp = {
+ .name = "Automation Expanded mode",
+ .mode = AUTO_EXP_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x2,
+};
+
+static struct spear_pmx_mode pmx_mode_small_printers = {
+ .name = "Small Printers mode",
+ .mode = SMALL_PRINTERS_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x3,
+};
+
+static struct spear_pmx_mode pmx_mode_extended = {
+ .name = "extended mode",
+ .mode = EXTENDED_MODE,
+ .reg = MODE_EXT_CONFIG_REG,
+ .mask = 0x00000001,
+ .val = 0x1,
+};
+
+static struct spear_pmx_mode *spear320_pmx_modes[] = {
+ &pmx_mode_auto_net_smii,
+ &pmx_mode_auto_net_mii,
+ &pmx_mode_auto_exp,
+ &pmx_mode_small_printers,
+ &pmx_mode_extended,
+};
+
+/* Extended mode registers and their offsets */
+#define EXT_CTRL_REG 0x0018
+ #define MII_MDIO_MASK (1 << 4)
+ #define MII_MDIO_10_11_VAL 0
+ #define MII_MDIO_81_VAL (1 << 4)
+ #define EMI_FSMC_DYNAMIC_MUX_MASK (1 << 5)
+ #define MAC_MODE_MII 0
+ #define MAC_MODE_RMII 1
+ #define MAC_MODE_SMII 2
+ #define MAC_MODE_SS_SMII 3
+ #define MAC_MODE_MASK 0x3
+ #define MAC1_MODE_SHIFT 16
+ #define MAC2_MODE_SHIFT 18
+
+#define IP_SEL_PAD_0_9_REG 0x00A4
+ #define PMX_PL_0_1_MASK (0x3F << 0)
+ #define PMX_UART2_PL_0_1_VAL 0x0
+ #define PMX_I2C2_PL_0_1_VAL (0x4 | (0x4 << 3))
+
+ #define PMX_PL_2_3_MASK (0x3F << 6)
+ #define PMX_I2C2_PL_2_3_VAL 0x0
+ #define PMX_UART6_PL_2_3_VAL ((0x1 << 6) | (0x1 << 9))
+ #define PMX_UART1_ENH_PL_2_3_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_4_5_MASK (0x3F << 12)
+ #define PMX_UART5_PL_4_5_VAL ((0x1 << 12) | (0x1 << 15))
+ #define PMX_UART1_ENH_PL_4_5_VAL ((0x4 << 12) | (0x4 << 15))
+ #define PMX_PL_5_MASK (0x7 << 15)
+ #define PMX_TOUCH_Y_PL_5_VAL 0x0
+
+ #define PMX_PL_6_7_MASK (0x3F << 18)
+ #define PMX_PL_6_MASK (0x7 << 18)
+ #define PMX_PL_7_MASK (0x7 << 21)
+ #define PMX_UART4_PL_6_7_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_PWM_3_PL_6_VAL (0x2 << 18)
+ #define PMX_PWM_2_PL_7_VAL (0x2 << 21)
+ #define PMX_UART1_ENH_PL_6_7_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_8_9_MASK (0x3F << 24)
+ #define PMX_UART3_PL_8_9_VAL ((0x1 << 24) | (0x1 << 27))
+ #define PMX_PWM_0_1_PL_8_9_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_I2C1_PL_8_9_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_10_19_REG 0x00A8
+ #define PMX_PL_10_11_MASK (0x3F << 0)
+ #define PMX_SMII_PL_10_11_VAL 0
+ #define PMX_RMII_PL_10_11_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_PL_12_MASK (0x7 << 6)
+ #define PMX_PWM3_PL_12_VAL 0
+ #define PMX_SDHCI_CD_PL_12_VAL (0x4 << 6)
+
+ #define PMX_PL_13_14_MASK (0x3F << 9)
+ #define PMX_PL_13_MASK (0x7 << 9)
+ #define PMX_PL_14_MASK (0x7 << 12)
+ #define PMX_SSP2_PL_13_14_15_16_VAL 0
+ #define PMX_UART4_PL_13_14_VAL ((0x1 << 9) | (0x1 << 12))
+ #define PMX_RMII_PL_13_14_VAL ((0x4 << 9) | (0x4 << 12))
+ #define PMX_PWM2_PL_13_VAL (0x2 << 9)
+ #define PMX_PWM1_PL_14_VAL (0x2 << 12)
+
+ #define PMX_PL_15_MASK (0x7 << 15)
+ #define PMX_PWM0_PL_15_VAL (0x2 << 15)
+ #define PMX_PL_15_16_MASK (0x3F << 15)
+ #define PMX_UART3_PL_15_16_VAL ((0x1 << 15) | (0x1 << 18))
+ #define PMX_RMII_PL_15_16_VAL ((0x4 << 15) | (0x4 << 18))
+
+ #define PMX_PL_17_18_MASK (0x3F << 21)
+ #define PMX_SSP1_PL_17_18_19_20_VAL 0
+ #define PMX_RMII_PL_17_18_VAL ((0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_19_MASK (0x7 << 27)
+ #define PMX_I2C2_PL_19_VAL (0x1 << 27)
+ #define PMX_RMII_PL_19_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_20_29_REG 0x00AC
+ #define PMX_PL_20_MASK (0x7 << 0)
+ #define PMX_I2C2_PL_20_VAL (0x1 << 0)
+ #define PMX_RMII_PL_20_VAL (0x4 << 0)
+
+ #define PMX_PL_21_TO_27_MASK (0x1FFFFF << 3)
+ #define PMX_SMII_PL_21_TO_27_VAL 0
+ #define PMX_RMII_PL_21_TO_27_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15) | (0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_28_29_MASK (0x3F << 24)
+ #define PMX_PL_28_MASK (0x7 << 24)
+ #define PMX_PL_29_MASK (0x7 << 27)
+ #define PMX_UART1_PL_28_29_VAL 0
+ #define PMX_PWM_3_PL_28_VAL (0x4 << 24)
+ #define PMX_PWM_2_PL_29_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_30_39_REG 0x00B0
+ #define PMX_PL_30_31_MASK (0x3F << 0)
+ #define PMX_CAN1_PL_30_31_VAL (0)
+ #define PMX_PL_30_MASK (0x7 << 0)
+ #define PMX_PL_31_MASK (0x7 << 3)
+ #define PMX_PWM1_EXT_PL_30_VAL (0x4 << 0)
+ #define PMX_PWM0_EXT_PL_31_VAL (0x4 << 3)
+ #define PMX_UART1_ENH_PL_31_VAL (0x3 << 3)
+
+ #define PMX_PL_32_33_MASK (0x3F << 6)
+ #define PMX_CAN0_PL_32_33_VAL 0
+ #define PMX_UART1_ENH_PL_32_33_VAL ((0x3 << 6) | (0x3 << 9))
+ #define PMX_SSP2_PL_32_33_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_34_MASK (0x7 << 12)
+ #define PMX_PWM2_PL_34_VAL 0
+ #define PMX_UART1_ENH_PL_34_VAL (0x2 << 12)
+ #define PMX_SSP2_PL_34_VAL (0x4 << 12)
+
+ #define PMX_PL_35_MASK (0x7 << 15)
+ #define PMX_I2S_REF_CLK_PL_35_VAL 0
+ #define PMX_UART1_ENH_PL_35_VAL (0x2 << 15)
+ #define PMX_SSP2_PL_35_VAL (0x4 << 15)
+
+ #define PMX_PL_36_MASK (0x7 << 18)
+ #define PMX_TOUCH_X_PL_36_VAL 0
+ #define PMX_UART1_ENH_PL_36_VAL (0x2 << 18)
+ #define PMX_SSP1_PL_36_VAL (0x4 << 18)
+
+ #define PMX_PL_37_38_MASK (0x3F << 21)
+ #define PMX_PWM0_1_PL_37_38_VAL 0
+ #define PMX_UART5_PL_37_38_VAL ((0x2 << 21) | (0x2 << 24))
+ #define PMX_SSP1_PL_37_38_VAL ((0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_39_MASK (0x7 << 27)
+ #define PMX_I2S_PL_39_VAL 0
+ #define PMX_UART4_PL_39_VAL (0x2 << 27)
+ #define PMX_SSP1_PL_39_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_40_49_REG 0x00B4
+ #define PMX_PL_40_MASK (0x7 << 0)
+ #define PMX_I2S_PL_40_VAL 0
+ #define PMX_UART4_PL_40_VAL (0x2 << 0)
+ #define PMX_PWM3_PL_40_VAL (0x4 << 0)
+
+ #define PMX_PL_41_42_MASK (0x3F << 3)
+ #define PMX_PL_41_MASK (0x7 << 3)
+ #define PMX_PL_42_MASK (0x7 << 6)
+ #define PMX_I2S_PL_41_42_VAL 0
+ #define PMX_UART3_PL_41_42_VAL ((0x2 << 3) | (0x2 << 6))
+ #define PMX_PWM2_PL_41_VAL (0x4 << 3)
+ #define PMX_PWM1_PL_42_VAL (0x4 << 6)
+
+ #define PMX_PL_43_MASK (0x7 << 9)
+ #define PMX_SDHCI_PL_43_VAL 0
+ #define PMX_UART1_ENH_PL_43_VAL (0x2 << 9)
+ #define PMX_PWM0_PL_43_VAL (0x4 << 9)
+
+ #define PMX_PL_44_45_MASK (0x3F << 12)
+ #define PMX_SDHCI_PL_44_45_VAL 0
+ #define PMX_UART1_ENH_PL_44_45_VAL ((0x2 << 12) | (0x2 << 15))
+ #define PMX_SSP2_PL_44_45_VAL ((0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_46_47_MASK (0x3F << 18)
+ #define PMX_SDHCI_PL_46_47_VAL 0
+ #define PMX_FSMC_EMI_PL_46_47_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_SSP2_PL_46_47_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_48_49_MASK (0x3F << 24)
+ #define PMX_SDHCI_PL_48_49_VAL 0
+ #define PMX_FSMC_EMI_PL_48_49_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_SSP1_PL_48_49_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_50_59_REG 0x00B8
+ #define PMX_PL_50_51_MASK (0x3F << 0)
+ #define PMX_EMI_PL_50_51_VAL ((0x2 << 0) | (0x2 << 3))
+ #define PMX_SSP1_PL_50_51_VAL ((0x4 << 0) | (0x4 << 3))
+ #define PMX_PL_50_MASK (0x7 << 0)
+ #define PMX_PL_51_MASK (0x7 << 3)
+ #define PMX_SDHCI_PL_50_VAL 0
+ #define PMX_SDHCI_CD_PL_51_VAL 0
+
+ #define PMX_PL_52_53_MASK (0x3F << 6)
+ #define PMX_FSMC_PL_52_53_VAL 0
+ #define PMX_EMI_PL_52_53_VAL ((0x2 << 6) | (0x2 << 9))
+ #define PMX_UART3_PL_52_53_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_54_55_56_MASK (0x1FF << 12)
+ #define PMX_FSMC_EMI_PL_54_55_56_VAL ((0x2 << 12) | (0x2 << 15) | (0x2 << 18))
+
+ #define PMX_PL_57_MASK (0x7 << 21)
+ #define PMX_FSMC_PL_57_VAL 0
+ #define PMX_PWM3_PL_57_VAL (0x4 << 21)
+
+ #define PMX_PL_58_59_MASK (0x3F << 24)
+ #define PMX_PL_58_MASK (0x7 << 24)
+ #define PMX_PL_59_MASK (0x7 << 27)
+ #define PMX_FSMC_EMI_PL_58_59_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_PWM2_PL_58_VAL (0x4 << 24)
+ #define PMX_PWM1_PL_59_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_60_69_REG 0x00BC
+ #define PMX_PL_60_MASK (0x7 << 0)
+ #define PMX_FSMC_PL_60_VAL 0
+ #define PMX_PWM0_PL_60_VAL (0x4 << 0)
+
+ #define PMX_PL_61_TO_64_MASK (0xFFF << 3)
+ #define PMX_FSMC_PL_61_TO_64_VAL ((0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12))
+ #define PMX_SSP2_PL_61_TO_64_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12))
+
+ #define PMX_PL_65_TO_68_MASK (0xFFF << 15)
+ #define PMX_FSMC_PL_65_TO_68_VAL ((0x2 << 15) | (0x2 << 18) | (0x2 << 21) | (0x2 << 24))
+ #define PMX_SSP1_PL_65_TO_68_VAL ((0x4 << 15) | (0x4 << 18) | (0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_69_MASK (0x7 << 27)
+ #define PMX_CLCD_PL_69_VAL (0)
+ #define PMX_EMI_PL_69_VAL (0x2 << 27)
+ #define PMX_SPP_PL_69_VAL (0x3 << 27)
+ #define PMX_UART5_PL_69_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_70_79_REG 0x00C0
+ #define PMX_PL_70_MASK (0x7 << 0)
+ #define PMX_CLCD_PL_70_VAL (0)
+ #define PMX_FSMC_EMI_PL_70_VAL (0x2 << 0)
+ #define PMX_SPP_PL_70_VAL (0x3 << 0)
+ #define PMX_UART5_PL_70_VAL (0x4 << 0)
+
+ #define PMX_PL_71_72_MASK (0x3F << 3)
+ #define PMX_CLCD_PL_71_72_VAL (0)
+ #define PMX_FSMC_EMI_PL_71_72_VAL ((0x2 << 3) | (0x2 << 6))
+ #define PMX_SPP_PL_71_72_VAL ((0x3 << 3) | (0x3 << 6))
+ #define PMX_UART4_PL_71_72_VAL ((0x4 << 3) | (0x4 << 6))
+
+ #define PMX_PL_73_MASK (0x7 << 9)
+ #define PMX_CLCD_PL_73_VAL (0)
+ #define PMX_FSMC_EMI_PL_73_VAL (0x2 << 9)
+ #define PMX_SPP_PL_73_VAL (0x3 << 9)
+ #define PMX_UART3_PL_73_VAL (0x4 << 9)
+
+ #define PMX_PL_74_MASK (0x7 << 12)
+ #define PMX_CLCD_PL_74_VAL (0)
+ #define PMX_EMI_PL_74_VAL (0x2 << 12)
+ #define PMX_SPP_PL_74_VAL (0x3 << 12)
+ #define PMX_UART3_PL_74_VAL (0x4 << 12)
+
+ #define PMX_PL_75_76_MASK (0x3F << 15)
+ #define PMX_CLCD_PL_75_76_VAL (0)
+ #define PMX_EMI_PL_75_76_VAL ((0x2 << 15) | (0x2 << 18))
+ #define PMX_SPP_PL_75_76_VAL ((0x3 << 15) | (0x3 << 18))
+ #define PMX_I2C2_PL_75_76_VAL ((0x4 << 15) | (0x4 << 18))
+
+ #define PMX_PL_77_78_79_MASK (0x1FF << 21)
+ #define PMX_CLCD_PL_77_78_79_VAL (0)
+ #define PMX_EMI_PL_77_78_79_VAL ((0x2 << 21) | (0x2 << 24) | (0x2 << 27))
+ #define PMX_SPP_PL_77_78_79_VAL ((0x3 << 21) | (0x3 << 24) | (0x3 << 27))
+ #define PMX_RS485_PL_77_78_79_VAL ((0x4 << 21) | (0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_80_89_REG 0x00C4
+ #define PMX_PL_80_TO_85_MASK (0x3FFFF << 0)
+ #define PMX_CLCD_PL_80_TO_85_VAL 0
+ #define PMX_MII2_PL_80_TO_85_VAL ((0x1 << 0) | (0x1 << 3) | (0x1 << 6) | (0x1 << 9) | (0x1 << 12) | (0x1 << 15))
+ #define PMX_EMI_PL_80_TO_85_VAL ((0x2 << 0) | (0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12) | (0x2 << 15))
+ #define PMX_SPP_PL_80_TO_85_VAL ((0x3 << 0) | (0x3 << 3) | (0x3 << 6) | (0x3 << 9) | (0x3 << 12) | (0x3 << 15))
+ #define PMX_UART1_ENH_PL_80_TO_85_VAL ((0x4 << 0) | (0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_86_87_MASK (0x3F << 18)
+ #define PMX_PL_86_MASK (0x7 << 18)
+ #define PMX_PL_87_MASK (0x7 << 21)
+ #define PMX_CLCD_PL_86_87_VAL 0
+ #define PMX_MII2_PL_86_87_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_EMI_PL_86_87_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_PWM3_PL_86_VAL (0x4 << 18)
+ #define PMX_PWM2_PL_87_VAL (0x4 << 21)
+
+ #define PMX_PL_88_89_MASK (0x3F << 24)
+ #define PMX_CLCD_PL_88_89_VAL 0
+ #define PMX_MII2_PL_88_89_VAL ((0x1 << 24) | (0x1 << 27))
+ #define PMX_EMI_PL_88_89_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_UART6_PL_88_89_VAL ((0x3 << 24) | (0x3 << 27))
+ #define PMX_PWM0_1_PL_88_89_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_90_99_REG 0x00C8
+ #define PMX_PL_90_91_MASK (0x3F << 0)
+ #define PMX_CLCD_PL_90_91_VAL 0
+ #define PMX_MII2_PL_90_91_VAL ((0x1 << 0) | (0x1 << 3))
+ #define PMX_EMI1_PL_90_91_VAL ((0x2 << 0) | (0x2 << 3))
+ #define PMX_UART5_PL_90_91_VAL ((0x3 << 0) | (0x3 << 3))
+ #define PMX_SSP2_PL_90_91_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_PL_92_93_MASK (0x3F << 6)
+ #define PMX_CLCD_PL_92_93_VAL 0
+ #define PMX_MII2_PL_92_93_VAL ((0x1 << 6) | (0x1 << 9))
+ #define PMX_EMI1_PL_92_93_VAL ((0x2 << 6) | (0x2 << 9))
+ #define PMX_UART4_PL_92_93_VAL ((0x3 << 6) | (0x3 << 9))
+ #define PMX_SSP2_PL_92_93_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_94_95_MASK (0x3F << 12)
+ #define PMX_CLCD_PL_94_95_VAL 0
+ #define PMX_MII2_PL_94_95_VAL ((0x1 << 12) | (0x1 << 15))
+ #define PMX_EMI1_PL_94_95_VAL ((0x2 << 12) | (0x2 << 15))
+ #define PMX_UART3_PL_94_95_VAL ((0x3 << 12) | (0x3 << 15))
+ #define PMX_SSP1_PL_94_95_VAL ((0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_96_97_MASK (0x3F << 18)
+ #define PMX_CLCD_PL_96_97_VAL 0
+ #define PMX_MII2_PL_96_97_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_EMI1_PL_96_97_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_I2C2_PL_96_97_VAL ((0x3 << 18) | (0x3 << 21))
+ #define PMX_SSP1_PL_96_97_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_98_MASK (0x7 << 24)
+ #define PMX_CLCD_PL_98_VAL 0
+ #define PMX_I2C1_PL_98_VAL (0x2 << 24)
+ #define PMX_UART3_PL_98_VAL (0x4 << 24)
+
+ #define PMX_PL_99_MASK (0x7 << 27)
+ #define PMX_SDHCI_PL_99_VAL 0
+ #define PMX_I2C1_PL_99_VAL (0x2 << 27)
+ #define PMX_UART3_PL_99_VAL (0x4 << 27)
+
+#define IP_SEL_MIX_PAD_REG 0x00CC
+ #define PMX_PL_100_101_MASK (0x3F << 0)
+ #define PMX_SDHCI_PL_100_101_VAL 0
+ #define PMX_UART4_PL_100_101_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_SSP1_PORT_SEL_MASK (0x7 << 8)
+ #define PMX_SSP1_PORT_94_TO_97_VAL 0
+ #define PMX_SSP1_PORT_65_TO_68_VAL (0x1 << 8)
+ #define PMX_SSP1_PORT_48_TO_51_VAL (0x2 << 8)
+ #define PMX_SSP1_PORT_36_TO_39_VAL (0x3 << 8)
+ #define PMX_SSP1_PORT_17_TO_20_VAL (0x4 << 8)
+
+ #define PMX_SSP2_PORT_SEL_MASK (0x7 << 11)
+ #define PMX_SSP2_PORT_90_TO_93_VAL 0
+ #define PMX_SSP2_PORT_61_TO_64_VAL (0x1 << 11)
+ #define PMX_SSP2_PORT_44_TO_47_VAL (0x2 << 11)
+ #define PMX_SSP2_PORT_32_TO_35_VAL (0x3 << 11)
+ #define PMX_SSP2_PORT_13_TO_16_VAL (0x4 << 11)
+
+ #define PMX_UART1_ENH_PORT_SEL_MASK (0x3 << 14)
+ #define PMX_UART1_ENH_PORT_81_TO_85_VAL 0
+ #define PMX_UART1_ENH_PORT_44_45_34_36_VAL (0x1 << 14)
+ #define PMX_UART1_ENH_PORT_32_TO_34_36_VAL (0x2 << 14)
+ #define PMX_UART1_ENH_PORT_3_TO_5_7_VAL (0x3 << 14)
+
+ #define PMX_UART3_PORT_SEL_MASK (0x7 << 16)
+ #define PMX_UART3_PORT_94_VAL 0
+ #define PMX_UART3_PORT_73_VAL (0x1 << 16)
+ #define PMX_UART3_PORT_52_VAL (0x2 << 16)
+ #define PMX_UART3_PORT_41_VAL (0x3 << 16)
+ #define PMX_UART3_PORT_15_VAL (0x4 << 16)
+ #define PMX_UART3_PORT_8_VAL (0x5 << 16)
+ #define PMX_UART3_PORT_99_VAL (0x6 << 16)
+
+ #define PMX_UART4_PORT_SEL_MASK (0x7 << 19)
+ #define PMX_UART4_PORT_92_VAL 0
+ #define PMX_UART4_PORT_71_VAL (0x1 << 19)
+ #define PMX_UART4_PORT_39_VAL (0x2 << 19)
+ #define PMX_UART4_PORT_13_VAL (0x3 << 19)
+ #define PMX_UART4_PORT_6_VAL (0x4 << 19)
+ #define PMX_UART4_PORT_101_VAL (0x5 << 19)
+
+ #define PMX_UART5_PORT_SEL_MASK (0x3 << 22)
+ #define PMX_UART5_PORT_90_VAL 0
+ #define PMX_UART5_PORT_69_VAL (0x1 << 22)
+ #define PMX_UART5_PORT_37_VAL (0x2 << 22)
+ #define PMX_UART5_PORT_4_VAL (0x3 << 22)
+
+ #define PMX_UART6_PORT_SEL_MASK (0x1 << 24)
+ #define PMX_UART6_PORT_88_VAL 0
+ #define PMX_UART6_PORT_2_VAL (0x1 << 24)
+
+ #define PMX_I2C1_PORT_SEL_MASK (0x1 << 25)
+ #define PMX_I2C1_PORT_8_9_VAL 0
+ #define PMX_I2C1_PORT_98_99_VAL (0x1 << 25)
+
+ #define PMX_I2C2_PORT_SEL_MASK (0x3 << 26)
+ #define PMX_I2C2_PORT_96_97_VAL 0
+ #define PMX_I2C2_PORT_75_76_VAL (0x1 << 26)
+ #define PMX_I2C2_PORT_19_20_VAL (0x2 << 26)
+ #define PMX_I2C2_PORT_2_3_VAL (0x3 << 26)
+ #define PMX_I2C2_PORT_0_1_VAL (0x4 << 26)
+
+ #define PMX_SDHCI_CD_PORT_SEL_MASK (0x1 << 29)
+ #define PMX_SDHCI_CD_PORT_12_VAL 0
+ #define PMX_SDHCI_CD_PORT_51_VAL (0x1 << 29)
+
+/* Pad multiplexing for CLCD device */
+static const unsigned clcd_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97 };
+static struct spear_muxreg clcd_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_CLCD_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_CLCD_PL_70_VAL | PMX_CLCD_PL_71_72_VAL |
+ PMX_CLCD_PL_73_VAL | PMX_CLCD_PL_74_VAL |
+ PMX_CLCD_PL_75_76_VAL | PMX_CLCD_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_CLCD_PL_80_TO_85_VAL | PMX_CLCD_PL_86_87_VAL |
+ PMX_CLCD_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK | PMX_PL_98_MASK,
+ .val = PMX_CLCD_PL_90_91_VAL | PMX_CLCD_PL_92_93_VAL |
+ PMX_CLCD_PL_94_95_VAL | PMX_CLCD_PL_96_97_VAL |
+ PMX_CLCD_PL_98_VAL,
+ },
+};
+
+static struct spear_modemux clcd_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = clcd_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_pingroup = {
+ .name = "clcd_grp",
+ .pins = clcd_pins,
+ .npins = ARRAY_SIZE(clcd_pins),
+ .modemuxs = clcd_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_grp" };
+static struct spear_function clcd_function = {
+ .name = "clcd",
+ .groups = clcd_grps,
+ .ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* Pad multiplexing for EMI (Parallel NOR flash) device */
+static const unsigned emi_pins[] = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97 };
+static struct spear_muxreg emi_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg emi_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+ .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_51_MASK | PMX_PL_52_53_MASK |
+ PMX_PL_54_55_56_MASK | PMX_PL_58_59_MASK,
+ .val = PMX_EMI_PL_50_51_VAL | PMX_EMI_PL_52_53_VAL |
+ PMX_FSMC_EMI_PL_54_55_56_VAL |
+ PMX_FSMC_EMI_PL_58_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_EMI_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+ PMX_FSMC_EMI_PL_73_VAL | PMX_EMI_PL_74_VAL |
+ PMX_EMI_PL_75_76_VAL | PMX_EMI_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_EMI_PL_80_TO_85_VAL | PMX_EMI_PL_86_87_VAL |
+ PMX_EMI_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_EMI1_PL_90_91_VAL | PMX_EMI1_PL_92_93_VAL |
+ PMX_EMI1_PL_94_95_VAL | PMX_EMI1_PL_96_97_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+ .val = EMI_FSMC_DYNAMIC_MUX_MASK,
+ },
+};
+
+static struct spear_modemux emi_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = emi_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = emi_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup emi_pingroup = {
+ .name = "emi_grp",
+ .pins = emi_pins,
+ .npins = ARRAY_SIZE(emi_pins),
+ .modemuxs = emi_modemux,
+ .nmodemuxs = ARRAY_SIZE(emi_modemux),
+};
+
+static const char *const emi_grps[] = { "emi_grp" };
+static struct spear_function emi_function = {
+ .name = "emi",
+ .groups = emi_grps,
+ .ngroups = ARRAY_SIZE(emi_grps),
+};
+
+/* Pad multiplexing for FSMC (NAND flash) device */
+static const unsigned fsmc_8bit_pins[] = { 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68 };
+static struct spear_muxreg fsmc_8bit_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_52_53_MASK | PMX_PL_54_55_56_MASK |
+ PMX_PL_57_MASK | PMX_PL_58_59_MASK,
+ .val = PMX_FSMC_PL_52_53_VAL | PMX_FSMC_EMI_PL_54_55_56_VAL |
+ PMX_FSMC_PL_57_VAL | PMX_FSMC_EMI_PL_58_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_60_MASK | PMX_PL_61_TO_64_MASK |
+ PMX_PL_65_TO_68_MASK,
+ .val = PMX_FSMC_PL_60_VAL | PMX_FSMC_PL_61_TO_64_VAL |
+ PMX_FSMC_PL_65_TO_68_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+ .val = EMI_FSMC_DYNAMIC_MUX_MASK,
+ },
+};
+
+static struct spear_modemux fsmc_8bit_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_8bit_pingroup = {
+ .name = "fsmc_8bit_grp",
+ .pins = fsmc_8bit_pins,
+ .npins = ARRAY_SIZE(fsmc_8bit_pins),
+ .modemuxs = fsmc_8bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_8bit_modemux),
+};
+
+static const unsigned fsmc_16bit_pins[] = { 46, 47, 48, 49, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73 };
+static struct spear_muxreg fsmc_16bit_autoexp_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg fsmc_16bit_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+ .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK,
+ .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+ PMX_FSMC_EMI_PL_73_VAL,
+ }
+};
+
+static struct spear_modemux fsmc_16bit_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+ }, {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = fsmc_16bit_autoexp_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_16bit_autoexp_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_16bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_16bit_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_16bit_pingroup = {
+ .name = "fsmc_16bit_grp",
+ .pins = fsmc_16bit_pins,
+ .npins = ARRAY_SIZE(fsmc_16bit_pins),
+ .modemuxs = fsmc_16bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_16bit_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_8bit_grp", "fsmc_16bit_grp" };
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* Pad multiplexing for SPP device */
+static const unsigned spp_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85 };
+static struct spear_muxreg spp_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_SPP_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_SPP_PL_70_VAL | PMX_SPP_PL_71_72_VAL |
+ PMX_SPP_PL_73_VAL | PMX_SPP_PL_74_VAL |
+ PMX_SPP_PL_75_76_VAL | PMX_SPP_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK,
+ .val = PMX_SPP_PL_80_TO_85_VAL,
+ },
+};
+
+static struct spear_modemux spp_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = spp_muxreg,
+ .nmuxregs = ARRAY_SIZE(spp_muxreg),
+ },
+};
+
+static struct spear_pingroup spp_pingroup = {
+ .name = "spp_grp",
+ .pins = spp_pins,
+ .npins = ARRAY_SIZE(spp_pins),
+ .modemuxs = spp_modemux,
+ .nmodemuxs = ARRAY_SIZE(spp_modemux),
+};
+
+static const char *const spp_grps[] = { "spp_grp" };
+static struct spear_function spp_function = {
+ .name = "spp",
+ .groups = spp_grps,
+ .ngroups = ARRAY_SIZE(spp_grps),
+};
+
+/* Pad multiplexing for SDHCI device */
+static const unsigned sdhci_led_pins[] = { 34 };
+static struct spear_muxreg sdhci_led_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg sdhci_led_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK,
+ .val = PMX_PWM2_PL_34_VAL,
+ },
+};
+
+static struct spear_modemux sdhci_led_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = sdhci_led_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_led_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_led_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_led_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_led_pingroup = {
+ .name = "sdhci_led_grp",
+ .pins = sdhci_led_pins,
+ .npins = ARRAY_SIZE(sdhci_led_pins),
+ .modemuxs = sdhci_led_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_led_modemux),
+};
+
+static const unsigned sdhci_cd_12_pins[] = { 12, 43, 44, 45, 46, 47, 48, 49,
+ 50};
+static const unsigned sdhci_cd_51_pins[] = { 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+static struct spear_muxreg sdhci_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg sdhci_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK | PMX_PL_46_47_MASK |
+ PMX_PL_48_49_MASK,
+ .val = PMX_SDHCI_PL_43_VAL | PMX_SDHCI_PL_44_45_VAL |
+ PMX_SDHCI_PL_46_47_VAL | PMX_SDHCI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_MASK,
+ .val = PMX_SDHCI_PL_50_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_99_MASK,
+ .val = PMX_SDHCI_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_PL_100_101_MASK,
+ .val = PMX_SDHCI_PL_100_101_VAL,
+ },
+};
+
+static struct spear_muxreg sdhci_cd_12_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_12_MASK,
+ .val = PMX_SDHCI_CD_PL_12_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+ .val = PMX_SDHCI_CD_PORT_12_VAL,
+ },
+};
+
+static struct spear_muxreg sdhci_cd_51_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_51_MASK,
+ .val = PMX_SDHCI_CD_PL_51_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+ .val = PMX_SDHCI_CD_PORT_51_VAL,
+ },
+};
+
+#define pmx_sdhci_common_modemux \
+ { \
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | \
+ SMALL_PRINTERS_MODE | EXTENDED_MODE, \
+ .muxregs = sdhci_muxreg, \
+ .nmuxregs = ARRAY_SIZE(sdhci_muxreg), \
+ }, { \
+ .modes = EXTENDED_MODE, \
+ .muxregs = sdhci_ext_muxreg, \
+ .nmuxregs = ARRAY_SIZE(sdhci_ext_muxreg), \
+ }
+
+static struct spear_modemux sdhci_modemux[][3] = {
+ {
+ /* select pin 12 for cd */
+ pmx_sdhci_common_modemux,
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_cd_12_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_cd_12_muxreg),
+ },
+ }, {
+ /* select pin 51 for cd */
+ pmx_sdhci_common_modemux,
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_cd_51_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_cd_51_muxreg),
+ },
+ }
+};
+
+static struct spear_pingroup sdhci_pingroup[] = {
+ {
+ .name = "sdhci_cd_12_grp",
+ .pins = sdhci_cd_12_pins,
+ .npins = ARRAY_SIZE(sdhci_cd_12_pins),
+ .modemuxs = sdhci_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(sdhci_modemux[0]),
+ }, {
+ .name = "sdhci_cd_51_grp",
+ .pins = sdhci_cd_51_pins,
+ .npins = ARRAY_SIZE(sdhci_cd_51_pins),
+ .modemuxs = sdhci_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(sdhci_modemux[1]),
+ },
+};
+
+static const char *const sdhci_grps[] = { "sdhci_cd_12_grp", "sdhci_cd_51_grp",
+ "sdhci_led_grp" };
+
+static struct spear_function sdhci_function = {
+ .name = "sdhci",
+ .groups = sdhci_grps,
+ .ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* Pad multiplexing for I2S device */
+static const unsigned i2s_pins[] = { 35, 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg i2s_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_35_MASK | PMX_PL_39_MASK,
+ .val = PMX_I2S_REF_CLK_PL_35_VAL | PMX_I2S_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK | PMX_PL_41_42_MASK,
+ .val = PMX_I2S_PL_40_VAL | PMX_I2S_PL_41_42_VAL,
+ },
+};
+
+static struct spear_modemux i2s_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = i2s_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2s_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup i2s_pingroup = {
+ .name = "i2s_grp",
+ .pins = i2s_pins,
+ .npins = ARRAY_SIZE(i2s_pins),
+ .modemuxs = i2s_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+ .name = "i2s",
+ .groups = i2s_grps,
+ .ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* Pad multiplexing for UART1 device */
+static const unsigned uart1_pins[] = { 28, 29 };
+static struct spear_muxreg uart1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_28_29_MASK,
+ .val = PMX_UART1_PL_28_29_VAL,
+ },
+};
+
+static struct spear_modemux uart1_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart1_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_pingroup = {
+ .name = "uart1_grp",
+ .pins = uart1_pins,
+ .npins = ARRAY_SIZE(uart1_pins),
+ .modemuxs = uart1_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+ .name = "uart1",
+ .groups = uart1_grps,
+ .ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* Pad multiplexing for UART1 Modem device */
+static const unsigned uart1_modem_2_to_7_pins[] = { 2, 3, 4, 5, 6, 7 };
+static const unsigned uart1_modem_31_to_36_pins[] = { 31, 32, 33, 34, 35, 36 };
+static const unsigned uart1_modem_34_to_45_pins[] = { 34, 35, 36, 43, 44, 45 };
+static const unsigned uart1_modem_80_to_85_pins[] = { 80, 81, 82, 83, 84, 85 };
+
+static struct spear_muxreg uart1_modem_ext_2_to_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK | PMX_I2C_MASK | PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK | PMX_PL_6_7_MASK,
+ .val = PMX_UART1_ENH_PL_2_3_VAL | PMX_UART1_ENH_PL_4_5_VAL |
+ PMX_UART1_ENH_PL_6_7_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_3_TO_5_7_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_31_to_36_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK |
+ PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_31_to_36_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_31_MASK | PMX_PL_32_33_MASK | PMX_PL_34_MASK |
+ PMX_PL_35_MASK | PMX_PL_36_MASK,
+ .val = PMX_UART1_ENH_PL_31_VAL | PMX_UART1_ENH_PL_32_33_VAL |
+ PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+ PMX_UART1_ENH_PL_36_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_32_TO_34_36_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_34_to_45_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK |
+ PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_34_to_45_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK | PMX_PL_35_MASK | PMX_PL_36_MASK,
+ .val = PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+ PMX_UART1_ENH_PL_36_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+ .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_44_45_34_36_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_80_to_85_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK,
+ .val = PMX_UART1_ENH_PL_80_TO_85_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+ .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_81_TO_85_VAL,
+ },
+};
+
+static struct spear_modemux uart1_modem_2_to_7_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_2_to_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_2_to_7_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_31_to_36_modemux[] = {
+ {
+ .modes = SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart1_modem_31_to_36_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_31_to_36_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_31_to_36_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_31_to_36_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_34_to_45_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = uart1_modem_34_to_45_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_34_to_45_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_34_to_45_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_34_to_45_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_80_to_85_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_80_to_85_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_80_to_85_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_modem_pingroup[] = {
+ {
+ .name = "uart1_modem_2_to_7_grp",
+ .pins = uart1_modem_2_to_7_pins,
+ .npins = ARRAY_SIZE(uart1_modem_2_to_7_pins),
+ .modemuxs = uart1_modem_2_to_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_2_to_7_modemux),
+ }, {
+ .name = "uart1_modem_31_to_36_grp",
+ .pins = uart1_modem_31_to_36_pins,
+ .npins = ARRAY_SIZE(uart1_modem_31_to_36_pins),
+ .modemuxs = uart1_modem_31_to_36_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_31_to_36_modemux),
+ }, {
+ .name = "uart1_modem_34_to_45_grp",
+ .pins = uart1_modem_34_to_45_pins,
+ .npins = ARRAY_SIZE(uart1_modem_34_to_45_pins),
+ .modemuxs = uart1_modem_34_to_45_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_34_to_45_modemux),
+ }, {
+ .name = "uart1_modem_80_to_85_grp",
+ .pins = uart1_modem_80_to_85_pins,
+ .npins = ARRAY_SIZE(uart1_modem_80_to_85_pins),
+ .modemuxs = uart1_modem_80_to_85_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_80_to_85_modemux),
+ },
+};
+
+static const char *const uart1_modem_grps[] = { "uart1_modem_2_to_7_grp",
+ "uart1_modem_31_to_36_grp", "uart1_modem_34_to_45_grp",
+ "uart1_modem_80_to_85_grp" };
+static struct spear_function uart1_modem_function = {
+ .name = "uart1_modem",
+ .groups = uart1_modem_grps,
+ .ngroups = ARRAY_SIZE(uart1_modem_grps),
+};
+
+/* Pad multiplexing for UART2 device */
+static const unsigned uart2_pins[] = { 0, 1 };
+static struct spear_muxreg uart2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart2_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_0_1_MASK,
+ .val = PMX_UART2_PL_0_1_VAL,
+ },
+};
+
+static struct spear_modemux uart2_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart2_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart2_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup uart2_pingroup = {
+ .name = "uart2_grp",
+ .pins = uart2_pins,
+ .npins = ARRAY_SIZE(uart2_pins),
+ .modemuxs = uart2_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+ .name = "uart2",
+ .groups = uart2_grps,
+ .ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* Pad multiplexing for uart3 device */
+static const unsigned uart3_pins[][2] = { { 8, 9 }, { 15, 16 }, { 41, 42 },
+ { 52, 53 }, { 73, 74 }, { 94, 95 }, { 98, 99 } };
+
+static struct spear_muxreg uart3_ext_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_UART3_PL_8_9_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_8_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_15_16_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_15_16_MASK,
+ .val = PMX_UART3_PL_15_16_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_15_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_41_42_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_41_42_MASK,
+ .val = PMX_UART3_PL_41_42_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_41_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_52_53_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_52_53_MASK,
+ .val = PMX_UART3_PL_52_53_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_52_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_73_74_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_73_MASK | PMX_PL_74_MASK,
+ .val = PMX_UART3_PL_73_VAL | PMX_UART3_PL_74_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_73_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_94_95_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_94_95_MASK,
+ .val = PMX_UART3_PL_94_95_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_94_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_98_99_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+ .val = PMX_UART3_PL_98_VAL | PMX_UART3_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_99_VAL,
+ },
+};
+
+static struct spear_modemux uart3_modemux[][1] = {
+ {
+ /* Select signals on pins 8_9 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_8_9_muxreg),
+ },
+ }, {
+ /* Select signals on pins 15_16 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_15_16_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_15_16_muxreg),
+ },
+ }, {
+ /* Select signals on pins 41_42 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_41_42_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_41_42_muxreg),
+ },
+ }, {
+ /* Select signals on pins 52_53 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_52_53_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_52_53_muxreg),
+ },
+ }, {
+ /* Select signals on pins 73_74 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_73_74_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_73_74_muxreg),
+ },
+ }, {
+ /* Select signals on pins 94_95 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_94_95_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_94_95_muxreg),
+ },
+ }, {
+ /* Select signals on pins 98_99 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_98_99_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_98_99_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart3_pingroup[] = {
+ {
+ .name = "uart3_8_9_grp",
+ .pins = uart3_pins[0],
+ .npins = ARRAY_SIZE(uart3_pins[0]),
+ .modemuxs = uart3_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[0]),
+ }, {
+ .name = "uart3_15_16_grp",
+ .pins = uart3_pins[1],
+ .npins = ARRAY_SIZE(uart3_pins[1]),
+ .modemuxs = uart3_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[1]),
+ }, {
+ .name = "uart3_41_42_grp",
+ .pins = uart3_pins[2],
+ .npins = ARRAY_SIZE(uart3_pins[2]),
+ .modemuxs = uart3_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[2]),
+ }, {
+ .name = "uart3_52_53_grp",
+ .pins = uart3_pins[3],
+ .npins = ARRAY_SIZE(uart3_pins[3]),
+ .modemuxs = uart3_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[3]),
+ }, {
+ .name = "uart3_73_74_grp",
+ .pins = uart3_pins[4],
+ .npins = ARRAY_SIZE(uart3_pins[4]),
+ .modemuxs = uart3_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[4]),
+ }, {
+ .name = "uart3_94_95_grp",
+ .pins = uart3_pins[5],
+ .npins = ARRAY_SIZE(uart3_pins[5]),
+ .modemuxs = uart3_modemux[5],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[5]),
+ }, {
+ .name = "uart3_98_99_grp",
+ .pins = uart3_pins[6],
+ .npins = ARRAY_SIZE(uart3_pins[6]),
+ .modemuxs = uart3_modemux[6],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[6]),
+ },
+};
+
+static const char *const uart3_grps[] = { "uart3_8_9_grp", "uart3_15_16_grp",
+ "uart3_41_42_grp", "uart3_52_53_grp", "uart3_73_74_grp",
+ "uart3_94_95_grp", "uart3_98_99_grp" };
+
+static struct spear_function uart3_function = {
+ .name = "uart3",
+ .groups = uart3_grps,
+ .ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* Pad multiplexing for uart4 device */
+static const unsigned uart4_pins[][2] = { { 6, 7 }, { 13, 14 }, { 39, 40 },
+ { 71, 72 }, { 92, 93 }, { 100, 101 } };
+
+static struct spear_muxreg uart4_ext_6_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_6_7_MASK,
+ .val = PMX_UART4_PL_6_7_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_6_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_13_14_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_14_MASK,
+ .val = PMX_UART4_PL_13_14_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_13_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_39_40_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_39_MASK,
+ .val = PMX_UART4_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK,
+ .val = PMX_UART4_PL_40_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_39_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_71_72_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_71_72_MASK,
+ .val = PMX_UART4_PL_71_72_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_71_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_92_93_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_92_93_MASK,
+ .val = PMX_UART4_PL_92_93_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_92_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_100_101_muxreg[] = {
+ {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_PL_100_101_MASK |
+ PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PL_100_101_VAL |
+ PMX_UART4_PORT_101_VAL,
+ },
+};
+
+static struct spear_modemux uart4_modemux[][1] = {
+ {
+ /* Select signals on pins 6_7 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_6_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_6_7_muxreg),
+ },
+ }, {
+ /* Select signals on pins 13_14 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_13_14_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_13_14_muxreg),
+ },
+ }, {
+ /* Select signals on pins 39_40 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_39_40_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_39_40_muxreg),
+ },
+ }, {
+ /* Select signals on pins 71_72 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_71_72_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_71_72_muxreg),
+ },
+ }, {
+ /* Select signals on pins 92_93 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_92_93_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_92_93_muxreg),
+ },
+ }, {
+ /* Select signals on pins 100_101_ */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_100_101_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_100_101_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart4_pingroup[] = {
+ {
+ .name = "uart4_6_7_grp",
+ .pins = uart4_pins[0],
+ .npins = ARRAY_SIZE(uart4_pins[0]),
+ .modemuxs = uart4_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[0]),
+ }, {
+ .name = "uart4_13_14_grp",
+ .pins = uart4_pins[1],
+ .npins = ARRAY_SIZE(uart4_pins[1]),
+ .modemuxs = uart4_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[1]),
+ }, {
+ .name = "uart4_39_40_grp",
+ .pins = uart4_pins[2],
+ .npins = ARRAY_SIZE(uart4_pins[2]),
+ .modemuxs = uart4_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[2]),
+ }, {
+ .name = "uart4_71_72_grp",
+ .pins = uart4_pins[3],
+ .npins = ARRAY_SIZE(uart4_pins[3]),
+ .modemuxs = uart4_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[3]),
+ }, {
+ .name = "uart4_92_93_grp",
+ .pins = uart4_pins[4],
+ .npins = ARRAY_SIZE(uart4_pins[4]),
+ .modemuxs = uart4_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[4]),
+ }, {
+ .name = "uart4_100_101_grp",
+ .pins = uart4_pins[5],
+ .npins = ARRAY_SIZE(uart4_pins[5]),
+ .modemuxs = uart4_modemux[5],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[5]),
+ },
+};
+
+static const char *const uart4_grps[] = { "uart4_6_7_grp", "uart4_13_14_grp",
+ "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp",
+ "uart4_100_101_grp" };
+
+static struct spear_function uart4_function = {
+ .name = "uart4",
+ .groups = uart4_grps,
+ .ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* Pad multiplexing for uart5 device */
+static const unsigned uart5_pins[][2] = { { 4, 5 }, { 37, 38 }, { 69, 70 },
+ { 90, 91 } };
+
+static struct spear_muxreg uart5_ext_4_5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_I2C_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_4_5_MASK,
+ .val = PMX_UART5_PL_4_5_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_4_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_37_38_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_37_38_MASK,
+ .val = PMX_UART5_PL_37_38_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_37_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_69_70_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_UART5_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK,
+ .val = PMX_UART5_PL_70_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_69_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_90_91_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK,
+ .val = PMX_UART5_PL_90_91_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_90_VAL,
+ },
+};
+
+static struct spear_modemux uart5_modemux[][1] = {
+ {
+ /* Select signals on pins 4_5 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_4_5_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_4_5_muxreg),
+ },
+ }, {
+ /* Select signals on pins 37_38 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_37_38_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_37_38_muxreg),
+ },
+ }, {
+ /* Select signals on pins 69_70 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_69_70_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_69_70_muxreg),
+ },
+ }, {
+ /* Select signals on pins 90_91 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_90_91_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_90_91_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart5_pingroup[] = {
+ {
+ .name = "uart5_4_5_grp",
+ .pins = uart5_pins[0],
+ .npins = ARRAY_SIZE(uart5_pins[0]),
+ .modemuxs = uart5_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[0]),
+ }, {
+ .name = "uart5_37_38_grp",
+ .pins = uart5_pins[1],
+ .npins = ARRAY_SIZE(uart5_pins[1]),
+ .modemuxs = uart5_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[1]),
+ }, {
+ .name = "uart5_69_70_grp",
+ .pins = uart5_pins[2],
+ .npins = ARRAY_SIZE(uart5_pins[2]),
+ .modemuxs = uart5_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[2]),
+ }, {
+ .name = "uart5_90_91_grp",
+ .pins = uart5_pins[3],
+ .npins = ARRAY_SIZE(uart5_pins[3]),
+ .modemuxs = uart5_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[3]),
+ },
+};
+
+static const char *const uart5_grps[] = { "uart5_4_5_grp", "uart5_37_38_grp",
+ "uart5_69_70_grp", "uart5_90_91_grp" };
+static struct spear_function uart5_function = {
+ .name = "uart5",
+ .groups = uart5_grps,
+ .ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* Pad multiplexing for uart6 device */
+static const unsigned uart6_pins[][2] = { { 2, 3 }, { 88, 89 } };
+static struct spear_muxreg uart6_ext_2_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK,
+ .val = PMX_UART6_PL_2_3_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART6_PORT_SEL_MASK,
+ .val = PMX_UART6_PORT_2_VAL,
+ },
+};
+
+static struct spear_muxreg uart6_ext_88_89_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_88_89_MASK,
+ .val = PMX_UART6_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART6_PORT_SEL_MASK,
+ .val = PMX_UART6_PORT_88_VAL,
+ },
+};
+
+static struct spear_modemux uart6_modemux[][1] = {
+ {
+ /* Select signals on pins 2_3 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart6_ext_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart6_ext_2_3_muxreg),
+ },
+ }, {
+ /* Select signals on pins 88_89 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart6_ext_88_89_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart6_ext_88_89_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart6_pingroup[] = {
+ {
+ .name = "uart6_2_3_grp",
+ .pins = uart6_pins[0],
+ .npins = ARRAY_SIZE(uart6_pins[0]),
+ .modemuxs = uart6_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart6_modemux[0]),
+ }, {
+ .name = "uart6_88_89_grp",
+ .pins = uart6_pins[1],
+ .npins = ARRAY_SIZE(uart6_pins[1]),
+ .modemuxs = uart6_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart6_modemux[1]),
+ },
+};
+
+static const char *const uart6_grps[] = { "uart6_2_3_grp", "uart6_88_89_grp" };
+static struct spear_function uart6_function = {
+ .name = "uart6",
+ .groups = uart6_grps,
+ .ngroups = ARRAY_SIZE(uart6_grps),
+};
+
+/* UART - RS485 pmx */
+static const unsigned rs485_pins[] = { 77, 78, 79 };
+static struct spear_muxreg rs485_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_77_78_79_MASK,
+ .val = PMX_RS485_PL_77_78_79_VAL,
+ },
+};
+
+static struct spear_modemux rs485_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = rs485_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_pingroup = {
+ .name = "rs485_grp",
+ .pins = rs485_pins,
+ .npins = ARRAY_SIZE(rs485_pins),
+ .modemuxs = rs485_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_modemux),
+};
+
+static const char *const rs485_grps[] = { "rs485_grp" };
+static struct spear_function rs485_function = {
+ .name = "rs485",
+ .groups = rs485_grps,
+ .ngroups = ARRAY_SIZE(rs485_grps),
+};
+
+/* Pad multiplexing for Touchscreen device */
+static const unsigned touchscreen_pins[] = { 5, 36 };
+static struct spear_muxreg touchscreen_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_I2C_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg touchscreen_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_5_MASK,
+ .val = PMX_TOUCH_Y_PL_5_VAL,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_36_MASK,
+ .val = PMX_TOUCH_X_PL_36_VAL,
+ },
+};
+
+static struct spear_modemux touchscreen_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = touchscreen_muxreg,
+ .nmuxregs = ARRAY_SIZE(touchscreen_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = touchscreen_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(touchscreen_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup touchscreen_pingroup = {
+ .name = "touchscreen_grp",
+ .pins = touchscreen_pins,
+ .npins = ARRAY_SIZE(touchscreen_pins),
+ .modemuxs = touchscreen_modemux,
+ .nmodemuxs = ARRAY_SIZE(touchscreen_modemux),
+};
+
+static const char *const touchscreen_grps[] = { "touchscreen_grp" };
+static struct spear_function touchscreen_function = {
+ .name = "touchscreen",
+ .groups = touchscreen_grps,
+ .ngroups = ARRAY_SIZE(touchscreen_grps),
+};
+
+/* Pad multiplexing for CAN device */
+static const unsigned can0_pins[] = { 32, 33 };
+static struct spear_muxreg can0_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg can0_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_32_33_MASK,
+ .val = PMX_CAN0_PL_32_33_VAL,
+ },
+};
+
+static struct spear_modemux can0_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | EXTENDED_MODE,
+ .muxregs = can0_muxreg,
+ .nmuxregs = ARRAY_SIZE(can0_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = can0_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(can0_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup can0_pingroup = {
+ .name = "can0_grp",
+ .pins = can0_pins,
+ .npins = ARRAY_SIZE(can0_pins),
+ .modemuxs = can0_modemux,
+ .nmodemuxs = ARRAY_SIZE(can0_modemux),
+};
+
+static const char *const can0_grps[] = { "can0_grp" };
+static struct spear_function can0_function = {
+ .name = "can0",
+ .groups = can0_grps,
+ .ngroups = ARRAY_SIZE(can0_grps),
+};
+
+static const unsigned can1_pins[] = { 30, 31 };
+static struct spear_muxreg can1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg can1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_30_31_MASK,
+ .val = PMX_CAN1_PL_30_31_VAL,
+ },
+};
+
+static struct spear_modemux can1_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | EXTENDED_MODE,
+ .muxregs = can1_muxreg,
+ .nmuxregs = ARRAY_SIZE(can1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = can1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(can1_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup can1_pingroup = {
+ .name = "can1_grp",
+ .pins = can1_pins,
+ .npins = ARRAY_SIZE(can1_pins),
+ .modemuxs = can1_modemux,
+ .nmodemuxs = ARRAY_SIZE(can1_modemux),
+};
+
+static const char *const can1_grps[] = { "can1_grp" };
+static struct spear_function can1_function = {
+ .name = "can1",
+ .groups = can1_grps,
+ .ngroups = ARRAY_SIZE(can1_grps),
+};
+
+/* Pad multiplexing for PWM0_1 device */
+static const unsigned pwm0_1_pins[][2] = { { 37, 38 }, { 14, 15 }, { 8, 9 },
+ { 30, 31 }, { 42, 43 }, { 59, 60 }, { 88, 89 } };
+
+static struct spear_muxreg pwm0_1_pin_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_PWM_0_1_PL_8_9_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_autoexpsmallpri_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_14_15_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_14_MASK | PMX_PL_15_MASK,
+ .val = PMX_PWM1_PL_14_VAL | PMX_PWM0_PL_15_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_30_31_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_30_MASK | PMX_PL_31_MASK,
+ .val = PMX_PWM1_EXT_PL_30_VAL | PMX_PWM0_EXT_PL_31_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_net_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_37_38_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_37_38_MASK,
+ .val = PMX_PWM0_1_PL_37_38_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_42_43_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_0_1_MASK ,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_42_MASK | PMX_PL_43_MASK,
+ .val = PMX_PWM1_PL_42_VAL |
+ PMX_PWM0_PL_43_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_59_60_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_59_MASK,
+ .val = PMX_PWM1_PL_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_60_MASK,
+ .val = PMX_PWM0_PL_60_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_88_89_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_88_89_MASK,
+ .val = PMX_PWM0_1_PL_88_89_VAL,
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_8_9_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_8_9_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_14_15_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = pwm0_1_autoexpsmallpri_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_autoexpsmallpri_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_14_15_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_14_15_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_30_31_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_30_31_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_30_31_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_37_38_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = pwm0_1_net_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_net_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_37_38_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_37_38_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_42_43_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_42_43_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_42_43_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_59_60_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_59_60_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_59_60_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_88_89_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_88_89_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_88_89_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm0_1_pingroup[] = {
+ {
+ .name = "pwm0_1_pin_8_9_grp",
+ .pins = pwm0_1_pins[0],
+ .npins = ARRAY_SIZE(pwm0_1_pins[0]),
+ .modemuxs = pwm0_1_pin_8_9_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_8_9_modemux),
+ }, {
+ .name = "pwm0_1_pin_14_15_grp",
+ .pins = pwm0_1_pins[1],
+ .npins = ARRAY_SIZE(pwm0_1_pins[1]),
+ .modemuxs = pwm0_1_pin_14_15_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_14_15_modemux),
+ }, {
+ .name = "pwm0_1_pin_30_31_grp",
+ .pins = pwm0_1_pins[2],
+ .npins = ARRAY_SIZE(pwm0_1_pins[2]),
+ .modemuxs = pwm0_1_pin_30_31_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_30_31_modemux),
+ }, {
+ .name = "pwm0_1_pin_37_38_grp",
+ .pins = pwm0_1_pins[3],
+ .npins = ARRAY_SIZE(pwm0_1_pins[3]),
+ .modemuxs = pwm0_1_pin_37_38_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_37_38_modemux),
+ }, {
+ .name = "pwm0_1_pin_42_43_grp",
+ .pins = pwm0_1_pins[4],
+ .npins = ARRAY_SIZE(pwm0_1_pins[4]),
+ .modemuxs = pwm0_1_pin_42_43_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_42_43_modemux),
+ }, {
+ .name = "pwm0_1_pin_59_60_grp",
+ .pins = pwm0_1_pins[5],
+ .npins = ARRAY_SIZE(pwm0_1_pins[5]),
+ .modemuxs = pwm0_1_pin_59_60_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_59_60_modemux),
+ }, {
+ .name = "pwm0_1_pin_88_89_grp",
+ .pins = pwm0_1_pins[6],
+ .npins = ARRAY_SIZE(pwm0_1_pins[6]),
+ .modemuxs = pwm0_1_pin_88_89_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_88_89_modemux),
+ },
+};
+
+static const char *const pwm0_1_grps[] = { "pwm0_1_pin_8_9_grp",
+ "pwm0_1_pin_14_15_grp", "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp",
+ "pwm0_1_pin_42_43_grp", "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp"
+};
+
+static struct spear_function pwm0_1_function = {
+ .name = "pwm0_1",
+ .groups = pwm0_1_grps,
+ .ngroups = ARRAY_SIZE(pwm0_1_grps),
+};
+
+/* Pad multiplexing for PWM2 device */
+static const unsigned pwm2_pins[][1] = { { 7 }, { 13 }, { 29 }, { 34 }, { 41 },
+ { 58 }, { 87 } };
+static struct spear_muxreg pwm2_net_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_7_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_7_MASK,
+ .val = PMX_PWM_2_PL_7_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_autoexpsmallpri_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_13_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_MASK,
+ .val = PMX_PWM2_PL_13_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_29_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN1_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_29_MASK,
+ .val = PMX_PWM_2_PL_29_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_34_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK,
+ .val = PMX_PWM2_PL_34_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_41_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_41_MASK,
+ .val = PMX_PWM2_PL_41_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_58_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_58_MASK,
+ .val = PMX_PWM2_PL_58_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_87_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_87_MASK,
+ .val = PMX_PWM2_PL_87_VAL,
+ },
+};
+
+static struct spear_modemux pwm2_pin_7_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = pwm2_net_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_net_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_7_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_13_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = pwm2_autoexpsmallpri_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_autoexpsmallpri_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_13_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_13_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_29_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_29_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_29_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_34_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_34_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_34_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_41_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_41_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_41_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_58_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_58_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_58_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_87_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_87_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_87_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm2_pingroup[] = {
+ {
+ .name = "pwm2_pin_7_grp",
+ .pins = pwm2_pins[0],
+ .npins = ARRAY_SIZE(pwm2_pins[0]),
+ .modemuxs = pwm2_pin_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_7_modemux),
+ }, {
+ .name = "pwm2_pin_13_grp",
+ .pins = pwm2_pins[1],
+ .npins = ARRAY_SIZE(pwm2_pins[1]),
+ .modemuxs = pwm2_pin_13_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_13_modemux),
+ }, {
+ .name = "pwm2_pin_29_grp",
+ .pins = pwm2_pins[2],
+ .npins = ARRAY_SIZE(pwm2_pins[2]),
+ .modemuxs = pwm2_pin_29_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_29_modemux),
+ }, {
+ .name = "pwm2_pin_34_grp",
+ .pins = pwm2_pins[3],
+ .npins = ARRAY_SIZE(pwm2_pins[3]),
+ .modemuxs = pwm2_pin_34_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_34_modemux),
+ }, {
+ .name = "pwm2_pin_41_grp",
+ .pins = pwm2_pins[4],
+ .npins = ARRAY_SIZE(pwm2_pins[4]),
+ .modemuxs = pwm2_pin_41_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_41_modemux),
+ }, {
+ .name = "pwm2_pin_58_grp",
+ .pins = pwm2_pins[5],
+ .npins = ARRAY_SIZE(pwm2_pins[5]),
+ .modemuxs = pwm2_pin_58_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_58_modemux),
+ }, {
+ .name = "pwm2_pin_87_grp",
+ .pins = pwm2_pins[6],
+ .npins = ARRAY_SIZE(pwm2_pins[6]),
+ .modemuxs = pwm2_pin_87_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_87_modemux),
+ },
+};
+
+static const char *const pwm2_grps[] = { "pwm2_pin_7_grp", "pwm2_pin_13_grp",
+ "pwm2_pin_29_grp", "pwm2_pin_34_grp", "pwm2_pin_41_grp",
+ "pwm2_pin_58_grp", "pwm2_pin_87_grp" };
+static struct spear_function pwm2_function = {
+ .name = "pwm2",
+ .groups = pwm2_grps,
+ .ngroups = ARRAY_SIZE(pwm2_grps),
+};
+
+/* Pad multiplexing for PWM3 device */
+static const unsigned pwm3_pins[][1] = { { 6 }, { 12 }, { 28 }, { 40 }, { 57 },
+ { 86 } };
+static struct spear_muxreg pwm3_pin_6_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_6_MASK,
+ .val = PMX_PWM_3_PL_6_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_12_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_12_MASK,
+ .val = PMX_PWM3_PL_12_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_28_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_28_MASK,
+ .val = PMX_PWM_3_PL_28_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_40_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK,
+ .val = PMX_PWM3_PL_40_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_57_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_57_MASK,
+ .val = PMX_PWM3_PL_57_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_86_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_86_MASK,
+ .val = PMX_PWM3_PL_86_VAL,
+ },
+};
+
+static struct spear_modemux pwm3_pin_6_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_6_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_6_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_12_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE |
+ AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = pwm3_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_12_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_12_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_28_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_28_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_28_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_40_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_40_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_40_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_57_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_57_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_57_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_86_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_86_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_86_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm3_pingroup[] = {
+ {
+ .name = "pwm3_pin_6_grp",
+ .pins = pwm3_pins[0],
+ .npins = ARRAY_SIZE(pwm3_pins[0]),
+ .modemuxs = pwm3_pin_6_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_6_modemux),
+ }, {
+ .name = "pwm3_pin_12_grp",
+ .pins = pwm3_pins[1],
+ .npins = ARRAY_SIZE(pwm3_pins[1]),
+ .modemuxs = pwm3_pin_12_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_12_modemux),
+ }, {
+ .name = "pwm3_pin_28_grp",
+ .pins = pwm3_pins[2],
+ .npins = ARRAY_SIZE(pwm3_pins[2]),
+ .modemuxs = pwm3_pin_28_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_28_modemux),
+ }, {
+ .name = "pwm3_pin_40_grp",
+ .pins = pwm3_pins[3],
+ .npins = ARRAY_SIZE(pwm3_pins[3]),
+ .modemuxs = pwm3_pin_40_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_40_modemux),
+ }, {
+ .name = "pwm3_pin_57_grp",
+ .pins = pwm3_pins[4],
+ .npins = ARRAY_SIZE(pwm3_pins[4]),
+ .modemuxs = pwm3_pin_57_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_57_modemux),
+ }, {
+ .name = "pwm3_pin_86_grp",
+ .pins = pwm3_pins[5],
+ .npins = ARRAY_SIZE(pwm3_pins[5]),
+ .modemuxs = pwm3_pin_86_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_86_modemux),
+ },
+};
+
+static const char *const pwm3_grps[] = { "pwm3_pin_6_grp", "pwm3_pin_12_grp",
+ "pwm3_pin_28_grp", "pwm3_pin_40_grp", "pwm3_pin_57_grp",
+ "pwm3_pin_86_grp" };
+static struct spear_function pwm3_function = {
+ .name = "pwm3",
+ .groups = pwm3_grps,
+ .ngroups = ARRAY_SIZE(pwm3_grps),
+};
+
+/* Pad multiplexing for SSP1 device */
+static const unsigned ssp1_pins[][2] = { { 17, 20 }, { 36, 39 }, { 48, 51 },
+ { 65, 68 }, { 94, 97 } };
+static struct spear_muxreg ssp1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_17_20_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+ .val = PMX_SSP1_PL_17_18_19_20_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK,
+ .val = PMX_SSP1_PL_17_18_19_20_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_17_TO_20_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_36_39_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_36_MASK | PMX_PL_37_38_MASK | PMX_PL_39_MASK,
+ .val = PMX_SSP1_PL_36_VAL | PMX_SSP1_PL_37_38_VAL |
+ PMX_SSP1_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_36_TO_39_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_48_51_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_48_49_MASK,
+ .val = PMX_SSP1_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_51_MASK,
+ .val = PMX_SSP1_PL_50_51_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_48_TO_51_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_65_68_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_65_TO_68_MASK,
+ .val = PMX_SSP1_PL_65_TO_68_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_65_TO_68_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_94_97_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_SSP1_PL_94_95_VAL | PMX_SSP1_PL_96_97_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_94_TO_97_VAL,
+ },
+};
+
+static struct spear_modemux ssp1_17_20_modemux[] = {
+ {
+ .modes = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE |
+ EXTENDED_MODE,
+ .muxregs = ssp1_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_17_20_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_17_20_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_36_39_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_36_39_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_36_39_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_48_51_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_48_51_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_48_51_muxreg),
+ },
+};
+static struct spear_modemux ssp1_65_68_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_65_68_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_65_68_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_94_97_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_94_97_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_94_97_muxreg),
+ },
+};
+
+static struct spear_pingroup ssp1_pingroup[] = {
+ {
+ .name = "ssp1_17_20_grp",
+ .pins = ssp1_pins[0],
+ .npins = ARRAY_SIZE(ssp1_pins[0]),
+ .modemuxs = ssp1_17_20_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_17_20_modemux),
+ }, {
+ .name = "ssp1_36_39_grp",
+ .pins = ssp1_pins[1],
+ .npins = ARRAY_SIZE(ssp1_pins[1]),
+ .modemuxs = ssp1_36_39_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_36_39_modemux),
+ }, {
+ .name = "ssp1_48_51_grp",
+ .pins = ssp1_pins[2],
+ .npins = ARRAY_SIZE(ssp1_pins[2]),
+ .modemuxs = ssp1_48_51_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_48_51_modemux),
+ }, {
+ .name = "ssp1_65_68_grp",
+ .pins = ssp1_pins[3],
+ .npins = ARRAY_SIZE(ssp1_pins[3]),
+ .modemuxs = ssp1_65_68_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_65_68_modemux),
+ }, {
+ .name = "ssp1_94_97_grp",
+ .pins = ssp1_pins[4],
+ .npins = ARRAY_SIZE(ssp1_pins[4]),
+ .modemuxs = ssp1_94_97_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_94_97_modemux),
+ },
+};
+
+static const char *const ssp1_grps[] = { "ssp1_17_20_grp", "ssp1_36_39_grp",
+ "ssp1_48_51_grp", "ssp1_65_68_grp", "ssp1_94_97_grp"
+};
+static struct spear_function ssp1_function = {
+ .name = "ssp1",
+ .groups = ssp1_grps,
+ .ngroups = ARRAY_SIZE(ssp1_grps),
+};
+
+/* Pad multiplexing for SSP2 device */
+static const unsigned ssp2_pins[][2] = { { 13, 16 }, { 32, 35 }, { 44, 47 },
+ { 61, 64 }, { 90, 93 } };
+static struct spear_muxreg ssp2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_13_16_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_14_MASK | PMX_PL_15_16_MASK,
+ .val = PMX_SSP2_PL_13_14_15_16_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_13_TO_16_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_32_35_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK | PMX_GPIO_PIN4_MASK |
+ PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_32_33_MASK | PMX_PL_34_MASK | PMX_PL_35_MASK,
+ .val = PMX_SSP2_PL_32_33_VAL | PMX_SSP2_PL_34_VAL |
+ PMX_SSP2_PL_35_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_32_TO_35_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_44_47_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_44_45_MASK | PMX_PL_46_47_MASK,
+ .val = PMX_SSP2_PL_44_45_VAL | PMX_SSP2_PL_46_47_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_44_TO_47_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_61_64_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_61_TO_64_MASK,
+ .val = PMX_SSP2_PL_61_TO_64_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_61_TO_64_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_90_93_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK,
+ .val = PMX_SSP2_PL_90_91_VAL | PMX_SSP2_PL_92_93_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_90_TO_93_VAL,
+ },
+};
+
+static struct spear_modemux ssp2_13_16_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = ssp2_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_13_16_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_13_16_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_32_35_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_32_35_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_32_35_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_44_47_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_44_47_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_44_47_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_61_64_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_61_64_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_61_64_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_90_93_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_90_93_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_90_93_muxreg),
+ },
+};
+
+static struct spear_pingroup ssp2_pingroup[] = {
+ {
+ .name = "ssp2_13_16_grp",
+ .pins = ssp2_pins[0],
+ .npins = ARRAY_SIZE(ssp2_pins[0]),
+ .modemuxs = ssp2_13_16_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_13_16_modemux),
+ }, {
+ .name = "ssp2_32_35_grp",
+ .pins = ssp2_pins[1],
+ .npins = ARRAY_SIZE(ssp2_pins[1]),
+ .modemuxs = ssp2_32_35_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_32_35_modemux),
+ }, {
+ .name = "ssp2_44_47_grp",
+ .pins = ssp2_pins[2],
+ .npins = ARRAY_SIZE(ssp2_pins[2]),
+ .modemuxs = ssp2_44_47_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_44_47_modemux),
+ }, {
+ .name = "ssp2_61_64_grp",
+ .pins = ssp2_pins[3],
+ .npins = ARRAY_SIZE(ssp2_pins[3]),
+ .modemuxs = ssp2_61_64_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_61_64_modemux),
+ }, {
+ .name = "ssp2_90_93_grp",
+ .pins = ssp2_pins[4],
+ .npins = ARRAY_SIZE(ssp2_pins[4]),
+ .modemuxs = ssp2_90_93_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_90_93_modemux),
+ },
+};
+
+static const char *const ssp2_grps[] = { "ssp2_13_16_grp", "ssp2_32_35_grp",
+ "ssp2_44_47_grp", "ssp2_61_64_grp", "ssp2_90_93_grp" };
+static struct spear_function ssp2_function = {
+ .name = "ssp2",
+ .groups = ssp2_grps,
+ .ngroups = ARRAY_SIZE(ssp2_grps),
+};
+
+/* Pad multiplexing for cadence mii2 as mii device */
+static const unsigned mii2_pins[] = { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97 };
+static struct spear_muxreg mii2_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_MII2_PL_80_TO_85_VAL | PMX_MII2_PL_86_87_VAL |
+ PMX_MII2_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_MII2_PL_90_91_VAL | PMX_MII2_PL_92_93_VAL |
+ PMX_MII2_PL_94_95_VAL | PMX_MII2_PL_96_97_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_MII << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MII << MAC1_MODE_SHIFT) |
+ MII_MDIO_81_VAL,
+ },
+};
+
+static struct spear_modemux mii2_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = mii2_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii2_muxreg),
+ },
+};
+
+static struct spear_pingroup mii2_pingroup = {
+ .name = "mii2_grp",
+ .pins = mii2_pins,
+ .npins = ARRAY_SIZE(mii2_pins),
+ .modemuxs = mii2_modemux,
+ .nmodemuxs = ARRAY_SIZE(mii2_modemux),
+};
+
+static const char *const mii2_grps[] = { "mii2_grp" };
+static struct spear_function mii2_function = {
+ .name = "mii2",
+ .groups = mii2_grps,
+ .ngroups = ARRAY_SIZE(mii2_grps),
+};
+
+/* Pad multiplexing for cadence mii 1_2 as smii or rmii device */
+static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27 };
+static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii0_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg smii0_1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_10_11_MASK,
+ .val = PMX_SMII_PL_10_11_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_21_TO_27_MASK,
+ .val = PMX_SMII_PL_21_TO_27_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_SMII << MAC2_MODE_SHIFT)
+ | (MAC_MODE_SMII << MAC1_MODE_SHIFT)
+ | MII_MDIO_10_11_VAL,
+ },
+};
+
+static struct spear_muxreg rmii0_1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_10_11_MASK | PMX_PL_13_14_MASK |
+ PMX_PL_15_16_MASK | PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+ .val = PMX_RMII_PL_10_11_VAL | PMX_RMII_PL_13_14_VAL |
+ PMX_RMII_PL_15_16_VAL | PMX_RMII_PL_17_18_VAL |
+ PMX_RMII_PL_19_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK | PMX_PL_21_TO_27_MASK,
+ .val = PMX_RMII_PL_20_VAL | PMX_RMII_PL_21_TO_27_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_RMII << MAC2_MODE_SHIFT)
+ | (MAC_MODE_RMII << MAC1_MODE_SHIFT)
+ | MII_MDIO_10_11_VAL,
+ },
+};
+
+static struct spear_modemux mii0_1_modemux[][2] = {
+ {
+ /* configure as smii */
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+ SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = mii0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = smii0_1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(smii0_1_ext_muxreg),
+ },
+ }, {
+ /* configure as rmii */
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+ SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = mii0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = rmii0_1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(rmii0_1_ext_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup mii0_1_pingroup[] = {
+ {
+ .name = "smii0_1_grp",
+ .pins = smii0_1_pins,
+ .npins = ARRAY_SIZE(smii0_1_pins),
+ .modemuxs = mii0_1_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[0]),
+ }, {
+ .name = "rmii0_1_grp",
+ .pins = rmii0_1_pins,
+ .npins = ARRAY_SIZE(rmii0_1_pins),
+ .modemuxs = mii0_1_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[1]),
+ },
+};
+
+static const char *const mii0_1_grps[] = { "smii0_1_grp", "rmii0_1_grp" };
+static struct spear_function mii0_1_function = {
+ .name = "mii0_1",
+ .groups = mii0_1_grps,
+ .ngroups = ARRAY_SIZE(mii0_1_grps),
+};
+
+/* Pad multiplexing for i2c1 device */
+static const unsigned i2c1_pins[][2] = { { 8, 9 }, { 98, 99 } };
+static struct spear_muxreg i2c1_ext_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_I2C1_PL_8_9_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C1_PORT_SEL_MASK,
+ .val = PMX_I2C1_PORT_8_9_VAL,
+ },
+};
+
+static struct spear_muxreg i2c1_ext_98_99_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+ .val = PMX_I2C1_PL_98_VAL | PMX_I2C1_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C1_PORT_SEL_MASK,
+ .val = PMX_I2C1_PORT_98_99_VAL,
+ },
+};
+
+static struct spear_modemux i2c1_modemux[][1] = {
+ {
+ /* Select signals on pins 8-9 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c1_ext_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c1_ext_8_9_muxreg),
+ },
+ }, {
+ /* Select signals on pins 98-99 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c1_ext_98_99_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c1_ext_98_99_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup i2c1_pingroup[] = {
+ {
+ .name = "i2c1_8_9_grp",
+ .pins = i2c1_pins[0],
+ .npins = ARRAY_SIZE(i2c1_pins[0]),
+ .modemuxs = i2c1_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(i2c1_modemux[0]),
+ }, {
+ .name = "i2c1_98_99_grp",
+ .pins = i2c1_pins[1],
+ .npins = ARRAY_SIZE(i2c1_pins[1]),
+ .modemuxs = i2c1_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(i2c1_modemux[1]),
+ },
+};
+
+static const char *const i2c1_grps[] = { "i2c1_8_9_grp", "i2c1_98_99_grp" };
+static struct spear_function i2c1_function = {
+ .name = "i2c1",
+ .groups = i2c1_grps,
+ .ngroups = ARRAY_SIZE(i2c1_grps),
+};
+
+/* Pad multiplexing for i2c2 device */
+static const unsigned i2c2_pins[][2] = { { 0, 1 }, { 2, 3 }, { 19, 20 },
+ { 75, 76 }, { 96, 97 } };
+static struct spear_muxreg i2c2_ext_0_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_0_1_MASK,
+ .val = PMX_I2C2_PL_0_1_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_0_1_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_2_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK,
+ .val = PMX_I2C2_PL_2_3_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_2_3_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_19_20_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_19_MASK,
+ .val = PMX_I2C2_PL_19_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK,
+ .val = PMX_I2C2_PL_20_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_19_20_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_75_76_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_75_76_MASK,
+ .val = PMX_I2C2_PL_75_76_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_75_76_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_96_97_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_96_97_MASK,
+ .val = PMX_I2C2_PL_96_97_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_96_97_VAL,
+ },
+};
+
+static struct spear_modemux i2c2_modemux[][1] = {
+ {
+ /* Select signals on pins 0_1 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_0_1_muxreg),
+ },
+ }, {
+ /* Select signals on pins 2_3 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_2_3_muxreg),
+ },
+ }, {
+ /* Select signals on pins 19_20 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_19_20_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_19_20_muxreg),
+ },
+ }, {
+ /* Select signals on pins 75_76 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_75_76_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_75_76_muxreg),
+ },
+ }, {
+ /* Select signals on pins 96_97 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_96_97_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_96_97_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup i2c2_pingroup[] = {
+ {
+ .name = "i2c2_0_1_grp",
+ .pins = i2c2_pins[0],
+ .npins = ARRAY_SIZE(i2c2_pins[0]),
+ .modemuxs = i2c2_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[0]),
+ }, {
+ .name = "i2c2_2_3_grp",
+ .pins = i2c2_pins[1],
+ .npins = ARRAY_SIZE(i2c2_pins[1]),
+ .modemuxs = i2c2_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[1]),
+ }, {
+ .name = "i2c2_19_20_grp",
+ .pins = i2c2_pins[2],
+ .npins = ARRAY_SIZE(i2c2_pins[2]),
+ .modemuxs = i2c2_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[2]),
+ }, {
+ .name = "i2c2_75_76_grp",
+ .pins = i2c2_pins[3],
+ .npins = ARRAY_SIZE(i2c2_pins[3]),
+ .modemuxs = i2c2_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[3]),
+ }, {
+ .name = "i2c2_96_97_grp",
+ .pins = i2c2_pins[4],
+ .npins = ARRAY_SIZE(i2c2_pins[4]),
+ .modemuxs = i2c2_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[4]),
+ },
+};
+
+static const char *const i2c2_grps[] = { "i2c2_0_1_grp", "i2c2_2_3_grp",
+ "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" };
+static struct spear_function i2c2_function = {
+ .name = "i2c2",
+ .groups = i2c2_grps,
+ .ngroups = ARRAY_SIZE(i2c2_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear320_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &clcd_pingroup,
+ &emi_pingroup,
+ &fsmc_8bit_pingroup,
+ &fsmc_16bit_pingroup,
+ &spp_pingroup,
+ &sdhci_led_pingroup,
+ &sdhci_pingroup[0],
+ &sdhci_pingroup[1],
+ &i2s_pingroup,
+ &uart1_pingroup,
+ &uart1_modem_pingroup[0],
+ &uart1_modem_pingroup[1],
+ &uart1_modem_pingroup[2],
+ &uart1_modem_pingroup[3],
+ &uart2_pingroup,
+ &uart3_pingroup[0],
+ &uart3_pingroup[1],
+ &uart3_pingroup[2],
+ &uart3_pingroup[3],
+ &uart3_pingroup[4],
+ &uart3_pingroup[5],
+ &uart3_pingroup[6],
+ &uart4_pingroup[0],
+ &uart4_pingroup[1],
+ &uart4_pingroup[2],
+ &uart4_pingroup[3],
+ &uart4_pingroup[4],
+ &uart4_pingroup[5],
+ &uart5_pingroup[0],
+ &uart5_pingroup[1],
+ &uart5_pingroup[2],
+ &uart5_pingroup[3],
+ &uart6_pingroup[0],
+ &uart6_pingroup[1],
+ &rs485_pingroup,
+ &touchscreen_pingroup,
+ &can0_pingroup,
+ &can1_pingroup,
+ &pwm0_1_pingroup[0],
+ &pwm0_1_pingroup[1],
+ &pwm0_1_pingroup[2],
+ &pwm0_1_pingroup[3],
+ &pwm0_1_pingroup[4],
+ &pwm0_1_pingroup[5],
+ &pwm0_1_pingroup[6],
+ &pwm2_pingroup[0],
+ &pwm2_pingroup[1],
+ &pwm2_pingroup[2],
+ &pwm2_pingroup[3],
+ &pwm2_pingroup[4],
+ &pwm2_pingroup[5],
+ &pwm2_pingroup[6],
+ &pwm3_pingroup[0],
+ &pwm3_pingroup[1],
+ &pwm3_pingroup[2],
+ &pwm3_pingroup[3],
+ &pwm3_pingroup[4],
+ &pwm3_pingroup[5],
+ &ssp1_pingroup[0],
+ &ssp1_pingroup[1],
+ &ssp1_pingroup[2],
+ &ssp1_pingroup[3],
+ &ssp1_pingroup[4],
+ &ssp2_pingroup[0],
+ &ssp2_pingroup[1],
+ &ssp2_pingroup[2],
+ &ssp2_pingroup[3],
+ &ssp2_pingroup[4],
+ &mii2_pingroup,
+ &mii0_1_pingroup[0],
+ &mii0_1_pingroup[1],
+ &i2c1_pingroup[0],
+ &i2c1_pingroup[1],
+ &i2c2_pingroup[0],
+ &i2c2_pingroup[1],
+ &i2c2_pingroup[2],
+ &i2c2_pingroup[3],
+ &i2c2_pingroup[4],
+};
+
+/* functions */
+static struct spear_function *spear320_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &clcd_function,
+ &emi_function,
+ &fsmc_function,
+ &spp_function,
+ &sdhci_function,
+ &i2s_function,
+ &uart1_function,
+ &uart1_modem_function,
+ &uart2_function,
+ &uart3_function,
+ &uart4_function,
+ &uart5_function,
+ &uart6_function,
+ &rs485_function,
+ &touchscreen_function,
+ &can0_function,
+ &can1_function,
+ &pwm0_1_function,
+ &pwm2_function,
+ &pwm3_function,
+ &ssp1_function,
+ &ssp2_function,
+ &mii2_function,
+ &mii0_1_function,
+ &i2c1_function,
+ &i2c2_function,
+};
+
+static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear320-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear320_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear320_pingroups);
+ spear3xx_machdata.functions = spear320_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear320_functions);
+
+ spear3xx_machdata.modes_supported = true;
+ spear3xx_machdata.pmx_modes = spear320_pmx_modes;
+ spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear320_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear320_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear320_pinctrl_of_match,
+ },
+ .probe = spear320_pinctrl_probe,
+ .remove = __devexit_p(spear320_pinctrl_remove),
+};
+
+static int __init spear320_pinctrl_init(void)
+{
+ return platform_driver_register(&spear320_pinctrl_driver);
+}
+arch_initcall(spear320_pinctrl_init);
+
+static void __exit spear320_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear320_pinctrl_driver);
+}
+module_exit(spear320_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
new file mode 100644
index 0000000..832049a
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -0,0 +1,588 @@
+/*
+ * Driver for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-spear3xx.h"
+
+/* pins */
+static const struct pinctrl_pin_desc spear3xx_pins[] = {
+ PINCTRL_PIN(0, "PLGPIO0"),
+ PINCTRL_PIN(1, "PLGPIO1"),
+ PINCTRL_PIN(2, "PLGPIO2"),
+ PINCTRL_PIN(3, "PLGPIO3"),
+ PINCTRL_PIN(4, "PLGPIO4"),
+ PINCTRL_PIN(5, "PLGPIO5"),
+ PINCTRL_PIN(6, "PLGPIO6"),
+ PINCTRL_PIN(7, "PLGPIO7"),
+ PINCTRL_PIN(8, "PLGPIO8"),
+ PINCTRL_PIN(9, "PLGPIO9"),
+ PINCTRL_PIN(10, "PLGPIO10"),
+ PINCTRL_PIN(11, "PLGPIO11"),
+ PINCTRL_PIN(12, "PLGPIO12"),
+ PINCTRL_PIN(13, "PLGPIO13"),
+ PINCTRL_PIN(14, "PLGPIO14"),
+ PINCTRL_PIN(15, "PLGPIO15"),
+ PINCTRL_PIN(16, "PLGPIO16"),
+ PINCTRL_PIN(17, "PLGPIO17"),
+ PINCTRL_PIN(18, "PLGPIO18"),
+ PINCTRL_PIN(19, "PLGPIO19"),
+ PINCTRL_PIN(20, "PLGPIO20"),
+ PINCTRL_PIN(21, "PLGPIO21"),
+ PINCTRL_PIN(22, "PLGPIO22"),
+ PINCTRL_PIN(23, "PLGPIO23"),
+ PINCTRL_PIN(24, "PLGPIO24"),
+ PINCTRL_PIN(25, "PLGPIO25"),
+ PINCTRL_PIN(26, "PLGPIO26"),
+ PINCTRL_PIN(27, "PLGPIO27"),
+ PINCTRL_PIN(28, "PLGPIO28"),
+ PINCTRL_PIN(29, "PLGPIO29"),
+ PINCTRL_PIN(30, "PLGPIO30"),
+ PINCTRL_PIN(31, "PLGPIO31"),
+ PINCTRL_PIN(32, "PLGPIO32"),
+ PINCTRL_PIN(33, "PLGPIO33"),
+ PINCTRL_PIN(34, "PLGPIO34"),
+ PINCTRL_PIN(35, "PLGPIO35"),
+ PINCTRL_PIN(36, "PLGPIO36"),
+ PINCTRL_PIN(37, "PLGPIO37"),
+ PINCTRL_PIN(38, "PLGPIO38"),
+ PINCTRL_PIN(39, "PLGPIO39"),
+ PINCTRL_PIN(40, "PLGPIO40"),
+ PINCTRL_PIN(41, "PLGPIO41"),
+ PINCTRL_PIN(42, "PLGPIO42"),
+ PINCTRL_PIN(43, "PLGPIO43"),
+ PINCTRL_PIN(44, "PLGPIO44"),
+ PINCTRL_PIN(45, "PLGPIO45"),
+ PINCTRL_PIN(46, "PLGPIO46"),
+ PINCTRL_PIN(47, "PLGPIO47"),
+ PINCTRL_PIN(48, "PLGPIO48"),
+ PINCTRL_PIN(49, "PLGPIO49"),
+ PINCTRL_PIN(50, "PLGPIO50"),
+ PINCTRL_PIN(51, "PLGPIO51"),
+ PINCTRL_PIN(52, "PLGPIO52"),
+ PINCTRL_PIN(53, "PLGPIO53"),
+ PINCTRL_PIN(54, "PLGPIO54"),
+ PINCTRL_PIN(55, "PLGPIO55"),
+ PINCTRL_PIN(56, "PLGPIO56"),
+ PINCTRL_PIN(57, "PLGPIO57"),
+ PINCTRL_PIN(58, "PLGPIO58"),
+ PINCTRL_PIN(59, "PLGPIO59"),
+ PINCTRL_PIN(60, "PLGPIO60"),
+ PINCTRL_PIN(61, "PLGPIO61"),
+ PINCTRL_PIN(62, "PLGPIO62"),
+ PINCTRL_PIN(63, "PLGPIO63"),
+ PINCTRL_PIN(64, "PLGPIO64"),
+ PINCTRL_PIN(65, "PLGPIO65"),
+ PINCTRL_PIN(66, "PLGPIO66"),
+ PINCTRL_PIN(67, "PLGPIO67"),
+ PINCTRL_PIN(68, "PLGPIO68"),
+ PINCTRL_PIN(69, "PLGPIO69"),
+ PINCTRL_PIN(70, "PLGPIO70"),
+ PINCTRL_PIN(71, "PLGPIO71"),
+ PINCTRL_PIN(72, "PLGPIO72"),
+ PINCTRL_PIN(73, "PLGPIO73"),
+ PINCTRL_PIN(74, "PLGPIO74"),
+ PINCTRL_PIN(75, "PLGPIO75"),
+ PINCTRL_PIN(76, "PLGPIO76"),
+ PINCTRL_PIN(77, "PLGPIO77"),
+ PINCTRL_PIN(78, "PLGPIO78"),
+ PINCTRL_PIN(79, "PLGPIO79"),
+ PINCTRL_PIN(80, "PLGPIO80"),
+ PINCTRL_PIN(81, "PLGPIO81"),
+ PINCTRL_PIN(82, "PLGPIO82"),
+ PINCTRL_PIN(83, "PLGPIO83"),
+ PINCTRL_PIN(84, "PLGPIO84"),
+ PINCTRL_PIN(85, "PLGPIO85"),
+ PINCTRL_PIN(86, "PLGPIO86"),
+ PINCTRL_PIN(87, "PLGPIO87"),
+ PINCTRL_PIN(88, "PLGPIO88"),
+ PINCTRL_PIN(89, "PLGPIO89"),
+ PINCTRL_PIN(90, "PLGPIO90"),
+ PINCTRL_PIN(91, "PLGPIO91"),
+ PINCTRL_PIN(92, "PLGPIO92"),
+ PINCTRL_PIN(93, "PLGPIO93"),
+ PINCTRL_PIN(94, "PLGPIO94"),
+ PINCTRL_PIN(95, "PLGPIO95"),
+ PINCTRL_PIN(96, "PLGPIO96"),
+ PINCTRL_PIN(97, "PLGPIO97"),
+ PINCTRL_PIN(98, "PLGPIO98"),
+ PINCTRL_PIN(99, "PLGPIO99"),
+ PINCTRL_PIN(100, "PLGPIO100"),
+ PINCTRL_PIN(101, "PLGPIO101"),
+};
+
+/* firda_pins */
+static const unsigned firda_pins[] = { 0, 1 };
+static struct spear_muxreg firda_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_FIRDA_MASK,
+ .val = PMX_FIRDA_MASK,
+ },
+};
+
+static struct spear_modemux firda_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = firda_muxreg,
+ .nmuxregs = ARRAY_SIZE(firda_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_firda_pingroup = {
+ .name = "firda_grp",
+ .pins = firda_pins,
+ .npins = ARRAY_SIZE(firda_pins),
+ .modemuxs = firda_modemux,
+ .nmodemuxs = ARRAY_SIZE(firda_modemux),
+};
+
+static const char *const firda_grps[] = { "firda_grp" };
+struct spear_function spear3xx_firda_function = {
+ .name = "firda",
+ .groups = firda_grps,
+ .ngroups = ARRAY_SIZE(firda_grps),
+};
+
+/* i2c_pins */
+static const unsigned i2c_pins[] = { 4, 5 };
+static struct spear_muxreg i2c_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_I2C_MASK,
+ .val = PMX_I2C_MASK,
+ },
+};
+
+static struct spear_modemux i2c_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = i2c_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_i2c_pingroup = {
+ .name = "i2c0_grp",
+ .pins = i2c_pins,
+ .npins = ARRAY_SIZE(i2c_pins),
+ .modemuxs = i2c_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2c_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c0_grp" };
+struct spear_function spear3xx_i2c_function = {
+ .name = "i2c0",
+ .groups = i2c_grps,
+ .ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* ssp_cs_pins */
+static const unsigned ssp_cs_pins[] = { 34, 35, 36 };
+static struct spear_muxreg ssp_cs_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_SSP_CS_MASK,
+ .val = PMX_SSP_CS_MASK,
+ },
+};
+
+static struct spear_modemux ssp_cs_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = ssp_cs_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp_cs_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_ssp_cs_pingroup = {
+ .name = "ssp_cs_grp",
+ .pins = ssp_cs_pins,
+ .npins = ARRAY_SIZE(ssp_cs_pins),
+ .modemuxs = ssp_cs_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp_cs_modemux),
+};
+
+static const char *const ssp_cs_grps[] = { "ssp_cs_grp" };
+struct spear_function spear3xx_ssp_cs_function = {
+ .name = "ssp_cs",
+ .groups = ssp_cs_grps,
+ .ngroups = ARRAY_SIZE(ssp_cs_grps),
+};
+
+/* ssp_pins */
+static const unsigned ssp_pins[] = { 6, 7, 8, 9 };
+static struct spear_muxreg ssp_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_SSP_MASK,
+ .val = PMX_SSP_MASK,
+ },
+};
+
+static struct spear_modemux ssp_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = ssp_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_ssp_pingroup = {
+ .name = "ssp0_grp",
+ .pins = ssp_pins,
+ .npins = ARRAY_SIZE(ssp_pins),
+ .modemuxs = ssp_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp_modemux),
+};
+
+static const char *const ssp_grps[] = { "ssp0_grp" };
+struct spear_function spear3xx_ssp_function = {
+ .name = "ssp0",
+ .groups = ssp_grps,
+ .ngroups = ARRAY_SIZE(ssp_grps),
+};
+
+/* mii_pins */
+static const unsigned mii_pins[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_MII_MASK,
+ .val = PMX_MII_MASK,
+ },
+};
+
+static struct spear_modemux mii_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = mii_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_mii_pingroup = {
+ .name = "mii0_grp",
+ .pins = mii_pins,
+ .npins = ARRAY_SIZE(mii_pins),
+ .modemuxs = mii_modemux,
+ .nmodemuxs = ARRAY_SIZE(mii_modemux),
+};
+
+static const char *const mii_grps[] = { "mii0_grp" };
+struct spear_function spear3xx_mii_function = {
+ .name = "mii0",
+ .groups = mii_grps,
+ .ngroups = ARRAY_SIZE(mii_grps),
+};
+
+/* gpio0_pin0_pins */
+static const unsigned gpio0_pin0_pins[] = { 28 };
+static struct spear_muxreg gpio0_pin0_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN0_MASK,
+ .val = PMX_GPIO_PIN0_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin0_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin0_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin0_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin0_pingroup = {
+ .name = "gpio0_pin0_grp",
+ .pins = gpio0_pin0_pins,
+ .npins = ARRAY_SIZE(gpio0_pin0_pins),
+ .modemuxs = gpio0_pin0_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin0_modemux),
+};
+
+/* gpio0_pin1_pins */
+static const unsigned gpio0_pin1_pins[] = { 29 };
+static struct spear_muxreg gpio0_pin1_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN1_MASK,
+ .val = PMX_GPIO_PIN1_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin1_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin1_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin1_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin1_pingroup = {
+ .name = "gpio0_pin1_grp",
+ .pins = gpio0_pin1_pins,
+ .npins = ARRAY_SIZE(gpio0_pin1_pins),
+ .modemuxs = gpio0_pin1_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin1_modemux),
+};
+
+/* gpio0_pin2_pins */
+static const unsigned gpio0_pin2_pins[] = { 30 };
+static struct spear_muxreg gpio0_pin2_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN2_MASK,
+ .val = PMX_GPIO_PIN2_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin2_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin2_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin2_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin2_pingroup = {
+ .name = "gpio0_pin2_grp",
+ .pins = gpio0_pin2_pins,
+ .npins = ARRAY_SIZE(gpio0_pin2_pins),
+ .modemuxs = gpio0_pin2_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin2_modemux),
+};
+
+/* gpio0_pin3_pins */
+static const unsigned gpio0_pin3_pins[] = { 31 };
+static struct spear_muxreg gpio0_pin3_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN3_MASK,
+ .val = PMX_GPIO_PIN3_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin3_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin3_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin3_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin3_pingroup = {
+ .name = "gpio0_pin3_grp",
+ .pins = gpio0_pin3_pins,
+ .npins = ARRAY_SIZE(gpio0_pin3_pins),
+ .modemuxs = gpio0_pin3_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin3_modemux),
+};
+
+/* gpio0_pin4_pins */
+static const unsigned gpio0_pin4_pins[] = { 32 };
+static struct spear_muxreg gpio0_pin4_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN4_MASK,
+ .val = PMX_GPIO_PIN4_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin4_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin4_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin4_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin4_pingroup = {
+ .name = "gpio0_pin4_grp",
+ .pins = gpio0_pin4_pins,
+ .npins = ARRAY_SIZE(gpio0_pin4_pins),
+ .modemuxs = gpio0_pin4_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin4_modemux),
+};
+
+/* gpio0_pin5_pins */
+static const unsigned gpio0_pin5_pins[] = { 33 };
+static struct spear_muxreg gpio0_pin5_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN5_MASK,
+ .val = PMX_GPIO_PIN5_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin5_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin5_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin5_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin5_pingroup = {
+ .name = "gpio0_pin5_grp",
+ .pins = gpio0_pin5_pins,
+ .npins = ARRAY_SIZE(gpio0_pin5_pins),
+ .modemuxs = gpio0_pin5_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin5_modemux),
+};
+
+static const char *const gpio0_grps[] = { "gpio0_pin0_grp", "gpio0_pin1_grp",
+ "gpio0_pin2_grp", "gpio0_pin3_grp", "gpio0_pin4_grp", "gpio0_pin5_grp",
+};
+struct spear_function spear3xx_gpio0_function = {
+ .name = "gpio0",
+ .groups = gpio0_grps,
+ .ngroups = ARRAY_SIZE(gpio0_grps),
+};
+
+/* uart0_ext_pins */
+static const unsigned uart0_ext_pins[] = { 37, 38, 39, 40, 41, 42 };
+static struct spear_muxreg uart0_ext_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = PMX_UART0_MODEM_MASK,
+ },
+};
+
+static struct spear_modemux uart0_ext_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = uart0_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart0_ext_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_uart0_ext_pingroup = {
+ .name = "uart0_ext_grp",
+ .pins = uart0_ext_pins,
+ .npins = ARRAY_SIZE(uart0_ext_pins),
+ .modemuxs = uart0_ext_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart0_ext_modemux),
+};
+
+static const char *const uart0_ext_grps[] = { "uart0_ext_grp" };
+struct spear_function spear3xx_uart0_ext_function = {
+ .name = "uart0_ext",
+ .groups = uart0_ext_grps,
+ .ngroups = ARRAY_SIZE(uart0_ext_grps),
+};
+
+/* uart0_pins */
+static const unsigned uart0_pins[] = { 2, 3 };
+static struct spear_muxreg uart0_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_UART0_MASK,
+ .val = PMX_UART0_MASK,
+ },
+};
+
+static struct spear_modemux uart0_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = uart0_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart0_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_uart0_pingroup = {
+ .name = "uart0_grp",
+ .pins = uart0_pins,
+ .npins = ARRAY_SIZE(uart0_pins),
+ .modemuxs = uart0_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart0_modemux),
+};
+
+static const char *const uart0_grps[] = { "uart0_grp" };
+struct spear_function spear3xx_uart0_function = {
+ .name = "uart0",
+ .groups = uart0_grps,
+ .ngroups = ARRAY_SIZE(uart0_grps),
+};
+
+/* timer_0_1_pins */
+static const unsigned timer_0_1_pins[] = { 43, 44, 47, 48 };
+static struct spear_muxreg timer_0_1_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = PMX_TIMER_0_1_MASK,
+ },
+};
+
+static struct spear_modemux timer_0_1_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = timer_0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(timer_0_1_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_timer_0_1_pingroup = {
+ .name = "timer_0_1_grp",
+ .pins = timer_0_1_pins,
+ .npins = ARRAY_SIZE(timer_0_1_pins),
+ .modemuxs = timer_0_1_modemux,
+ .nmodemuxs = ARRAY_SIZE(timer_0_1_modemux),
+};
+
+static const char *const timer_0_1_grps[] = { "timer_0_1_grp" };
+struct spear_function spear3xx_timer_0_1_function = {
+ .name = "timer_0_1",
+ .groups = timer_0_1_grps,
+ .ngroups = ARRAY_SIZE(timer_0_1_grps),
+};
+
+/* timer_2_3_pins */
+static const unsigned timer_2_3_pins[] = { 45, 46, 49, 50 };
+static struct spear_muxreg timer_2_3_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_TIMER_2_3_MASK,
+ .val = PMX_TIMER_2_3_MASK,
+ },
+};
+
+static struct spear_modemux timer_2_3_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = timer_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(timer_2_3_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_timer_2_3_pingroup = {
+ .name = "timer_2_3_grp",
+ .pins = timer_2_3_pins,
+ .npins = ARRAY_SIZE(timer_2_3_pins),
+ .modemuxs = timer_2_3_modemux,
+ .nmodemuxs = ARRAY_SIZE(timer_2_3_modemux),
+};
+
+static const char *const timer_2_3_grps[] = { "timer_2_3_grp" };
+struct spear_function spear3xx_timer_2_3_function = {
+ .name = "timer_2_3",
+ .groups = timer_2_3_grps,
+ .ngroups = ARRAY_SIZE(timer_2_3_grps),
+};
+
+struct spear_pinctrl_machdata spear3xx_machdata = {
+ .pins = spear3xx_pins,
+ .npins = ARRAY_SIZE(spear3xx_pins),
+};
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.h b/drivers/pinctrl/spear/pinctrl-spear3xx.h
new file mode 100644
index 0000000..5d5fdd8
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.h
@@ -0,0 +1,92 @@
+/*
+ * Header file for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINMUX_SPEAR3XX_H__
+#define __PINMUX_SPEAR3XX_H__
+
+#include "pinctrl-spear.h"
+
+/* pad mux declarations */
+#define PMX_FIRDA_MASK (1 << 14)
+#define PMX_I2C_MASK (1 << 13)
+#define PMX_SSP_CS_MASK (1 << 12)
+#define PMX_SSP_MASK (1 << 11)
+#define PMX_MII_MASK (1 << 10)
+#define PMX_GPIO_PIN0_MASK (1 << 9)
+#define PMX_GPIO_PIN1_MASK (1 << 8)
+#define PMX_GPIO_PIN2_MASK (1 << 7)
+#define PMX_GPIO_PIN3_MASK (1 << 6)
+#define PMX_GPIO_PIN4_MASK (1 << 5)
+#define PMX_GPIO_PIN5_MASK (1 << 4)
+#define PMX_UART0_MODEM_MASK (1 << 3)
+#define PMX_UART0_MASK (1 << 2)
+#define PMX_TIMER_2_3_MASK (1 << 1)
+#define PMX_TIMER_0_1_MASK (1 << 0)
+
+extern struct spear_pingroup spear3xx_firda_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin0_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin1_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin2_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin3_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin4_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin5_pingroup;
+extern struct spear_pingroup spear3xx_i2c_pingroup;
+extern struct spear_pingroup spear3xx_mii_pingroup;
+extern struct spear_pingroup spear3xx_ssp_cs_pingroup;
+extern struct spear_pingroup spear3xx_ssp_pingroup;
+extern struct spear_pingroup spear3xx_timer_0_1_pingroup;
+extern struct spear_pingroup spear3xx_timer_2_3_pingroup;
+extern struct spear_pingroup spear3xx_uart0_ext_pingroup;
+extern struct spear_pingroup spear3xx_uart0_pingroup;
+
+#define SPEAR3XX_COMMON_PINGROUPS \
+ &spear3xx_firda_pingroup, \
+ &spear3xx_gpio0_pin0_pingroup, \
+ &spear3xx_gpio0_pin1_pingroup, \
+ &spear3xx_gpio0_pin2_pingroup, \
+ &spear3xx_gpio0_pin3_pingroup, \
+ &spear3xx_gpio0_pin4_pingroup, \
+ &spear3xx_gpio0_pin5_pingroup, \
+ &spear3xx_i2c_pingroup, \
+ &spear3xx_mii_pingroup, \
+ &spear3xx_ssp_cs_pingroup, \
+ &spear3xx_ssp_pingroup, \
+ &spear3xx_timer_0_1_pingroup, \
+ &spear3xx_timer_2_3_pingroup, \
+ &spear3xx_uart0_ext_pingroup, \
+ &spear3xx_uart0_pingroup
+
+extern struct spear_function spear3xx_firda_function;
+extern struct spear_function spear3xx_gpio0_function;
+extern struct spear_function spear3xx_i2c_function;
+extern struct spear_function spear3xx_mii_function;
+extern struct spear_function spear3xx_ssp_cs_function;
+extern struct spear_function spear3xx_ssp_function;
+extern struct spear_function spear3xx_timer_0_1_function;
+extern struct spear_function spear3xx_timer_2_3_function;
+extern struct spear_function spear3xx_uart0_ext_function;
+extern struct spear_function spear3xx_uart0_function;
+
+#define SPEAR3XX_COMMON_FUNCTIONS \
+ &spear3xx_firda_function, \
+ &spear3xx_gpio0_function, \
+ &spear3xx_i2c_function, \
+ &spear3xx_mii_function, \
+ &spear3xx_ssp_cs_function, \
+ &spear3xx_ssp_function, \
+ &spear3xx_timer_0_1_function, \
+ &spear3xx_timer_2_3_function, \
+ &spear3xx_uart0_ext_function, \
+ &spear3xx_uart0_function
+
+extern struct spear_pinctrl_machdata spear3xx_machdata;
+
+#endif /* __PINMUX_SPEAR3XX_H__ */
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 6b26666..c4c1a54 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1,7 +1,7 @@
/*-*-linux-c-*-*/
/*
- Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
Copyright (C) 2008 Tony Vroon <tony@linx.net>
Based on earlier work:
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 222ccd8..f5d6d37 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -451,7 +451,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
}
/*
- * Return the battery Voltage in milivolts
+ * Return the battery Voltage in millivolts
* Or < 0 if something fails.
*/
static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index a409fa0..93d0a8b 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -338,7 +338,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
mutex_unlock(&ps3av->mutex);
return 0;
- err:
+err:
mutex_unlock(&ps3av->mutex);
printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
return res;
@@ -477,7 +477,6 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
static int ps3av_set_videomode(void)
@@ -501,7 +500,7 @@ static void ps3av_set_videomode_packet(u32 id)
video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
- avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
+ avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
avb_param.num_of_audio_pkt = 0;
avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
ps3av->av_hw_conf.num_of_avmulti;
@@ -521,7 +520,7 @@ static void ps3av_set_videomode_packet(u32 id)
#ifndef PS3AV_HDMI_YUV
if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
- av_video_cs = RGB8; /* use RGB for HDMI */
+ av_video_cs = RGB8; /* use RGB for HDMI */
#endif
len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
ps3av->av_port[i],
@@ -590,8 +589,8 @@ static void ps3avd(struct work_struct *work)
#define SHIFT_VESA 8
static const struct {
- unsigned mask : 19;
- unsigned id : 4;
+ unsigned mask:19;
+ unsigned id:4;
} ps3av_preferred_modes[] = {
{ PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA },
{ PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 },
@@ -667,7 +666,8 @@ static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
return id;
}
-static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+static void ps3av_monitor_info_dump(
+ const struct ps3av_pkt_av_get_monitor_info *monitor_info)
{
const struct ps3av_info_monitor *info = &monitor_info->info;
const struct ps3av_info_audio *audio = info->audio;
@@ -717,8 +717,8 @@ static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *
/* audio block */
for (i = 0; i < info->num_of_audio_block; i++) {
- pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
- "%02x\n",
+ pr_debug(
+ "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
i, audio->type, audio->max_num_of_ch, audio->fs,
audio->sbit);
audio++;
@@ -870,21 +870,18 @@ int ps3av_set_video_mode(int id)
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
int ps3av_get_auto_mode(void)
{
return ps3av_auto_videomode(&ps3av->av_hw_conf);
}
-
EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
int ps3av_get_mode(void)
{
return ps3av ? ps3av->ps3av_mode : 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_get_mode);
/* get resolution by video_mode */
@@ -902,7 +899,6 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
*yres = video_mode_table[id].y;
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
/* mute */
@@ -911,7 +907,6 @@ int ps3av_video_mute(int mute)
return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
: PS3AV_CMD_MUTE_OFF);
}
-
EXPORT_SYMBOL_GPL(ps3av_video_mute);
/* mute analog output only */
@@ -935,7 +930,6 @@ int ps3av_audio_mute(int mute)
return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
: PS3AV_CMD_MUTE_OFF);
}
-
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 5648dad..ffdf712 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -70,7 +70,7 @@ config DP83640_PHY
using the SO_TIMESTAMPING API.
In order for this to work, your MAC driver must also
- implement the skb_tx_timetamp() function.
+ implement the skb_tx_timestamp() function.
config PTP_1588_CLOCK_PCH
tristate "Intel PCH EG20T as PTP clock"
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 28b81ae4..c3482b9 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -27,13 +27,8 @@ struct pm8607_regulator_info {
unsigned int *vol_table;
unsigned int *vol_suspend;
- int vol_reg;
- int vol_shift;
- int vol_nbits;
int update_reg;
int update_bit;
- int enable_reg;
- int enable_bit;
int slope_double;
};
@@ -216,7 +211,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
int ret = -EINVAL;
- if (info->vol_table && (index < (1 << info->vol_nbits))) {
+ if (info->vol_table && (index < rdev->desc->n_voltages)) {
ret = info->vol_table[index];
if (info->slope_double)
ret <<= 1;
@@ -224,51 +219,16 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
return ret;
}
-static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- int i, ret = -ENOENT;
-
- if (info->slope_double) {
- min_uV = min_uV >> 1;
- max_uV = max_uV >> 1;
- }
- if (info->vol_table) {
- for (i = 0; i < (1 << info->vol_nbits); i++) {
- if (!info->vol_table[i])
- break;
- if ((min_uV <= info->vol_table[i])
- && (max_uV >= info->vol_table[i])) {
- ret = i;
- break;
- }
- }
- }
- if (ret < 0)
- pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
- return ret;
-}
-
-static int pm8607_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- uint8_t val, mask;
+ uint8_t val;
int ret;
- if (min_uV > max_uV) {
- pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
- return -EINVAL;
- }
+ val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
- ret = choose_voltage(rdev, min_uV, max_uV);
- if (ret < 0)
- return -EINVAL;
- *selector = ret;
- val = (uint8_t)(ret << info->vol_shift);
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
-
- ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
+ ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, val);
if (ret)
return ret;
switch (info->desc.id) {
@@ -282,60 +242,16 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
return ret;
}
-static int pm8607_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- uint8_t val, mask;
- int ret;
-
- ret = pm860x_reg_read(info->i2c, info->vol_reg);
- if (ret < 0)
- return ret;
-
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
- val = ((unsigned char)ret & mask) >> info->vol_shift;
-
- return pm8607_list_voltage(rdev, val);
-}
-
-static int pm8607_enable(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-
- return pm860x_set_bits(info->i2c, info->enable_reg,
- 1 << info->enable_bit,
- 1 << info->enable_bit);
-}
-
-static int pm8607_disable(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-
- return pm860x_set_bits(info->i2c, info->enable_reg,
- 1 << info->enable_bit, 0);
-}
-
-static int pm8607_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
-
- ret = pm860x_reg_read(info->i2c, info->enable_reg);
- if (ret < 0)
- return ret;
-
- return !!((unsigned char)ret & (1 << info->enable_bit));
-}
-
static struct regulator_ops pm8607_regulator_ops = {
- .set_voltage = pm8607_set_voltage,
- .get_voltage = pm8607_get_voltage,
- .enable = pm8607_enable,
- .disable = pm8607_disable,
- .is_enabled = pm8607_is_enabled,
+ .list_voltage = pm8607_list_voltage,
+ .set_voltage_sel = pm8607_set_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
};
-#define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit) \
+#define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \
{ \
.desc = { \
.name = #vreg, \
@@ -343,20 +259,20 @@ static struct regulator_ops pm8607_regulator_ops = {
.type = REGULATOR_VOLTAGE, \
.id = PM8607_ID_##vreg, \
.owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(vreg##_table), \
+ .vsel_reg = PM8607_##vreg, \
+ .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \
+ .enable_reg = PM8607_##ereg, \
+ .enable_mask = 1 << (ebit), \
}, \
- .vol_reg = PM8607_##vreg, \
- .vol_shift = (0), \
- .vol_nbits = (nbits), \
.update_reg = PM8607_##ureg, \
.update_bit = (ubit), \
- .enable_reg = PM8607_##ereg, \
- .enable_bit = (ebit), \
.slope_double = (0), \
.vol_table = (unsigned int *)&vreg##_table, \
.vol_suspend = (unsigned int *)&vreg##_suspend_table, \
}
-#define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit) \
+#define PM8607_LDO(_id, vreg, shift, ereg, ebit) \
{ \
.desc = { \
.name = "LDO" #_id, \
@@ -364,35 +280,35 @@ static struct regulator_ops pm8607_regulator_ops = {
.type = REGULATOR_VOLTAGE, \
.id = PM8607_ID_LDO##_id, \
.owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(LDO##_id##_table), \
+ .vsel_reg = PM8607_##vreg, \
+ .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
+ .enable_reg = PM8607_##ereg, \
+ .enable_mask = 1 << (ebit), \
}, \
- .vol_reg = PM8607_##vreg, \
- .vol_shift = (shift), \
- .vol_nbits = (nbits), \
- .enable_reg = PM8607_##ereg, \
- .enable_bit = (ebit), \
.slope_double = (0), \
.vol_table = (unsigned int *)&LDO##_id##_table, \
.vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \
}
static struct pm8607_regulator_info pm8607_regulator_info[] = {
- PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
- PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
- PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
-
- PM8607_LDO( 1, LDO1, 0, 2, SUPPLIES_EN11, 3),
- PM8607_LDO( 2, LDO2, 0, 3, SUPPLIES_EN11, 4),
- PM8607_LDO( 3, LDO3, 0, 3, SUPPLIES_EN11, 5),
- PM8607_LDO( 4, LDO4, 0, 3, SUPPLIES_EN11, 6),
- PM8607_LDO( 5, LDO5, 0, 2, SUPPLIES_EN11, 7),
- PM8607_LDO( 6, LDO6, 0, 3, SUPPLIES_EN12, 0),
- PM8607_LDO( 7, LDO7, 0, 3, SUPPLIES_EN12, 1),
- PM8607_LDO( 8, LDO8, 0, 3, SUPPLIES_EN12, 2),
- PM8607_LDO( 9, LDO9, 0, 3, SUPPLIES_EN12, 3),
- PM8607_LDO(10, LDO10, 0, 4, SUPPLIES_EN12, 4),
- PM8607_LDO(12, LDO12, 0, 4, SUPPLIES_EN12, 5),
- PM8607_LDO(13, VIBRATOR_SET, 1, 3, VIBRATOR_SET, 0),
- PM8607_LDO(14, LDO14, 0, 3, SUPPLIES_EN12, 6),
+ PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
+ PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
+ PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
+
+ PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3),
+ PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4),
+ PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5),
+ PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6),
+ PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7),
+ PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0),
+ PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1),
+ PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2),
+ PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3),
+ PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4),
+ PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5),
+ PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
+ PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6),
};
static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
@@ -400,6 +316,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm8607_regulator_info *info = NULL;
struct regulator_init_data *pdata = pdev->dev.platform_data;
+ struct regulator_config config = { };
struct resource *res;
int i;
@@ -425,9 +342,17 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
info->slope_double = 1;
+ config.dev = &pdev->dev;
+ config.init_data = pdata;
+ config.driver_data = info;
+
+ if (chip->id == CHIP_PM8607)
+ config.regmap = chip->regmap;
+ else
+ config.regmap = chip->regmap_companion;
+
/* replace driver_data with info */
- info->regulator = regulator_register(&info->desc, &pdev->dev,
- pdata, info, NULL);
+ info->regulator = regulator_register(&info->desc, &config);
if (IS_ERR(info->regulator)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
info->desc.name);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 36db5a4..c86b886 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -223,6 +223,16 @@ config REGULATOR_PCF50633
Say Y here to support the voltage regulators and convertors
on PCF50633
+config REGULATOR_RC5T583
+ tristate "RICOH RC5T583 Power regulators"
+ depends on MFD_RC5T583
+ help
+ Select this option to enable the power regulator of RICOH
+ PMIC RC5T583.
+ This driver supports the control of different power rails of device
+ through regulator interface. The device supports multiple DCDC/LDO
+ outputs which can be controlled by i2c communication.
+
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
depends on MFD_S5M_CORE
@@ -258,6 +268,18 @@ config REGULATOR_DB8500_PRCMU
This driver supports the voltage domain regulators controlled by the
DB8500 PRCMU
+config REGULATOR_PALMAS
+ tristate "TI Palmas PMIC Regulators"
+ depends on MFD_PALMAS
+ help
+ If you wish to control the regulators on the Palmas series of
+ chips say Y here. This will enable support for all the software
+ controllable SMPS/LDO regulators.
+
+ The regulators available on Palmas series chips vary depending
+ on the muxing. This is handled automatically in the driver by
+ reading the mux info from OTP.
+
config REGULATOR_TPS6105X
tristate "TI TPS6105X Power regulators"
depends on TPS6105X
@@ -268,11 +290,11 @@ config REGULATOR_TPS6105X
audio amplifiers.
config REGULATOR_TPS62360
- tristate "TI TPS62360 Power Regulator"
+ tristate "TI TPS6236x Power Regulator"
depends on I2C
select REGMAP_I2C
help
- This driver supports TPS62360 voltage regulator chip. This
+ This driver supports TPS6236x voltage regulator chip. This
regulator is meant for processor core supply. This chip is
high-frequency synchronous step down dc-dc converter optimized
for battery-powered portable applications.
@@ -294,6 +316,13 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
+config REGULATOR_TPS65090
+ tristate "TI TPS65090 Power regulator"
+ depends on MFD_TPS65090
+ help
+ This driver provides support for the voltage regulators on the
+ TI TPS65090 PMIC.
+
config REGULATOR_TPS65217
tristate "TI TPS65217 Power regulators"
depends on MFD_TPS65217
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 94b5274..977fd46 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
-obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
@@ -20,6 +19,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
@@ -33,13 +33,16 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index 9ed5c5d..06776ca 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -24,7 +24,6 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -178,6 +177,7 @@ static struct aat2870_regulator *aat2870_get_regulator(int id)
static int aat2870_regulator_probe(struct platform_device *pdev)
{
struct aat2870_regulator *ri;
+ struct regulator_config config = { 0 };
struct regulator_dev *rdev;
ri = aat2870_get_regulator(pdev->id);
@@ -187,8 +187,11 @@ static int aat2870_regulator_probe(struct platform_device *pdev)
}
ri->aat2870 = dev_get_drvdata(pdev->dev.parent);
- rdev = regulator_register(&ri->desc, &pdev->dev,
- pdev->dev.platform_data, ri, NULL);
+ config.dev = &pdev->dev;
+ config.driver_data = ri;
+ config.init_data = pdev->dev.platform_data;
+
+ rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register regulator %s\n",
ri->desc.name);
@@ -231,3 +234,4 @@ module_exit(aat2870_regulator_exit);
MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
+MODULE_ALIAS("platform:aat2870-regulator");
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 042271a..03f4d9c 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/abx500.h>
@@ -305,53 +304,12 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
return abreg->typ_voltages[regval];
}
-static int ab3100_get_best_voltage_index(struct regulator_dev *reg,
- int min_uV, int max_uV)
-{
- struct ab3100_regulator *abreg = reg->reg_data;
- int i;
- int bestmatch;
- int bestindex;
-
- /*
- * Locate the minimum voltage fitting the criteria on
- * this regulator. The switchable voltages are not
- * in strict falling order so we need to check them
- * all for the best match.
- */
- bestmatch = INT_MAX;
- bestindex = -1;
- for (i = 0; i < abreg->voltages_len; i++) {
- if (abreg->typ_voltages[i] <= max_uV &&
- abreg->typ_voltages[i] >= min_uV &&
- abreg->typ_voltages[i] < bestmatch) {
- bestmatch = abreg->typ_voltages[i];
- bestindex = i;
- }
- }
-
- if (bestindex < 0) {
- dev_warn(&reg->dev, "requested %d<=x<=%d uV, out of range!\n",
- min_uV, max_uV);
- return -EINVAL;
- }
- return bestindex;
-}
-
-static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
- int min_uV, int max_uV,
- unsigned *selector)
+static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg,
+ unsigned selector)
{
struct ab3100_regulator *abreg = reg->reg_data;
u8 regval;
int err;
- int bestindex;
-
- bestindex = ab3100_get_best_voltage_index(reg, min_uV, max_uV);
- if (bestindex < 0)
- return bestindex;
-
- *selector = bestindex;
err = abx500_get_register_interruptible(abreg->dev, 0,
abreg->regreg, &regval);
@@ -364,7 +322,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
/* The highest three bits control the variable regulators */
regval &= ~0xE0;
- regval |= (bestindex << 5);
+ regval |= (selector << 5);
err = abx500_set_register_interruptible(abreg->dev, 0,
abreg->regreg, regval);
@@ -392,7 +350,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
return -EINVAL;
/* LDO E and BUCK have special suspend voltages you can set */
- bestindex = ab3100_get_best_voltage_index(reg, uV, uV);
+ bestindex = regulator_map_voltage_iterate(reg, uV, uV);
err = abx500_get_register_interruptible(abreg->dev, 0,
targetreg, &regval);
@@ -464,7 +422,7 @@ static struct regulator_ops regulator_ops_variable = {
.disable = ab3100_disable_regulator,
.is_enabled = ab3100_is_enabled_regulator,
.get_voltage = ab3100_get_voltage_regulator,
- .set_voltage = ab3100_set_voltage_regulator,
+ .set_voltage_sel = ab3100_set_voltage_regulator_sel,
.list_voltage = ab3100_list_voltage_regulator,
.enable_time = ab3100_enable_time_regulator,
};
@@ -474,7 +432,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = {
.disable = ab3100_disable_regulator,
.is_enabled = ab3100_is_enabled_regulator,
.get_voltage = ab3100_get_voltage_regulator,
- .set_voltage = ab3100_set_voltage_regulator,
+ .set_voltage_sel = ab3100_set_voltage_regulator_sel,
.set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
.list_voltage = ab3100_list_voltage_regulator,
.enable_time = ab3100_enable_time_regulator,
@@ -582,6 +540,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
{
struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+ struct regulator_config config = { };
int err = 0;
u8 data;
int i;
@@ -627,15 +586,15 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
reg->dev = &pdev->dev;
reg->plfdata = plfdata;
+ config.dev = &pdev->dev;
+ config.driver_data = reg;
+ config.init_data = &plfdata->reg_constraints[i];
+
/*
* Register the regulator, pass around
* the ab3100_regulator struct
*/
- rdev = regulator_register(&ab3100_regulator_desc[i],
- &pdev->dev,
- &plfdata->reg_constraints[i],
- reg, NULL);
-
+ rdev = regulator_register(&ab3100_regulator_desc[i], &config);
if (IS_ERR(rdev)) {
err = PTR_ERR(rdev);
dev_err(&pdev->dev,
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index c7ee4c1..e1b8c54 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -18,9 +18,12 @@
#include <linux/platform_device.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
+#include <linux/slab.h>
/**
* struct ab8500_regulator_info - ab8500 regulator information
@@ -234,25 +237,8 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
return val;
}
-static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- int i;
-
- /* check the supported voltage */
- for (i = 0; i < info->voltages_len; i++) {
- if ((info->voltages[i] >= min_uV) &&
- (info->voltages[i] <= max_uV))
- return i;
- }
-
- return -EINVAL;
-}
-
-static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
@@ -263,18 +249,8 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
return -EINVAL;
}
- /* get the appropriate voltages within the range */
- ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
- if (ret < 0) {
- dev_err(rdev_get_dev(rdev),
- "couldn't get best voltage for regulator\n");
- return ret;
- }
-
- *selector = ret;
-
/* set the registers for the request */
- regval = (u8)ret;
+ regval = (u8)selector;
ret = abx500_mask_and_set_register_interruptible(info->dev,
info->voltage_bank, info->voltage_reg,
info->voltage_mask, regval);
@@ -319,7 +295,7 @@ static struct regulator_ops ab8500_regulator_ops = {
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage_sel = ab8500_regulator_get_voltage_sel,
- .set_voltage = ab8500_regulator_set_voltage,
+ .set_voltage_sel = ab8500_regulator_set_voltage_sel,
.list_voltage = ab8500_list_voltage,
.enable_time = ab8500_regulator_enable_time,
.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
@@ -735,12 +711,139 @@ static struct ab8500_reg_init ab8500_reg_init[] = {
REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16),
};
+static __devinit int
+ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value)
+{
+ int err;
+
+ if (value & ~ab8500_reg_init[id].mask) {
+ dev_err(&pdev->dev,
+ "Configuration error: value outside mask.\n");
+ return -EINVAL;
+ }
+
+ err = abx500_mask_and_set_register_interruptible(
+ &pdev->dev,
+ ab8500_reg_init[id].bank,
+ ab8500_reg_init[id].addr,
+ ab8500_reg_init[id].mask,
+ value);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Failed to initialize 0x%02x, 0x%02x.\n",
+ ab8500_reg_init[id].bank,
+ ab8500_reg_init[id].addr);
+ return err;
+ }
+
+ dev_vdbg(&pdev->dev,
+ "init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ ab8500_reg_init[id].bank,
+ ab8500_reg_init[id].addr,
+ ab8500_reg_init[id].mask,
+ value);
+
+ return 0;
+}
+
+static __devinit int ab8500_regulator_register(struct platform_device *pdev,
+ struct regulator_init_data *init_data,
+ int id,
+ struct device_node *np)
+{
+ struct ab8500_regulator_info *info = NULL;
+ struct regulator_config config = { };
+ int err;
+
+ /* assign per-regulator data */
+ info = &ab8500_regulator_info[id];
+ info->dev = &pdev->dev;
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = info;
+ config.of_node = np;
+
+ /* fix for hardware before ab8500v2.0 */
+ if (abx500_get_chip_id(info->dev) < 0x20) {
+ if (info->desc.id == AB8500_LDO_AUX3) {
+ info->desc.n_voltages =
+ ARRAY_SIZE(ldo_vauxn_voltages);
+ info->voltages = ldo_vauxn_voltages;
+ info->voltages_len =
+ ARRAY_SIZE(ldo_vauxn_voltages);
+ info->voltage_mask = 0xf;
+ }
+ }
+
+ /* register regulator with framework */
+ info->regulator = regulator_register(&info->desc, &config);
+ if (IS_ERR(info->regulator)) {
+ err = PTR_ERR(info->regulator);
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ /* when we fail, un-register all earlier regulators */
+ while (--id >= 0) {
+ info = &ab8500_regulator_info[id];
+ regulator_unregister(info->regulator);
+ }
+ return err;
+ }
+
+ return 0;
+}
+
+static struct of_regulator_match ab8500_regulator_matches[] = {
+ { .name = "LDO-AUX1", .driver_data = (void *) AB8500_LDO_AUX1, },
+ { .name = "LDO-AUX2", .driver_data = (void *) AB8500_LDO_AUX2, },
+ { .name = "LDO-AUX3", .driver_data = (void *) AB8500_LDO_AUX3, },
+ { .name = "LDO-INTCORE", .driver_data = (void *) AB8500_LDO_INTCORE, },
+ { .name = "LDO-TVOUT", .driver_data = (void *) AB8500_LDO_TVOUT, },
+ { .name = "LDO-USB", .driver_data = (void *) AB8500_LDO_USB, },
+ { .name = "LDO-AUDIO", .driver_data = (void *) AB8500_LDO_AUDIO, },
+ { .name = "LDO-ANAMIC1", .driver_data = (void *) AB8500_LDO_ANAMIC1, },
+ { .name = "LDO-ANAMIC2", .driver_data = (void *) AB8500_LDO_ANAMIC2, },
+ { .name = "LDO-DMIC", .driver_data = (void *) AB8500_LDO_DMIC, },
+ { .name = "LDO-ANA", .driver_data = (void *) AB8500_LDO_ANA, },
+};
+
+static __devinit int
+ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ err = ab8500_regulator_register(
+ pdev, ab8500_regulator_matches[i].init_data,
+ i, ab8500_regulator_matches[i].of_node);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *pdata;
+ struct device_node *np = pdev->dev.of_node;
int i, err;
+ if (np) {
+ err = of_regulator_match(&pdev->dev, np,
+ ab8500_regulator_matches,
+ ARRAY_SIZE(ab8500_regulator_matches));
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Error parsing regulator init data: %d\n", err);
+ return err;
+ }
+
+ err = ab8500_regulator_of_probe(pdev, np);
+ return err;
+ }
+
if (!ab8500) {
dev_err(&pdev->dev, "null mfd parent\n");
return -EINVAL;
@@ -759,8 +862,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
/* initialize registers */
for (i = 0; i < pdata->num_regulator_reg_init; i++) {
- int id;
- u8 value;
+ int id, value;
id = pdata->regulator_reg_init[i].id;
value = pdata->regulator_reg_init[i].value;
@@ -771,70 +873,17 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
"Configuration error: id outside range.\n");
return -EINVAL;
}
- if (value & ~ab8500_reg_init[id].mask) {
- dev_err(&pdev->dev,
- "Configuration error: value outside mask.\n");
- return -EINVAL;
- }
- /* initialize register */
- err = abx500_mask_and_set_register_interruptible(&pdev->dev,
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr,
- ab8500_reg_init[id].mask,
- value);
- if (err < 0) {
- dev_err(&pdev->dev,
- "Failed to initialize 0x%02x, 0x%02x.\n",
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr);
+ err = ab8500_regulator_init_registers(pdev, id, value);
+ if (err < 0)
return err;
- }
- dev_vdbg(&pdev->dev,
- " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr,
- ab8500_reg_init[id].mask,
- value);
}
/* register all regulators */
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
- struct ab8500_regulator_info *info = NULL;
-
- /* assign per-regulator data */
- info = &ab8500_regulator_info[i];
- info->dev = &pdev->dev;
-
- /* fix for hardware before ab8500v2.0 */
- if (abx500_get_chip_id(info->dev) < 0x20) {
- if (info->desc.id == AB8500_LDO_AUX3) {
- info->desc.n_voltages =
- ARRAY_SIZE(ldo_vauxn_voltages);
- info->voltages = ldo_vauxn_voltages;
- info->voltages_len =
- ARRAY_SIZE(ldo_vauxn_voltages);
- info->voltage_mask = 0xf;
- }
- }
-
- /* register regulator with framework */
- info->regulator = regulator_register(&info->desc, &pdev->dev,
- &pdata->regulator[i], info, NULL);
- if (IS_ERR(info->regulator)) {
- err = PTR_ERR(info->regulator);
- dev_err(&pdev->dev, "failed to register regulator %s\n",
- info->desc.name);
- /* when we fail, un-register all earlier regulators */
- while (--i >= 0) {
- info = &ab8500_regulator_info[i];
- regulator_unregister(info->regulator);
- }
+ err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL);
+ if (err < 0)
return err;
- }
-
- dev_vdbg(rdev_get_dev(info->regulator),
- "%s-probed\n", info->desc.name);
}
return 0;
@@ -857,12 +906,18 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id ab8500_regulator_match[] = {
+ { .compatible = "stericsson,ab8500-regulator", },
+ {}
+};
+
static struct platform_driver ab8500_regulator_driver = {
.probe = ab8500_regulator_probe,
.remove = __devexit_p(ab8500_regulator_remove),
.driver = {
.name = "ab8500-regulator",
.owner = THIS_MODULE,
+ .of_match_table = ab8500_regulator_match,
},
};
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 26d23ad..46d05f3 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -99,8 +99,8 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int
if (ad5398_calc_current(chip, selector) > max_uA)
return -EINVAL;
- dev_dbg(&client->dev, "changing current %dmA\n",
- ad5398_calc_current(chip, selector) / 1000);
+ dev_dbg(&client->dev, "changing current %duA\n",
+ ad5398_calc_current(chip, selector));
/* read chip enable bit */
ret = ad5398_read_reg(client, &data);
@@ -184,7 +184,7 @@ static struct regulator_ops ad5398_ops = {
.is_enabled = ad5398_is_enabled,
};
-static struct regulator_desc ad5398_reg = {
+static const struct regulator_desc ad5398_reg = {
.name = "isink",
.id = 0,
.ops = &ad5398_ops,
@@ -212,6 +212,7 @@ static int __devinit ad5398_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regulator_init_data *init_data = client->dev.platform_data;
+ struct regulator_config config = { };
struct ad5398_chip_info *chip;
const struct ad5398_current_data_format *df =
(struct ad5398_current_data_format *)id->driver_data;
@@ -220,10 +221,14 @@ static int __devinit ad5398_probe(struct i2c_client *client,
if (!init_data)
return -EINVAL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ config.dev = &client->dev;
+ config.init_data = init_data;
+ config.driver_data = chip;
+
chip->client = client;
chip->min_uA = df->min_uA;
@@ -232,8 +237,7 @@ static int __devinit ad5398_probe(struct i2c_client *client,
chip->current_offset = df->current_offset;
chip->current_mask = (chip->current_level - 1) << chip->current_offset;
- chip->rdev = regulator_register(&ad5398_reg, &client->dev,
- init_data, chip, NULL);
+ chip->rdev = regulator_register(&ad5398_reg, &config);
if (IS_ERR(chip->rdev)) {
ret = PTR_ERR(chip->rdev);
dev_err(&client->dev, "failed to register %s %s\n",
@@ -246,7 +250,6 @@ static int __devinit ad5398_probe(struct i2c_client *client,
return 0;
err:
- kfree(chip);
return ret;
}
@@ -255,8 +258,6 @@ static int __devexit ad5398_remove(struct i2c_client *client)
struct ad5398_chip_info *chip = i2c_get_clientdata(client);
regulator_unregister(chip->rdev);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 81fd606..49b2112 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -122,6 +122,7 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
struct anatop_regulator *sreg;
struct regulator_init_data *initdata;
struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
int ret = 0;
initdata = of_get_regulator_init_data(dev, np);
@@ -178,9 +179,13 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage)
/ 25000 + 1;
+ config.dev = &pdev->dev;
+ config.init_data = initdata;
+ config.driver_data = sreg;
+ config.of_node = pdev->dev.of_node;
+
/* register regulator */
- rdev = regulator_register(rdesc, dev,
- initdata, sreg, pdev->dev.of_node);
+ rdev = regulator_register(rdesc, &config);
if (IS_ERR(rdev)) {
dev_err(dev, "failed to register %s\n",
rdesc->name);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 046fb1b..7584a74 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -24,6 +24,7 @@
#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/of.h>
+#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
@@ -74,6 +75,7 @@ struct regulator_map {
struct regulator {
struct device *dev;
struct list_head list;
+ unsigned int always_on:1;
int uA_load;
int min_uV;
int max_uV;
@@ -155,6 +157,17 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
return regnode;
}
+static int _regulator_can_change_status(struct regulator_dev *rdev)
+{
+ if (!rdev->constraints)
+ return 0;
+
+ if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
+ return 1;
+ else
+ return 0;
+}
+
/* Platform voltage constraint check */
static int regulator_check_voltage(struct regulator_dev *rdev,
int *min_uV, int *max_uV)
@@ -649,7 +662,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
/* get input voltage */
input_uV = 0;
if (rdev->supply)
- input_uV = _regulator_get_voltage(rdev);
+ input_uV = regulator_get_voltage(rdev->supply);
if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0)
@@ -673,17 +686,14 @@ static int suspend_set_state(struct regulator_dev *rdev,
struct regulator_state *rstate)
{
int ret = 0;
- bool can_set_state;
-
- can_set_state = rdev->desc->ops->set_suspend_enable &&
- rdev->desc->ops->set_suspend_disable;
/* If we have no suspend mode configration don't set anything;
- * only warn if the driver actually makes the suspend mode
- * configurable.
+ * only warn if the driver implements set_suspend_voltage or
+ * set_suspend_mode callback.
*/
if (!rstate->enabled && !rstate->disabled) {
- if (can_set_state)
+ if (rdev->desc->ops->set_suspend_voltage ||
+ rdev->desc->ops->set_suspend_mode)
rdev_warn(rdev, "No configuration\n");
return 0;
}
@@ -693,15 +703,13 @@ static int suspend_set_state(struct regulator_dev *rdev,
return -EINVAL;
}
- if (!can_set_state) {
- rdev_err(rdev, "no way to set suspend state\n");
- return -EINVAL;
- }
-
- if (rstate->enabled)
+ if (rstate->enabled && rdev->desc->ops->set_suspend_enable)
ret = rdev->desc->ops->set_suspend_enable(rdev);
- else
+ else if (rstate->disabled && rdev->desc->ops->set_suspend_disable)
ret = rdev->desc->ops->set_suspend_disable(rdev);
+ else /* OK if set_suspend_enable or set_suspend_disable is NULL */
+ ret = 0;
+
if (ret < 0) {
rdev_err(rdev, "failed to enabled/disable\n");
return ret;
@@ -1146,6 +1154,15 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
&regulator->max_uV);
}
+ /*
+ * Check now if the regulator is an always on regulator - if
+ * it is then we don't need to do nearly so much work for
+ * enable/disable calls.
+ */
+ if (!_regulator_can_change_status(rdev) &&
+ _regulator_is_enabled(rdev))
+ regulator->always_on = true;
+
mutex_unlock(&rdev->mutex);
return regulator;
link_name_err:
@@ -1169,26 +1186,52 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
}
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
- const char *supply)
+ const char *supply,
+ int *ret)
{
struct regulator_dev *r;
struct device_node *node;
+ struct regulator_map *map;
+ const char *devname = NULL;
/* first do a dt based lookup */
if (dev && dev->of_node) {
node = of_get_regulator(dev, supply);
- if (node)
+ if (node) {
list_for_each_entry(r, &regulator_list, list)
if (r->dev.parent &&
node == r->dev.of_node)
return r;
+ } else {
+ /*
+ * If we couldn't even get the node then it's
+ * not just that the device didn't register
+ * yet, there's no node and we'll never
+ * succeed.
+ */
+ *ret = -ENODEV;
+ }
}
/* if not found, try doing it non-dt way */
+ if (dev)
+ devname = dev_name(dev);
+
list_for_each_entry(r, &regulator_list, list)
if (strcmp(rdev_get_name(r), supply) == 0)
return r;
+ list_for_each_entry(map, &regulator_map_list, list) {
+ /* If the mapping has a device set up it must match */
+ if (map->dev_name &&
+ (!devname || strcmp(map->dev_name, devname)))
+ continue;
+
+ if (strcmp(map->supply, supply) == 0)
+ return map->regulator;
+ }
+
+
return NULL;
}
@@ -1197,7 +1240,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
int exclusive)
{
struct regulator_dev *rdev;
- struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
const char *devname = NULL;
int ret;
@@ -1212,22 +1254,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
mutex_lock(&regulator_list_mutex);
- rdev = regulator_dev_lookup(dev, id);
+ rdev = regulator_dev_lookup(dev, id, &ret);
if (rdev)
goto found;
- list_for_each_entry(map, &regulator_map_list, list) {
- /* If the mapping has a device set up it must match */
- if (map->dev_name &&
- (!devname || strcmp(map->dev_name, devname)))
- continue;
-
- if (strcmp(map->supply, id) == 0) {
- rdev = map->regulator;
- goto found;
- }
- }
-
if (board_wants_dummy_regulator) {
rdev = dummy_regulator_rdev;
goto found;
@@ -1438,17 +1468,6 @@ void devm_regulator_put(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(devm_regulator_put);
-static int _regulator_can_change_status(struct regulator_dev *rdev)
-{
- if (!rdev->constraints)
- return 0;
-
- if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
- return 1;
- else
- return 0;
-}
-
/* locks held by regulator_enable() */
static int _regulator_enable(struct regulator_dev *rdev)
{
@@ -1528,6 +1547,9 @@ int regulator_enable(struct regulator *regulator)
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
+ if (regulator->always_on)
+ return 0;
+
if (rdev->supply) {
ret = regulator_enable(rdev->supply);
if (ret != 0)
@@ -1606,6 +1628,9 @@ int regulator_disable(struct regulator *regulator)
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
+ if (regulator->always_on)
+ return 0;
+
mutex_lock(&rdev->mutex);
ret = _regulator_disable(rdev);
mutex_unlock(&rdev->mutex);
@@ -1714,6 +1739,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
struct regulator_dev *rdev = regulator->rdev;
int ret;
+ if (regulator->always_on)
+ return 0;
+
mutex_lock(&rdev->mutex);
rdev->deferred_disables++;
mutex_unlock(&rdev->mutex);
@@ -1727,6 +1755,61 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
+/**
+ * regulator_is_enabled_regmap - standard is_enabled() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their is_enabled operation, saving some code.
+ */
+int regulator_is_enabled_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ return (val & rdev->desc->enable_mask) != 0;
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
+
+/**
+ * regulator_enable_regmap - standard enable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+int regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask,
+ rdev->desc->enable_mask);
+}
+EXPORT_SYMBOL_GPL(regulator_enable_regmap);
+
+/**
+ * regulator_disable_regmap - standard disable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+int regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, 0);
+}
+EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
/* If we don't know then assume that the regulator is always on */
@@ -1752,6 +1835,9 @@ int regulator_is_enabled(struct regulator *regulator)
{
int ret;
+ if (regulator->always_on)
+ return 1;
+
mutex_lock(&regulator->rdev->mutex);
ret = _regulator_is_enabled(regulator->rdev);
mutex_unlock(&regulator->rdev->mutex);
@@ -1777,6 +1863,26 @@ int regulator_count_voltages(struct regulator *regulator)
EXPORT_SYMBOL_GPL(regulator_count_voltages);
/**
+ * regulator_list_voltage_linear - List voltages with simple calculation
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+
+ return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
+
+/**
* regulator_list_voltage - enumerate supported voltages
* @regulator: regulator source
* @selector: identify voltage to list
@@ -1840,75 +1946,183 @@ int regulator_is_supported_voltage(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
+/**
+ * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their get_voltage_vsel operation, saving some code.
+ */
+int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
+
+/**
+ * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
+{
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
+
+/**
+ * regulator_map_voltage_iterate - map_voltage() based on list_voltage()
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers implementing set_voltage_sel() and list_voltage() can use
+ * this as their map_voltage() operation. It will find a suitable
+ * voltage by calling list_voltage() until it gets something in bounds
+ * for the requested voltages.
+ */
+int regulator_map_voltage_iterate(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int best_val = INT_MAX;
+ int selector = 0;
+ int i, ret;
+
+ /* Find the smallest voltage that falls within the specified
+ * range.
+ */
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ ret = rdev->desc->ops->list_voltage(rdev, i);
+ if (ret < 0)
+ continue;
+
+ if (ret < best_val && ret >= min_uV && ret <= max_uV) {
+ best_val = ret;
+ selector = i;
+ }
+ }
+
+ if (best_val != INT_MAX)
+ return selector;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for simple linear mappings
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing min_uV and uV_step in their regulator_desc can
+ * use this as their map_voltage() operation.
+ */
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret, voltage;
+
+ if (!rdev->desc->uV_step) {
+ BUG_ON(!rdev->desc->uV_step);
+ return -EINVAL;
+ }
+
+ ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
+ if (ret < 0)
+ return ret;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
+
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
int ret;
int delay = 0;
+ int best_val;
unsigned int selector;
+ int old_selector = -1;
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
min_uV += rdev->constraints->uV_offset;
max_uV += rdev->constraints->uV_offset;
+ /*
+ * If we can't obtain the old selector there is not enough
+ * info to call set_voltage_time_sel().
+ */
+ if (rdev->desc->ops->set_voltage_time_sel &&
+ rdev->desc->ops->get_voltage_sel) {
+ old_selector = rdev->desc->ops->get_voltage_sel(rdev);
+ if (old_selector < 0)
+ return old_selector;
+ }
+
if (rdev->desc->ops->set_voltage) {
ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
&selector);
-
- if (rdev->desc->ops->list_voltage)
- selector = rdev->desc->ops->list_voltage(rdev,
- selector);
- else
- selector = -1;
} else if (rdev->desc->ops->set_voltage_sel) {
- int best_val = INT_MAX;
- int i;
-
- selector = 0;
-
- /* Find the smallest voltage that falls within the specified
- * range.
- */
- for (i = 0; i < rdev->desc->n_voltages; i++) {
- ret = rdev->desc->ops->list_voltage(rdev, i);
- if (ret < 0)
- continue;
+ if (rdev->desc->ops->map_voltage)
+ ret = rdev->desc->ops->map_voltage(rdev, min_uV,
+ max_uV);
+ else
+ ret = regulator_map_voltage_iterate(rdev, min_uV,
+ max_uV);
- if (ret < best_val && ret >= min_uV && ret <= max_uV) {
- best_val = ret;
- selector = i;
- }
+ if (ret >= 0) {
+ selector = ret;
+ ret = rdev->desc->ops->set_voltage_sel(rdev, ret);
}
+ } else {
+ ret = -EINVAL;
+ }
- /*
- * If we can't obtain the old selector there is not enough
- * info to call set_voltage_time_sel().
- */
- if (rdev->desc->ops->set_voltage_time_sel &&
- rdev->desc->ops->get_voltage_sel) {
- unsigned int old_selector = 0;
+ if (rdev->desc->ops->list_voltage)
+ best_val = rdev->desc->ops->list_voltage(rdev, selector);
+ else
+ best_val = -1;
- ret = rdev->desc->ops->get_voltage_sel(rdev);
- if (ret < 0)
- return ret;
- old_selector = ret;
- ret = rdev->desc->ops->set_voltage_time_sel(rdev,
- old_selector, selector);
- if (ret < 0)
- rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret);
- else
- delay = ret;
- }
+ /* Call set_voltage_time_sel if successfully obtained old_selector */
+ if (ret == 0 && old_selector >= 0 &&
+ rdev->desc->ops->set_voltage_time_sel) {
- if (best_val != INT_MAX) {
- ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
- selector = best_val;
- } else {
- ret = -EINVAL;
+ delay = rdev->desc->ops->set_voltage_time_sel(rdev,
+ old_selector, selector);
+ if (delay < 0) {
+ rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n",
+ delay);
+ delay = 0;
}
- } else {
- ret = -EINVAL;
}
/* Insert any necessary delays */
@@ -1923,7 +2137,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
NULL);
- trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
+ trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
return ret;
}
@@ -2327,6 +2541,9 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
*/
ret = -EINVAL;
+ if (!rdev->desc->ops->set_mode)
+ goto out;
+
/* get output voltage */
output_uV = _regulator_get_voltage(rdev);
if (output_uV <= 0) {
@@ -2528,9 +2745,13 @@ int regulator_bulk_enable(int num_consumers,
int i;
int ret = 0;
- for (i = 0; i < num_consumers; i++)
- async_schedule_domain(regulator_bulk_enable_async,
- &consumers[i], &async_domain);
+ for (i = 0; i < num_consumers; i++) {
+ if (consumers[i].consumer->always_on)
+ consumers[i].ret = 0;
+ else
+ async_schedule_domain(regulator_bulk_enable_async,
+ &consumers[i], &async_domain);
+ }
async_synchronize_full_domain(&async_domain);
@@ -2569,7 +2790,7 @@ int regulator_bulk_disable(int num_consumers,
struct regulator_bulk_data *consumers)
{
int i;
- int ret;
+ int ret, r;
for (i = num_consumers - 1; i >= 0; --i) {
ret = regulator_disable(consumers[i].consumer);
@@ -2581,8 +2802,12 @@ int regulator_bulk_disable(int num_consumers,
err:
pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
- for (++i; i < num_consumers; ++i)
- regulator_enable(consumers[i].consumer);
+ for (++i; i < num_consumers; ++i) {
+ r = regulator_enable(consumers[i].consumer);
+ if (r != 0)
+ pr_err("Failed to reename %s: %d\n",
+ consumers[i].supply, r);
+ }
return ret;
}
@@ -2759,10 +2984,6 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
return status;
}
- /* suspend mode constraints need multiple supporting methods */
- if (!(ops->set_suspend_enable && ops->set_suspend_disable))
- return status;
-
status = device_create_file(dev, &dev_attr_suspend_standby_state);
if (status < 0)
return status;
@@ -2823,28 +3044,29 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
- * @dev: struct device for the regulator
- * @init_data: platform provided init data, passed through by driver
- * @driver_data: private regulator data
- * @of_node: OpenFirmware node to parse for device tree bindings (may be
- * NULL).
+ * @config: runtime configuration for regulator
*
* Called by regulator drivers to register a regulator.
* Returns 0 on success.
*/
-struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- struct device *dev, const struct regulator_init_data *init_data,
- void *driver_data, struct device_node *of_node)
+struct regulator_dev *
+regulator_register(const struct regulator_desc *regulator_desc,
+ const struct regulator_config *config)
{
const struct regulation_constraints *constraints = NULL;
+ const struct regulator_init_data *init_data;
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
+ struct device *dev;
int ret, i;
const char *supply = NULL;
- if (regulator_desc == NULL)
+ if (regulator_desc == NULL || config == NULL)
return ERR_PTR(-EINVAL);
+ dev = config->dev;
+ WARN_ON(!dev);
+
if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
return ERR_PTR(-EINVAL);
@@ -2868,6 +3090,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
return ERR_PTR(-EINVAL);
}
+ init_data = config->init_data;
+
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL)
return ERR_PTR(-ENOMEM);
@@ -2875,9 +3099,10 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
mutex_lock(&regulator_list_mutex);
mutex_init(&rdev->mutex);
- rdev->reg_data = driver_data;
+ rdev->reg_data = config->driver_data;
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
+ rdev->regmap = config->regmap;
INIT_LIST_HEAD(&rdev->consumer_list);
INIT_LIST_HEAD(&rdev->list);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
@@ -2892,7 +3117,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
/* register with sysfs */
rdev->dev.class = &regulator_class;
- rdev->dev.of_node = of_node;
+ rdev->dev.of_node = config->of_node;
rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(&regulator_no) - 1);
@@ -2925,7 +3150,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (supply) {
struct regulator_dev *r;
- r = regulator_dev_lookup(dev, supply);
+ r = regulator_dev_lookup(dev, supply, &ret);
if (!r) {
dev_err(dev, "Failed to find supply %s\n", supply);
@@ -2938,8 +3163,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
goto scrub;
/* Enable supply if rail is enabled */
- if (rdev->desc->ops->is_enabled &&
- rdev->desc->ops->is_enabled(rdev)) {
+ if (_regulator_is_enabled(rdev)) {
ret = regulator_enable(rdev->supply);
if (ret < 0)
goto scrub;
@@ -2971,6 +3195,8 @@ unset_supplies:
unset_regulator_supplies(rdev);
scrub:
+ if (rdev->supply)
+ regulator_put(rdev->supply);
kfree(rdev->constraints);
device_unregister(&rdev->dev);
/* device core frees rdev */
@@ -3069,7 +3295,7 @@ int regulator_suspend_finish(void)
goto unlock;
if (!ops->disable)
goto unlock;
- if (ops->is_enabled && !ops->is_enabled(rdev))
+ if (!_regulator_is_enabled(rdev))
goto unlock;
error = ops->disable(rdev);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 1851f09..1005f5f 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -76,9 +76,7 @@
struct da903x_regulator_info {
struct regulator_desc desc;
- int min_uV;
int max_uV;
- int step_uV;
int vol_reg;
int vol_shift;
int vol_nbits;
@@ -88,10 +86,6 @@ struct da903x_regulator_info {
int enable_bit;
};
-static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950,
- 2000, 2050, 2700, 2750, 2800, 2850,
- 2900, 2950, 3000, 3050 };
-
static inline struct device *to_da903x_dev(struct regulator_dev *rdev)
{
return rdev_get_dev(rdev)->parent->parent;
@@ -100,34 +94,26 @@ static inline struct device *to_da903x_dev(struct regulator_dev *rdev)
static inline int check_range(struct da903x_regulator_info *info,
int min_uV, int max_uV)
{
- if (min_uV < info->min_uV || min_uV > info->max_uV)
+ if (min_uV < info->desc.min_uV || min_uV > info->max_uV)
return -EINVAL;
return 0;
}
/* DA9030/DA9034 common operations */
-static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
uint8_t val, mask;
- if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
- return -EINVAL;
- }
-
- val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
- *selector = val;
- val <<= info->vol_shift;
+ val = selector << info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
return da903x_update(da9034_dev, info->vol_reg, val, mask);
}
-static int da903x_get_voltage(struct regulator_dev *rdev)
+static int da903x_get_voltage_sel(struct regulator_dev *rdev)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
@@ -141,7 +127,7 @@ static int da903x_get_voltage(struct regulator_dev *rdev)
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
val = (val & mask) >> info->vol_shift;
- return info->min_uV + info->step_uV * val;
+ return val;
}
static int da903x_enable(struct regulator_dev *rdev)
@@ -176,35 +162,16 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
return !!(reg_val & (1 << info->enable_bit));
}
-static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
- struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
-
- ret = info->min_uV + info->step_uV * selector;
- if (ret > info->max_uV)
- return -EINVAL;
- return ret;
-}
-
/* DA9030 specific operations */
-static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int da9030_set_ldo1_15_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da903x_dev = to_da903x_dev(rdev);
uint8_t val, mask;
int ret;
- if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
- return -EINVAL;
- }
-
- val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
- *selector = val;
- val <<= info->vol_shift;
+ val = selector << info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
mask |= DA9030_LDO_UNLOCK_MASK;
@@ -217,73 +184,57 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
return da903x_update(da903x_dev, info->vol_reg, val, mask);
}
-static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int da9030_map_ldo14_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- struct device *da903x_dev = to_da903x_dev(rdev);
- uint8_t val, mask;
- int thresh;
+ int thresh, sel;
if (check_range(info, min_uV, max_uV)) {
pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
- thresh = (info->max_uV + info->min_uV) / 2;
+ thresh = (info->max_uV + info->desc.min_uV) / 2;
if (min_uV < thresh) {
- val = DIV_ROUND_UP(thresh - min_uV, info->step_uV);
- val |= 0x4;
+ sel = DIV_ROUND_UP(thresh - min_uV, info->desc.uV_step);
+ sel |= 0x4;
} else {
- val = DIV_ROUND_UP(min_uV - thresh, info->step_uV);
+ sel = DIV_ROUND_UP(min_uV - thresh, info->desc.uV_step);
}
- *selector = val;
- val <<= info->vol_shift;
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
-
- return da903x_update(da903x_dev, info->vol_reg, val, mask);
+ return sel;
}
-static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+static int da9030_list_ldo14_voltage(struct regulator_dev *rdev,
+ unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- struct device *da903x_dev = to_da903x_dev(rdev);
- uint8_t val, mask;
- int ret;
+ int volt;
- ret = da903x_read(da903x_dev, info->vol_reg, &val);
- if (ret)
- return ret;
+ if (selector & 0x4)
+ volt = rdev->desc->min_uV +
+ rdev->desc->uV_step * (3 - (selector & ~0x4));
+ else
+ volt = (info->max_uV + rdev->desc->min_uV) / 2 +
+ rdev->desc->uV_step * (selector & ~0x4);
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
- val = (val & mask) >> info->vol_shift;
+ if (volt > info->max_uV)
+ return -EINVAL;
- if (val & 0x4)
- return info->min_uV + info->step_uV * (3 - (val & ~0x4));
- else
- return (info->max_uV + info->min_uV) / 2 +
- info->step_uV * (val & ~0x4);
+ return volt;
}
/* DA9034 specific operations */
-static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
uint8_t val, mask;
int ret;
- if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
- return -EINVAL;
- }
-
- val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
- *selector = val;
- val <<= info->vol_shift;
+ val = selector << info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
@@ -295,59 +246,45 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
return ret;
}
-static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int da9034_map_ldo12_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- struct device *da9034_dev = to_da903x_dev(rdev);
- uint8_t val, mask;
+ int sel;
if (check_range(info, min_uV, max_uV)) {
pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
- val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
- val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val);
- *selector = val;
- val <<= info->vol_shift;
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step);
+ sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel);
- return da903x_update(da9034_dev, info->vol_reg, val, mask);
+ return sel;
}
-static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
+ unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- struct device *da9034_dev = to_da903x_dev(rdev);
- uint8_t val, mask;
- int ret;
-
- ret = da903x_read(da9034_dev, info->vol_reg, &val);
- if (ret)
- return ret;
-
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
- val = (val & mask) >> info->vol_shift;
+ int volt;
- if (val >= 8)
- return 2700000 + info->step_uV * (val - 8);
-
- return info->min_uV + info->step_uV * val;
-}
+ if (selector >= 8)
+ volt = 2700000 + rdev->desc->uV_step * (selector - 8);
+ else
+ volt = rdev->desc->min_uV + rdev->desc->uV_step * selector;
-static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector >= ARRAY_SIZE(da9034_ldo12_data))
+ if (volt > info->max_uV)
return -EINVAL;
- return da9034_ldo12_data[selector] * 1000;
+
+ return volt;
}
static struct regulator_ops da903x_regulator_ldo_ops = {
- .set_voltage = da903x_set_ldo_voltage,
- .get_voltage = da903x_get_voltage,
- .list_voltage = da903x_list_voltage,
+ .set_voltage_sel = da903x_set_voltage_sel,
+ .get_voltage_sel = da903x_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -355,9 +292,10 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
/* NOTE: this is dedicated for the insane DA9030 LDO14 */
static struct regulator_ops da9030_regulator_ldo14_ops = {
- .set_voltage = da9030_set_ldo14_voltage,
- .get_voltage = da9030_get_ldo14_voltage,
- .list_voltage = da903x_list_voltage,
+ .set_voltage_sel = da903x_set_voltage_sel,
+ .get_voltage_sel = da903x_get_voltage_sel,
+ .list_voltage = da9030_list_ldo14_voltage,
+ .map_voltage = da9030_map_ldo14_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -365,18 +303,20 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */
static struct regulator_ops da9030_regulator_ldo1_15_ops = {
- .set_voltage = da9030_set_ldo1_15_voltage,
- .get_voltage = da903x_get_voltage,
- .list_voltage = da903x_list_voltage,
+ .set_voltage_sel = da9030_set_ldo1_15_voltage_sel,
+ .get_voltage_sel = da903x_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
};
static struct regulator_ops da9034_regulator_dvc_ops = {
- .set_voltage = da9034_set_dvc_voltage,
- .get_voltage = da903x_get_voltage,
- .list_voltage = da903x_list_voltage,
+ .set_voltage_sel = da9034_set_dvc_voltage_sel,
+ .get_voltage_sel = da903x_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -384,9 +324,10 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
/* NOTE: this is dedicated for the insane LDO12 */
static struct regulator_ops da9034_regulator_ldo12_ops = {
- .set_voltage = da9034_set_ldo12_voltage,
- .get_voltage = da9034_get_ldo12_voltage,
+ .set_voltage_sel = da903x_set_voltage_sel,
+ .get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = da9034_list_ldo12_voltage,
+ .map_voltage = da9034_map_ldo12_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -401,10 +342,10 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.id = _pmic##_ID_LDO##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
+ .min_uV = (min) * 1000, \
+ .uV_step = (step) * 1000, \
}, \
- .min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \
- .step_uV = (step) * 1000, \
.vol_reg = _pmic##_##vreg, \
.vol_shift = (shift), \
.vol_nbits = (nbits), \
@@ -421,10 +362,10 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.id = _pmic##_ID_##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
+ .min_uV = (min) * 1000, \
+ .uV_step = (step) * 1000, \
}, \
- .min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \
- .step_uV = (step) * 1000, \
.vol_reg = _pmic##_##vreg, \
.vol_shift = (0), \
.vol_nbits = (nbits), \
@@ -517,6 +458,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
{
struct da903x_regulator_info *ri = NULL;
struct regulator_dev *rdev;
+ struct regulator_config config = { };
ri = find_regulator_info(pdev->id);
if (ri == NULL) {
@@ -527,7 +469,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
/* Workaround for the weird LDO12 voltage setting */
if (ri->desc.id == DA9034_ID_LDO12) {
ri->desc.ops = &da9034_regulator_ldo12_ops;
- ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data);
+ ri->desc.n_voltages = 16;
}
if (ri->desc.id == DA9030_ID_LDO14)
@@ -536,8 +478,11 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
ri->desc.ops = &da9030_regulator_ldo1_15_ops;
- rdev = regulator_register(&ri->desc, &pdev->dev,
- pdev->dev.platform_data, ri, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = ri;
+
+ rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 09915e8..88976d8 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -19,6 +19,10 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+#endif
#include <linux/mfd/da9052/da9052.h>
#include <linux/mfd/da9052/reg.h>
@@ -37,6 +41,22 @@
#define DA9052_BUCK_ILIM_MASK_EVEN 0x0c
#define DA9052_BUCK_ILIM_MASK_ODD 0xc0
+/* DA9052 REGULATOR IDs */
+#define DA9052_ID_BUCK1 0
+#define DA9052_ID_BUCK2 1
+#define DA9052_ID_BUCK3 2
+#define DA9052_ID_BUCK4 3
+#define DA9052_ID_LDO1 4
+#define DA9052_ID_LDO2 5
+#define DA9052_ID_LDO3 6
+#define DA9052_ID_LDO4 7
+#define DA9052_ID_LDO5 8
+#define DA9052_ID_LDO6 9
+#define DA9052_ID_LDO7 10
+#define DA9052_ID_LDO8 11
+#define DA9052_ID_LDO9 12
+#define DA9052_ID_LDO10 13
+
static const u32 da9052_current_limits[3][4] = {
{700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */
{1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */
@@ -50,8 +70,6 @@ struct da9052_regulator_info {
int step_uV;
int min_uV;
int max_uV;
- unsigned char volt_shift;
- unsigned char en_bit;
unsigned char activate_bit;
};
@@ -70,42 +88,6 @@ static int verify_range(struct da9052_regulator_info *info,
return 0;
}
-static int da9052_regulator_enable(struct regulator_dev *rdev)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
-
- return da9052_reg_update(regulator->da9052,
- DA9052_BUCKCORE_REG + offset,
- 1 << info->en_bit, 1 << info->en_bit);
-}
-
-static int da9052_regulator_disable(struct regulator_dev *rdev)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
-
- return da9052_reg_update(regulator->da9052,
- DA9052_BUCKCORE_REG + offset,
- 1 << info->en_bit, 0);
-}
-
-static int da9052_regulator_is_enabled(struct regulator_dev *rdev)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
- int ret;
-
- ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
- if (ret < 0)
- return ret;
-
- return ret & (1 << info->en_bit);
-}
-
static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)
{
struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
@@ -173,36 +155,23 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,
reg_val << 6);
}
-static int da9052_list_buckperi_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int volt_uV;
-
- if ((regulator->da9052->chip_id == DA9052) &&
- (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {
- volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)
- + info->min_uV);
- volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)
- * (DA9052_BUCK_PERI_3uV_STEP);
- } else
- volt_uV = (selector * info->step_uV) + info->min_uV;
-
- if (volt_uV > info->max_uV)
- return -EINVAL;
-
- return volt_uV;
-}
-
static int da9052_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
struct da9052_regulator_info *info = regulator->info;
+ int id = rdev_get_id(rdev);
int volt_uV;
- volt_uV = info->min_uV + info->step_uV * selector;
+ if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
+ && (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {
+ volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)
+ + info->min_uV);
+ volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)
+ * (DA9052_BUCK_PERI_3uV_STEP);
+ } else {
+ volt_uV = (selector * info->step_uV) + info->min_uV;
+ }
if (volt_uV > info->max_uV)
return -EINVAL;
@@ -210,103 +179,13 @@ static int da9052_list_voltage(struct regulator_dev *rdev,
return volt_uV;
}
-static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned int *selector)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
- int ret;
-
- ret = verify_range(info, min_uV, max_uV);
- if (ret < 0)
- return ret;
-
- if (min_uV < info->min_uV)
- min_uV = info->min_uV;
-
- *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
-
- ret = da9052_list_voltage(rdev, *selector);
- if (ret < 0)
- return ret;
-
- return da9052_reg_update(regulator->da9052,
- DA9052_BUCKCORE_REG + offset,
- (1 << info->volt_shift) - 1, *selector);
-}
-
-static int da9052_set_ldo_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned int *selector)
-{
- return da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
-}
-
-static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned int *selector)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int ret;
-
- ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
- if (ret < 0)
- return ret;
-
- /* Some LDOs are DVC controlled which requires enabling of
- * the LDO activate bit to implment the changes on the
- * LDO output.
- */
- return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
- info->activate_bit, info->activate_bit);
-}
-
-static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned int *selector)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int ret;
-
- ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
- if (ret < 0)
- return ret;
-
- /* Some DCDCs are DVC controlled which requires enabling of
- * the DCDC activate bit to implment the changes on the
- * DCDC output.
- */
- return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
- info->activate_bit, info->activate_bit);
-}
-
-static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
- int ret;
-
- ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
- if (ret < 0)
- return ret;
-
- ret &= ((1 << info->volt_shift) - 1);
-
- return ret;
-}
-
-static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned int *selector)
+static int da9052_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
- int ret;
+ int id = rdev_get_id(rdev);
+ int ret, sel;
ret = verify_range(info, min_uV, max_uV);
if (ret < 0)
@@ -315,192 +194,147 @@ static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV,
if (min_uV < info->min_uV)
min_uV = info->min_uV;
- if ((regulator->da9052->chip_id == DA9052) &&
- (min_uV >= DA9052_CONST_3uV))
- *selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
- DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
- DA9052_BUCK_PERI_3uV_STEP);
- else
- *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+ if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
+ && (min_uV >= DA9052_CONST_3uV)) {
+ sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
+ DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
+ DA9052_BUCK_PERI_3uV_STEP);
+ } else {
+ sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+ }
- ret = da9052_list_buckperi_voltage(rdev, *selector);
+ ret = da9052_list_voltage(rdev, sel);
if (ret < 0)
return ret;
- return da9052_reg_update(regulator->da9052,
- DA9052_BUCKCORE_REG + offset,
- (1 << info->volt_shift) - 1, *selector);
+ return sel;
}
-static int da9052_get_buckperi_voltage_sel(struct regulator_dev *rdev)
+static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
struct da9052_regulator_info *info = regulator->info;
- int offset = rdev_get_id(rdev);
+ int id = rdev_get_id(rdev);
int ret;
- ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
+ ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, selector);
if (ret < 0)
return ret;
- ret &= ((1 << info->volt_shift) - 1);
+ /* Some LDOs and DCDCs are DVC controlled which requires enabling of
+ * the activate bit to implment the changes on the output.
+ */
+ switch (id) {
+ case DA9052_ID_BUCK1:
+ case DA9052_ID_BUCK2:
+ case DA9052_ID_BUCK3:
+ case DA9052_ID_LDO2:
+ case DA9052_ID_LDO3:
+ ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+ info->activate_bit, info->activate_bit);
+ break;
+ }
return ret;
}
-static struct regulator_ops da9052_buckperi_ops = {
- .list_voltage = da9052_list_buckperi_voltage,
- .get_voltage_sel = da9052_get_buckperi_voltage_sel,
- .set_voltage = da9052_set_buckperi_voltage,
-
- .get_current_limit = da9052_dcdc_get_current_limit,
- .set_current_limit = da9052_dcdc_set_current_limit,
-
- .is_enabled = da9052_regulator_is_enabled,
- .enable = da9052_regulator_enable,
- .disable = da9052_regulator_disable,
-};
-
static struct regulator_ops da9052_dcdc_ops = {
- .set_voltage = da9052_set_dcdc_voltage,
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
.list_voltage = da9052_list_voltage,
- .get_voltage_sel = da9052_get_regulator_voltage_sel,
- .is_enabled = da9052_regulator_is_enabled,
- .enable = da9052_regulator_enable,
- .disable = da9052_regulator_disable,
-};
-
-static struct regulator_ops da9052_ldo5_6_ops = {
- .set_voltage = da9052_set_ldo5_6_voltage,
-
- .list_voltage = da9052_list_voltage,
- .get_voltage_sel = da9052_get_regulator_voltage_sel,
- .is_enabled = da9052_regulator_is_enabled,
- .enable = da9052_regulator_enable,
- .disable = da9052_regulator_disable,
+ .map_voltage = da9052_map_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
static struct regulator_ops da9052_ldo_ops = {
- .set_voltage = da9052_set_ldo_voltage,
-
.list_voltage = da9052_list_voltage,
- .get_voltage_sel = da9052_get_regulator_voltage_sel,
- .is_enabled = da9052_regulator_is_enabled,
- .enable = da9052_regulator_enable,
- .disable = da9052_regulator_disable,
+ .map_voltage = da9052_map_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
-#define DA9052_LDO5_6(_id, step, min, max, sbits, ebits, abits) \
-{\
- .reg_desc = {\
- .name = "LDO" #_id,\
- .ops = &da9052_ldo5_6_ops,\
- .type = REGULATOR_VOLTAGE,\
- .id = _id,\
- .n_voltages = (max - min) / step + 1, \
- .owner = THIS_MODULE,\
- },\
- .min_uV = (min) * 1000,\
- .max_uV = (max) * 1000,\
- .step_uV = (step) * 1000,\
- .volt_shift = (sbits),\
- .en_bit = (ebits),\
- .activate_bit = (abits),\
-}
-
#define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \
{\
.reg_desc = {\
- .name = "LDO" #_id,\
+ .name = #_id,\
.ops = &da9052_ldo_ops,\
.type = REGULATOR_VOLTAGE,\
- .id = _id,\
+ .id = DA9052_ID_##_id,\
.n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
+ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
+ .vsel_mask = (1 << (sbits)) - 1,\
+ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
+ .enable_mask = 1 << (ebits),\
},\
.min_uV = (min) * 1000,\
.max_uV = (max) * 1000,\
.step_uV = (step) * 1000,\
- .volt_shift = (sbits),\
- .en_bit = (ebits),\
.activate_bit = (abits),\
}
#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
{\
.reg_desc = {\
- .name = "BUCK" #_id,\
+ .name = #_id,\
.ops = &da9052_dcdc_ops,\
.type = REGULATOR_VOLTAGE,\
- .id = _id,\
+ .id = DA9052_ID_##_id,\
.n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
+ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
+ .vsel_mask = (1 << (sbits)) - 1,\
+ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
+ .enable_mask = 1 << (ebits),\
},\
.min_uV = (min) * 1000,\
.max_uV = (max) * 1000,\
.step_uV = (step) * 1000,\
- .volt_shift = (sbits),\
- .en_bit = (ebits),\
- .activate_bit = (abits),\
-}
-
-#define DA9052_BUCKPERI(_id, step, min, max, sbits, ebits, abits) \
-{\
- .reg_desc = {\
- .name = "BUCK" #_id,\
- .ops = &da9052_buckperi_ops,\
- .type = REGULATOR_VOLTAGE,\
- .id = _id,\
- .n_voltages = (max - min) / step + 1, \
- .owner = THIS_MODULE,\
- },\
- .min_uV = (min) * 1000,\
- .max_uV = (max) * 1000,\
- .step_uV = (step) * 1000,\
- .volt_shift = (sbits),\
- .en_bit = (ebits),\
.activate_bit = (abits),\
}
static struct da9052_regulator_info da9052_regulator_info[] = {
- /* Buck1 - 4 */
- DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
- DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
- DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
- DA9052_BUCKPERI(3, 50, 1800, 3600, 5, 6, 0),
- /* LD01 - LDO10 */
- DA9052_LDO(4, 50, 600, 1800, 5, 6, 0),
- DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
- DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
- DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0),
- DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0),
- DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0),
+ DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
+ DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
+ DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
+ DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0),
+ DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0),
+ DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
+ DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
+ DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0),
+ DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0),
+ DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0),
};
static struct da9052_regulator_info da9053_regulator_info[] = {
- /* Buck1 - 4 */
- DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
- DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
- DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
- DA9052_BUCKPERI(3, 25, 925, 2500, 6, 6, 0),
- /* LD01 - LDO10 */
- DA9052_LDO(4, 50, 600, 1800, 5, 6, 0),
- DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
- DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
- DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0),
- DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0),
- DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0),
- DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0),
+ DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
+ DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
+ DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
+ DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0),
+ DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0),
+ DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
+ DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
+ DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0),
+ DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0),
+ DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0),
+ DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0),
};
static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
@@ -533,10 +367,10 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
static int __devinit da9052_regulator_probe(struct platform_device *pdev)
{
+ struct regulator_config config = { };
struct da9052_regulator *regulator;
struct da9052 *da9052;
struct da9052_pdata *pdata;
- int ret;
regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),
GFP_KERNEL);
@@ -551,26 +385,49 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev)
pdev->id);
if (regulator->info == NULL) {
dev_err(&pdev->dev, "invalid regulator ID specified\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
+
+ config.dev = &pdev->dev;
+ config.driver_data = regulator;
+ config.regmap = da9052->regmap;
+ if (pdata && pdata->regulators) {
+ config.init_data = pdata->regulators[pdev->id];
+ } else {
+#ifdef CONFIG_OF
+ struct device_node *nproot = da9052->dev->of_node;
+ struct device_node *np;
+
+ if (!nproot)
+ return -ENODEV;
+
+ nproot = of_find_node_by_name(nproot, "regulators");
+ if (!nproot)
+ return -ENODEV;
+
+ for (np = of_get_next_child(nproot, NULL); np;
+ np = of_get_next_child(nproot, np)) {
+ if (!of_node_cmp(np->name,
+ regulator->info->reg_desc.name)) {
+ config.init_data = of_get_regulator_init_data(
+ &pdev->dev, np);
+ break;
+ }
+ }
+#endif
+ }
+
regulator->rdev = regulator_register(&regulator->info->reg_desc,
- &pdev->dev,
- pdata->regulators[pdev->id],
- regulator, NULL);
+ &config);
if (IS_ERR(regulator->rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
regulator->info->reg_desc.name);
- ret = PTR_ERR(regulator->rdev);
- goto err;
+ return PTR_ERR(regulator->rdev);
}
platform_set_drvdata(pdev, regulator);
return 0;
-err:
- devm_kfree(&pdev->dev, regulator);
- return ret;
}
static int __devexit da9052_regulator_remove(struct platform_device *pdev)
@@ -578,8 +435,6 @@ static int __devexit da9052_regulator_remove(struct platform_device *pdev)
struct da9052_regulator *regulator = platform_get_drvdata(pdev);
regulator_unregister(regulator->rdev);
- devm_kfree(&pdev->dev, regulator);
-
return 0;
}
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 4bd25e7..968f97f 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -17,6 +17,8 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
#include <linux/module.h>
#include "dbx500-prcmu.h"
@@ -410,45 +412,120 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
},
};
+static __devinit int db8500_regulator_register(struct platform_device *pdev,
+ struct regulator_init_data *init_data,
+ int id,
+ struct device_node *np)
+{
+ struct dbx500_regulator_info *info;
+ struct regulator_config config = { };
+ int err;
+
+ /* assign per-regulator data */
+ info = &dbx500_regulator_info[id];
+ info->dev = &pdev->dev;
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = info;
+ config.of_node = np;
+
+ /* register with the regulator framework */
+ info->rdev = regulator_register(&info->desc, &config);
+ if (IS_ERR(info->rdev)) {
+ err = PTR_ERR(info->rdev);
+ dev_err(&pdev->dev, "failed to register %s: err %i\n",
+ info->desc.name, err);
+
+ /* if failing, unregister all earlier regulators */
+ while (--id >= 0) {
+ info = &dbx500_regulator_info[id];
+ regulator_unregister(info->rdev);
+ }
+ return err;
+ }
+
+ dev_dbg(rdev_get_dev(info->rdev),
+ "regulator-%s-probed\n", info->desc.name);
+
+ return 0;
+}
+
+static struct of_regulator_match db8500_regulator_matches[] = {
+ { .name = "db8500-vape", .driver_data = (void *) DB8500_REGULATOR_VAPE, },
+ { .name = "db8500-varm", .driver_data = (void *) DB8500_REGULATOR_VARM, },
+ { .name = "db8500-vmodem", .driver_data = (void *) DB8500_REGULATOR_VMODEM, },
+ { .name = "db8500-vpll", .driver_data = (void *) DB8500_REGULATOR_VPLL, },
+ { .name = "db8500-vsmps1", .driver_data = (void *) DB8500_REGULATOR_VSMPS1, },
+ { .name = "db8500-vsmps2", .driver_data = (void *) DB8500_REGULATOR_VSMPS2, },
+ { .name = "db8500-vsmps3", .driver_data = (void *) DB8500_REGULATOR_VSMPS3, },
+ { .name = "db8500-vrf1", .driver_data = (void *) DB8500_REGULATOR_VRF1, },
+ { .name = "db8500-sva-mmdsp", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAMMDSP, },
+ { .name = "db8500-sva-mmdsp-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAMMDSPRET, },
+ { .name = "db8500-sva-pipe", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAPIPE, },
+ { .name = "db8500-sia-mmdsp", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAMMDSP, },
+ { .name = "db8500-sia-mmdsp-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAMMDSPRET, },
+ { .name = "db8500-sia-pipe", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAPIPE, },
+ { .name = "db8500-sga", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SGA, },
+ { .name = "db8500-b2r2-mcde", .driver_data = (void *) DB8500_REGULATOR_SWITCH_B2R2_MCDE, },
+ { .name = "db8500-esram12", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM12, },
+ { .name = "db8500-esram12-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM12RET, },
+ { .name = "db8500-esram34", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34, },
+ { .name = "db8500-esram34-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34RET, },
+};
+
+static __devinit int
+db8500_regulator_of_probe(struct platform_device *pdev,
+ struct device_node *np)
+{
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+ err = db8500_regulator_register(
+ pdev, db8500_regulator_matches[i].init_data,
+ i, db8500_regulator_matches[i].of_node);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int __devinit db8500_regulator_probe(struct platform_device *pdev)
{
struct regulator_init_data *db8500_init_data =
dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
int i, err;
/* register all regulators */
- for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
- struct dbx500_regulator_info *info;
- struct regulator_init_data *init_data = &db8500_init_data[i];
-
- /* assign per-regulator data */
- info = &dbx500_regulator_info[i];
- info->dev = &pdev->dev;
-
- /* register with the regulator framework */
- info->rdev = regulator_register(&info->desc, &pdev->dev,
- init_data, info, NULL);
- if (IS_ERR(info->rdev)) {
- err = PTR_ERR(info->rdev);
- dev_err(&pdev->dev, "failed to register %s: err %i\n",
- info->desc.name, err);
-
- /* if failing, unregister all earlier regulators */
- while (--i >= 0) {
- info = &dbx500_regulator_info[i];
- regulator_unregister(info->rdev);
- }
+ if (np) {
+ err = of_regulator_match(&pdev->dev, np,
+ db8500_regulator_matches,
+ ARRAY_SIZE(db8500_regulator_matches));
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Error parsing regulator init data: %d\n", err);
return err;
}
- dev_dbg(rdev_get_dev(info->rdev),
- "regulator-%s-probed\n", info->desc.name);
+ err = db8500_regulator_of_probe(pdev, np);
+ if (err)
+ return err;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+ err = db8500_regulator_register(pdev,
+ &db8500_init_data[i],
+ i, NULL);
+ if (err)
+ return err;
+ }
}
+
err = ux500_regulator_debug_init(pdev,
dbx500_regulator_info,
ARRAY_SIZE(dbx500_regulator_info));
-
- return err;
+ return 0;
}
static int __exit db8500_regulator_remove(struct platform_device *pdev)
@@ -470,10 +547,16 @@ static int __exit db8500_regulator_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id db8500_prcmu_regulator_match[] = {
+ { .compatible = "stericsson,db8500-prcmu-regulator", },
+ {}
+};
+
static struct platform_driver db8500_regulator_driver = {
.driver = {
.name = "db8500-prcmu-regulators",
.owner = THIS_MODULE,
+ .of_match_table = db8500_prcmu_regulator_match,
},
.probe = db8500_regulator_probe,
.remove = __exit_p(db8500_regulator_remove),
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index 0ee00de..86f655c 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -39,10 +39,13 @@ static struct regulator_desc dummy_desc = {
static int __devinit dummy_regulator_probe(struct platform_device *pdev)
{
+ struct regulator_config config = { };
int ret;
- dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
- &dummy_initdata, NULL, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = &dummy_initdata;
+
+ dummy_regulator_rdev = regulator_register(&dummy_desc, &config);
if (IS_ERR(dummy_regulator_rdev)) {
ret = PTR_ERR(dummy_regulator_rdev);
pr_err("Failed to register regulator: %d\n", ret);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 40f3803..f09fe7b 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -25,7 +25,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
#include <linux/gpio.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
@@ -91,6 +90,9 @@ of_get_fixed_voltage_config(struct device *dev)
if (of_find_property(np, "enable-active-high", NULL))
config->enable_high = true;
+ if (of_find_property(np, "gpio-open-drain", NULL))
+ config->gpio_is_open_drain = true;
+
return config;
}
@@ -105,10 +107,8 @@ static int fixed_voltage_enable(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
- if (gpio_is_valid(data->gpio)) {
- gpio_set_value_cansleep(data->gpio, data->enable_high);
- data->is_enabled = true;
- }
+ gpio_set_value_cansleep(data->gpio, data->enable_high);
+ data->is_enabled = true;
return 0;
}
@@ -117,10 +117,8 @@ static int fixed_voltage_disable(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
- if (gpio_is_valid(data->gpio)) {
- gpio_set_value_cansleep(data->gpio, !data->enable_high);
- data->is_enabled = false;
- }
+ gpio_set_value_cansleep(data->gpio, !data->enable_high);
+ data->is_enabled = false;
return 0;
}
@@ -153,7 +151,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
return data->microvolts;
}
-static struct regulator_ops fixed_voltage_ops = {
+static struct regulator_ops fixed_voltage_gpio_ops = {
.is_enabled = fixed_voltage_is_enabled,
.enable = fixed_voltage_enable,
.disable = fixed_voltage_disable,
@@ -162,10 +160,16 @@ static struct regulator_ops fixed_voltage_ops = {
.list_voltage = fixed_voltage_list_voltage,
};
+static struct regulator_ops fixed_voltage_ops = {
+ .get_voltage = fixed_voltage_get_voltage,
+ .list_voltage = fixed_voltage_list_voltage,
+};
+
static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
{
struct fixed_voltage_config *config;
struct fixed_voltage_data *drvdata;
+ struct regulator_config cfg = { };
int ret;
if (pdev->dev.of_node)
@@ -176,7 +180,8 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
if (!config)
return -ENOMEM;
- drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
+ GFP_KERNEL);
if (drvdata == NULL) {
dev_err(&pdev->dev, "Failed to allocate device data\n");
ret = -ENOMEM;
@@ -191,7 +196,6 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
- drvdata->desc.ops = &fixed_voltage_ops;
if (config->microvolts)
drvdata->desc.n_voltages = 1;
@@ -201,6 +205,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->startup_delay = config->startup_delay;
if (gpio_is_valid(config->gpio)) {
+ int gpio_flag;
drvdata->enable_high = config->enable_high;
/* FIXME: Remove below print warning
@@ -218,39 +223,39 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
dev_warn(&pdev->dev,
"using GPIO 0 for regulator enable control\n");
- ret = gpio_request(config->gpio, config->supply_name);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not obtain regulator enable GPIO %d: %d\n",
- config->gpio, ret);
- goto err_name;
- }
-
- /* set output direction without changing state
+ /*
+ * set output direction without changing state
* to prevent glitch
*/
drvdata->is_enabled = config->enabled_at_boot;
ret = drvdata->is_enabled ?
config->enable_high : !config->enable_high;
+ gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+
+ if (config->gpio_is_open_drain)
+ gpio_flag |= GPIOF_OPEN_DRAIN;
- ret = gpio_direction_output(config->gpio, ret);
+ ret = gpio_request_one(config->gpio, gpio_flag,
+ config->supply_name);
if (ret) {
dev_err(&pdev->dev,
- "Could not configure regulator enable GPIO %d direction: %d\n",
+ "Could not obtain regulator enable GPIO %d: %d\n",
config->gpio, ret);
- goto err_gpio;
+ goto err_name;
}
+ drvdata->desc.ops = &fixed_voltage_gpio_ops;
+
} else {
- /* Regulator without GPIO control is considered
- * always enabled
- */
- drvdata->is_enabled = true;
+ drvdata->desc.ops = &fixed_voltage_ops;
}
- drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
- config->init_data, drvdata,
- pdev->dev.of_node);
+ cfg.dev = &pdev->dev;
+ cfg.init_data = config->init_data;
+ cfg.driver_data = drvdata;
+ cfg.of_node = pdev->dev.of_node;
+
+ drvdata->dev = regulator_register(&drvdata->desc, &cfg);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
@@ -270,7 +275,6 @@ err_gpio:
err_name:
kfree(drvdata->desc.name);
err:
- kfree(drvdata);
return ret;
}
@@ -282,7 +286,6 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
if (gpio_is_valid(drvdata->gpio))
gpio_free(drvdata->gpio);
kfree(drvdata->desc.name);
- kfree(drvdata);
return 0;
}
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 42e1cb1..9997d7a 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -30,7 +30,6 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/gpio-regulator.h>
#include <linux/gpio.h>
-#include <linux/delay.h>
#include <linux/slab.h>
struct gpio_regulator_data {
@@ -105,15 +104,15 @@ static int gpio_regulator_set_value(struct regulator_dev *dev,
int min, int max)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
- int ptr, target, state;
+ int ptr, target, state, best_val = INT_MAX;
- target = -1;
for (ptr = 0; ptr < data->nr_states; ptr++)
- if (data->states[ptr].value >= min &&
+ if (data->states[ptr].value < best_val &&
+ data->states[ptr].value >= min &&
data->states[ptr].value <= max)
target = data->states[ptr].gpios;
- if (target < 0)
+ if (best_val == INT_MAX)
return -EINVAL;
for (ptr = 0; ptr < data->nr_gpios; ptr++) {
@@ -172,9 +171,11 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
{
struct gpio_regulator_config *config = pdev->dev.platform_data;
struct gpio_regulator_data *drvdata;
+ struct regulator_config cfg = { };
int ptr, ret, state;
- drvdata = kzalloc(sizeof(struct gpio_regulator_data), GFP_KERNEL);
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
+ GFP_KERNEL);
if (drvdata == NULL) {
dev_err(&pdev->dev, "Failed to allocate device data\n");
return -ENOMEM;
@@ -283,8 +284,11 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
}
drvdata->state = state;
- drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
- config->init_data, drvdata, NULL);
+ cfg.dev = &pdev->dev;
+ cfg.init_data = config->init_data;
+ cfg.driver_data = &drvdata;
+
+ drvdata->dev = regulator_register(&drvdata->desc, &cfg);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
@@ -307,7 +311,6 @@ err_memgpio:
err_name:
kfree(drvdata->desc.name);
err:
- kfree(drvdata);
return ret;
}
@@ -326,7 +329,6 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev)
gpio_free(drvdata->enable_gpio);
kfree(drvdata->desc.name);
- kfree(drvdata);
return 0;
}
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index 775f5fd..56d273f 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#define ISL6271A_VOLTAGE_MIN 850000
@@ -36,47 +35,30 @@ struct isl_pmic {
struct mutex mtx;
};
-static int isl6271a_get_voltage(struct regulator_dev *dev)
+static int isl6271a_get_voltage_sel(struct regulator_dev *dev)
{
struct isl_pmic *pmic = rdev_get_drvdata(dev);
- int idx, data;
+ int idx;
mutex_lock(&pmic->mtx);
idx = i2c_smbus_read_byte(pmic->client);
- if (idx < 0) {
+ if (idx < 0)
dev_err(&pmic->client->dev, "Error getting voltage\n");
- data = idx;
- goto out;
- }
-
- /* Convert the data from chip to microvolts */
- data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf));
-out:
mutex_unlock(&pmic->mtx);
- return data;
+ return idx;
}
-static int isl6271a_set_voltage(struct regulator_dev *dev,
- int minuV, int maxuV,
- unsigned *selector)
+static int isl6271a_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
{
struct isl_pmic *pmic = rdev_get_drvdata(dev);
- int err, data;
-
- if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX)
- return -EINVAL;
- if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX)
- return -EINVAL;
-
- data = DIV_ROUND_UP(minuV - ISL6271A_VOLTAGE_MIN,
- ISL6271A_VOLTAGE_STEP);
- *selector = data;
+ int err;
mutex_lock(&pmic->mtx);
- err = i2c_smbus_write_byte(pmic->client, data);
+ err = i2c_smbus_write_byte(pmic->client, selector);
if (err < 0)
dev_err(&pmic->client->dev, "Error setting voltage\n");
@@ -84,15 +66,11 @@ static int isl6271a_set_voltage(struct regulator_dev *dev,
return err;
}
-static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector)
-{
- return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector);
-}
-
static struct regulator_ops isl_core_ops = {
- .get_voltage = isl6271a_get_voltage,
- .set_voltage = isl6271a_set_voltage,
- .list_voltage = isl6271a_list_voltage,
+ .get_voltage_sel = isl6271a_get_voltage_sel,
+ .set_voltage_sel = isl6271a_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
};
static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
@@ -112,7 +90,7 @@ static struct regulator_ops isl_fixed_ops = {
.list_voltage = isl6271a_list_fixed_voltage,
};
-static struct regulator_desc isl_rd[] = {
+static const struct regulator_desc isl_rd[] = {
{
.name = "Core Buck",
.id = 0,
@@ -120,6 +98,8 @@ static struct regulator_desc isl_rd[] = {
.ops = &isl_core_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = ISL6271A_VOLTAGE_MIN,
+ .uV_step = ISL6271A_VOLTAGE_STEP,
}, {
.name = "LDO1",
.id = 1,
@@ -140,6 +120,7 @@ static struct regulator_desc isl_rd[] = {
static int __devinit isl6271a_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ struct regulator_config config = { };
struct regulator_init_data *init_data = i2c->dev.platform_data;
struct isl_pmic *pmic;
int err, i;
@@ -147,12 +128,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c,
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- if (!init_data) {
- dev_err(&i2c->dev, "no platform data supplied\n");
- return -EIO;
- }
-
- pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL);
+ pmic = devm_kzalloc(&i2c->dev, sizeof(struct isl_pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
@@ -161,8 +137,14 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c,
mutex_init(&pmic->mtx);
for (i = 0; i < 3; i++) {
- pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
- init_data, pmic, NULL);
+ config.dev = &i2c->dev;
+ if (i == 0)
+ config.init_data = init_data;
+ else
+ config.init_data = 0;
+ config.driver_data = pmic;
+
+ pmic->rdev[i] = regulator_register(&isl_rd[i], &config);
if (IS_ERR(pmic->rdev[i])) {
dev_err(&i2c->dev, "failed to register %s\n", id->name);
err = PTR_ERR(pmic->rdev[i]);
@@ -177,8 +159,6 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c,
error:
while (--i >= 0)
regulator_unregister(pmic->rdev[i]);
-
- kfree(pmic);
return err;
}
@@ -189,9 +169,6 @@ static int __devexit isl6271a_remove(struct i2c_client *i2c)
for (i = 0; i < 3; i++)
regulator_unregister(pmic->rdev[i]);
-
- kfree(pmic);
-
return 0;
}
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 0cfabd3..981bea9 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -124,6 +124,10 @@ static const int *ldo_voltage_map[] = {
static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
{
int ldo = rdev_get_id(dev) - LP3971_LDO1;
+
+ if (index > LDO_VOL_MAX_IDX)
+ return -EINVAL;
+
return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
}
@@ -168,32 +172,15 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
}
-static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV,
- unsigned int *selector)
+static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
+ unsigned int selector)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const int *vol_map = LDO_VOL_VALUE_MAP(ldo);
- u16 val;
-
- if (min_vol < vol_map[LDO_VOL_MIN_IDX] ||
- min_vol > vol_map[LDO_VOL_MAX_IDX])
- return -EINVAL;
-
- for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++)
- if (vol_map[val] >= min_vol)
- break;
-
- if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol)
- return -EINVAL;
-
- *selector = val;
return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
- val << LDO_VOL_CONTR_SHIFT(ldo));
+ selector << LDO_VOL_CONTR_SHIFT(ldo));
}
static struct regulator_ops lp3971_ldo_ops = {
@@ -202,11 +189,14 @@ static struct regulator_ops lp3971_ldo_ops = {
.enable = lp3971_ldo_enable,
.disable = lp3971_ldo_disable,
.get_voltage = lp3971_ldo_get_voltage,
- .set_voltage = lp3971_ldo_set_voltage,
+ .set_voltage_sel = lp3971_ldo_set_voltage_sel,
};
static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
{
+ if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX)
+ return -EINVAL;
+
return 1000 * buck_voltage_map[index];
}
@@ -259,33 +249,15 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
return val;
}
-static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV,
- unsigned int *selector)
+static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
+ unsigned int selector)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const int *vol_map = buck_voltage_map;
- u16 val;
int ret;
- if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] ||
- min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX])
- return -EINVAL;
-
- for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX;
- val++)
- if (vol_map[val] >= min_vol)
- break;
-
- if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol)
- return -EINVAL;
-
- *selector = val;
-
ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
- BUCK_TARGET_VOL_MASK, val);
+ BUCK_TARGET_VOL_MASK, selector);
if (ret)
return ret;
@@ -306,10 +278,10 @@ static struct regulator_ops lp3971_dcdc_ops = {
.enable = lp3971_dcdc_enable,
.disable = lp3971_dcdc_disable,
.get_voltage = lp3971_dcdc_get_voltage,
- .set_voltage = lp3971_dcdc_set_voltage,
+ .set_voltage_sel = lp3971_dcdc_set_voltage_sel,
};
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
{
.name = "LDO1",
.id = LP3971_LDO1,
@@ -449,10 +421,15 @@ static int __devinit setup_regulators(struct lp3971 *lp3971,
/* Instantiate the regulators */
for (i = 0; i < pdata->num_regulators; i++) {
+ struct regulator_config config = { };
struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
- lp3971->rdev[i] = regulator_register(&regulators[reg->id],
- lp3971->dev, reg->initdata, lp3971, NULL);
+ config.dev = lp3971->dev;
+ config.init_data = reg->initdata;
+ config.driver_data = lp3971;
+
+ lp3971->rdev[i] = regulator_register(&regulators[reg->id],
+ &config);
if (IS_ERR(lp3971->rdev[i])) {
err = PTR_ERR(lp3971->rdev[i]);
dev_err(lp3971->dev, "regulator init failed: %d\n",
@@ -545,23 +522,7 @@ static struct i2c_driver lp3971_i2c_driver = {
.id_table = lp3971_i2c_id,
};
-static int __init lp3971_module_init(void)
-{
- int ret;
-
- ret = i2c_add_driver(&lp3971_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register I2C driver: %d\n", ret);
-
- return ret;
-}
-module_init(lp3971_module_init);
-
-static void __exit lp3971_module_exit(void)
-{
- i2c_del_driver(&lp3971_i2c_driver);
-}
-module_exit(lp3971_module_exit);
+module_i2c_driver(lp3971_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 49a15ee..de073df 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -245,6 +245,11 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
{
int ldo = rdev_get_id(dev) - LP3972_LDO1;
+
+ if (index < LP3972_LDO_VOL_MIN_IDX(ldo) ||
+ index > LP3972_LDO_VOL_MAX_IDX(ldo))
+ return -EINVAL;
+
return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
}
@@ -292,34 +297,16 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
}
-static int lp3972_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV,
- unsigned int *selector)
+static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
+ unsigned int selector)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3972_LDO1;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo);
- u16 val;
int shift, ret;
- if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] ||
- min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)])
- return -EINVAL;
-
- for (val = LP3972_LDO_VOL_MIN_IDX(ldo);
- val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++)
- if (vol_map[val] >= min_vol)
- break;
-
- if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol)
- return -EINVAL;
-
- *selector = val;
-
shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
- LP3972_LDO_VOL_MASK(ldo) << shift, val << shift);
+ LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift);
if (ret)
return ret;
@@ -355,12 +342,17 @@ static struct regulator_ops lp3972_ldo_ops = {
.enable = lp3972_ldo_enable,
.disable = lp3972_ldo_disable,
.get_voltage = lp3972_ldo_get_voltage,
- .set_voltage = lp3972_ldo_set_voltage,
+ .set_voltage_sel = lp3972_ldo_set_voltage_sel,
};
static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
{
int buck = rdev_get_id(dev) - LP3972_DCDC1;
+
+ if (index < LP3972_BUCK_VOL_MIN_IDX(buck) ||
+ index > LP3972_BUCK_VOL_MAX_IDX(buck))
+ return -EINVAL;
+
return 1000 * buck_voltage_map[buck][index];
}
@@ -419,34 +411,15 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
return val;
}
-static int lp3972_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV,
- unsigned int *selector)
+static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
+ unsigned int selector)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3972_DCDC1;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const int *vol_map = buck_voltage_map[buck];
- u16 val;
int ret;
- if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] ||
- min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)])
- return -EINVAL;
-
- for (val = LP3972_BUCK_VOL_MIN_IDX(buck);
- val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++)
- if (vol_map[val] >= min_vol)
- break;
-
- if (val > LP3972_BUCK_VOL_MAX_IDX(buck) ||
- vol_map[val] > max_vol)
- return -EINVAL;
-
- *selector = val;
-
ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
- LP3972_BUCK_VOL_MASK, val);
+ LP3972_BUCK_VOL_MASK, selector);
if (ret)
return ret;
@@ -468,10 +441,10 @@ static struct regulator_ops lp3972_dcdc_ops = {
.enable = lp3972_dcdc_enable,
.disable = lp3972_dcdc_disable,
.get_voltage = lp3972_dcdc_get_voltage,
- .set_voltage = lp3972_dcdc_set_voltage,
+ .set_voltage_sel = lp3972_dcdc_set_voltage_sel,
};
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
{
.name = "LDO1",
.id = LP3972_LDO1,
@@ -554,9 +527,14 @@ static int __devinit setup_regulators(struct lp3972 *lp3972,
/* Instantiate the regulators */
for (i = 0; i < pdata->num_regulators; i++) {
struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
- lp3972->rdev[i] = regulator_register(&regulators[reg->id],
- lp3972->dev, reg->initdata, lp3972, NULL);
+ struct regulator_config config = { };
+ config.dev = lp3972->dev;
+ config.init_data = reg->initdata;
+ config.driver_data = lp3972;
+
+ lp3972->rdev[i] = regulator_register(&regulators[reg->id],
+ &config);
if (IS_ERR(lp3972->rdev[i])) {
err = PTR_ERR(lp3972->rdev[i]);
dev_err(lp3972->dev, "regulator init failed: %d\n",
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 282d2ee..b9444ee 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -161,7 +161,7 @@ static struct regulator_ops max1586_v6_ops = {
.list_voltage = max1586_v6_list,
};
-static struct regulator_desc max1586_reg[] = {
+static const struct regulator_desc max1586_reg[] = {
{
.name = "Output_V3",
.id = MAX1586_V3,
@@ -185,21 +185,21 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
{
struct regulator_dev **rdev;
struct max1586_platform_data *pdata = client->dev.platform_data;
+ struct regulator_config config = { };
struct max1586_data *max1586;
int i, id, ret = -ENOMEM;
- max1586 = kzalloc(sizeof(struct max1586_data) +
+ max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) +
sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
GFP_KERNEL);
if (!max1586)
- goto out;
+ return -ENOMEM;
max1586->client = client;
- if (!pdata->v3_gain) {
- ret = -EINVAL;
- goto out_unmap;
- }
+ if (!pdata->v3_gain)
+ return -EINVAL;
+
max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000;
max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000;
@@ -212,9 +212,12 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
dev_err(&client->dev, "invalid regulator id %d\n", id);
goto err;
}
- rdev[i] = regulator_register(&max1586_reg[id], &client->dev,
- pdata->subdevs[i].platform_data,
- max1586, NULL);
+
+ config.dev = &client->dev;
+ config.init_data = pdata->subdevs[i].platform_data;
+ config.driver_data = max1586;
+
+ rdev[i] = regulator_register(&max1586_reg[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&client->dev, "failed to register %s\n",
@@ -230,9 +233,6 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
err:
while (--i >= 0)
regulator_unregister(rdev[i]);
-out_unmap:
- kfree(max1586);
-out:
return ret;
}
@@ -244,8 +244,6 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client)
for (i = 0; i <= MAX1586_V6; i++)
if (max1586->rdev[i])
regulator_unregister(max1586->rdev[i]);
- kfree(max1586);
-
return 0;
}
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 824c650..1f4bb80 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -53,7 +53,6 @@ struct max8649_regulator_info {
struct device *dev;
struct regmap *regmap;
- int vol_reg;
unsigned mode:2; /* bit[1:0] = VID1, VID0 */
unsigned extclk_freq:2;
unsigned extclk:1;
@@ -61,53 +60,6 @@ struct max8649_regulator_info {
unsigned ramp_down:1;
};
-/* I2C operations */
-
-static inline int check_range(int min_uV, int max_uV)
-{
- if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX)
- || (min_uV > max_uV))
- return -EINVAL;
- return 0;
-}
-
-static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
- return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP);
-}
-
-static int max8649_get_voltage(struct regulator_dev *rdev)
-{
- struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
- unsigned int val;
- unsigned char data;
- int ret;
-
- ret = regmap_read(info->regmap, info->vol_reg, &val);
- if (ret != 0)
- return ret;
- data = (unsigned char)val & MAX8649_VOL_MASK;
- return max8649_list_voltage(rdev, data);
-}
-
-static int max8649_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
- unsigned char data, mask;
-
- if (check_range(min_uV, max_uV)) {
- dev_err(info->dev, "invalid voltage range (%d, %d) uV\n",
- min_uV, max_uV);
- return -EINVAL;
- }
- data = DIV_ROUND_UP(min_uV - MAX8649_DCDC_VMIN, MAX8649_DCDC_STEP);
- mask = MAX8649_VOL_MASK;
- *selector = data & mask;
-
- return regmap_update_bits(info->regmap, info->vol_reg, mask, data);
-}
-
/* EN_PD means pulldown on EN input */
static int max8649_enable(struct regulator_dev *rdev)
{
@@ -145,11 +97,11 @@ static int max8649_enable_time(struct regulator_dev *rdev)
unsigned int val;
/* get voltage */
- ret = regmap_read(info->regmap, info->vol_reg, &val);
+ ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
if (ret != 0)
return ret;
val &= MAX8649_VOL_MASK;
- voltage = max8649_list_voltage(rdev, (unsigned char)val); /* uV */
+ voltage = regulator_list_voltage_linear(rdev, (unsigned char)val);
/* get rate */
ret = regmap_read(info->regmap, MAX8649_RAMP, &val);
@@ -167,11 +119,11 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
switch (mode) {
case REGULATOR_MODE_FAST:
- regmap_update_bits(info->regmap, info->vol_reg, MAX8649_FORCE_PWM,
- MAX8649_FORCE_PWM);
+ regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
+ MAX8649_FORCE_PWM, MAX8649_FORCE_PWM);
break;
case REGULATOR_MODE_NORMAL:
- regmap_update_bits(info->regmap, info->vol_reg,
+ regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
MAX8649_FORCE_PWM, 0);
break;
default:
@@ -186,7 +138,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev)
unsigned int val;
int ret;
- ret = regmap_read(info->regmap, info->vol_reg, &val);
+ ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
if (ret != 0)
return ret;
if (val & MAX8649_FORCE_PWM)
@@ -195,9 +147,10 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev)
}
static struct regulator_ops max8649_dcdc_ops = {
- .set_voltage = max8649_set_voltage,
- .get_voltage = max8649_get_voltage,
- .list_voltage = max8649_list_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.enable = max8649_enable,
.disable = max8649_disable,
.is_enabled = max8649_is_enabled,
@@ -213,6 +166,9 @@ static struct regulator_desc dcdc_desc = {
.type = REGULATOR_VOLTAGE,
.n_voltages = 1 << 6,
.owner = THIS_MODULE,
+ .vsel_mask = MAX8649_VOL_MASK,
+ .min_uV = MAX8649_DCDC_VMIN,
+ .uV_step = MAX8649_DCDC_STEP,
};
static struct regmap_config max8649_regmap_config = {
@@ -225,21 +181,23 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
{
struct max8649_platform_data *pdata = client->dev.platform_data;
struct max8649_regulator_info *info = NULL;
+ struct regulator_config config = { };
unsigned int val;
unsigned char data;
int ret;
- info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL);
+ info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info),
+ GFP_KERNEL);
if (!info) {
dev_err(&client->dev, "No enough memory\n");
return -ENOMEM;
}
- info->regmap = regmap_init_i2c(client, &max8649_regmap_config);
+ info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);
if (IS_ERR(info->regmap)) {
ret = PTR_ERR(info->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n", ret);
- goto fail;
+ return ret;
}
info->dev = &client->dev;
@@ -248,16 +206,16 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
info->mode = pdata->mode;
switch (info->mode) {
case 0:
- info->vol_reg = MAX8649_MODE0;
+ dcdc_desc.vsel_reg = MAX8649_MODE0;
break;
case 1:
- info->vol_reg = MAX8649_MODE1;
+ dcdc_desc.vsel_reg = MAX8649_MODE1;
break;
case 2:
- info->vol_reg = MAX8649_MODE2;
+ dcdc_desc.vsel_reg = MAX8649_MODE2;
break;
case 3:
- info->vol_reg = MAX8649_MODE3;
+ dcdc_desc.vsel_reg = MAX8649_MODE3;
break;
default:
break;
@@ -267,7 +225,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
if (ret != 0) {
dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
ret);
- goto out;
+ return ret;
}
dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);
@@ -277,7 +235,8 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
/* enable/disable external clock synchronization */
info->extclk = pdata->extclk;
data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
- regmap_update_bits(info->regmap, info->vol_reg, MAX8649_SYNC_EXTCLK, data);
+ regmap_update_bits(info->regmap, dcdc_desc.vsel_reg,
+ MAX8649_SYNC_EXTCLK, data);
if (info->extclk) {
/* set external clock frequency */
info->extclk_freq = pdata->extclk_freq;
@@ -297,22 +256,18 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
MAX8649_RAMP_DOWN);
}
- info->regulator = regulator_register(&dcdc_desc, &client->dev,
- pdata->regulator, info, NULL);
+ config.dev = &client->dev;
+ config.init_data = pdata->regulator;
+ config.driver_data = info;
+
+ info->regulator = regulator_register(&dcdc_desc, &config);
if (IS_ERR(info->regulator)) {
dev_err(info->dev, "failed to register regulator %s\n",
dcdc_desc.name);
- ret = PTR_ERR(info->regulator);
- goto out;
+ return PTR_ERR(info->regulator);
}
- dev_info(info->dev, "Max8649 regulator device is detected.\n");
return 0;
-out:
- regmap_exit(info->regmap);
-fail:
- kfree(info);
- return ret;
}
static int __devexit max8649_regulator_remove(struct i2c_client *client)
@@ -322,8 +277,6 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client)
if (info) {
if (info->regulator)
regulator_unregister(info->regulator);
- regmap_exit(info->regmap);
- kfree(info);
}
return 0;
@@ -360,4 +313,3 @@ module_exit(max8649_exit);
MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 4c5b053..8d53174 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -126,42 +126,22 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev)
return max8660_write(max8660, MAX8660_OVER1, mask, 0);
}
-static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector)
-{
- if (selector > MAX8660_DCDC_MAX_SEL)
- return -EINVAL;
- return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
-}
-
-static int max8660_dcdc_get(struct regulator_dev *rdev)
+static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
+
u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
u8 selector = max8660->shadow_regs[reg];
- return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+ return selector;
}
-static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned int *s)
+static int max8660_dcdc_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
- u8 reg, selector, bits;
+ u8 reg, bits;
int ret;
- if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV)
- return -EINVAL;
- if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV)
- return -EINVAL;
-
- selector = DIV_ROUND_UP(min_uV - MAX8660_DCDC_MIN_UV,
- MAX8660_DCDC_STEP);
-
- ret = max8660_dcdc_list(rdev, selector);
- if (ret < 0 || ret > max_uV)
- return -EINVAL;
-
- *s = selector;
-
reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
ret = max8660_write(max8660, reg, 0, selector);
if (ret)
@@ -174,9 +154,10 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV,
static struct regulator_ops max8660_dcdc_ops = {
.is_enabled = max8660_dcdc_is_enabled,
- .list_voltage = max8660_dcdc_list,
- .set_voltage = max8660_dcdc_set,
- .get_voltage = max8660_dcdc_get,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = max8660_dcdc_set_voltage_sel,
+ .get_voltage_sel = max8660_dcdc_get_voltage_sel,
};
@@ -184,42 +165,20 @@ static struct regulator_ops max8660_dcdc_ops = {
* LDO5 functions
*/
-static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector)
-{
- if (selector > MAX8660_LDO5_MAX_SEL)
- return -EINVAL;
- return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
-}
-
-static int max8660_ldo5_get(struct regulator_dev *rdev)
+static int max8660_ldo5_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
- u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
- return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+ u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
+ return selector;
}
-static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned int *s)
+static int max8660_ldo5_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
- u8 selector;
int ret;
- if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV)
- return -EINVAL;
- if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV)
- return -EINVAL;
-
- selector = DIV_ROUND_UP(min_uV - MAX8660_LDO5_MIN_UV,
- MAX8660_LDO5_STEP);
-
- ret = max8660_ldo5_list(rdev, selector);
- if (ret < 0 || ret > max_uV)
- return -EINVAL;
-
- *s = selector;
-
ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
if (ret)
return ret;
@@ -229,9 +188,10 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV,
}
static struct regulator_ops max8660_ldo5_ops = {
- .list_voltage = max8660_ldo5_list,
- .set_voltage = max8660_ldo5_set,
- .get_voltage = max8660_ldo5_get,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = max8660_ldo5_set_voltage_sel,
+ .get_voltage_sel = max8660_ldo5_get_voltage_sel,
};
@@ -261,59 +221,38 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev)
return max8660_write(max8660, MAX8660_OVER2, mask, 0);
}
-static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector)
-{
- if (selector > MAX8660_LDO67_MAX_SEL)
- return -EINVAL;
- return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
-}
-
-static int max8660_ldo67_get(struct regulator_dev *rdev)
+static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
+
u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
-
- return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+ return selector;
}
-static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned int *s)
+static int max8660_ldo67_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
- u8 selector;
- int ret;
-
- if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV)
- return -EINVAL;
- if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV)
- return -EINVAL;
-
- selector = DIV_ROUND_UP(min_uV - MAX8660_LDO67_MIN_UV,
- MAX8660_LDO67_STEP);
-
- ret = max8660_ldo67_list(rdev, selector);
- if (ret < 0 || ret > max_uV)
- return -EINVAL;
-
- *s = selector;
if (rdev_get_id(rdev) == MAX8660_V6)
return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
else
- return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4);
+ return max8660_write(max8660, MAX8660_L12VCR, 0x0f,
+ selector << 4);
}
static struct regulator_ops max8660_ldo67_ops = {
.is_enabled = max8660_ldo67_is_enabled,
.enable = max8660_ldo67_enable,
.disable = max8660_ldo67_disable,
- .list_voltage = max8660_ldo67_list,
- .get_voltage = max8660_ldo67_get,
- .set_voltage = max8660_ldo67_set,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = max8660_ldo67_get_voltage_sel,
+ .set_voltage_sel = max8660_ldo67_set_voltage_sel,
};
-static struct regulator_desc max8660_reg[] = {
+static const struct regulator_desc max8660_reg[] = {
{
.name = "V3(DCDC)",
.id = MAX8660_V3,
@@ -321,6 +260,8 @@ static struct regulator_desc max8660_reg[] = {
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX8660_DCDC_MAX_SEL + 1,
.owner = THIS_MODULE,
+ .min_uV = MAX8660_DCDC_MIN_UV,
+ .uV_step = MAX8660_DCDC_STEP,
},
{
.name = "V4(DCDC)",
@@ -329,6 +270,8 @@ static struct regulator_desc max8660_reg[] = {
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX8660_DCDC_MAX_SEL + 1,
.owner = THIS_MODULE,
+ .min_uV = MAX8660_DCDC_MIN_UV,
+ .uV_step = MAX8660_DCDC_STEP,
},
{
.name = "V5(LDO)",
@@ -337,6 +280,8 @@ static struct regulator_desc max8660_reg[] = {
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX8660_LDO5_MAX_SEL + 1,
.owner = THIS_MODULE,
+ .min_uV = MAX8660_LDO5_MIN_UV,
+ .uV_step = MAX8660_LDO5_STEP,
},
{
.name = "V6(LDO)",
@@ -345,6 +290,8 @@ static struct regulator_desc max8660_reg[] = {
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX8660_LDO67_MAX_SEL + 1,
.owner = THIS_MODULE,
+ .min_uV = MAX8660_LDO67_MIN_UV,
+ .uV_step = MAX8660_LDO67_STEP,
},
{
.name = "V7(LDO)",
@@ -353,6 +300,8 @@ static struct regulator_desc max8660_reg[] = {
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX8660_LDO67_MAX_SEL + 1,
.owner = THIS_MODULE,
+ .min_uV = MAX8660_LDO67_MIN_UV,
+ .uV_step = MAX8660_LDO67_STEP,
},
};
@@ -361,21 +310,20 @@ static int __devinit max8660_probe(struct i2c_client *client,
{
struct regulator_dev **rdev;
struct max8660_platform_data *pdata = client->dev.platform_data;
+ struct regulator_config config = { };
struct max8660 *max8660;
int boot_on, i, id, ret = -EINVAL;
if (pdata->num_subdevs > MAX8660_V_END) {
dev_err(&client->dev, "Too many regulators found!\n");
- goto out;
+ return -EINVAL;
}
- max8660 = kzalloc(sizeof(struct max8660) +
+ max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) +
sizeof(struct regulator_dev *) * MAX8660_V_END,
GFP_KERNEL);
- if (!max8660) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!max8660)
+ return -ENOMEM;
max8660->client = client;
rdev = max8660->rdev;
@@ -404,7 +352,7 @@ static int __devinit max8660_probe(struct i2c_client *client,
for (i = 0; i < pdata->num_subdevs; i++) {
if (!pdata->subdevs[i].platform_data)
- goto err_free;
+ goto err_out;
boot_on = pdata->subdevs[i].platform_data->constraints.boot_on;
@@ -430,7 +378,7 @@ static int __devinit max8660_probe(struct i2c_client *client,
case MAX8660_V7:
if (!strcmp(i2c_id->name, "max8661")) {
dev_err(&client->dev, "Regulator not on this chip!\n");
- goto err_free;
+ goto err_out;
}
if (boot_on)
@@ -440,7 +388,7 @@ static int __devinit max8660_probe(struct i2c_client *client,
default:
dev_err(&client->dev, "invalid regulator %s\n",
pdata->subdevs[i].name);
- goto err_free;
+ goto err_out;
}
}
@@ -449,9 +397,11 @@ static int __devinit max8660_probe(struct i2c_client *client,
id = pdata->subdevs[i].id;
- rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
- pdata->subdevs[i].platform_data,
- max8660, NULL);
+ config.dev = &client->dev;
+ config.init_data = pdata->subdevs[i].platform_data;
+ config.driver_data = max8660;
+
+ rdev[i] = regulator_register(&max8660_reg[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&client->dev, "failed to register %s\n",
@@ -461,15 +411,12 @@ static int __devinit max8660_probe(struct i2c_client *client,
}
i2c_set_clientdata(client, max8660);
- dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
return 0;
err_unregister:
while (--i >= 0)
regulator_unregister(rdev[i]);
-err_free:
- kfree(max8660);
-out:
+err_out:
return ret;
}
@@ -481,8 +428,6 @@ static int __devexit max8660_remove(struct i2c_client *client)
for (i = 0; i < MAX8660_V_END; i++)
if (max8660->rdev[i])
regulator_unregister(max8660->rdev[i]);
- kfree(max8660);
-
return 0;
}
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 2f242f4..43dc97ec 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -38,50 +38,20 @@ struct max8925_regulator_info {
struct i2c_client *i2c;
struct max8925_chip *chip;
- int min_uV;
- int max_uV;
- int step_uV;
int vol_reg;
- int vol_shift;
- int vol_nbits;
int enable_reg;
};
-static inline int check_range(struct max8925_regulator_info *info,
- int min_uV, int max_uV)
-{
- if (min_uV < info->min_uV || min_uV > info->max_uV)
- return -EINVAL;
-
- return 0;
-}
-
-static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
- struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
- return info->min_uV + index * info->step_uV;
-}
-
-static int max8925_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned int *selector)
+static int max8925_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
- unsigned char data, mask;
-
- if (check_range(info, min_uV, max_uV)) {
- dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
- min_uV, max_uV);
- return -EINVAL;
- }
- data = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
- *selector = data;
- data <<= info->vol_shift;
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ unsigned char mask = rdev->desc->n_voltages - 1;
- return max8925_set_bits(info->i2c, info->vol_reg, mask, data);
+ return max8925_set_bits(info->i2c, info->vol_reg, mask, selector);
}
-static int max8925_get_voltage(struct regulator_dev *rdev)
+static int max8925_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data, mask;
@@ -90,10 +60,10 @@ static int max8925_get_voltage(struct regulator_dev *rdev)
ret = max8925_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
- mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
- data = (ret & mask) >> info->vol_shift;
+ mask = rdev->desc->n_voltages - 1;
+ data = ret & mask;
- return max8925_list_voltage(rdev, data);
+ return data;
}
static int max8925_enable(struct regulator_dev *rdev)
@@ -163,8 +133,10 @@ static int max8925_set_dvm_disable(struct regulator_dev *rdev)
}
static struct regulator_ops max8925_regulator_sdv_ops = {
- .set_voltage = max8925_set_voltage,
- .get_voltage = max8925_get_voltage,
+ .map_voltage = regulator_map_voltage_linear,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = max8925_set_voltage_sel,
+ .get_voltage_sel = max8925_get_voltage_sel,
.enable = max8925_enable,
.disable = max8925_disable,
.is_enabled = max8925_is_enabled,
@@ -174,8 +146,10 @@ static struct regulator_ops max8925_regulator_sdv_ops = {
};
static struct regulator_ops max8925_regulator_ldo_ops = {
- .set_voltage = max8925_set_voltage,
- .get_voltage = max8925_get_voltage,
+ .map_voltage = regulator_map_voltage_linear,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = max8925_set_voltage_sel,
+ .get_voltage_sel = max8925_get_voltage_sel,
.enable = max8925_enable,
.disable = max8925_disable,
.is_enabled = max8925_is_enabled,
@@ -189,13 +163,11 @@ static struct regulator_ops max8925_regulator_ldo_ops = {
.type = REGULATOR_VOLTAGE, \
.id = MAX8925_ID_SD##_id, \
.owner = THIS_MODULE, \
+ .n_voltages = 64, \
+ .min_uV = min * 1000, \
+ .uV_step = step * 1000, \
}, \
- .min_uV = min * 1000, \
- .max_uV = max * 1000, \
- .step_uV = step * 1000, \
.vol_reg = MAX8925_SDV##_id, \
- .vol_shift = 0, \
- .vol_nbits = 6, \
.enable_reg = MAX8925_SDCTL##_id, \
}
@@ -207,13 +179,11 @@ static struct regulator_ops max8925_regulator_ldo_ops = {
.type = REGULATOR_VOLTAGE, \
.id = MAX8925_ID_LDO##_id, \
.owner = THIS_MODULE, \
+ .n_voltages = 64, \
+ .min_uV = min * 1000, \
+ .uV_step = step * 1000, \
}, \
- .min_uV = min * 1000, \
- .max_uV = max * 1000, \
- .step_uV = step * 1000, \
.vol_reg = MAX8925_LDOVOUT##_id, \
- .vol_shift = 0, \
- .vol_nbits = 6, \
.enable_reg = MAX8925_LDOCTL##_id, \
}
@@ -261,6 +231,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct max8925_platform_data *pdata = chip->dev->platform_data;
+ struct regulator_config config = { };
struct max8925_regulator_info *ri;
struct regulator_dev *rdev;
@@ -272,8 +243,11 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev)
ri->i2c = chip->i2c;
ri->chip = chip;
- rdev = regulator_register(&ri->desc, &pdev->dev,
- pdata->regulator[pdev->id], ri, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = pdata->regulator[pdev->id];
+ config.driver_data = ri;
+
+ rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
@@ -319,4 +293,3 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");
MODULE_ALIAS("platform:max8925-regulator");
-
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 75d8940..910c9b2 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -69,11 +69,6 @@ static int max8952_write_reg(struct max8952_data *max8952,
return i2c_smbus_write_byte_data(max8952->client, reg, value);
}
-static int max8952_voltage(struct max8952_data *max8952, u8 mode)
-{
- return (max8952->pdata->dvs_mode[mode] * 10 + 770) * 1000;
-}
-
static int max8952_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
@@ -82,7 +77,7 @@ static int max8952_list_voltage(struct regulator_dev *rdev,
if (rdev_get_id(rdev) != 0)
return -EINVAL;
- return max8952_voltage(max8952, selector);
+ return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000;
}
static int max8952_is_enabled(struct regulator_dev *rdev)
@@ -117,7 +112,7 @@ static int max8952_disable(struct regulator_dev *rdev)
return 0;
}
-static int max8952_get_voltage(struct regulator_dev *rdev)
+static int max8952_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8952_data *max8952 = rdev_get_drvdata(rdev);
u8 vid = 0;
@@ -127,14 +122,13 @@ static int max8952_get_voltage(struct regulator_dev *rdev)
if (max8952->vid1)
vid += 2;
- return max8952_voltage(max8952, vid);
+ return vid;
}
-static int max8952_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int max8952_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct max8952_data *max8952 = rdev_get_drvdata(rdev);
- s8 vid = -1, i;
if (!gpio_is_valid(max8952->pdata->gpio_vid0) ||
!gpio_is_valid(max8952->pdata->gpio_vid1)) {
@@ -142,23 +136,10 @@ static int max8952_set_voltage(struct regulator_dev *rdev,
return -EPERM;
}
- for (i = 0; i < MAX8952_NUM_DVS_MODE; i++) {
- int volt = max8952_voltage(max8952, i);
-
- /* Set the voltage as low as possible within the range */
- if (volt <= max_uV && volt >= min_uV)
- if (vid == -1 || max8952_voltage(max8952, vid) > volt)
- vid = i;
- }
-
- if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) {
- max8952->vid0 = (vid % 2 == 1);
- max8952->vid1 = (((vid >> 1) % 2) == 1);
- *selector = vid;
- gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0);
- gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1);
- } else
- return -EINVAL;
+ max8952->vid0 = selector & 0x1;
+ max8952->vid1 = (selector >> 1) & 0x1;
+ gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0);
+ gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1);
return 0;
}
@@ -168,12 +149,12 @@ static struct regulator_ops max8952_ops = {
.is_enabled = max8952_is_enabled,
.enable = max8952_enable,
.disable = max8952_disable,
- .get_voltage = max8952_get_voltage,
- .set_voltage = max8952_set_voltage,
+ .get_voltage_sel = max8952_get_voltage_sel,
+ .set_voltage_sel = max8952_set_voltage_sel,
.set_suspend_disable = max8952_disable,
};
-static struct regulator_desc regulator = {
+static const struct regulator_desc regulator = {
.name = "MAX8952_VOUT",
.id = 0,
.n_voltages = MAX8952_NUM_DVS_MODE,
@@ -187,6 +168,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct max8952_platform_data *pdata = client->dev.platform_data;
+ struct regulator_config config = { };
struct max8952_data *max8952;
int ret = 0, err = 0;
@@ -199,7 +181,8 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
- max8952 = kzalloc(sizeof(struct max8952_data), GFP_KERNEL);
+ max8952 = devm_kzalloc(&client->dev, sizeof(struct max8952_data),
+ GFP_KERNEL);
if (!max8952)
return -ENOMEM;
@@ -207,18 +190,21 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
max8952->dev = &client->dev;
max8952->pdata = pdata;
- max8952->rdev = regulator_register(&regulator, max8952->dev,
- &pdata->reg_data, max8952, NULL);
+ config.dev = max8952->dev;
+ config.init_data = &pdata->reg_data;
+ config.driver_data = max8952;
+
+ max8952->rdev = regulator_register(&regulator, &config);
if (IS_ERR(max8952->rdev)) {
ret = PTR_ERR(max8952->rdev);
dev_err(max8952->dev, "regulator init failed (%d)\n", ret);
- goto err_reg;
+ return ret;
}
max8952->en = !!(pdata->reg_data.constraints.boot_on);
- max8952->vid0 = (pdata->default_mode % 2) == 1;
- max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1;
+ max8952->vid0 = pdata->default_mode & 0x1;
+ max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
if (gpio_is_valid(pdata->gpio_en)) {
if (!gpio_request(pdata->gpio_en, "MAX8952 EN"))
@@ -241,13 +227,13 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
gpio_is_valid(pdata->gpio_vid1)) {
if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0"))
gpio_direction_output(pdata->gpio_vid0,
- (pdata->default_mode) % 2);
+ (pdata->default_mode) & 0x1);
else
err = 1;
if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1"))
gpio_direction_output(pdata->gpio_vid1,
- (pdata->default_mode >> 1) % 2);
+ (pdata->default_mode >> 1) & 0x1);
else {
if (!err)
gpio_free(pdata->gpio_vid0);
@@ -310,10 +296,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
i2c_set_clientdata(client, max8952);
return 0;
-
-err_reg:
- kfree(max8952);
- return ret;
}
static int __devexit max8952_pmic_remove(struct i2c_client *client)
@@ -327,8 +309,6 @@ static int __devexit max8952_pmic_remove(struct i2c_client *client)
gpio_free(pdata->gpio_vid0);
gpio_free(pdata->gpio_vid1);
gpio_free(pdata->gpio_en);
-
- kfree(max8952);
return 0;
}
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 17a58c5..704cd49 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -22,7 +22,6 @@
*/
#include <linux/bug.h>
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -68,29 +67,28 @@ struct voltage_map_desc {
int min;
int max;
int step;
- unsigned int n_bits;
};
/* Voltage maps in mV */
static const struct voltage_map_desc ldo_voltage_map_desc = {
- .min = 800, .max = 3950, .step = 50, .n_bits = 6,
+ .min = 800, .max = 3950, .step = 50,
}; /* LDO1 ~ 18, 21 all */
static const struct voltage_map_desc buck1245_voltage_map_desc = {
- .min = 650, .max = 2225, .step = 25, .n_bits = 6,
+ .min = 650, .max = 2225, .step = 25,
}; /* Buck1, 2, 4, 5 */
static const struct voltage_map_desc buck37_voltage_map_desc = {
- .min = 750, .max = 3900, .step = 50, .n_bits = 6,
+ .min = 750, .max = 3900, .step = 50,
}; /* Buck3, 7 */
/* current map in mA */
static const struct voltage_map_desc charger_current_map_desc = {
- .min = 200, .max = 950, .step = 50, .n_bits = 4,
+ .min = 200, .max = 950, .step = 50,
};
static const struct voltage_map_desc topoff_current_map_desc = {
- .min = 50, .max = 200, .step = 10, .n_bits = 4,
+ .min = 50, .max = 200, .step = 10,
};
static const struct voltage_map_desc *reg_voltage_map[] = {
@@ -279,9 +277,7 @@ static int max8997_reg_is_enabled(struct regulator_dev *rdev)
u8 val;
ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
- if (ret == -EINVAL)
- return 1; /* "not controllable" */
- else if (ret)
+ if (ret)
return ret;
ret = max8997_read_reg(i2c, reg, &val);
@@ -320,6 +316,7 @@ static int max8997_reg_disable(struct regulator_dev *rdev)
static int max8997_get_voltage_register(struct regulator_dev *rdev,
int *_reg, int *_shift, int *_mask)
{
+ struct max8997_data *max8997 = rdev_get_drvdata(rdev);
int rid = rdev_get_id(rdev);
int reg, shift = 0, mask = 0x3f;
@@ -329,9 +326,13 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev,
break;
case MAX8997_BUCK1:
reg = MAX8997_REG_BUCK1DVS1;
+ if (max8997->buck1_gpiodvs)
+ reg += max8997->buck125_gpioindex;
break;
case MAX8997_BUCK2:
reg = MAX8997_REG_BUCK2DVS1;
+ if (max8997->buck2_gpiodvs)
+ reg += max8997->buck125_gpioindex;
break;
case MAX8997_BUCK3:
reg = MAX8997_REG_BUCK3DVS;
@@ -341,6 +342,8 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev,
break;
case MAX8997_BUCK5:
reg = MAX8997_REG_BUCK5DVS1;
+ if (max8997->buck5_gpiodvs)
+ reg += max8997->buck125_gpioindex;
break;
case MAX8997_BUCK7:
reg = MAX8997_REG_BUCK7DVS;
@@ -376,23 +379,17 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev,
return 0;
}
-static int max8997_get_voltage(struct regulator_dev *rdev)
+static int max8997_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8997->iodev->i2c;
int reg, shift, mask, ret;
- int rid = rdev_get_id(rdev);
u8 val;
ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
- if ((rid == MAX8997_BUCK1 && max8997->buck1_gpiodvs) ||
- (rid == MAX8997_BUCK2 && max8997->buck2_gpiodvs) ||
- (rid == MAX8997_BUCK5 && max8997->buck5_gpiodvs))
- reg += max8997->buck125_gpioindex;
-
ret = max8997_read_reg(i2c, reg, &val);
if (ret)
return ret;
@@ -400,22 +397,14 @@ static int max8997_get_voltage(struct regulator_dev *rdev)
val >>= shift;
val &= mask;
- if (rdev->desc && rdev->desc->ops && rdev->desc->ops->list_voltage)
- return rdev->desc->ops->list_voltage(rdev, val);
-
- /*
- * max8997_list_voltage returns value for any rdev with voltage_map,
- * which works for "CHARGER" and "CHARGER TOPOFF" that do not have
- * list_voltage ops (they are current regulators).
- */
- return max8997_list_voltage(rdev, val);
+ return val;
}
static inline int max8997_get_voltage_proper_val(
const struct voltage_map_desc *desc,
int min_vol, int max_vol)
{
- int i = 0;
+ int i;
if (desc == NULL)
return -EINVAL;
@@ -423,14 +412,12 @@ static inline int max8997_get_voltage_proper_val(
if (max_vol < desc->min || min_vol > desc->max)
return -EINVAL;
- while (desc->min + desc->step * i < min_vol &&
- desc->min + desc->step * i < desc->max)
- i++;
+ if (min_vol < desc->min)
+ min_vol = desc->min;
- if (desc->min + desc->step * i > max_vol)
- return -EINVAL;
+ i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
- if (i >= (1 << desc->n_bits))
+ if (desc->min + desc->step * i > max_vol)
return -EINVAL;
return i;
@@ -499,9 +486,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
const struct voltage_map_desc *desc;
int rid = rdev_get_id(rdev);
- int reg, shift = 0, mask, ret;
- int i;
- u8 org;
+ int i, reg, shift, mask, ret;
switch (rid) {
case MAX8997_LDO1 ... MAX8997_LDO21:
@@ -530,21 +515,50 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
if (ret)
return ret;
- max8997_read_reg(i2c, reg, &org);
- org = (org & mask) >> shift;
-
ret = max8997_update_reg(i2c, reg, i << shift, mask << shift);
*selector = i;
- if (rid == MAX8997_BUCK1 || rid == MAX8997_BUCK2 ||
- rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) {
- /* If the voltage is increasing */
- if (org < i)
- udelay(DIV_ROUND_UP(desc->step * (i - org),
- max8997->ramp_delay));
+ return ret;
+}
+
+static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+ int rid = rdev_get_id(rdev);
+ const struct voltage_map_desc *desc = reg_voltage_map[rid];
+
+ /* Delay is required only if the voltage is increasing */
+ if (old_selector >= new_selector)
+ return 0;
+
+ /* No need to delay if gpio_dvs_mode */
+ switch (rid) {
+ case MAX8997_BUCK1:
+ if (max8997->buck1_gpiodvs)
+ return 0;
+ break;
+ case MAX8997_BUCK2:
+ if (max8997->buck2_gpiodvs)
+ return 0;
+ break;
+ case MAX8997_BUCK5:
+ if (max8997->buck5_gpiodvs)
+ return 0;
+ break;
}
- return ret;
+ switch (rid) {
+ case MAX8997_BUCK1:
+ case MAX8997_BUCK2:
+ case MAX8997_BUCK4:
+ case MAX8997_BUCK5:
+ return DIV_ROUND_UP(desc->step * (new_selector - old_selector),
+ max8997->ramp_delay);
+ }
+
+ return 0;
}
/*
@@ -751,11 +765,6 @@ static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
return ret;
}
-static int max8997_reg_enable_suspend(struct regulator_dev *rdev)
-{
- return 0;
-}
-
static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
@@ -788,9 +797,9 @@ static struct regulator_ops max8997_ldo_ops = {
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
- .get_voltage = max8997_get_voltage,
+ .get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_ldobuck,
- .set_suspend_enable = max8997_reg_enable_suspend,
+ .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -799,9 +808,9 @@ static struct regulator_ops max8997_buck_ops = {
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
- .get_voltage = max8997_get_voltage,
+ .get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_buck,
- .set_suspend_enable = max8997_reg_enable_suspend,
+ .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -810,7 +819,6 @@ static struct regulator_ops max8997_fixedvolt_ops = {
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
- .set_suspend_enable = max8997_reg_enable_suspend,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -819,144 +827,117 @@ static struct regulator_ops max8997_safeout_ops = {
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
- .get_voltage = max8997_get_voltage,
+ .get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_safeout,
- .set_suspend_enable = max8997_reg_enable_suspend,
.set_suspend_disable = max8997_reg_disable_suspend,
};
static struct regulator_ops max8997_fixedstate_ops = {
.list_voltage = max8997_list_voltage_charger_cv,
- .get_voltage = max8997_get_voltage,
+ .get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_charger_cv,
};
-static int max8997_set_voltage_ldobuck_wrap(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+static int max8997_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
{
unsigned dummy;
+ int rid = rdev_get_id(rdev);
+
+ if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF)
+ return -EINVAL;
- return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, &dummy);
+ /* Reuse max8997_set_voltage_ldobuck to set current_limit. */
+ return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy);
}
+static int max8997_get_current_limit(struct regulator_dev *rdev)
+{
+ int sel, rid = rdev_get_id(rdev);
+
+ if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF)
+ return -EINVAL;
+
+ sel = max8997_get_voltage_sel(rdev);
+ if (sel < 0)
+ return sel;
+
+ /* Reuse max8997_list_voltage to get current_limit. */
+ return max8997_list_voltage(rdev, sel);
+}
static struct regulator_ops max8997_charger_ops = {
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
- .get_current_limit = max8997_get_voltage,
- .set_current_limit = max8997_set_voltage_ldobuck_wrap,
+ .get_current_limit = max8997_get_current_limit,
+ .set_current_limit = max8997_set_current_limit,
};
static struct regulator_ops max8997_charger_fixedstate_ops = {
- .is_enabled = max8997_reg_is_enabled,
- .get_current_limit = max8997_get_voltage,
- .set_current_limit = max8997_set_voltage_ldobuck_wrap,
+ .get_current_limit = max8997_get_current_limit,
+ .set_current_limit = max8997_set_current_limit,
};
-#define regulator_desc_ldo(num) { \
- .name = "LDO"#num, \
- .id = MAX8997_LDO##num, \
- .ops = &max8997_ldo_ops, \
+#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\
+ .name = #_name, \
+ .id = MAX8997_##_name, \
+ .ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
-#define regulator_desc_buck(num) { \
- .name = "BUCK"#num, \
- .id = MAX8997_BUCK##num, \
- .ops = &max8997_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
+
+#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\
+ .name = #_name, \
+ .id = MAX8997_##_name, \
+ .ops = &_ops, \
+ .type = REGULATOR_CURRENT, \
.owner = THIS_MODULE, \
}
static struct regulator_desc regulators[] = {
- regulator_desc_ldo(1),
- regulator_desc_ldo(2),
- regulator_desc_ldo(3),
- regulator_desc_ldo(4),
- regulator_desc_ldo(5),
- regulator_desc_ldo(6),
- regulator_desc_ldo(7),
- regulator_desc_ldo(8),
- regulator_desc_ldo(9),
- regulator_desc_ldo(10),
- regulator_desc_ldo(11),
- regulator_desc_ldo(12),
- regulator_desc_ldo(13),
- regulator_desc_ldo(14),
- regulator_desc_ldo(15),
- regulator_desc_ldo(16),
- regulator_desc_ldo(17),
- regulator_desc_ldo(18),
- regulator_desc_ldo(21),
- regulator_desc_buck(1),
- regulator_desc_buck(2),
- regulator_desc_buck(3),
- regulator_desc_buck(4),
- regulator_desc_buck(5),
- {
- .name = "BUCK6",
- .id = MAX8997_BUCK6,
- .ops = &max8997_fixedvolt_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- regulator_desc_buck(7),
- {
- .name = "EN32KHz_AP",
- .id = MAX8997_EN32KHZ_AP,
- .ops = &max8997_fixedvolt_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "EN32KHz_CP",
- .id = MAX8997_EN32KHZ_CP,
- .ops = &max8997_fixedvolt_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "ENVICHG",
- .id = MAX8997_ENVICHG,
- .ops = &max8997_fixedvolt_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "ESAFEOUT1",
- .id = MAX8997_ESAFEOUT1,
- .ops = &max8997_safeout_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "ESAFEOUT2",
- .id = MAX8997_ESAFEOUT2,
- .ops = &max8997_safeout_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "CHARGER_CV",
- .id = MAX8997_CHARGER_CV,
- .ops = &max8997_fixedstate_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- }, {
- .name = "CHARGER",
- .id = MAX8997_CHARGER,
- .ops = &max8997_charger_ops,
- .type = REGULATOR_CURRENT,
- .owner = THIS_MODULE,
- }, {
- .name = "CHARGER_TOPOFF",
- .id = MAX8997_CHARGER_TOPOFF,
- .ops = &max8997_charger_fixedstate_ops,
- .type = REGULATOR_CURRENT,
- .owner = THIS_MODULE,
- },
+ MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops),
+ MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops),
+ MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops),
+ MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops),
+ MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops),
+ MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops),
+ MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops),
+ MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops),
+ MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops),
+ MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF,
+ max8997_charger_fixedstate_ops),
};
static __devinit int max8997_pmic_probe(struct platform_device *pdev)
{
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct regulator_config config = { };
struct regulator_dev **rdev;
struct max8997_data *max8997;
struct i2c_client *i2c;
@@ -968,16 +949,15 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
return -ENODEV;
}
- max8997 = kzalloc(sizeof(struct max8997_data), GFP_KERNEL);
+ max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data),
+ GFP_KERNEL);
if (!max8997)
return -ENOMEM;
size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8997->rdev = kzalloc(size, GFP_KERNEL);
- if (!max8997->rdev) {
- kfree(max8997);
+ max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!max8997->rdev)
return -ENOMEM;
- }
rdev = max8997->rdev;
max8997->dev = &pdev->dev;
@@ -1001,7 +981,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
pdata->buck1_voltage[i] / 1000 +
buck1245_voltage_map_desc.step);
if (ret < 0)
- goto err_alloc;
+ goto err_out;
max8997->buck2_vol[i] = ret =
max8997_get_voltage_proper_val(
@@ -1010,7 +990,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
pdata->buck2_voltage[i] / 1000 +
buck1245_voltage_map_desc.step);
if (ret < 0)
- goto err_alloc;
+ goto err_out;
max8997->buck5_vol[i] = ret =
max8997_get_voltage_proper_val(
@@ -1019,7 +999,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
pdata->buck5_voltage[i] / 1000 +
buck1245_voltage_map_desc.step);
if (ret < 0)
- goto err_alloc;
+ goto err_out;
if (max_buck1 < max8997->buck1_vol[i])
max_buck1 = max8997->buck1_vol[i];
@@ -1052,7 +1032,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
!gpio_is_valid(pdata->buck125_gpios[2])) {
dev_err(&pdev->dev, "GPIO NOT VALID\n");
ret = -EINVAL;
- goto err_alloc;
+ goto err_out;
}
ret = gpio_request(pdata->buck125_gpios[0],
@@ -1061,7 +1041,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Duplicated gpio request"
" on SET1\n");
else if (ret)
- goto err_alloc;
+ goto err_out;
else
gpio1set = true;
@@ -1073,7 +1053,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
else if (ret) {
if (gpio1set)
gpio_free(pdata->buck125_gpios[0]);
- goto err_alloc;
+ goto err_out;
} else
gpio2set = true;
@@ -1087,7 +1067,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
gpio_free(pdata->buck125_gpios[0]);
if (gpio2set)
gpio_free(pdata->buck125_gpios[1]);
- goto err_alloc;
+ goto err_out;
}
gpio_direction_output(pdata->buck125_gpios[0],
@@ -1140,8 +1120,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
else if (id == MAX8997_CHARGER_CV)
regulators[id].n_voltages = 16;
- rdev[i] = regulator_register(&regulators[id], max8997->dev,
- pdata->regulators[i].initdata, max8997, NULL);
+ config.dev = max8997->dev;
+ config.init_data = pdata->regulators[i].initdata;
+ config.driver_data = max8997;
+
+ rdev[i] = regulator_register(&regulators[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(max8997->dev, "regulator init failed for %d\n",
@@ -1153,13 +1136,9 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
return 0;
err:
- for (i = 0; i < max8997->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
-err_alloc:
- kfree(max8997->rdev);
- kfree(max8997);
-
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+err_out:
return ret;
}
@@ -1170,12 +1149,7 @@ static int __devexit max8997_pmic_remove(struct platform_device *pdev)
int i;
for (i = 0; i < max8997->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
-
- kfree(max8997->rdev);
- kfree(max8997);
-
+ regulator_unregister(rdev[i]);
return 0;
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 5890265..18bb58b 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/max8998.h>
@@ -277,7 +276,7 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev,
return 0;
}
-static int max8998_get_voltage(struct regulator_dev *rdev)
+static int max8998_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
@@ -295,7 +294,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev)
val >>= shift;
val &= mask;
- return max8998_list_voltage(rdev, val);
+ return val;
}
static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
@@ -306,8 +305,7 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
const struct voltage_map_desc *desc;
int ldo = rdev_get_id(rdev);
- int reg, shift = 0, mask, ret;
- int i = 0;
+ int reg, shift = 0, mask, ret, i;
if (ldo >= ARRAY_SIZE(ldo_voltage_map))
return -EINVAL;
@@ -319,9 +317,10 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
if (max_vol < desc->min || min_vol > desc->max)
return -EINVAL;
- while (desc->min + desc->step*i < min_vol &&
- desc->min + desc->step*i < desc->max)
- i++;
+ if (min_vol < desc->min)
+ min_vol = desc->min;
+
+ i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
if (desc->min + desc->step*i > max_vol)
return -EINVAL;
@@ -359,8 +358,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
const struct voltage_map_desc *desc;
int buck = rdev_get_id(rdev);
int reg, shift = 0, mask, ret;
- int difference = 0, i = 0, j = 0, previous_vol = 0;
- u8 val = 0;
+ int i, j, previous_sel;
static u8 buck1_last_val;
if (buck >= ARRAY_SIZE(ldo_voltage_map))
@@ -374,9 +372,10 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
if (max_vol < desc->min || min_vol > desc->max)
return -EINVAL;
- while (desc->min + desc->step*i < min_vol &&
- desc->min + desc->step*i < desc->max)
- i++;
+ if (min_vol < desc->min)
+ min_vol = desc->min;
+
+ i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
if (desc->min + desc->step*i > max_vol)
return -EINVAL;
@@ -387,13 +386,14 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
if (ret)
return ret;
- previous_vol = max8998_get_voltage(rdev);
+ previous_sel = max8998_get_voltage_sel(rdev);
/* Check if voltage needs to be changed */
/* if previous_voltage equal new voltage, return */
- if (previous_vol == max8998_list_voltage(rdev, i)) {
+ if (previous_sel == i) {
dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
- previous_vol, max8998_list_voltage(rdev, i));
+ max8998_list_voltage(rdev, previous_sel),
+ max8998_list_voltage(rdev, i));
return ret;
}
@@ -482,19 +482,40 @@ buck2_exit:
break;
}
+ return ret;
+}
+
+static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+ struct i2c_client *i2c = max8998->iodev->i2c;
+ const struct voltage_map_desc *desc;
+ int buck = rdev_get_id(rdev);
+ u8 val = 0;
+ int difference, ret;
+
+ if (buck < MAX8998_BUCK1 || buck > MAX8998_BUCK4)
+ return -EINVAL;
+
+ desc = ldo_voltage_map[buck];
+
/* Voltage stabilization */
- max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val);
+ ret = max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val);
+ if (ret)
+ return ret;
/* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */
/* MAX8998 has ENRAMP bit implemented, so test it*/
if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP))
- return ret;
+ return 0;
- difference = desc->min + desc->step*i - previous_vol/1000;
+ difference = (new_selector - old_selector) * desc->step;
if (difference > 0)
- udelay(difference / ((val & 0x0f) + 1));
+ return difference / ((val & 0x0f) + 1);
- return ret;
+ return 0;
}
static struct regulator_ops max8998_ldo_ops = {
@@ -502,7 +523,7 @@ static struct regulator_ops max8998_ldo_ops = {
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
- .get_voltage = max8998_get_voltage,
+ .get_voltage_sel = max8998_get_voltage_sel,
.set_voltage = max8998_set_voltage_ldo,
.set_suspend_enable = max8998_ldo_enable,
.set_suspend_disable = max8998_ldo_disable,
@@ -513,8 +534,9 @@ static struct regulator_ops max8998_buck_ops = {
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
- .get_voltage = max8998_get_voltage,
+ .get_voltage_sel = max8998_get_voltage_sel,
.set_voltage = max8998_set_voltage_buck,
+ .set_voltage_time_sel = max8998_set_voltage_buck_time_sel,
.set_suspend_enable = max8998_ldo_enable,
.set_suspend_disable = max8998_ldo_disable,
};
@@ -685,6 +707,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
{
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct regulator_config config = { };
struct regulator_dev **rdev;
struct max8998_data *max8998;
struct i2c_client *i2c;
@@ -695,16 +718,15 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
return -ENODEV;
}
- max8998 = kzalloc(sizeof(struct max8998_data), GFP_KERNEL);
+ max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_data),
+ GFP_KERNEL);
if (!max8998)
return -ENOMEM;
size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8998->rdev = kzalloc(size, GFP_KERNEL);
- if (!max8998->rdev) {
- kfree(max8998);
+ max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!max8998->rdev)
return -ENOMEM;
- }
rdev = max8998->rdev;
max8998->dev = &pdev->dev;
@@ -728,14 +750,14 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set1);
ret = -EIO;
- goto err_free_mem;
+ goto err_out;
}
/* Check if SET2 is not equal to 0 */
if (!pdata->buck1_set2) {
printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set2);
ret = -EIO;
- goto err_free_mem;
+ goto err_out;
}
gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1");
@@ -755,7 +777,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
/* Set predefined value for BUCK1 register 2 */
i = 0;
@@ -767,7 +789,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[1] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
/* Set predefined value for BUCK1 register 3 */
i = 0;
@@ -779,7 +801,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[2] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
/* Set predefined value for BUCK1 register 4 */
i = 0;
@@ -791,7 +813,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[3] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
}
@@ -801,7 +823,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck2_set3);
ret = -EIO;
- goto err_free_mem;
+ goto err_out;
}
gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");
gpio_direction_output(pdata->buck2_set3,
@@ -816,7 +838,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck2_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
/* BUCK2 register 2 */
i = 0;
@@ -827,7 +849,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck2_vol[1] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
if (ret)
- goto err_free_mem;
+ goto err_out;
}
for (i = 0; i < pdata->num_regulators; i++) {
@@ -840,8 +862,12 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
int count = (desc->max - desc->min) / desc->step + 1;
regulators[index].n_voltages = count;
}
- rdev[i] = regulator_register(&regulators[index], max8998->dev,
- pdata->regulators[i].initdata, max8998, NULL);
+
+ config.dev = max8998->dev;
+ config.init_data = pdata->regulators[i].initdata;
+ config.driver_data = max8998;
+
+ rdev[i] = regulator_register(&regulators[index], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(max8998->dev, "regulator init failed\n");
@@ -853,14 +879,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
return 0;
err:
- for (i = 0; i < max8998->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
-
-err_free_mem:
- kfree(max8998->rdev);
- kfree(max8998);
-
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+err_out:
return ret;
}
@@ -871,12 +892,7 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
int i;
for (i = 0; i < max8998->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
-
- kfree(max8998->rdev);
- kfree(max8998);
-
+ regulator_unregister(rdev[i]);
return 0;
}
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 6c0face..7dcdfa2 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -340,6 +340,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
struct mc13xxx_regulator_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct mc13xxx_regulator_init_data *init_data;
+ struct regulator_config config = { };
int i, ret;
dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id);
@@ -357,11 +358,16 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
priv->mc13xxx = mc13783;
for (i = 0; i < pdata->num_regulators; i++) {
+ struct regulator_desc *desc;
+
init_data = &pdata->regulators[i];
- priv->regulators[i] = regulator_register(
- &mc13783_regulators[init_data->id].desc,
- &pdev->dev, init_data->init_data, priv, NULL);
+ desc = &mc13783_regulators[init_data->id].desc;
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data->init_data;
+ config.driver_data = priv;
+ priv->regulators[i] = regulator_register(desc, &config);
if (IS_ERR(priv->regulators[i])) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
mc13783_regulators[i].desc.name);
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 845aa22..970a233 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -428,24 +428,15 @@ static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
return val;
}
-static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
int hi, value, mask, id = rdev_get_id(rdev);
u32 valread;
int ret;
- dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
- __func__, id, min_uV, max_uV);
-
- /* Find the best index */
- value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
- dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
- if (value < 0)
- return value;
-
- value = mc13892_regulators[id].voltages[value];
+ value = mc13892_regulators[id].voltages[selector];
mc13xxx_lock(priv->mc13xxx);
ret = mc13xxx_reg_read(priv->mc13xxx,
@@ -480,7 +471,7 @@ err:
static struct regulator_ops mc13892_sw_regulator_ops = {
.is_enabled = mc13xxx_sw_regulator_is_enabled,
.list_voltage = mc13xxx_regulator_list_voltage,
- .set_voltage = mc13892_sw_regulator_set_voltage,
+ .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
.get_voltage = mc13892_sw_regulator_get_voltage,
};
@@ -528,6 +519,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
struct mc13xxx_regulator_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct mc13xxx_regulator_init_data *mc13xxx_data;
+ struct regulator_config config = { };
int i, ret;
int num_regulators = 0;
u32 val;
@@ -597,9 +589,12 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
}
desc = &mc13892_regulators[id].desc;
- priv->regulators[i] = regulator_register(
- desc, &pdev->dev, init_data, priv, node);
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = priv;
+ config.of_node = node;
+ priv->regulators[i] = regulator_register(desc, &config);
if (IS_ERR(priv->regulators[i])) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
mc13892_regulators[i].desc.name);
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 62dcd0a..4fa9704 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -94,62 +94,18 @@ int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
-int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
- int reg_id = rdev_get_id(rdev);
- int i;
- int bestmatch;
- int bestindex;
-
- /*
- * Locate the minimum voltage fitting the criteria on
- * this regulator. The switchable voltages are not
- * in strict falling order so we need to check them
- * all for the best match.
- */
- bestmatch = INT_MAX;
- bestindex = -1;
- for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) {
- if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV &&
- mc13xxx_regulators[reg_id].voltages[i] < bestmatch) {
- bestmatch = mc13xxx_regulators[reg_id].voltages[i];
- bestindex = i;
- }
- }
-
- if (bestindex < 0 || bestmatch > max_uV) {
- dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
- min_uV, max_uV);
- return -EINVAL;
- }
- return bestindex;
-}
-EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index);
-
-static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
- struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
- int value, id = rdev_get_id(rdev);
+ int id = rdev_get_id(rdev);
int ret;
- dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
- __func__, id, min_uV, max_uV);
-
- /* Find the best index */
- value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
- dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
- if (value < 0)
- return value;
-
mc13xxx_lock(priv->mc13xxx);
ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg,
mc13xxx_regulators[id].vsel_mask,
- value << mc13xxx_regulators[id].vsel_shift);
+ selector << mc13xxx_regulators[id].vsel_shift);
mc13xxx_unlock(priv->mc13xxx);
return ret;
@@ -187,7 +143,7 @@ struct regulator_ops mc13xxx_regulator_ops = {
.disable = mc13xxx_regulator_disable,
.is_enabled = mc13xxx_regulator_is_enabled,
.list_voltage = mc13xxx_regulator_list_voltage,
- .set_voltage = mc13xxx_regulator_set_voltage,
+ .set_voltage_sel = mc13xxx_regulator_set_voltage_sel,
.get_voltage = mc13xxx_regulator_get_voltage,
};
EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops);
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index b3961c6..044aba4 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -35,8 +35,6 @@ struct mc13xxx_regulator_priv {
extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
-extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
- int min_uV, int max_uV);
extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
unsigned selector);
extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 679734d..56593b7 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data)
@@ -85,3 +86,49 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
return init_data;
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
+
+/**
+ * of_regulator_match - extract regulator init data
+ * @dev: device requesting the data
+ * @node: parent device node of the regulators
+ * @matches: match table for the regulators
+ * @num_matches: number of entries in match table
+ *
+ * This function uses a match table specified by the regulator driver and
+ * looks up the corresponding init data in the device tree. Note that the
+ * match table is modified in place.
+ *
+ * Returns the number of matches found or a negative error code on failure.
+ */
+int of_regulator_match(struct device *dev, struct device_node *node,
+ struct of_regulator_match *matches,
+ unsigned int num_matches)
+{
+ unsigned int count = 0;
+ unsigned int i;
+
+ if (!dev || !node)
+ return -EINVAL;
+
+ for (i = 0; i < num_matches; i++) {
+ struct of_regulator_match *match = &matches[i];
+ struct device_node *child;
+
+ child = of_find_node_by_name(node, match->name);
+ if (!child)
+ continue;
+
+ match->init_data = of_get_regulator_init_data(dev, child);
+ if (!match->init_data) {
+ dev_err(dev, "failed to parse DT for regulator %s\n",
+ child->name);
+ return -EINVAL;
+ }
+
+ match->of_node = child;
+ count++;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(of_regulator_match);
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
new file mode 100644
index 0000000..c4435f6
--- /dev/null
+++ b/drivers/regulator/palmas-regulator.c
@@ -0,0 +1,822 @@
+/*
+ * Driver for Regulator part of Palmas PMIC Chips
+ *
+ * Copyright 2011-2012 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/palmas.h>
+
+struct regs_info {
+ char *name;
+ u8 vsel_addr;
+ u8 ctrl_addr;
+ u8 tstep_addr;
+};
+
+static const struct regs_info palmas_regs_info[] = {
+ {
+ .name = "SMPS12",
+ .vsel_addr = PALMAS_SMPS12_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS12_CTRL,
+ .tstep_addr = PALMAS_SMPS12_TSTEP,
+ },
+ {
+ .name = "SMPS123",
+ .vsel_addr = PALMAS_SMPS12_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS12_CTRL,
+ .tstep_addr = PALMAS_SMPS12_TSTEP,
+ },
+ {
+ .name = "SMPS3",
+ .vsel_addr = PALMAS_SMPS3_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS3_CTRL,
+ },
+ {
+ .name = "SMPS45",
+ .vsel_addr = PALMAS_SMPS45_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS45_CTRL,
+ .tstep_addr = PALMAS_SMPS45_TSTEP,
+ },
+ {
+ .name = "SMPS457",
+ .vsel_addr = PALMAS_SMPS45_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS45_CTRL,
+ .tstep_addr = PALMAS_SMPS45_TSTEP,
+ },
+ {
+ .name = "SMPS6",
+ .vsel_addr = PALMAS_SMPS6_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS6_CTRL,
+ .tstep_addr = PALMAS_SMPS6_TSTEP,
+ },
+ {
+ .name = "SMPS7",
+ .vsel_addr = PALMAS_SMPS7_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS7_CTRL,
+ },
+ {
+ .name = "SMPS8",
+ .vsel_addr = PALMAS_SMPS8_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS8_CTRL,
+ .tstep_addr = PALMAS_SMPS8_TSTEP,
+ },
+ {
+ .name = "SMPS9",
+ .vsel_addr = PALMAS_SMPS9_VOLTAGE,
+ .ctrl_addr = PALMAS_SMPS9_CTRL,
+ },
+ {
+ .name = "SMPS10",
+ },
+ {
+ .name = "LDO1",
+ .vsel_addr = PALMAS_LDO1_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO1_CTRL,
+ },
+ {
+ .name = "LDO2",
+ .vsel_addr = PALMAS_LDO2_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO2_CTRL,
+ },
+ {
+ .name = "LDO3",
+ .vsel_addr = PALMAS_LDO3_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO3_CTRL,
+ },
+ {
+ .name = "LDO4",
+ .vsel_addr = PALMAS_LDO4_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO4_CTRL,
+ },
+ {
+ .name = "LDO5",
+ .vsel_addr = PALMAS_LDO5_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO5_CTRL,
+ },
+ {
+ .name = "LDO6",
+ .vsel_addr = PALMAS_LDO6_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO6_CTRL,
+ },
+ {
+ .name = "LDO7",
+ .vsel_addr = PALMAS_LDO7_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO7_CTRL,
+ },
+ {
+ .name = "LDO8",
+ .vsel_addr = PALMAS_LDO8_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO8_CTRL,
+ },
+ {
+ .name = "LDO9",
+ .vsel_addr = PALMAS_LDO9_VOLTAGE,
+ .ctrl_addr = PALMAS_LDO9_CTRL,
+ },
+ {
+ .name = "LDOLN",
+ .vsel_addr = PALMAS_LDOLN_VOLTAGE,
+ .ctrl_addr = PALMAS_LDOLN_CTRL,
+ },
+ {
+ .name = "LDOUSB",
+ .vsel_addr = PALMAS_LDOUSB_VOLTAGE,
+ .ctrl_addr = PALMAS_LDOUSB_CTRL,
+ },
+};
+
+#define SMPS_CTRL_MODE_OFF 0x00
+#define SMPS_CTRL_MODE_ON 0x01
+#define SMPS_CTRL_MODE_ECO 0x02
+#define SMPS_CTRL_MODE_PWM 0x03
+
+/* These values are derived from the data sheet. And are the number of steps
+ * where there is a voltage change, the ranges at beginning and end of register
+ * max/min values where there are no change are ommitted.
+ *
+ * So they are basically (maxV-minV)/stepV
+ */
+#define PALMAS_SMPS_NUM_VOLTAGES 116
+#define PALMAS_SMPS10_NUM_VOLTAGES 2
+#define PALMAS_LDO_NUM_VOLTAGES 50
+
+#define SMPS10_VSEL (1<<3)
+#define SMPS10_BOOST_EN (1<<2)
+#define SMPS10_BYPASS_EN (1<<1)
+#define SMPS10_SWITCH_EN (1<<0)
+
+#define REGULATOR_SLAVE 0
+
+static int palmas_smps_read(struct palmas *palmas, unsigned int reg,
+ unsigned int *dest)
+{
+ unsigned int addr;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg);
+
+ return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest);
+}
+
+static int palmas_smps_write(struct palmas *palmas, unsigned int reg,
+ unsigned int value)
+{
+ unsigned int addr;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg);
+
+ return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
+}
+
+static int palmas_ldo_read(struct palmas *palmas, unsigned int reg,
+ unsigned int *dest)
+{
+ unsigned int addr;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg);
+
+ return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest);
+}
+
+static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
+ unsigned int value)
+{
+ unsigned int addr;
+
+ addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg);
+
+ return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
+}
+
+static int palmas_is_enabled_smps(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+
+ reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
+ reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+
+ return !!(reg);
+}
+
+static int palmas_enable_smps(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+
+ reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
+ reg |= SMPS_CTRL_MODE_ON;
+
+ palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
+
+ return 0;
+}
+
+static int palmas_disable_smps(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+
+ reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
+
+ palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
+
+ return 0;
+}
+
+
+static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+ reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK;
+ reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ reg |= SMPS_CTRL_MODE_ON;
+ break;
+ case REGULATOR_MODE_IDLE:
+ reg |= SMPS_CTRL_MODE_ECO;
+ break;
+ case REGULATOR_MODE_FAST:
+ reg |= SMPS_CTRL_MODE_PWM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
+
+ return 0;
+}
+
+static unsigned int palmas_get_mode_smps(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+ reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
+ reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+
+ switch (reg) {
+ case SMPS_CTRL_MODE_ON:
+ return REGULATOR_MODE_NORMAL;
+ case SMPS_CTRL_MODE_ECO:
+ return REGULATOR_MODE_IDLE;
+ case SMPS_CTRL_MODE_PWM:
+ return REGULATOR_MODE_FAST;
+ }
+
+ return 0;
+}
+
+static int palmas_list_voltage_smps(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ int mult = 1;
+
+ if (!selector)
+ return 0;
+
+ /* Read the multiplier set in VSEL register to return
+ * the correct voltage.
+ */
+ if (pmic->range[id])
+ mult = 2;
+
+ /* Voltage is (0.49V + (selector * 0.01V)) * RANGE
+ * as defined in data sheet. RANGE is either x1 or x2
+ */
+ return (490000 + (selector * 10000)) * mult;
+}
+
+static int palmas_get_voltage_smps_sel(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ int selector;
+ unsigned int reg;
+ unsigned int addr;
+
+ addr = palmas_regs_info[id].vsel_addr;
+
+ palmas_smps_read(pmic->palmas, addr, &reg);
+
+ selector = reg & PALMAS_SMPS12_VOLTAGE_VSEL_MASK;
+
+ /* Adjust selector to match list_voltage ranges */
+ if ((selector > 0) && (selector < 6))
+ selector = 6;
+ if (!selector)
+ selector = 5;
+ if (selector > 121)
+ selector = 121;
+ selector -= 5;
+
+ return selector;
+}
+
+static int palmas_set_voltage_smps_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg = 0;
+ unsigned int addr;
+
+ addr = palmas_regs_info[id].vsel_addr;
+
+ /* Make sure we don't change the value of RANGE */
+ if (pmic->range[id])
+ reg |= PALMAS_SMPS12_VOLTAGE_RANGE;
+
+ /* Adjust the linux selector into range used in VSEL register */
+ if (selector)
+ reg |= selector + 5;
+
+ palmas_smps_write(pmic->palmas, addr, reg);
+
+ return 0;
+}
+
+static int palmas_map_voltage_smps(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret, voltage;
+
+ ret = ((min_uV - 500000) / 10000) + 1;
+ if (ret < 0)
+ return ret;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = palmas_list_voltage_smps(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+
+static struct regulator_ops palmas_ops_smps = {
+ .is_enabled = palmas_is_enabled_smps,
+ .enable = palmas_enable_smps,
+ .disable = palmas_disable_smps,
+ .set_mode = palmas_set_mode_smps,
+ .get_mode = palmas_get_mode_smps,
+ .get_voltage_sel = palmas_get_voltage_smps_sel,
+ .set_voltage_sel = palmas_set_voltage_smps_sel,
+ .list_voltage = palmas_list_voltage_smps,
+ .map_voltage = palmas_map_voltage_smps,
+};
+
+static int palmas_list_voltage_smps10(struct regulator_dev *dev,
+ unsigned selector)
+{
+ return 3750000 + (selector * 1250000);
+}
+
+static struct regulator_ops palmas_ops_smps10 = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = palmas_list_voltage_smps10,
+};
+
+static int palmas_is_enabled_ldo(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg;
+
+ palmas_ldo_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
+
+ reg &= PALMAS_LDO1_CTRL_STATUS;
+
+ return !!(reg);
+}
+
+static int palmas_list_voltage_ldo(struct regulator_dev *dev,
+ unsigned selector)
+{
+ if (!selector)
+ return 0;
+
+ /* voltage is 0.85V + (selector * 0.05v) */
+ return 850000 + (selector * 50000);
+}
+
+static int palmas_get_voltage_ldo_sel(struct regulator_dev *dev)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ int selector;
+ unsigned int reg;
+ unsigned int addr;
+
+ addr = palmas_regs_info[id].vsel_addr;
+
+ palmas_ldo_read(pmic->palmas, addr, &reg);
+
+ selector = reg & PALMAS_LDO1_VOLTAGE_VSEL_MASK;
+
+ /* Adjust selector to match list_voltage ranges */
+ if (selector > 49)
+ selector = 49;
+
+ return selector;
+}
+
+static int palmas_set_voltage_ldo_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev);
+ unsigned int reg = 0;
+ unsigned int addr;
+
+ addr = palmas_regs_info[id].vsel_addr;
+
+ reg = selector;
+
+ palmas_ldo_write(pmic->palmas, addr, reg);
+
+ return 0;
+}
+
+static int palmas_map_voltage_ldo(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret, voltage;
+
+ ret = ((min_uV - 900000) / 50000) + 1;
+ if (ret < 0)
+ return ret;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = palmas_list_voltage_ldo(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+
+static struct regulator_ops palmas_ops_ldo = {
+ .is_enabled = palmas_is_enabled_ldo,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = palmas_get_voltage_ldo_sel,
+ .set_voltage_sel = palmas_set_voltage_ldo_sel,
+ .list_voltage = palmas_list_voltage_ldo,
+ .map_voltage = palmas_map_voltage_ldo,
+};
+
+/*
+ * setup the hardware based sleep configuration of the SMPS/LDO regulators
+ * from the platform data. This is different to the software based control
+ * supported by the regulator framework as it is controlled by toggling
+ * pins on the PMIC such as PREQ, SYSEN, ...
+ */
+static int palmas_smps_init(struct palmas *palmas, int id,
+ struct palmas_reg_init *reg_init)
+{
+ unsigned int reg;
+ unsigned int addr;
+ int ret;
+
+ addr = palmas_regs_info[id].ctrl_addr;
+
+ ret = palmas_smps_read(palmas, addr, &reg);
+ if (ret)
+ return ret;
+
+ if (id != PALMAS_REG_SMPS10) {
+ if (reg_init->warm_reset)
+ reg |= PALMAS_SMPS12_CTRL_WR_S;
+
+ if (reg_init->roof_floor)
+ reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
+
+ if (reg_init->mode_sleep) {
+ reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
+ reg |= reg_init->mode_sleep <<
+ PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
+ }
+ } else {
+ if (reg_init->mode_sleep) {
+ reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+ reg |= reg_init->mode_sleep <<
+ PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
+ }
+
+ }
+ ret = palmas_smps_write(palmas, addr, reg);
+ if (ret)
+ return ret;
+
+ if (palmas_regs_info[id].tstep_addr && reg_init->tstep) {
+ addr = palmas_regs_info[id].tstep_addr;
+
+ reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK;
+
+ ret = palmas_smps_write(palmas, addr, reg);
+ if (ret)
+ return ret;
+ }
+
+ if (palmas_regs_info[id].vsel_addr && reg_init->vsel) {
+ addr = palmas_regs_info[id].vsel_addr;
+
+ reg = reg_init->vsel;
+
+ ret = palmas_smps_write(palmas, addr, reg);
+ if (ret)
+ return ret;
+ }
+
+
+ return 0;
+}
+
+static int palmas_ldo_init(struct palmas *palmas, int id,
+ struct palmas_reg_init *reg_init)
+{
+ unsigned int reg;
+ unsigned int addr;
+ int ret;
+
+ addr = palmas_regs_info[id].ctrl_addr;
+
+ ret = palmas_smps_read(palmas, addr, &reg);
+ if (ret)
+ return ret;
+
+ if (reg_init->warm_reset)
+ reg |= PALMAS_LDO1_CTRL_WR_S;
+
+ if (reg_init->mode_sleep)
+ reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
+
+ ret = palmas_smps_write(palmas, addr, reg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static __devinit int palmas_probe(struct platform_device *pdev)
+{
+ struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+ struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
+ struct regulator_dev *rdev;
+ struct regulator_config config = { };
+ struct palmas_pmic *pmic;
+ struct palmas_reg_init *reg_init;
+ int id = 0, ret;
+ unsigned int addr, reg;
+
+ if (!pdata)
+ return -EINVAL;
+ if (!pdata->reg_data)
+ return -EINVAL;
+
+ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ pmic->dev = &pdev->dev;
+ pmic->palmas = palmas;
+ palmas->pmic = pmic;
+ platform_set_drvdata(pdev, pmic);
+
+ ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, &reg);
+ if (ret)
+ goto err_unregister_regulator;
+
+ if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN)
+ pmic->smps123 = 1;
+
+ if (reg & PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN)
+ pmic->smps457 = 1;
+
+ config.regmap = palmas->regmap[REGULATOR_SLAVE];
+ config.dev = &pdev->dev;
+ config.driver_data = pmic;
+
+ for (id = 0; id < PALMAS_REG_LDO1; id++) {
+
+ /*
+ * Miss out regulators which are not available due
+ * to slaving configurations.
+ */
+ switch (id) {
+ case PALMAS_REG_SMPS12:
+ case PALMAS_REG_SMPS3:
+ if (pmic->smps123)
+ continue;
+ break;
+ case PALMAS_REG_SMPS123:
+ if (!pmic->smps123)
+ continue;
+ break;
+ case PALMAS_REG_SMPS45:
+ case PALMAS_REG_SMPS7:
+ if (pmic->smps457)
+ continue;
+ break;
+ case PALMAS_REG_SMPS457:
+ if (!pmic->smps457)
+ continue;
+ }
+
+ /* Register the regulators */
+ pmic->desc[id].name = palmas_regs_info[id].name;
+ pmic->desc[id].id = id;
+
+ if (id != PALMAS_REG_SMPS10) {
+ pmic->desc[id].ops = &palmas_ops_smps;
+ pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
+ } else {
+ pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
+ pmic->desc[id].ops = &palmas_ops_smps10;
+ pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
+ pmic->desc[id].vsel_mask = SMPS10_VSEL;
+ pmic->desc[id].enable_reg = PALMAS_SMPS10_STATUS;
+ pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+ }
+
+ pmic->desc[id].type = REGULATOR_VOLTAGE;
+ pmic->desc[id].owner = THIS_MODULE;
+
+ /* Initialise sleep/init values from platform data */
+ if (pdata && pdata->reg_init) {
+ reg_init = pdata->reg_init[id];
+ if (reg_init) {
+ ret = palmas_smps_init(palmas, id, reg_init);
+ if (ret)
+ goto err_unregister_regulator;
+ }
+ }
+
+ /*
+ * read and store the RANGE bit for later use
+ * This must be done before regulator is probed otherwise
+ * we error in probe with unsuportable ranges.
+ */
+ if (id != PALMAS_REG_SMPS10) {
+ addr = palmas_regs_info[id].vsel_addr;
+
+ ret = palmas_smps_read(pmic->palmas, addr, &reg);
+ if (ret)
+ goto err_unregister_regulator;
+ if (reg & PALMAS_SMPS12_VOLTAGE_RANGE)
+ pmic->range[id] = 1;
+ }
+
+ if (pdata && pdata->reg_data)
+ config.init_data = pdata->reg_data[id];
+ else
+ config.init_data = NULL;
+
+ rdev = regulator_register(&pmic->desc[id], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ ret = PTR_ERR(rdev);
+ goto err_unregister_regulator;
+ }
+
+ /* Save regulator for cleanup */
+ pmic->rdev[id] = rdev;
+ }
+
+ /* Start this loop from the id left from previous loop */
+ for (; id < PALMAS_NUM_REGS; id++) {
+
+ /* Miss out regulators which are not available due
+ * to alternate functions.
+ */
+
+ /* Register the regulators */
+ pmic->desc[id].name = palmas_regs_info[id].name;
+ pmic->desc[id].id = id;
+ pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
+
+ pmic->desc[id].ops = &palmas_ops_ldo;
+
+ pmic->desc[id].type = REGULATOR_VOLTAGE;
+ pmic->desc[id].owner = THIS_MODULE;
+ pmic->desc[id].enable_reg = palmas_regs_info[id].ctrl_addr;
+ pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
+
+ if (pdata && pdata->reg_data)
+ config.init_data = pdata->reg_data[id];
+ else
+ config.init_data = NULL;
+
+ rdev = regulator_register(&pmic->desc[id], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ ret = PTR_ERR(rdev);
+ goto err_unregister_regulator;
+ }
+
+ /* Save regulator for cleanup */
+ pmic->rdev[id] = rdev;
+
+ /* Initialise sleep/init values from platform data */
+ if (pdata->reg_init) {
+ reg_init = pdata->reg_init[id];
+ if (reg_init) {
+ ret = palmas_ldo_init(palmas, id, reg_init);
+ if (ret)
+ goto err_unregister_regulator;
+ }
+ }
+ }
+
+ return 0;
+
+err_unregister_regulator:
+ while (--id >= 0)
+ regulator_unregister(pmic->rdev[id]);
+ kfree(pmic->rdev);
+ kfree(pmic->desc);
+ kfree(pmic);
+ return ret;
+}
+
+static int __devexit palmas_remove(struct platform_device *pdev)
+{
+ struct palmas_pmic *pmic = platform_get_drvdata(pdev);
+ int id;
+
+ for (id = 0; id < PALMAS_NUM_REGS; id++)
+ regulator_unregister(pmic->rdev[id]);
+
+ kfree(pmic->rdev);
+ kfree(pmic->desc);
+ kfree(pmic);
+ return 0;
+}
+
+static struct platform_driver palmas_driver = {
+ .driver = {
+ .name = "palmas-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = palmas_probe,
+ .remove = __devexit_p(palmas_remove),
+};
+
+static int __init palmas_init(void)
+{
+ return platform_driver_register(&palmas_driver);
+}
+subsys_initcall(palmas_init);
+
+static void __exit palmas_exit(void)
+{
+ platform_driver_unregister(&palmas_driver);
+}
+module_exit(palmas_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("Palmas voltage regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:palmas-pmic");
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index a5aab1b..8211101 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -150,57 +150,33 @@ static struct pcap_regulator vreg_table[] = {
VREG_INFO(SW2S, PCAP_REG_LOWPWR, NA, 20, NA, NA), */
};
-static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
void *pcap = rdev_get_drvdata(rdev);
- int uV;
- u8 i;
/* the regulator doesn't support voltage switching */
if (vreg->n_voltages == 1)
return -EINVAL;
- for (i = 0; i < vreg->n_voltages; i++) {
- /* For V1 the first is not the best match */
- if (i == 0 && rdev_get_id(rdev) == V1)
- i = 1;
- else if (i + 1 == vreg->n_voltages && rdev_get_id(rdev) == V1)
- i = 0;
-
- uV = vreg->voltage_table[i] * 1000;
- if (min_uV <= uV && uV <= max_uV) {
- *selector = i;
- return ezx_pcap_set_bits(pcap, vreg->reg,
- (vreg->n_voltages - 1) << vreg->index,
- i << vreg->index);
- }
-
- if (i == 0 && rdev_get_id(rdev) == V1)
- i = vreg->n_voltages - 1;
- }
-
- /* the requested voltage range is not supported by this regulator */
- return -EINVAL;
+ return ezx_pcap_set_bits(pcap, vreg->reg,
+ (vreg->n_voltages - 1) << vreg->index,
+ selector << vreg->index);
}
-static int pcap_regulator_get_voltage(struct regulator_dev *rdev)
+static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
void *pcap = rdev_get_drvdata(rdev);
u32 tmp;
- int mV;
if (vreg->n_voltages == 1)
- return vreg->voltage_table[0] * 1000;
+ return 0;
ezx_pcap_read(pcap, vreg->reg, &tmp);
tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
- mV = vreg->voltage_table[tmp];
-
- return mV * 1000;
+ return tmp;
}
static int pcap_regulator_enable(struct regulator_dev *rdev)
@@ -248,8 +224,8 @@ static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
static struct regulator_ops pcap_regulator_ops = {
.list_voltage = pcap_regulator_list_voltage,
- .set_voltage = pcap_regulator_set_voltage,
- .get_voltage = pcap_regulator_get_voltage,
+ .set_voltage_sel = pcap_regulator_set_voltage_sel,
+ .get_voltage_sel = pcap_regulator_get_voltage_sel,
.enable = pcap_regulator_enable,
.disable = pcap_regulator_disable,
.is_enabled = pcap_regulator_is_enabled,
@@ -265,7 +241,7 @@ static struct regulator_ops pcap_regulator_ops = {
.owner = THIS_MODULE, \
}
-static struct regulator_desc pcap_regulators[] = {
+static const struct regulator_desc pcap_regulators[] = {
VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7),
VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3),
VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2),
@@ -275,9 +251,13 @@ static int __devinit pcap_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
void *pcap = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = pcap;
- rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, pcap, NULL);
+ rdev = regulator_register(&pcap_regulators[pdev->id], &config);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 6db46c6..3c9d14c 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -24,35 +24,25 @@
#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/pmic.h>
-#define PCF50633_REGULATOR(_name, _id, _n) \
- { \
- .name = _name, \
- .id = _id, \
- .ops = &pcf50633_regulator_ops, \
- .n_voltages = _n, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
+#define PCF50633_REGULATOR(_name, _id, _n) \
+ { \
+ .name = _name, \
+ .id = PCF50633_REGULATOR_##_id, \
+ .ops = &pcf50633_regulator_ops, \
+ .n_voltages = _n, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = PCF50633_REG_##_id##OUT, \
+ .vsel_mask = 0xff, \
+ .enable_reg = PCF50633_REG_##_id##OUT + 1, \
+ .enable_mask = PCF50633_REGULATOR_ON, \
}
-static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
- [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
- [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT,
- [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT,
- [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT,
- [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT,
- [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT,
- [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT,
- [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT,
- [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT,
- [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT,
- [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT,
-};
-
/* Bits from voltage value */
static u8 auto_voltage_bits(unsigned int millivolts)
{
if (millivolts < 1800)
- return 0;
+ return 0x2f;
if (millivolts > 3800)
return 0xff;
@@ -87,6 +77,9 @@ static u8 ldo_voltage_bits(unsigned int millivolts)
/* Obtain voltage value from bits */
static unsigned int auto_voltage_value(u8 bits)
{
+ /* AUTOOUT: 00000000 to 00101110 are reserved.
+ * Return 0 for bits in reserved range, which means this selector code
+ * can't be used on this system */
if (bits < 0x2f)
return 0;
@@ -123,7 +116,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
millivolts = min_uV / 1000;
- regnr = pcf50633_regulator_registers[regulator_id];
+ regnr = rdev->desc->vsel_reg;
switch (regulator_id) {
case PCF50633_REGULATOR_AUTO:
@@ -154,20 +147,22 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
return pcf50633_reg_write(pcf, regnr, volt_bits);
}
-static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,
- u8 bits)
+static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned int index)
{
+ int regulator_id = rdev_get_id(rdev);
+
int millivolts;
- switch (id) {
+ switch (regulator_id) {
case PCF50633_REGULATOR_AUTO:
- millivolts = auto_voltage_value(bits);
+ millivolts = auto_voltage_value(index);
break;
case PCF50633_REGULATOR_DOWN1:
- millivolts = down_voltage_value(bits);
+ millivolts = down_voltage_value(index);
break;
case PCF50633_REGULATOR_DOWN2:
- millivolts = down_voltage_value(bits);
+ millivolts = down_voltage_value(index);
break;
case PCF50633_REGULATOR_LDO1:
case PCF50633_REGULATOR_LDO2:
@@ -177,7 +172,7 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,
case PCF50633_REGULATOR_LDO6:
case PCF50633_REGULATOR_HCLDO:
case PCF50633_REGULATOR_MEMLDO:
- millivolts = ldo_voltage_value(bits);
+ millivolts = ldo_voltage_value(index);
break;
default:
return -EINVAL;
@@ -186,140 +181,44 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,
return millivolts * 1000;
}
-static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
-{
- struct pcf50633 *pcf;
- int regulator_id;
- u8 volt_bits, regnr;
-
- pcf = rdev_get_drvdata(rdev);
-
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= PCF50633_NUM_REGULATORS)
- return -EINVAL;
-
- regnr = pcf50633_regulator_registers[regulator_id];
-
- volt_bits = pcf50633_reg_read(pcf, regnr);
-
- return pcf50633_regulator_voltage_value(regulator_id, volt_bits);
-}
-
-static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned int index)
-{
- struct pcf50633 *pcf;
- int regulator_id;
-
- pcf = rdev_get_drvdata(rdev);
-
- regulator_id = rdev_get_id(rdev);
-
- switch (regulator_id) {
- case PCF50633_REGULATOR_AUTO:
- index += 0x2f;
- break;
- default:
- break;
- }
-
- return pcf50633_regulator_voltage_value(regulator_id, index);
-}
-
-static int pcf50633_regulator_enable(struct regulator_dev *rdev)
-{
- struct pcf50633 *pcf = rdev_get_drvdata(rdev);
- int regulator_id;
- u8 regnr;
-
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= PCF50633_NUM_REGULATORS)
- return -EINVAL;
-
- /* The *ENA register is always one after the *OUT register */
- regnr = pcf50633_regulator_registers[regulator_id] + 1;
-
- return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON,
- PCF50633_REGULATOR_ON);
-}
-
-static int pcf50633_regulator_disable(struct regulator_dev *rdev)
-{
- struct pcf50633 *pcf = rdev_get_drvdata(rdev);
- int regulator_id;
- u8 regnr;
-
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= PCF50633_NUM_REGULATORS)
- return -EINVAL;
-
- /* the *ENA register is always one after the *OUT register */
- regnr = pcf50633_regulator_registers[regulator_id] + 1;
-
- return pcf50633_reg_set_bit_mask(pcf, regnr,
- PCF50633_REGULATOR_ON, 0);
-}
-
-static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
-{
- struct pcf50633 *pcf = rdev_get_drvdata(rdev);
- int regulator_id = rdev_get_id(rdev);
- u8 regnr;
-
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= PCF50633_NUM_REGULATORS)
- return -EINVAL;
-
- /* the *ENA register is always one after the *OUT register */
- regnr = pcf50633_regulator_registers[regulator_id] + 1;
-
- return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON;
-}
-
static struct regulator_ops pcf50633_regulator_ops = {
.set_voltage = pcf50633_regulator_set_voltage,
- .get_voltage = pcf50633_regulator_get_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = pcf50633_regulator_list_voltage,
- .enable = pcf50633_regulator_enable,
- .disable = pcf50633_regulator_disable,
- .is_enabled = pcf50633_regulator_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
};
-static struct regulator_desc regulators[] = {
- [PCF50633_REGULATOR_AUTO] =
- PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 81),
- [PCF50633_REGULATOR_DOWN1] =
- PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 96),
- [PCF50633_REGULATOR_DOWN2] =
- PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 96),
- [PCF50633_REGULATOR_LDO1] =
- PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 28),
- [PCF50633_REGULATOR_LDO2] =
- PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 28),
- [PCF50633_REGULATOR_LDO3] =
- PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 28),
- [PCF50633_REGULATOR_LDO4] =
- PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 28),
- [PCF50633_REGULATOR_LDO5] =
- PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 28),
- [PCF50633_REGULATOR_LDO6] =
- PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 28),
- [PCF50633_REGULATOR_HCLDO] =
- PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 28),
- [PCF50633_REGULATOR_MEMLDO] =
- PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 28),
+static const struct regulator_desc regulators[] = {
+ [PCF50633_REGULATOR_AUTO] = PCF50633_REGULATOR("auto", AUTO, 128),
+ [PCF50633_REGULATOR_DOWN1] = PCF50633_REGULATOR("down1", DOWN1, 96),
+ [PCF50633_REGULATOR_DOWN2] = PCF50633_REGULATOR("down2", DOWN2, 96),
+ [PCF50633_REGULATOR_LDO1] = PCF50633_REGULATOR("ldo1", LDO1, 28),
+ [PCF50633_REGULATOR_LDO2] = PCF50633_REGULATOR("ldo2", LDO2, 28),
+ [PCF50633_REGULATOR_LDO3] = PCF50633_REGULATOR("ldo3", LDO3, 28),
+ [PCF50633_REGULATOR_LDO4] = PCF50633_REGULATOR("ldo4", LDO4, 28),
+ [PCF50633_REGULATOR_LDO5] = PCF50633_REGULATOR("ldo5", LDO5, 28),
+ [PCF50633_REGULATOR_LDO6] = PCF50633_REGULATOR("ldo6", LDO6, 28),
+ [PCF50633_REGULATOR_HCLDO] = PCF50633_REGULATOR("hcldo", HCLDO, 28),
+ [PCF50633_REGULATOR_MEMLDO] = PCF50633_REGULATOR("memldo", MEMLDO, 28),
};
static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
struct pcf50633 *pcf;
+ struct regulator_config config = { };
/* Already set by core driver */
pcf = dev_to_pcf50633(pdev->dev.parent);
- rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, pcf, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = pcf;
+ config.regmap = pcf->regmap;
+
+ rdev = regulator_register(&regulators[pdev->id], &config);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
new file mode 100644
index 0000000..1d34e64
--- /dev/null
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -0,0 +1,255 @@
+/*
+ * Regulator driver for RICOH RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rc5t583.h>
+
+struct rc5t583_regulator_info {
+ int deepsleep_id;
+
+ /* Regulator register address.*/
+ uint8_t reg_disc_reg;
+ uint8_t disc_bit;
+ uint8_t deepsleep_reg;
+
+ /* Regulator specific turn-on delay and voltage settling time*/
+ int enable_uv_per_us;
+ int change_uv_per_us;
+
+ /* Used by regulator core */
+ struct regulator_desc desc;
+};
+
+struct rc5t583_regulator {
+ struct rc5t583_regulator_info *reg_info;
+
+ /* Devices */
+ struct device *dev;
+ struct rc5t583 *mfd;
+ struct regulator_dev *rdev;
+};
+
+static int rc5t583_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ int vsel = regulator_get_voltage_sel_regmap(rdev);
+ int curr_uV = regulator_list_voltage_linear(rdev, vsel);
+
+ return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
+}
+
+static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+ old_uV = regulator_list_voltage_linear(rdev, old_selector);
+
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = regulator_list_voltage_linear(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV),
+ reg->reg_info->change_uv_per_us);
+}
+
+
+static struct regulator_ops rc5t583_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .enable_time = rc5t583_regulator_enable_time,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_time_sel = rc5t583_set_voltage_time_sel,
+};
+
+#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \
+ _vout_mask, _min_mv, _max_mv, _step_uV, _enable_mv) \
+{ \
+ .reg_disc_reg = RC5T583_REG_##_disc_reg, \
+ .disc_bit = _disc_bit, \
+ .deepsleep_reg = RC5T583_REG_##_id##DAC_DS, \
+ .enable_uv_per_us = _enable_mv * 1000, \
+ .change_uv_per_us = 40 * 1000, \
+ .deepsleep_id = RC5T583_DS_##_id, \
+ .desc = { \
+ .name = "rc5t583-regulator-"#_id, \
+ .id = RC5T583_REGULATOR_##_id, \
+ .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \
+ .ops = &rc5t583_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = RC5T583_REG_##_id##DAC, \
+ .vsel_mask = _vout_mask, \
+ .enable_reg = RC5T583_REG_##_en_reg, \
+ .enable_mask = BIT(_en_bit), \
+ .min_uV = _min_mv * 1000, \
+ .uV_step = _step_uV, \
+ }, \
+}
+
+static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = {
+ RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, 0x7F, 700, 1500, 12500, 4),
+ RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, 0x7F, 700, 1500, 12500, 14),
+ RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, 0x7F, 900, 2400, 12500, 14),
+ RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, 0x7F, 900, 2400, 12500, 14),
+ RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, 0x7F, 900, 3400, 25000, 160),
+ RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, 0x7F, 900, 3400, 25000, 160),
+ RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, 0x7F, 900, 3400, 25000, 160),
+ RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, 0x7F, 900, 3400, 25000, 160),
+ RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, 0x3F, 750, 1500, 12500, 133),
+ RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, 0x7F, 900, 3400, 25000, 267),
+ RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, 0x7F, 900, 3400, 25000, 133),
+ RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, 0x7F, 900, 3400, 25000, 233),
+ RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, 0x7F, 900, 3400, 25000, 233),
+ RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, 0x7F, 900, 3400, 25000, 133),
+};
+
+static int __devinit rc5t583_regulator_probe(struct platform_device *pdev)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
+ struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
+ struct regulator_init_data *reg_data;
+ struct regulator_config config = { };
+ struct rc5t583_regulator *reg = NULL;
+ struct rc5t583_regulator *regs;
+ struct regulator_dev *rdev;
+ struct rc5t583_regulator_info *ri;
+ int ret;
+ int id;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data, exiting...\n");
+ return -ENODEV;
+ }
+
+ regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *
+ sizeof(struct rc5t583_regulator), GFP_KERNEL);
+ if (!regs) {
+ dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ return -ENOMEM;
+ }
+
+
+ for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) {
+ reg_data = pdata->reg_init_data[id];
+
+ /* No need to register if there is no regulator data */
+ if (!reg_data)
+ continue;
+
+ reg = &regs[id];
+ ri = &rc5t583_reg_info[id];
+ reg->reg_info = ri;
+ reg->mfd = rc5t583;
+ reg->dev = &pdev->dev;
+
+ if (ri->deepsleep_id == RC5T583_DS_NONE)
+ goto skip_ext_pwr_config;
+
+ ret = rc5t583_ext_power_req_config(rc5t583->dev,
+ ri->deepsleep_id,
+ pdata->regulator_ext_pwr_control[id],
+ pdata->regulator_deepsleep_slot[id]);
+ /*
+ * Configuring external control is not a major issue,
+ * just give warning.
+ */
+ if (ret < 0)
+ dev_warn(&pdev->dev,
+ "Failed to configure ext control %d\n", id);
+
+skip_ext_pwr_config:
+ config.dev = &pdev->dev;
+ config.init_data = reg_data;
+ config.driver_data = reg;
+ config.regmap = rc5t583->regmap;
+
+ rdev = regulator_register(&ri->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register regulator %s\n",
+ ri->desc.name);
+ ret = PTR_ERR(rdev);
+ goto clean_exit;
+ }
+ reg->rdev = rdev;
+ }
+ platform_set_drvdata(pdev, regs);
+ return 0;
+
+clean_exit:
+ while (--id >= 0)
+ regulator_unregister(regs[id].rdev);
+
+ return ret;
+}
+
+static int __devexit rc5t583_regulator_remove(struct platform_device *pdev)
+{
+ struct rc5t583_regulator *regs = platform_get_drvdata(pdev);
+ int id;
+
+ for (id = 0; id < RC5T583_REGULATOR_MAX; ++id)
+ regulator_unregister(regs[id].rdev);
+ return 0;
+}
+
+static struct platform_driver rc5t583_regulator_driver = {
+ .driver = {
+ .name = "rc5t583-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = rc5t583_regulator_probe,
+ .remove = __devexit_p(rc5t583_regulator_remove),
+};
+
+static int __init rc5t583_regulator_init(void)
+{
+ return platform_driver_register(&rc5t583_regulator_driver);
+}
+subsys_initcall(rc5t583_regulator_init);
+
+static void __exit rc5t583_regulator_exit(void)
+{
+ platform_driver_unregister(&rc5t583_regulator_driver);
+}
+module_exit(rc5t583_regulator_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RC5T583 regulator driver");
+MODULE_ALIAS("platform:rc5t583-regulator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 4ca2db0..290d6fc 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -12,7 +12,6 @@
*/
#include <linux/bug.h>
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -28,6 +27,7 @@ struct s5m8767_info {
struct s5m87xx_dev *iodev;
int num_regulators;
struct regulator_dev **rdev;
+ struct s5m_opmode_data *opmode;
int ramp_delay;
bool buck2_ramp;
@@ -141,9 +141,56 @@ static int s5m8767_list_voltage(struct regulator_dev *rdev,
return val;
}
-static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
+static unsigned int s5m8767_opmode_reg[][4] = {
+ /* {OFF, ON, LOWPOWER, SUSPEND} */
+ /* LDO1 ... LDO28 */
+ {0x0, 0x3, 0x2, 0x1}, /* LDO1 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x0, 0x0, 0x0},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO5 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO10 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO15 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x0, 0x0, 0x0},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO20 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x0, 0x0, 0x0},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO25 */
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* LDO28 */
+
+ /* BUCK1 ... BUCK9 */
+ {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x1, 0x1},
+ {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
+};
+
+static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
+ int *enable_ctrl)
{
int reg_id = rdev_get_id(rdev);
+ unsigned int mode;
+ struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
switch (reg_id) {
case S5M8767_LDO1 ... S5M8767_LDO2:
@@ -168,6 +215,8 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
return -EINVAL;
}
+ mode = s5m8767->opmode[reg_id].mode;
+ *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
return 0;
}
@@ -175,10 +224,10 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
int ret, reg;
- int mask = 0xc0, pattern = 0xc0;
+ int mask = 0xc0, enable_ctrl;
u8 val;
- ret = s5m8767_get_register(rdev, &reg);
+ ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
if (ret == -EINVAL)
return 1;
else if (ret)
@@ -188,33 +237,33 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
if (ret)
return ret;
- return (val & mask) == pattern;
+ return (val & mask) == enable_ctrl;
}
static int s5m8767_reg_enable(struct regulator_dev *rdev)
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
int ret, reg;
- int mask = 0xc0, pattern = 0xc0;
+ int mask = 0xc0, enable_ctrl;
- ret = s5m8767_get_register(rdev, &reg);
+ ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
if (ret)
return ret;
- return s5m_reg_update(s5m8767->iodev, reg, pattern, mask);
+ return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
}
static int s5m8767_reg_disable(struct regulator_dev *rdev)
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
int ret, reg;
- int mask = 0xc0, pattern = 0xc0;
+ int mask = 0xc0, enable_ctrl;
- ret = s5m8767_get_register(rdev, &reg);
+ ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
if (ret)
return ret;
- return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask);
+ return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask);
}
static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
@@ -297,7 +346,10 @@ static int s5m8767_convert_voltage_to_sel(
if (max_vol < desc->min || min_vol > desc->max)
return -EINVAL;
- selector = (min_vol - desc->min) / desc->step;
+ if (min_vol < desc->min)
+ min_vol = desc->min;
+
+ selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
if (desc->min + desc->step * selector > max_vol)
return -EINVAL;
@@ -305,14 +357,33 @@ static int s5m8767_convert_voltage_to_sel(
return selector;
}
+static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
+{
+ int temp_index = s5m8767->buck_gpioindex;
+
+ gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+ gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
+ gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+}
+
+static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
+{
+ int temp_index = s5m8767->buck_gpioindex;
+
+ gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+ gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
+ gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+}
+
static int s5m8767_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector)
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
const struct s5m_voltage_desc *desc;
int reg_id = rdev_get_id(rdev);
- int sel, reg, mask, ret;
+ int sel, reg, mask, ret = 0, old_index, index = 0;
u8 val;
+ u8 *buck234_vol = NULL;
switch (reg_id) {
case S5M8767_LDO1 ... S5M8767_LDO28:
@@ -320,6 +391,12 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
break;
case S5M8767_BUCK1 ... S5M8767_BUCK6:
mask = 0xff;
+ if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
+ buck234_vol = &s5m8767->buck2_vol[0];
+ else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
+ buck234_vol = &s5m8767->buck3_vol[0];
+ else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs)
+ buck234_vol = &s5m8767->buck4_vol[0];
break;
case S5M8767_BUCK7 ... S5M8767_BUCK8:
return -EINVAL;
@@ -336,102 +413,32 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
if (sel < 0)
return sel;
- ret = s5m8767_get_voltage_register(rdev, &reg);
- if (ret)
- return ret;
-
- s5m_reg_read(s5m8767->iodev, reg, &val);
- val &= ~mask;
- val |= sel;
-
- ret = s5m_reg_write(s5m8767->iodev, reg, val);
- *selector = sel;
-
- return ret;
-}
-
-static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
-{
- int temp_index = s5m8767->buck_gpioindex;
-
- gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
-}
-
-static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
-{
- int temp_index = s5m8767->buck_gpioindex;
-
- gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
- gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
- gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
-}
-
-static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int reg_id = rdev_get_id(rdev);
- const struct s5m_voltage_desc *desc;
- int new_val, old_val, i = 0;
-
- if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6)
- return -EINVAL;
-
- switch (reg_id) {
- case S5M8767_BUCK1:
- return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
- case S5M8767_BUCK2 ... S5M8767_BUCK4:
- break;
- case S5M8767_BUCK5 ... S5M8767_BUCK6:
- return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
- case S5M8767_BUCK9:
- return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
- }
+ /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
+ if (buck234_vol) {
+ while (*buck234_vol != sel) {
+ buck234_vol++;
+ index++;
+ }
+ old_index = s5m8767->buck_gpioindex;
+ s5m8767->buck_gpioindex = index;
+
+ if (index > old_index)
+ s5m8767_set_high(s5m8767);
+ else
+ s5m8767_set_low(s5m8767);
+ } else {
+ ret = s5m8767_get_voltage_register(rdev, &reg);
+ if (ret)
+ return ret;
- desc = reg_voltage_map[reg_id];
- new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
- if (new_val < 0)
- return new_val;
+ s5m_reg_read(s5m8767->iodev, reg, &val);
+ val = (val & ~mask) | sel;
- switch (reg_id) {
- case S5M8767_BUCK2:
- if (s5m8767->buck2_gpiodvs) {
- while (s5m8767->buck2_vol[i] != new_val)
- i++;
- } else
- return s5m8767_set_voltage(rdev, min_uV,
- max_uV, selector);
- break;
- case S5M8767_BUCK3:
- if (s5m8767->buck3_gpiodvs) {
- while (s5m8767->buck3_vol[i] != new_val)
- i++;
- } else
- return s5m8767_set_voltage(rdev, min_uV,
- max_uV, selector);
- break;
- case S5M8767_BUCK4:
- if (s5m8767->buck3_gpiodvs) {
- while (s5m8767->buck4_vol[i] != new_val)
- i++;
- } else
- return s5m8767_set_voltage(rdev, min_uV,
- max_uV, selector);
- break;
+ ret = s5m_reg_write(s5m8767->iodev, reg, val);
}
- old_val = s5m8767->buck_gpioindex;
- s5m8767->buck_gpioindex = i;
-
- if (i > old_val)
- s5m8767_set_high(s5m8767);
- else
- s5m8767_set_low(s5m8767);
-
- *selector = new_val;
- return 0;
+ *selector = sel;
+ return ret;
}
static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
@@ -450,7 +457,7 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
return 0;
}
-static struct regulator_ops s5m8767_ldo_ops = {
+static struct regulator_ops s5m8767_ops = {
.list_voltage = s5m8767_list_voltage,
.is_enabled = s5m8767_reg_is_enabled,
.enable = s5m8767_reg_enable,
@@ -460,75 +467,59 @@ static struct regulator_ops s5m8767_ldo_ops = {
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
};
-static struct regulator_ops s5m8767_buck_ops = {
- .list_voltage = s5m8767_list_voltage,
- .is_enabled = s5m8767_reg_is_enabled,
- .enable = s5m8767_reg_enable,
- .disable = s5m8767_reg_disable,
- .get_voltage_sel = s5m8767_get_voltage_sel,
- .set_voltage = s5m8767_set_voltage_buck,
- .set_voltage_time_sel = s5m8767_set_voltage_time_sel,
-};
-
-#define regulator_desc_ldo(num) { \
- .name = "LDO"#num, \
- .id = S5M8767_LDO##num, \
- .ops = &s5m8767_ldo_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
-}
-#define regulator_desc_buck(num) { \
- .name = "BUCK"#num, \
- .id = S5M8767_BUCK##num, \
- .ops = &s5m8767_buck_ops, \
+#define s5m8767_regulator_desc(_name) { \
+ .name = #_name, \
+ .id = S5M8767_##_name, \
+ .ops = &s5m8767_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
static struct regulator_desc regulators[] = {
- regulator_desc_ldo(1),
- regulator_desc_ldo(2),
- regulator_desc_ldo(3),
- regulator_desc_ldo(4),
- regulator_desc_ldo(5),
- regulator_desc_ldo(6),
- regulator_desc_ldo(7),
- regulator_desc_ldo(8),
- regulator_desc_ldo(9),
- regulator_desc_ldo(10),
- regulator_desc_ldo(11),
- regulator_desc_ldo(12),
- regulator_desc_ldo(13),
- regulator_desc_ldo(14),
- regulator_desc_ldo(15),
- regulator_desc_ldo(16),
- regulator_desc_ldo(17),
- regulator_desc_ldo(18),
- regulator_desc_ldo(19),
- regulator_desc_ldo(20),
- regulator_desc_ldo(21),
- regulator_desc_ldo(22),
- regulator_desc_ldo(23),
- regulator_desc_ldo(24),
- regulator_desc_ldo(25),
- regulator_desc_ldo(26),
- regulator_desc_ldo(27),
- regulator_desc_ldo(28),
- regulator_desc_buck(1),
- regulator_desc_buck(2),
- regulator_desc_buck(3),
- regulator_desc_buck(4),
- regulator_desc_buck(5),
- regulator_desc_buck(6),
- regulator_desc_buck(7),
- regulator_desc_buck(8),
- regulator_desc_buck(9),
+ s5m8767_regulator_desc(LDO1),
+ s5m8767_regulator_desc(LDO2),
+ s5m8767_regulator_desc(LDO3),
+ s5m8767_regulator_desc(LDO4),
+ s5m8767_regulator_desc(LDO5),
+ s5m8767_regulator_desc(LDO6),
+ s5m8767_regulator_desc(LDO7),
+ s5m8767_regulator_desc(LDO8),
+ s5m8767_regulator_desc(LDO9),
+ s5m8767_regulator_desc(LDO10),
+ s5m8767_regulator_desc(LDO11),
+ s5m8767_regulator_desc(LDO12),
+ s5m8767_regulator_desc(LDO13),
+ s5m8767_regulator_desc(LDO14),
+ s5m8767_regulator_desc(LDO15),
+ s5m8767_regulator_desc(LDO16),
+ s5m8767_regulator_desc(LDO17),
+ s5m8767_regulator_desc(LDO18),
+ s5m8767_regulator_desc(LDO19),
+ s5m8767_regulator_desc(LDO20),
+ s5m8767_regulator_desc(LDO21),
+ s5m8767_regulator_desc(LDO22),
+ s5m8767_regulator_desc(LDO23),
+ s5m8767_regulator_desc(LDO24),
+ s5m8767_regulator_desc(LDO25),
+ s5m8767_regulator_desc(LDO26),
+ s5m8767_regulator_desc(LDO27),
+ s5m8767_regulator_desc(LDO28),
+ s5m8767_regulator_desc(BUCK1),
+ s5m8767_regulator_desc(BUCK2),
+ s5m8767_regulator_desc(BUCK3),
+ s5m8767_regulator_desc(BUCK4),
+ s5m8767_regulator_desc(BUCK5),
+ s5m8767_regulator_desc(BUCK6),
+ s5m8767_regulator_desc(BUCK7),
+ s5m8767_regulator_desc(BUCK8),
+ s5m8767_regulator_desc(BUCK9),
};
static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
{
struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct regulator_config config = { };
struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
int i, ret, size;
@@ -586,6 +577,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
+ s5m8767->opmode = pdata->opmode;
for (i = 0; i < 8; i++) {
if (s5m8767->buck2_gpiodvs) {
@@ -723,8 +715,11 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
regulators[id].n_voltages =
(desc->max - desc->min) / desc->step + 1;
- rdev[i] = regulator_register(&regulators[id], s5m8767->dev,
- pdata->regulators[i].initdata, s5m8767, NULL);
+ config.dev = s5m8767->dev;
+ config.init_data = pdata->regulators[i].initdata;
+ config.driver_data = s5m8767;
+
+ rdev[i] = regulator_register(&regulators[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(s5m8767->dev, "regulator init failed for %d\n",
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index d9278da..d840d84 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -123,7 +123,7 @@ static struct regulator_ops tps6105x_regulator_ops = {
.list_voltage = tps6105x_regulator_list_voltage,
};
-static struct regulator_desc tps6105x_regulator_desc = {
+static const struct regulator_desc tps6105x_regulator_desc = {
.name = "tps6105x-boost",
.ops = &tps6105x_regulator_ops,
.type = REGULATOR_VOLTAGE,
@@ -139,6 +139,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
{
struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
struct tps6105x_platform_data *pdata = tps6105x->pdata;
+ struct regulator_config config = { };
int ret;
/* This instance is not set for regulator mode so bail out */
@@ -148,11 +149,13 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
return 0;
}
+ config.dev = &tps6105x->client->dev;
+ config.init_data = pdata->regulator_data;
+ config.driver_data = tps6105x;
+
/* Register regulator with framework */
tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
- &tps6105x->client->dev,
- pdata->regulator_data, tps6105x,
- NULL);
+ &config);
if (IS_ERR(tps6105x->regulator)) {
ret = PTR_ERR(tps6105x->regulator);
dev_err(&tps6105x->client->dev,
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index e2ec730..e534269 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -1,7 +1,7 @@
/*
* tps62360.c -- TI tps62360
*
- * Driver for processor core supply tps62360 and tps62361B
+ * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363.
*
* Copyright (c) 2012, NVIDIA Corporation.
*
@@ -26,13 +26,16 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/tps62360.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -46,20 +49,20 @@
#define REG_RAMPCTRL 6
#define REG_CHIPID 8
-enum chips {TPS62360, TPS62361};
+#define FORCE_PWM_ENABLE BIT(7)
-#define TPS62360_BASE_VOLTAGE 770
+enum chips {TPS62360, TPS62361, TPS62362, TPS62363};
+
+#define TPS62360_BASE_VOLTAGE 770000
#define TPS62360_N_VOLTAGES 64
-#define TPS62361_BASE_VOLTAGE 500
+#define TPS62361_BASE_VOLTAGE 500000
#define TPS62361_N_VOLTAGES 128
/* tps 62360 chip information */
struct tps62360_chip {
- const char *name;
struct device *dev;
struct regulator_desc desc;
- struct i2c_client *client;
struct regulator_dev *rdev;
struct regmap *regmap;
int chip_id;
@@ -68,12 +71,12 @@ struct tps62360_chip {
int voltage_base;
u8 voltage_reg_mask;
bool en_internal_pulldn;
- bool en_force_pwm;
bool en_discharge;
bool valid_gpios;
int lru_index[4];
int curr_vset_vsel[4];
int curr_vset_id;
+ int change_uv_per_us;
};
/*
@@ -99,6 +102,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps,
bool found = false;
int new_vset_reg = tps->lru_index[3];
int found_index = 3;
+
for (i = 0; i < 4; ++i) {
if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
new_vset_reg = tps->lru_index[i];
@@ -117,7 +121,7 @@ update_lru_index:
return found;
}
-static int tps62360_dcdc_get_voltage(struct regulator_dev *dev)
+static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct tps62360_chip *tps = rdev_get_drvdata(dev);
int vsel;
@@ -126,196 +130,312 @@ static int tps62360_dcdc_get_voltage(struct regulator_dev *dev)
ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
if (ret < 0) {
- dev_err(tps->dev, "%s: Error in reading register %d\n",
- __func__, REG_VSET0 + tps->curr_vset_id);
+ dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
return ret;
}
vsel = (int)data & tps->voltage_reg_mask;
- return (tps->voltage_base + vsel * 10) * 1000;
+ return vsel;
}
-static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV, unsigned *selector)
+static int tps62360_dcdc_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
{
struct tps62360_chip *tps = rdev_get_drvdata(dev);
- int vsel;
int ret;
bool found = false;
int new_vset_id = tps->curr_vset_id;
- if (max_uV < min_uV)
- return -EINVAL;
-
- if (min_uV >
- ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000))
- return -EINVAL;
-
- if (max_uV < tps->voltage_base * 1000)
- return -EINVAL;
-
- vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000);
- if (selector)
- *selector = (vsel & tps->voltage_reg_mask);
-
/*
* If gpios are available to select the VSET register then least
* recently used register for new configuration.
*/
if (tps->valid_gpios)
- found = find_voltage_set_register(tps, vsel, &new_vset_id);
+ found = find_voltage_set_register(tps, selector, &new_vset_id);
if (!found) {
ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
- tps->voltage_reg_mask, vsel);
+ tps->voltage_reg_mask, selector);
if (ret < 0) {
- dev_err(tps->dev, "%s: Error in updating register %d\n",
- __func__, REG_VSET0 + new_vset_id);
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + new_vset_id, ret);
return ret;
}
tps->curr_vset_id = new_vset_id;
- tps->curr_vset_vsel[new_vset_id] = vsel;
+ tps->curr_vset_vsel[new_vset_id] = selector;
}
/* Select proper VSET register vio gpios */
if (tps->valid_gpios) {
- gpio_set_value_cansleep(tps->vsel0_gpio,
- new_vset_id & 0x1);
+ gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1);
gpio_set_value_cansleep(tps->vsel1_gpio,
(new_vset_id >> 1) & 0x1);
}
return 0;
}
-static int tps62360_dcdc_list_voltage(struct regulator_dev *dev,
- unsigned selector)
+static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
{
- struct tps62360_chip *tps = rdev_get_drvdata(dev);
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
- if (selector >= tps->desc.n_voltages)
- return -EINVAL;
- return (tps->voltage_base + selector * 10) * 1000;
+ old_uV = regulator_list_voltage_linear(rdev, old_selector);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = regulator_list_voltage_linear(rdev, new_selector);
+ if (new_uV < 0)
+ return new_uV;
+
+ return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us);
}
-static struct regulator_ops tps62360_dcdc_ops = {
- .get_voltage = tps62360_dcdc_get_voltage,
- .set_voltage = tps62360_dcdc_set_voltage,
- .list_voltage = tps62360_dcdc_list_voltage,
-};
+static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
+ int i;
+ int val;
+ int ret;
+
+ /* Enable force PWM mode in FAST mode only. */
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = FORCE_PWM_ENABLE;
+ break;
+
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
-static int tps62360_init_force_pwm(struct tps62360_chip *tps,
- struct tps62360_regulator_platform_data *pdata,
- int vset_id)
+ default:
+ return -EINVAL;
+ }
+
+ if (!tps->valid_gpios) {
+ ret = regmap_update_bits(tps->regmap,
+ REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val);
+ if (ret < 0)
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
+ return ret;
+ }
+
+ /* If gpios are valid then all register set need to be control */
+ for (i = 0; i < 4; ++i) {
+ ret = regmap_update_bits(tps->regmap,
+ REG_VSET0 + i, FORCE_PWM_ENABLE, val);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_VSET0 + i, ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static unsigned int tps62360_get_mode(struct regulator_dev *rdev)
{
+ struct tps62360_chip *tps = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
- ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data);
+
+ ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
if (ret < 0) {
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_VSET0 + vset_id);
+ dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
+ __func__, REG_VSET0 + tps->curr_vset_id, ret);
return ret;
}
- tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask;
- if (pdata->en_force_pwm)
- data |= BIT(7);
- else
- data &= ~BIT(7);
- ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data);
- if (ret < 0)
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_VSET0 + vset_id);
- return ret;
+ return (data & FORCE_PWM_ENABLE) ?
+ REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
}
-static int tps62360_init_dcdc(struct tps62360_chip *tps,
+static struct regulator_ops tps62360_dcdc_ops = {
+ .get_voltage_sel = tps62360_dcdc_get_voltage_sel,
+ .set_voltage_sel = tps62360_dcdc_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_time_sel = tps62360_set_voltage_time_sel,
+ .set_mode = tps62360_set_mode,
+ .get_mode = tps62360_get_mode,
+};
+
+static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps,
struct tps62360_regulator_platform_data *pdata)
{
int ret;
- int i;
+ unsigned int ramp_ctrl;
- /* Initailize internal pull up/down control */
+ /* Initialize internal pull up/down control */
if (tps->en_internal_pulldn)
ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0);
else
ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
if (ret < 0) {
- dev_err(tps->dev, "%s() fails in writing reg %d\n",
- __func__, REG_CONTROL);
+ dev_err(tps->dev,
+ "%s(): register %d write failed with err %d\n",
+ __func__, REG_CONTROL, ret);
return ret;
}
- /* Initailize force PWM mode */
- if (tps->valid_gpios) {
- for (i = 0; i < 4; ++i) {
- ret = tps62360_init_force_pwm(tps, pdata, i);
- if (ret < 0)
- return ret;
- }
- } else {
- ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id);
- if (ret < 0)
- return ret;
- }
-
/* Reset output discharge path to reduce power consumption */
ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0);
- if (ret < 0)
- dev_err(tps->dev, "%s() fails in updating reg %d\n",
- __func__, REG_RAMPCTRL);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_RAMPCTRL, ret);
+ return ret;
+ }
+
+ /* Get ramp value from ramp control register */
+ ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl);
+ if (ret < 0) {
+ dev_err(tps->dev,
+ "%s(): register %d read failed with err %d\n",
+ __func__, REG_RAMPCTRL, ret);
+ return ret;
+ }
+ ramp_ctrl = (ramp_ctrl >> 4) & 0x7;
+
+ /* ramp mV/us = 32/(2^ramp_ctrl) */
+ tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
return ret;
}
static const struct regmap_config tps62360_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_CHIPID,
+ .cache_type = REGCACHE_RBTREE,
};
+static struct tps62360_regulator_platform_data *
+ of_get_tps62360_platform_data(struct device *dev)
+{
+ struct tps62360_regulator_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "Memory alloc failed for platform data\n");
+ return NULL;
+ }
+
+ pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+ if (!pdata->reg_init_data) {
+ dev_err(dev, "Not able to get OF regulator init data\n");
+ return NULL;
+ }
+
+ pdata->vsel0_gpio = of_get_named_gpio(np, "vsel0-gpio", 0);
+ pdata->vsel1_gpio = of_get_named_gpio(np, "vsel1-gpio", 0);
+
+ if (of_find_property(np, "ti,vsel0-state-high", NULL))
+ pdata->vsel0_def_state = 1;
+
+ if (of_find_property(np, "ti,vsel1-state-high", NULL))
+ pdata->vsel1_def_state = 1;
+
+ if (of_find_property(np, "ti,enable-pull-down", NULL))
+ pdata->en_internal_pulldn = true;
+
+ if (of_find_property(np, "ti,enable-vout-discharge", NULL))
+ pdata->en_discharge = true;
+
+ return pdata;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tps62360_of_match[] = {
+ { .compatible = "ti,tps62360", .data = (void *)TPS62360},
+ { .compatible = "ti,tps62361", .data = (void *)TPS62361},
+ { .compatible = "ti,tps62362", .data = (void *)TPS62362},
+ { .compatible = "ti,tps62363", .data = (void *)TPS62363},
+ {},
+};
+MODULE_DEVICE_TABLE(of, tps62360_of_match);
+#endif
+
static int __devinit tps62360_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct regulator_config config = { };
struct tps62360_regulator_platform_data *pdata;
struct regulator_dev *rdev;
struct tps62360_chip *tps;
int ret;
int i;
+ int chip_id;
pdata = client->dev.platform_data;
+ chip_id = id->driver_data;
+
+ if (client->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_device(of_match_ptr(tps62360_of_match),
+ &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ chip_id = (int)match->data;
+ if (!pdata)
+ pdata = of_get_tps62360_platform_data(&client->dev);
+ }
+
if (!pdata) {
- dev_err(&client->dev, "%s() Err: Platform data not found\n",
+ dev_err(&client->dev, "%s(): Platform data not found\n",
__func__);
return -EIO;
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps) {
- dev_err(&client->dev, "%s() Err: Memory allocation fails\n",
+ dev_err(&client->dev, "%s(): Memory allocation failed\n",
__func__);
return -ENOMEM;
}
- tps->en_force_pwm = pdata->en_force_pwm;
tps->en_discharge = pdata->en_discharge;
tps->en_internal_pulldn = pdata->en_internal_pulldn;
tps->vsel0_gpio = pdata->vsel0_gpio;
tps->vsel1_gpio = pdata->vsel1_gpio;
- tps->client = client;
tps->dev = &client->dev;
- tps->name = id->name;
- tps->voltage_base = (id->driver_data == TPS62360) ?
- TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE;
- tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F;
+
+ switch (chip_id) {
+ case TPS62360:
+ case TPS62362:
+ tps->voltage_base = TPS62360_BASE_VOLTAGE;
+ tps->voltage_reg_mask = 0x3F;
+ tps->desc.n_voltages = TPS62360_N_VOLTAGES;
+ break;
+ case TPS62361:
+ case TPS62363:
+ tps->voltage_base = TPS62361_BASE_VOLTAGE;
+ tps->voltage_reg_mask = 0x7F;
+ tps->desc.n_voltages = TPS62361_N_VOLTAGES;
+ break;
+ default:
+ return -ENODEV;
+ }
tps->desc.name = id->name;
tps->desc.id = 0;
- tps->desc.n_voltages = (id->driver_data == TPS62360) ?
- TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES;
tps->desc.ops = &tps62360_dcdc_ops;
tps->desc.type = REGULATOR_VOLTAGE;
tps->desc.owner = THIS_MODULE;
- tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config);
+ tps->desc.min_uV = tps->voltage_base;
+ tps->desc.uV_step = 10000;
+
+ tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
- dev_err(&client->dev, "%s() Err: Failed to allocate register"
- "map: %d\n", __func__, ret);
+ dev_err(&client->dev,
+ "%s(): regmap allocation failed with err %d\n",
+ __func__, ret);
return ret;
}
i2c_set_clientdata(client, tps);
@@ -326,35 +446,26 @@ static int __devinit tps62360_probe(struct i2c_client *client,
tps->valid_gpios = false;
if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) {
- ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0");
+ int gpio_flags;
+ gpio_flags = (pdata->vsel0_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel0_gpio,
+ gpio_flags, "tps62360-vsel0");
if (ret) {
dev_err(&client->dev,
- "Err: Could not obtain vsel0 GPIO %d: %d\n",
- tps->vsel0_gpio, ret);
- goto err_gpio0;
- }
- ret = gpio_direction_output(tps->vsel0_gpio,
- pdata->vsel0_def_state);
- if (ret) {
- dev_err(&client->dev, "Err: Could not set direction of"
- "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret);
- gpio_free(tps->vsel0_gpio);
+ "%s(): Could not obtain vsel0 GPIO %d: %d\n",
+ __func__, tps->vsel0_gpio, ret);
goto err_gpio0;
}
- ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1");
+ gpio_flags = (pdata->vsel1_def_state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ ret = gpio_request_one(tps->vsel1_gpio,
+ gpio_flags, "tps62360-vsel1");
if (ret) {
dev_err(&client->dev,
- "Err: Could not obtain vsel1 GPIO %d: %d\n",
- tps->vsel1_gpio, ret);
- goto err_gpio1;
- }
- ret = gpio_direction_output(tps->vsel1_gpio,
- pdata->vsel1_def_state);
- if (ret) {
- dev_err(&client->dev, "Err: Could not set direction of"
- "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret);
- gpio_free(tps->vsel1_gpio);
+ "%s(): Could not obtain vsel1 GPIO %d: %d\n",
+ __func__, tps->vsel1_gpio, ret);
goto err_gpio1;
}
tps->valid_gpios = true;
@@ -371,17 +482,22 @@ static int __devinit tps62360_probe(struct i2c_client *client,
ret = tps62360_init_dcdc(tps, pdata);
if (ret < 0) {
- dev_err(tps->dev, "%s() Err: Init fails with = %d\n",
+ dev_err(tps->dev, "%s(): Init failed with err = %d\n",
__func__, ret);
goto err_init;
}
+ config.dev = &client->dev;
+ config.init_data = pdata->reg_init_data;
+ config.driver_data = tps;
+ config.of_node = client->dev.of_node;
+
/* Register the regulators */
- rdev = regulator_register(&tps->desc, &client->dev,
- &pdata->reg_init_data, tps, NULL);
+ rdev = regulator_register(&tps->desc, &config);
if (IS_ERR(rdev)) {
- dev_err(tps->dev, "%s() Err: Failed to register %s\n",
- __func__, id->name);
+ dev_err(tps->dev,
+ "%s(): regulator register failed with err %s\n",
+ __func__, id->name);
ret = PTR_ERR(rdev);
goto err_init;
}
@@ -396,7 +512,6 @@ err_gpio1:
if (gpio_is_valid(tps->vsel0_gpio))
gpio_free(tps->vsel0_gpio);
err_gpio0:
- regmap_exit(tps->regmap);
return ret;
}
@@ -417,7 +532,6 @@ static int __devexit tps62360_remove(struct i2c_client *client)
gpio_free(tps->vsel0_gpio);
regulator_unregister(tps->rdev);
- regmap_exit(tps->regmap);
return 0;
}
@@ -432,13 +546,16 @@ static void tps62360_shutdown(struct i2c_client *client)
/* Configure the output discharge path */
st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
if (st < 0)
- dev_err(tps->dev, "%s() fails in updating reg %d\n",
- __func__, REG_RAMPCTRL);
+ dev_err(tps->dev,
+ "%s(): register %d update failed with err %d\n",
+ __func__, REG_RAMPCTRL, st);
}
static const struct i2c_device_id tps62360_id[] = {
{.name = "tps62360", .driver_data = TPS62360},
{.name = "tps62361", .driver_data = TPS62361},
+ {.name = "tps62362", .driver_data = TPS62362},
+ {.name = "tps62363", .driver_data = TPS62363},
{},
};
@@ -448,6 +565,7 @@ static struct i2c_driver tps62360_i2c_driver = {
.driver = {
.name = "tps62360",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps62360_of_match),
},
.probe = tps62360_probe,
.remove = __devexit_p(tps62360_remove),
@@ -468,5 +586,5 @@ static void __exit tps62360_cleanup(void)
module_exit(tps62360_cleanup);
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("TPS62360 voltage regulator driver");
+MODULE_DESCRIPTION("TPS6236x voltage regulator driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 43e4902..f841bd0 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -23,7 +23,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -72,7 +71,7 @@
/* LDO_CTRL bitfields */
#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
-#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4))
+#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0x0F << ((ldo_id)*4))
/* Number of step-down converters available */
#define TPS65023_NUM_DCDC 3
@@ -139,7 +138,6 @@ struct tps_info {
/* PMIC details */
struct tps_pmic {
struct regulator_desc desc[TPS65023_NUM_REGULATOR];
- struct i2c_client *client;
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
const struct tps_info *info[TPS65023_NUM_REGULATOR];
struct regmap *regmap;
@@ -152,96 +150,6 @@ struct tps_driver_data {
u8 core_regulator;
};
-static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int data, dcdc = rdev_get_id(dev);
- int ret;
- u8 shift;
-
- if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
- return -EINVAL;
-
- shift = TPS65023_NUM_REGULATOR - dcdc;
- ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
-
- if (ret != 0)
- return ret;
- else
- return (data & 1<<shift) ? 1 : 0;
-}
-
-static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int data, ldo = rdev_get_id(dev);
- int ret;
- u8 shift;
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
-
- shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
- ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
-
- if (ret != 0)
- return ret;
- else
- return (data & 1<<shift) ? 1 : 0;
-}
-
-static int tps65023_dcdc_enable(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int dcdc = rdev_get_id(dev);
- u8 shift;
-
- if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
- return -EINVAL;
-
- shift = TPS65023_NUM_REGULATOR - dcdc;
- return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
-}
-
-static int tps65023_dcdc_disable(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int dcdc = rdev_get_id(dev);
- u8 shift;
-
- if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
- return -EINVAL;
-
- shift = TPS65023_NUM_REGULATOR - dcdc;
- return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
-}
-
-static int tps65023_ldo_enable(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int ldo = rdev_get_id(dev);
- u8 shift;
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
-
- shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
- return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
-}
-
-static int tps65023_ldo_disable(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int ldo = rdev_get_id(dev);
- u8 shift;
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
-
- shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
- return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
-}
-
static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
@@ -261,50 +169,28 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
return tps->info[dcdc]->min_uV;
}
-static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
- int vsel;
int ret;
if (dcdc != tps->core_regulator)
return -EINVAL;
- if (min_uV < tps->info[dcdc]->min_uV
- || min_uV > tps->info[dcdc]->max_uV)
- return -EINVAL;
- if (max_uV < tps->info[dcdc]->min_uV
- || max_uV > tps->info[dcdc]->max_uV)
- return -EINVAL;
-
- for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
- int mV = tps->info[dcdc]->table[vsel];
- int uV = mV * 1000;
-
- /* Break at the first in-range value */
- if (min_uV <= uV && uV <= max_uV)
- break;
- }
- *selector = vsel;
-
- if (vsel == tps->info[dcdc]->table_len)
- goto failed;
-
- ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, vsel);
+ ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector);
+ if (ret)
+ goto out;
/* Tell the chip that we have changed the value in DEFCORE
* and its time to update the core voltage
*/
- regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
- TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
+ ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
+ TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
+out:
return ret;
-
-failed:
- return -EINVAL;
}
static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
@@ -325,42 +211,15 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
return tps->info[ldo]->table[data] * 1000;
}
-static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV, unsigned *selector)
+static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
- int data, vsel, ldo = rdev_get_id(dev);
- int ret;
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
+ int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
- if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
- return -EINVAL;
- if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
- return -EINVAL;
-
- for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
- int mV = tps->info[ldo]->table[vsel];
- int uV = mV * 1000;
-
- /* Break at the first in-range value */
- if (min_uV <= uV && uV <= max_uV)
- break;
- }
-
- if (vsel == tps->info[ldo]->table_len)
- return -EINVAL;
-
- *selector = vsel;
-
- ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
- if (ret != 0)
- return ret;
-
- data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1);
- data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)));
- return regmap_write(tps->regmap, TPS65023_REG_LDO_CTRL, data);
+ return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
+ TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
+ selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
}
static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
@@ -398,21 +257,21 @@ static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
/* Operations permitted on VDCDCx */
static struct regulator_ops tps65023_dcdc_ops = {
- .is_enabled = tps65023_dcdc_is_enabled,
- .enable = tps65023_dcdc_enable,
- .disable = tps65023_dcdc_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_voltage = tps65023_dcdc_get_voltage,
- .set_voltage = tps65023_dcdc_set_voltage,
+ .set_voltage_sel = tps65023_dcdc_set_voltage_sel,
.list_voltage = tps65023_dcdc_list_voltage,
};
/* Operations permitted on LDOx */
static struct regulator_ops tps65023_ldo_ops = {
- .is_enabled = tps65023_ldo_is_enabled,
- .enable = tps65023_ldo_enable,
- .disable = tps65023_ldo_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_voltage = tps65023_ldo_get_voltage,
- .set_voltage = tps65023_ldo_set_voltage,
+ .set_voltage_sel = tps65023_ldo_set_voltage_sel,
.list_voltage = tps65023_ldo_list_voltage,
};
@@ -426,6 +285,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
{
const struct tps_driver_data *drv_data = (void *)id->driver_data;
const struct tps_info *info = drv_data->info;
+ struct regulator_config config = { };
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps_pmic *tps;
@@ -443,20 +303,19 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
if (!init_data)
return -EIO;
- tps = kzalloc(sizeof(*tps), GFP_KERNEL);
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
- tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config);
+ tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
if (IS_ERR(tps->regmap)) {
error = PTR_ERR(tps->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
error);
- goto fail_alloc;
+ return error;
}
/* common for all regulators */
- tps->client = client;
tps->core_regulator = drv_data->core_regulator;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
@@ -471,9 +330,22 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
+ tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
+ if (i == TPS65023_LDO_1)
+ tps->desc[i].enable_mask = 1 << 1;
+ else if (i == TPS65023_LDO_2)
+ tps->desc[i].enable_mask = 1 << 2;
+ else /* DCDCx */
+ tps->desc[i].enable_mask =
+ 1 << (TPS65023_NUM_REGULATOR - i);
+
+ config.dev = &client->dev;
+ config.init_data = init_data;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+
/* Register the regulators */
- rdev = regulator_register(&tps->desc[i], &client->dev,
- init_data, tps, NULL);
+ rdev = regulator_register(&tps->desc[i], &config);
if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
@@ -496,19 +368,9 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
fail:
while (--i >= 0)
regulator_unregister(tps->rdev[i]);
-
- regmap_exit(tps->regmap);
- fail_alloc:
- kfree(tps);
return error;
}
-/**
- * tps_65023_remove - TPS65023 driver i2c remove handler
- * @client: i2c driver client device structure
- *
- * Unregister TPS driver as an i2c client device driver
- */
static int __devexit tps_65023_remove(struct i2c_client *client)
{
struct tps_pmic *tps = i2c_get_clientdata(client);
@@ -516,10 +378,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]);
-
- regmap_exit(tps->regmap);
- kfree(tps);
-
return 0;
}
@@ -638,13 +496,13 @@ static struct tps_driver_data tps65020_drv_data = {
};
static struct tps_driver_data tps65021_drv_data = {
- .info = tps65021_regs,
- .core_regulator = TPS65023_DCDC_3,
+ .info = tps65021_regs,
+ .core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
- .info = tps65023_regs,
- .core_regulator = TPS65023_DCDC_1,
+ .info = tps65023_regs,
+ .core_regulator = TPS65023_DCDC_1,
};
static const struct i2c_device_id tps_65023_id[] = {
@@ -669,22 +527,12 @@ static struct i2c_driver tps_65023_i2c_driver = {
.id_table = tps_65023_id,
};
-/**
- * tps_65023_init
- *
- * Module init function
- */
static int __init tps_65023_init(void)
{
return i2c_add_driver(&tps_65023_i2c_driver);
}
subsys_initcall(tps_65023_init);
-/**
- * tps_65023_cleanup
- *
- * Module exit function
- */
static void __exit tps_65023_cleanup(void)
{
i2c_del_driver(&tps_65023_i2c_driver);
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 832833f..da38be1 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -23,7 +23,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/tps6507x.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mfd/tps6507x.h>
@@ -283,7 +282,7 @@ static int tps6507x_pmic_disable(struct regulator_dev *dev)
1 << shift);
}
-static int tps6507x_pmic_get_voltage(struct regulator_dev *dev)
+static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
{
struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, rid = rdev_get_id(dev);
@@ -325,7 +324,7 @@ static int tps6507x_pmic_get_voltage(struct regulator_dev *dev)
return data;
data &= mask;
- return tps->info[rid]->table[data] * 1000;
+ return data;
}
static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
@@ -395,7 +394,7 @@ static struct regulator_ops tps6507x_pmic_ops = {
.is_enabled = tps6507x_pmic_is_enabled,
.enable = tps6507x_pmic_enable,
.disable = tps6507x_pmic_disable,
- .get_voltage = tps6507x_pmic_get_voltage,
+ .get_voltage_sel = tps6507x_pmic_get_voltage_sel,
.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
.list_voltage = tps6507x_pmic_list_voltage,
};
@@ -404,6 +403,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
struct tps_info *info = &tps6507x_pmic_regs[0];
+ struct regulator_config config = { };
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps6507x_pmic *tps;
@@ -428,7 +428,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
if (!init_data)
return -EINVAL;
- tps = kzalloc(sizeof(*tps), GFP_KERNEL);
+ tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
@@ -453,8 +453,11 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
- rdev = regulator_register(&tps->desc[i],
- tps6507x_dev->dev, init_data, tps, NULL);
+ config.dev = tps6507x_dev->dev;
+ config.init_data = init_data;
+ config.driver_data = tps;
+
+ rdev = regulator_register(&tps->desc[i], &config);
if (IS_ERR(rdev)) {
dev_err(tps6507x_dev->dev,
"failed to register %s regulator\n",
@@ -475,8 +478,6 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
fail:
while (--i >= 0)
regulator_unregister(tps->rdev[i]);
-
- kfree(tps);
return error;
}
@@ -488,9 +489,6 @@ static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]);
-
- kfree(tps);
-
return 0;
}
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
new file mode 100644
index 0000000..001ad55
--- /dev/null
+++ b/drivers/regulator/tps65090-regulator.c
@@ -0,0 +1,150 @@
+/*
+ * Regulator driver for tps65090 power management chip.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regulator/tps65090-regulator.h>
+
+struct tps65090_regulator {
+ int id;
+ /* used by regulator core */
+ struct regulator_desc desc;
+
+ /* Device */
+ struct device *dev;
+};
+
+static struct regulator_ops tps65090_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+#define tps65090_REG(_id) \
+{ \
+ .id = TPS65090_ID_##_id, \
+ .desc = { \
+ .name = tps65090_rails(_id), \
+ .id = TPS65090_ID_##_id, \
+ .ops = &tps65090_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .enable_reg = (TPS65090_ID_##_id) + 12, \
+ .enable_mask = BIT(0), \
+ }, \
+}
+
+static struct tps65090_regulator TPS65090_regulator[] = {
+ tps65090_REG(DCDC1),
+ tps65090_REG(DCDC2),
+ tps65090_REG(DCDC3),
+ tps65090_REG(FET1),
+ tps65090_REG(FET2),
+ tps65090_REG(FET3),
+ tps65090_REG(FET4),
+ tps65090_REG(FET5),
+ tps65090_REG(FET6),
+ tps65090_REG(FET7),
+};
+
+static inline struct tps65090_regulator *find_regulator_info(int id)
+{
+ struct tps65090_regulator *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) {
+ ri = &TPS65090_regulator[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
+{
+ struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
+ struct tps65090_regulator *ri = NULL;
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ struct tps65090_regulator_platform_data *tps_pdata;
+ int id = pdev->id;
+
+ dev_dbg(&pdev->dev, "Probing regulator %d\n", id);
+
+ ri = find_regulator_info(id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+ tps_pdata = pdev->dev.platform_data;
+ ri->dev = &pdev->dev;
+
+ config.dev = &pdev->dev;
+ config.init_data = &tps_pdata->regulator;
+ config.driver_data = ri;
+ config.regmap = tps65090_mfd->rmap;
+
+ rdev = regulator_register(&ri->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit tps65090_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver tps65090_regulator_driver = {
+ .driver = {
+ .name = "tps65090-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65090_regulator_probe,
+ .remove = __devexit_p(tps65090_regulator_remove),
+};
+
+static int __init tps65090_regulator_init(void)
+{
+ return platform_driver_register(&tps65090_regulator_driver);
+}
+subsys_initcall(tps65090_regulator_init);
+
+static void __exit tps65090_regulator_exit(void)
+{
+ platform_driver_unregister(&tps65090_regulator_driver);
+}
+module_exit(tps65090_regulator_exit);
+
+MODULE_DESCRIPTION("tps65090 regulator driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index e39521b..9d371d2 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -213,65 +213,56 @@ static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev)
return selector;
}
-static int tps65217_pmic_ldo1_set_voltage_sel(struct regulator_dev *dev,
- unsigned selector)
+static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
{
+ int ret;
struct tps65217 *tps = rdev_get_drvdata(dev);
- int ldo = rdev_get_id(dev);
+ unsigned int rid = rdev_get_id(dev);
- if (ldo != TPS65217_LDO_1)
- return -EINVAL;
+ /* Set the voltage based on vsel value and write protect level is 2 */
+ ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
+ tps->info[rid]->set_vout_mask,
+ selector, TPS65217_PROTECT_L2);
- if (selector >= tps->info[ldo]->table_len)
- return -EINVAL;
+ /* Set GO bit for DCDCx to initiate voltage transistion */
+ switch (rid) {
+ case TPS65217_DCDC_1 ... TPS65217_DCDC_3:
+ ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW,
+ TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO,
+ TPS65217_PROTECT_L2);
+ break;
+ }
- /* Set the voltage based on vsel value and write protect level is 2 */
- return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg,
- tps->info[ldo]->set_vout_mask,
- selector, TPS65217_PROTECT_L2);
+ return ret;
}
-static int tps65217_pmic_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV, unsigned *selector)
+static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
{
- int ret;
+
struct tps65217 *tps = rdev_get_drvdata(dev);
- unsigned int rid = rdev_get_id(dev);
+ unsigned int sel, rid = rdev_get_id(dev);
+ int ret;
- /* LDO1 implements set_voltage_sel callback */
+ /* LDO1 uses regulator_map_voltage_iterate() */
if (rid == TPS65217_LDO_1)
return -EINVAL;
if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
return -EINVAL;
- if (min_uV < tps->info[rid]->min_uV
- || min_uV > tps->info[rid]->max_uV)
+ if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
return -EINVAL;
- if (max_uV < tps->info[rid]->min_uV
- || max_uV > tps->info[rid]->max_uV)
+ if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV)
return -EINVAL;
- ret = tps->info[rid]->uv_to_vsel(min_uV, selector);
+ ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
if (ret)
return ret;
- /* Set the voltage based on vsel value and write protect level is 2 */
- ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
- tps->info[rid]->set_vout_mask,
- *selector, TPS65217_PROTECT_L2);
-
- /* Set GO bit for DCDCx to initiate voltage transistion */
- switch (rid) {
- case TPS65217_DCDC_1 ... TPS65217_DCDC_3:
- ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW,
- TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO,
- TPS65217_PROTECT_L2);
- break;
- }
-
- return ret;
+ return sel;
}
static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
@@ -298,8 +289,9 @@ static struct regulator_ops tps65217_pmic_ops = {
.enable = tps65217_pmic_enable,
.disable = tps65217_pmic_disable,
.get_voltage_sel = tps65217_pmic_get_voltage_sel,
- .set_voltage = tps65217_pmic_set_voltage,
+ .set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = tps65217_pmic_list_voltage,
+ .map_voltage = tps65217_pmic_map_voltage,
};
/* Operations permitted on LDO1 */
@@ -308,11 +300,11 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
.enable = tps65217_pmic_enable,
.disable = tps65217_pmic_disable,
.get_voltage_sel = tps65217_pmic_get_voltage_sel,
- .set_voltage_sel = tps65217_pmic_ldo1_set_voltage_sel,
+ .set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = tps65217_pmic_list_voltage,
};
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64),
TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64),
TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64),
@@ -327,13 +319,17 @@ static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
struct tps65217 *tps;
struct tps_info *info = &tps65217_pmic_regs[pdev->id];
+ struct regulator_config config = { };
/* Already set by core driver */
tps = dev_to_tps65217(pdev->dev.parent);
tps->info[pdev->id] = info;
- rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, tps, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = tps;
+
+ rdev = regulator_register(&regulators[pdev->id], &config);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 4a421be..b88b3df 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -458,12 +458,10 @@ static int list_voltage(struct regulator_dev *rdev, unsigned selector)
info->voltages[selector] : -EINVAL);
}
-static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned *selector)
+static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
const struct supply_info *info;
struct tps6524x *hw;
- unsigned i;
hw = rdev_get_drvdata(rdev);
info = &supply_info[rdev_get_id(rdev)];
@@ -471,20 +469,10 @@ static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
if (info->flags & FIXED_VOLTAGE)
return -EINVAL;
- for (i = 0; i < info->n_voltages; i++)
- if (min_uV <= info->voltages[i] &&
- max_uV >= info->voltages[i])
- break;
-
- if (i >= info->n_voltages)
- i = info->n_voltages - 1;
-
- *selector = i;
-
- return write_field(hw, &info->voltage, i);
+ return write_field(hw, &info->voltage, selector);
}
-static int get_voltage(struct regulator_dev *rdev)
+static int get_voltage_sel(struct regulator_dev *rdev)
{
const struct supply_info *info;
struct tps6524x *hw;
@@ -502,7 +490,7 @@ static int get_voltage(struct regulator_dev *rdev)
if (WARN_ON(ret >= info->n_voltages))
return -EIO;
- return info->voltages[ret];
+ return ret;
}
static int set_current_limit(struct regulator_dev *rdev, int min_uA,
@@ -587,8 +575,8 @@ static struct regulator_ops regulator_ops = {
.is_enabled = is_supply_enabled,
.enable = enable_supply,
.disable = disable_supply,
- .get_voltage = get_voltage,
- .set_voltage = set_voltage,
+ .get_voltage_sel = get_voltage_sel,
+ .set_voltage_sel = set_voltage_sel,
.list_voltage = list_voltage,
.set_current_limit = set_current_limit,
.get_current_limit = get_current_limit,
@@ -607,7 +595,6 @@ static int pmic_remove(struct spi_device *spi)
hw->rdev[i] = NULL;
}
spi_set_drvdata(spi, NULL);
- kfree(hw);
return 0;
}
@@ -617,6 +604,7 @@ static int __devinit pmic_probe(struct spi_device *spi)
struct device *dev = &spi->dev;
const struct supply_info *info = supply_info;
struct regulator_init_data *init_data;
+ struct regulator_config config = { };
int ret = 0, i;
init_data = dev->platform_data;
@@ -625,7 +613,7 @@ static int __devinit pmic_probe(struct spi_device *spi)
return -EINVAL;
}
- hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL);
+ hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
if (!hw) {
dev_err(dev, "cannot allocate regulator private data\n");
return -ENOMEM;
@@ -648,8 +636,11 @@ static int __devinit pmic_probe(struct spi_device *spi)
if (info->flags & FIXED_VOLTAGE)
hw->desc[i].n_voltages = 1;
- hw->rdev[i] = regulator_register(&hw->desc[i], dev,
- init_data, hw, NULL);
+ config.dev = dev;
+ config.init_data = init_data;
+ config.driver_data = hw;
+
+ hw->rdev[i] = regulator_register(&hw->desc[i], &config);
if (IS_ERR(hw->rdev[i])) {
ret = PTR_ERR(hw->rdev[i]);
hw->rdev[i] = NULL;
@@ -673,17 +664,7 @@ static struct spi_driver pmic_driver = {
},
};
-static int __init pmic_driver_init(void)
-{
- return spi_register_driver(&pmic_driver);
-}
-module_init(pmic_driver_init);
-
-static void __exit pmic_driver_exit(void)
-{
- spi_unregister_driver(&pmic_driver);
-}
-module_exit(pmic_driver_exit);
+module_spi_driver(pmic_driver);
MODULE_DESCRIPTION("TPS6524X PMIC Driver");
MODULE_AUTHOR("Cyril Chemparathy");
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index cfc1f16..c0a2145 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -75,8 +75,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
return rdev_get_dev(rdev)->parent->parent;
}
-static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
+static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector)
{
struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
int rid = rdev_get_id(rdev);
@@ -89,47 +88,34 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
}
-static int __tps6586x_ldo_set_voltage(struct device *parent,
- struct tps6586x_regulator *ri,
- int min_uV, int max_uV,
- unsigned *selector)
+static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
- int val, uV;
+ struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_tps6586x_dev(rdev);
+ int ret, val, rid = rdev_get_id(rdev);
uint8_t mask;
- for (val = 0; val < ri->desc.n_voltages; val++) {
- uV = ri->voltages[val] * 1000;
-
- /* LDO0 has minimal voltage 1.2 rather than 1.25 */
- if (ri->desc.id == TPS6586X_ID_LDO_0 && val == 0)
- uV -= 50 * 1000;
-
- /* use the first in-range value */
- if (min_uV <= uV && uV <= max_uV) {
-
- *selector = val;
+ val = selector << ri->volt_shift;
+ mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
- val <<= ri->volt_shift;
- mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+ ret = tps6586x_update(parent, ri->volt_reg, val, mask);
+ if (ret)
+ return ret;
- return tps6586x_update(parent, ri->volt_reg, val, mask);
- }
+ /* Update go bit for DVM regulators */
+ switch (rid) {
+ case TPS6586X_ID_LDO_2:
+ case TPS6586X_ID_LDO_4:
+ case TPS6586X_ID_SM_0:
+ case TPS6586X_ID_SM_1:
+ ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
+ break;
}
-
- return -EINVAL;
-}
-
-static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
- struct device *parent = to_tps6586x_dev(rdev);
-
- return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
- selector);
+ return ret;
}
-static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
+static int tps6586x_get_voltage_sel(struct regulator_dev *rdev)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
@@ -146,22 +132,7 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
if (val >= ri->desc.n_voltages)
BUG();
- return ri->voltages[val] * 1000;
-}
-
-static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
- struct device *parent = to_tps6586x_dev(rdev);
- int ret;
-
- ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
- selector);
- if (ret)
- return ret;
-
- return tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
+ return val;
}
static int tps6586x_regulator_enable(struct regulator_dev *rdev)
@@ -196,20 +167,10 @@ static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
return !!(reg_val & (1 << ri->enable_bit[0]));
}
-static struct regulator_ops tps6586x_regulator_ldo_ops = {
- .list_voltage = tps6586x_ldo_list_voltage,
- .get_voltage = tps6586x_ldo_get_voltage,
- .set_voltage = tps6586x_ldo_set_voltage,
-
- .is_enabled = tps6586x_regulator_is_enabled,
- .enable = tps6586x_regulator_enable,
- .disable = tps6586x_regulator_disable,
-};
-
-static struct regulator_ops tps6586x_regulator_dvm_ops = {
- .list_voltage = tps6586x_ldo_list_voltage,
- .get_voltage = tps6586x_ldo_get_voltage,
- .set_voltage = tps6586x_dvm_set_voltage,
+static struct regulator_ops tps6586x_regulator_ops = {
+ .list_voltage = tps6586x_list_voltage,
+ .get_voltage_sel = tps6586x_get_voltage_sel,
+ .set_voltage_sel = tps6586x_set_voltage_sel,
.is_enabled = tps6586x_regulator_is_enabled,
.enable = tps6586x_regulator_enable,
@@ -241,11 +202,11 @@ static int tps6586x_dvm_voltages[] = {
1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
};
-#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \
+#define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
.desc = { \
.name = "REG-" #_id, \
- .ops = &tps6586x_regulator_##_ops, \
+ .ops = &tps6586x_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \
@@ -267,14 +228,14 @@ static int tps6586x_dvm_voltages[] = {
#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
- TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
}
#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
- TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
}
@@ -384,6 +345,7 @@ static inline struct tps6586x_regulator *find_regulator_info(int id)
static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
{
struct tps6586x_regulator *ri = NULL;
+ struct regulator_config config = { };
struct regulator_dev *rdev;
int id = pdev->id;
int err;
@@ -400,8 +362,12 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
if (err)
return err;
- rdev = regulator_register(&ri->desc, &pdev->dev,
- pdev->dev.platform_data, ri, NULL);
+ config.dev = &pdev->dev;
+ config.of_node = pdev->dev.of_node;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = ri;
+
+ rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 4a37c2b6..4e01a42 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -20,10 +20,10 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/mfd/tps65910.h>
+#include <linux/regulator/of_regulator.h>
#define TPS65910_SUPPLY_STATE_ENABLED 0x1
#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \
@@ -31,54 +31,54 @@
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
-/* supported VIO voltages in milivolts */
+/* supported VIO voltages in millivolts */
static const u16 VIO_VSEL_table[] = {
1500, 1800, 2500, 3300,
};
/* VSEL tables for TPS65910 specific LDOs and dcdc's */
-/* supported VDD3 voltages in milivolts */
+/* supported VDD3 voltages in millivolts */
static const u16 VDD3_VSEL_table[] = {
5000,
};
-/* supported VDIG1 voltages in milivolts */
+/* supported VDIG1 voltages in millivolts */
static const u16 VDIG1_VSEL_table[] = {
1200, 1500, 1800, 2700,
};
-/* supported VDIG2 voltages in milivolts */
+/* supported VDIG2 voltages in millivolts */
static const u16 VDIG2_VSEL_table[] = {
1000, 1100, 1200, 1800,
};
-/* supported VPLL voltages in milivolts */
+/* supported VPLL voltages in millivolts */
static const u16 VPLL_VSEL_table[] = {
1000, 1100, 1800, 2500,
};
-/* supported VDAC voltages in milivolts */
+/* supported VDAC voltages in millivolts */
static const u16 VDAC_VSEL_table[] = {
1800, 2600, 2800, 2850,
};
-/* supported VAUX1 voltages in milivolts */
+/* supported VAUX1 voltages in millivolts */
static const u16 VAUX1_VSEL_table[] = {
1800, 2500, 2800, 2850,
};
-/* supported VAUX2 voltages in milivolts */
+/* supported VAUX2 voltages in millivolts */
static const u16 VAUX2_VSEL_table[] = {
1800, 2800, 2900, 3300,
};
-/* supported VAUX33 voltages in milivolts */
+/* supported VAUX33 voltages in millivolts */
static const u16 VAUX33_VSEL_table[] = {
1800, 2000, 2800, 3300,
};
-/* supported VMMC voltages in milivolts */
+/* supported VMMC voltages in millivolts */
static const u16 VMMC_VSEL_table[] = {
1800, 2800, 3000, 3300,
};
@@ -94,11 +94,11 @@ struct tps_info {
static struct tps_info tps65910_regs[] = {
{
- .name = "VRTC",
+ .name = "vrtc",
.enable_time_us = 2200,
},
{
- .name = "VIO",
+ .name = "vio",
.min_uV = 1500000,
.max_uV = 3300000,
.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
@@ -106,19 +106,19 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 350,
},
{
- .name = "VDD1",
+ .name = "vdd1",
.min_uV = 600000,
.max_uV = 4500000,
.enable_time_us = 350,
},
{
- .name = "VDD2",
+ .name = "vdd2",
.min_uV = 600000,
.max_uV = 4500000,
.enable_time_us = 350,
},
{
- .name = "VDD3",
+ .name = "vdd3",
.min_uV = 5000000,
.max_uV = 5000000,
.n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
@@ -126,7 +126,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 200,
},
{
- .name = "VDIG1",
+ .name = "vdig1",
.min_uV = 1200000,
.max_uV = 2700000,
.n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
@@ -134,7 +134,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VDIG2",
+ .name = "vdig2",
.min_uV = 1000000,
.max_uV = 1800000,
.n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
@@ -142,7 +142,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VPLL",
+ .name = "vpll",
.min_uV = 1000000,
.max_uV = 2500000,
.n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
@@ -150,7 +150,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VDAC",
+ .name = "vdac",
.min_uV = 1800000,
.max_uV = 2850000,
.n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
@@ -158,7 +158,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VAUX1",
+ .name = "vaux1",
.min_uV = 1800000,
.max_uV = 2850000,
.n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
@@ -166,7 +166,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VAUX2",
+ .name = "vaux2",
.min_uV = 1800000,
.max_uV = 3300000,
.n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
@@ -174,7 +174,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VAUX33",
+ .name = "vaux33",
.min_uV = 1800000,
.max_uV = 3300000,
.n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
@@ -182,7 +182,7 @@ static struct tps_info tps65910_regs[] = {
.enable_time_us = 100,
},
{
- .name = "VMMC",
+ .name = "vmmc",
.min_uV = 1800000,
.max_uV = 3300000,
.n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
@@ -193,11 +193,11 @@ static struct tps_info tps65910_regs[] = {
static struct tps_info tps65911_regs[] = {
{
- .name = "VRTC",
+ .name = "vrtc",
.enable_time_us = 2200,
},
{
- .name = "VIO",
+ .name = "vio",
.min_uV = 1500000,
.max_uV = 3300000,
.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
@@ -205,77 +205,77 @@ static struct tps_info tps65911_regs[] = {
.enable_time_us = 350,
},
{
- .name = "VDD1",
+ .name = "vdd1",
.min_uV = 600000,
.max_uV = 4500000,
.n_voltages = 73,
.enable_time_us = 350,
},
{
- .name = "VDD2",
+ .name = "vdd2",
.min_uV = 600000,
.max_uV = 4500000,
.n_voltages = 73,
.enable_time_us = 350,
},
{
- .name = "VDDCTRL",
+ .name = "vddctrl",
.min_uV = 600000,
.max_uV = 1400000,
.n_voltages = 65,
.enable_time_us = 900,
},
{
- .name = "LDO1",
+ .name = "ldo1",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 47,
.enable_time_us = 420,
},
{
- .name = "LDO2",
+ .name = "ldo2",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 47,
.enable_time_us = 420,
},
{
- .name = "LDO3",
+ .name = "ldo3",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 24,
.enable_time_us = 230,
},
{
- .name = "LDO4",
+ .name = "ldo4",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 47,
.enable_time_us = 230,
},
{
- .name = "LDO5",
+ .name = "ldo5",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 24,
.enable_time_us = 230,
},
{
- .name = "LDO6",
+ .name = "ldo6",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 24,
.enable_time_us = 230,
},
{
- .name = "LDO7",
+ .name = "ldo7",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 24,
.enable_time_us = 230,
},
{
- .name = "LDO8",
+ .name = "ldo8",
.min_uV = 1000000,
.max_uV = 3300000,
.n_voltages = 24,
@@ -467,48 +467,6 @@ static int tps65911_get_ctrl_register(int id)
}
}
-static int tps65910_is_enabled(struct regulator_dev *dev)
-{
- struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int reg, value, id = rdev_get_id(dev);
-
- reg = pmic->get_ctrl_reg(id);
- if (reg < 0)
- return reg;
-
- value = tps65910_reg_read(pmic, reg);
- if (value < 0)
- return value;
-
- return value & TPS65910_SUPPLY_STATE_ENABLED;
-}
-
-static int tps65910_enable(struct regulator_dev *dev)
-{
- struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- struct tps65910 *mfd = pmic->mfd;
- int reg, id = rdev_get_id(dev);
-
- reg = pmic->get_ctrl_reg(id);
- if (reg < 0)
- return reg;
-
- return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
-}
-
-static int tps65910_disable(struct regulator_dev *dev)
-{
- struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- struct tps65910 *mfd = pmic->mfd;
- int reg, id = rdev_get_id(dev);
-
- reg = pmic->get_ctrl_reg(id);
- if (reg < 0)
- return reg;
-
- return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
-}
-
static int tps65910_enable_time(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
@@ -621,10 +579,10 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
return -EINVAL;
}
-static int tps65910_get_voltage(struct regulator_dev *dev)
+static int tps65910_get_voltage_sel(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int reg, value, id = rdev_get_id(dev), voltage = 0;
+ int reg, value, id = rdev_get_id(dev);
reg = pmic->get_ctrl_reg(id);
if (reg < 0)
@@ -651,9 +609,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
return -EINVAL;
}
- voltage = pmic->info[id]->voltage_table[value] * 1000;
-
- return voltage;
+ return value;
}
static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
@@ -661,10 +617,10 @@ static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
return 5 * 1000 * 1000;
}
-static int tps65911_get_voltage(struct regulator_dev *dev)
+static int tps65911_get_voltage_sel(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int step_mv, id = rdev_get_id(dev);
+ int id = rdev_get_id(dev);
u8 value, reg;
reg = pmic->get_ctrl_reg(id);
@@ -677,13 +633,6 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
case TPS65911_REG_LDO4:
value &= LDO1_SEL_MASK;
value >>= LDO_SEL_SHIFT;
- /* The first 5 values of the selector correspond to 1V */
- if (value < 5)
- value = 0;
- else
- value -= 4;
-
- step_mv = 50;
break;
case TPS65911_REG_LDO3:
case TPS65911_REG_LDO5:
@@ -692,23 +641,16 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
case TPS65911_REG_LDO8:
value &= LDO3_SEL_MASK;
value >>= LDO_SEL_SHIFT;
- /* The first 3 values of the selector correspond to 1V */
- if (value < 3)
- value = 0;
- else
- value -= 2;
-
- step_mv = 100;
break;
case TPS65910_REG_VIO:
value &= LDO_SEL_MASK;
value >>= LDO_SEL_SHIFT;
- return pmic->info[id]->voltage_table[value] * 1000;
+ break;
default:
return -EINVAL;
}
- return (LDO_MIN_VOLT + value * step_mv) * 1000;
+ return value;
}
static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
@@ -914,9 +856,9 @@ static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
/* Regulator ops (except VRTC) */
static struct regulator_ops tps65910_ops_dcdc = {
- .is_enabled = tps65910_is_enabled,
- .enable = tps65910_enable,
- .disable = tps65910_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
@@ -927,9 +869,9 @@ static struct regulator_ops tps65910_ops_dcdc = {
};
static struct regulator_ops tps65910_ops_vdd3 = {
- .is_enabled = tps65910_is_enabled,
- .enable = tps65910_enable,
- .disable = tps65910_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
@@ -938,25 +880,25 @@ static struct regulator_ops tps65910_ops_vdd3 = {
};
static struct regulator_ops tps65910_ops = {
- .is_enabled = tps65910_is_enabled,
- .enable = tps65910_enable,
- .disable = tps65910_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
- .get_voltage = tps65910_get_voltage,
+ .get_voltage_sel = tps65910_get_voltage_sel,
.set_voltage_sel = tps65910_set_voltage_sel,
.list_voltage = tps65910_list_voltage,
};
static struct regulator_ops tps65911_ops = {
- .is_enabled = tps65910_is_enabled,
- .enable = tps65910_enable,
- .disable = tps65910_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
- .get_voltage = tps65911_get_voltage,
+ .get_voltage_sel = tps65911_get_voltage_sel,
.set_voltage_sel = tps65911_set_voltage_sel,
.list_voltage = tps65911_list_voltage,
};
@@ -1094,23 +1036,141 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
return ret;
}
+#ifdef CONFIG_OF
+
+static struct of_regulator_match tps65910_matches[] = {
+ { .name = "vrtc", .driver_data = (void *) &tps65910_regs[0] },
+ { .name = "vio", .driver_data = (void *) &tps65910_regs[1] },
+ { .name = "vdd1", .driver_data = (void *) &tps65910_regs[2] },
+ { .name = "vdd2", .driver_data = (void *) &tps65910_regs[3] },
+ { .name = "vdd3", .driver_data = (void *) &tps65910_regs[4] },
+ { .name = "vdig1", .driver_data = (void *) &tps65910_regs[5] },
+ { .name = "vdig2", .driver_data = (void *) &tps65910_regs[6] },
+ { .name = "vpll", .driver_data = (void *) &tps65910_regs[7] },
+ { .name = "vdac", .driver_data = (void *) &tps65910_regs[8] },
+ { .name = "vaux1", .driver_data = (void *) &tps65910_regs[9] },
+ { .name = "vaux2", .driver_data = (void *) &tps65910_regs[10] },
+ { .name = "vaux33", .driver_data = (void *) &tps65910_regs[11] },
+ { .name = "vmmc", .driver_data = (void *) &tps65910_regs[12] },
+};
+
+static struct of_regulator_match tps65911_matches[] = {
+ { .name = "vrtc", .driver_data = (void *) &tps65911_regs[0] },
+ { .name = "vio", .driver_data = (void *) &tps65911_regs[1] },
+ { .name = "vdd1", .driver_data = (void *) &tps65911_regs[2] },
+ { .name = "vdd2", .driver_data = (void *) &tps65911_regs[3] },
+ { .name = "vddctrl", .driver_data = (void *) &tps65911_regs[4] },
+ { .name = "ldo1", .driver_data = (void *) &tps65911_regs[5] },
+ { .name = "ldo2", .driver_data = (void *) &tps65911_regs[6] },
+ { .name = "ldo3", .driver_data = (void *) &tps65911_regs[7] },
+ { .name = "ldo4", .driver_data = (void *) &tps65911_regs[8] },
+ { .name = "ldo5", .driver_data = (void *) &tps65911_regs[9] },
+ { .name = "ldo6", .driver_data = (void *) &tps65911_regs[10] },
+ { .name = "ldo7", .driver_data = (void *) &tps65911_regs[11] },
+ { .name = "ldo8", .driver_data = (void *) &tps65911_regs[12] },
+};
+
+static struct tps65910_board *tps65910_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps65910_reg_matches)
+{
+ struct tps65910_board *pmic_plat_data;
+ struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ struct of_regulator_match *matches;
+ unsigned int prop;
+ int idx = 0, ret, count;
+
+ pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data),
+ GFP_KERNEL);
+
+ if (!pmic_plat_data) {
+ dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ return NULL;
+ }
+
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulator node not found\n");
+ return NULL;
+ }
+
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65910:
+ count = ARRAY_SIZE(tps65910_matches);
+ matches = tps65910_matches;
+ break;
+ case TPS65911:
+ count = ARRAY_SIZE(tps65911_matches);
+ matches = tps65911_matches;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid tps chip version\n");
+ return NULL;
+ }
+
+ ret = of_regulator_match(pdev->dev.parent, regulators, matches, count);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return NULL;
+ }
+
+ *tps65910_reg_matches = matches;
+
+ for (idx = 0; idx < count; idx++) {
+ if (!matches[idx].init_data || !matches[idx].of_node)
+ continue;
+
+ pmic_plat_data->tps65910_pmic_init_data[idx] =
+ matches[idx].init_data;
+
+ ret = of_property_read_u32(matches[idx].of_node,
+ "ti,regulator-ext-sleep-control", &prop);
+ if (!ret)
+ pmic_plat_data->regulator_ext_sleep_control[idx] = prop;
+ }
+
+ return pmic_plat_data;
+}
+#else
+static inline struct tps65910_board *tps65910_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps65910_reg_matches)
+{
+ *tps65910_reg_matches = NULL;
+ return 0;
+}
+#endif
+
static __devinit int tps65910_probe(struct platform_device *pdev)
{
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
struct tps_info *info;
struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
struct tps65910_reg *pmic;
struct tps65910_board *pmic_plat_data;
+ struct of_regulator_match *tps65910_reg_matches = NULL;
int i, err;
pmic_plat_data = dev_get_platdata(tps65910->dev);
- if (!pmic_plat_data)
+ if (!pmic_plat_data && tps65910->dev->of_node)
+ pmic_plat_data = tps65910_parse_dt_reg_data(pdev,
+ &tps65910_reg_matches);
+
+ if (!pmic_plat_data) {
+ dev_err(&pdev->dev, "Platform data not found\n");
return -EINVAL;
+ }
- pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
- if (!pmic)
+ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic) {
+ dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
return -ENOMEM;
+ }
mutex_init(&pmic->mutex);
pmic->mfd = tps65910;
@@ -1134,30 +1194,29 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
info = tps65911_regs;
break;
default:
- pr_err("Invalid tps chip version\n");
- kfree(pmic);
+ dev_err(&pdev->dev, "Invalid tps chip version\n");
return -ENODEV;
}
- pmic->desc = kcalloc(pmic->num_regulators,
+ pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_desc), GFP_KERNEL);
if (!pmic->desc) {
- err = -ENOMEM;
- goto err_free_pmic;
+ dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+ return -ENOMEM;
}
- pmic->info = kcalloc(pmic->num_regulators,
+ pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct tps_info *), GFP_KERNEL);
if (!pmic->info) {
- err = -ENOMEM;
- goto err_free_desc;
+ dev_err(&pdev->dev, "Memory alloc fails for info\n");
+ return -ENOMEM;
}
- pmic->rdev = kcalloc(pmic->num_regulators,
+ pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_dev *), GFP_KERNEL);
if (!pmic->rdev) {
- err = -ENOMEM;
- goto err_free_info;
+ dev_err(&pdev->dev, "Memory alloc fails for rdev\n");
+ return -ENOMEM;
}
for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
@@ -1205,9 +1264,18 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
pmic->desc[i].type = REGULATOR_VOLTAGE;
pmic->desc[i].owner = THIS_MODULE;
+ pmic->desc[i].enable_reg = pmic->get_ctrl_reg(i);
+ pmic->desc[i].enable_mask = TPS65910_SUPPLY_STATE_ENABLED;
+
+ config.dev = tps65910->dev;
+ config.init_data = reg_data;
+ config.driver_data = pmic;
+ config.regmap = tps65910->regmap;
+
+ if (tps65910_reg_matches)
+ config.of_node = tps65910_reg_matches[i].of_node;
- rdev = regulator_register(&pmic->desc[i],
- tps65910->dev, reg_data, pmic, NULL);
+ rdev = regulator_register(&pmic->desc[i], &config);
if (IS_ERR(rdev)) {
dev_err(tps65910->dev,
"failed to register %s regulator\n",
@@ -1224,13 +1292,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
err_unregister_regulator:
while (--i >= 0)
regulator_unregister(pmic->rdev[i]);
- kfree(pmic->rdev);
-err_free_info:
- kfree(pmic->info);
-err_free_desc:
- kfree(pmic->desc);
-err_free_pmic:
- kfree(pmic);
return err;
}
@@ -1242,10 +1303,6 @@ static int __devexit tps65910_remove(struct platform_device *pdev)
for (i = 0; i < pmic->num_regulators; i++)
regulator_unregister(pmic->rdev[i]);
- kfree(pmic->rdev);
- kfree(pmic->info);
- kfree(pmic->desc);
- kfree(pmic);
return 0;
}
diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c
index b36799b..18b2a1d 100644
--- a/drivers/regulator/tps65912-regulator.c
+++ b/drivers/regulator/tps65912-regulator.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/mfd/tps65912.h>
@@ -372,12 +371,14 @@ static unsigned int tps65912_get_mode(struct regulator_dev *dev)
return mode;
}
-static int tps65912_list_voltage_dcdc(struct regulator_dev *dev,
- unsigned selector)
+static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector)
{
struct tps65912_reg *pmic = rdev_get_drvdata(dev);
int range, voltage = 0, id = rdev_get_id(dev);
+ if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10)
+ return tps65912_vsel_to_uv_ldo(selector);
+
if (id > TPS65912_REG_DCDC4)
return -EINVAL;
@@ -404,7 +405,7 @@ static int tps65912_list_voltage_dcdc(struct regulator_dev *dev,
return voltage;
}
-static int tps65912_get_voltage_dcdc(struct regulator_dev *dev)
+static int tps65912_get_voltage_sel(struct regulator_dev *dev)
{
struct tps65912_reg *pmic = rdev_get_drvdata(dev);
struct tps65912 *mfd = pmic->mfd;
@@ -418,7 +419,7 @@ static int tps65912_get_voltage_dcdc(struct regulator_dev *dev)
vsel = tps65912_reg_read(mfd, reg);
vsel &= 0x3F;
- return tps65912_list_voltage_dcdc(dev, vsel);
+ return vsel;
}
static int tps65912_set_voltage_sel(struct regulator_dev *dev,
@@ -436,32 +437,6 @@ static int tps65912_set_voltage_sel(struct regulator_dev *dev,
return tps65912_reg_write(mfd, reg, selector | value);
}
-static int tps65912_get_voltage_ldo(struct regulator_dev *dev)
-{
- struct tps65912_reg *pmic = rdev_get_drvdata(dev);
- struct tps65912 *mfd = pmic->mfd;
- int id = rdev_get_id(dev);
- int vsel = 0;
- u8 reg;
-
- reg = tps65912_get_sel_register(pmic, id);
- vsel = tps65912_reg_read(mfd, reg);
- vsel &= 0x3F;
-
- return tps65912_vsel_to_uv_ldo(vsel);
-}
-
-static int tps65912_list_voltage_ldo(struct regulator_dev *dev,
- unsigned selector)
-{
- int ldo = rdev_get_id(dev);
-
- if (ldo < TPS65912_REG_LDO1 || ldo > TPS65912_REG_LDO10)
- return -EINVAL;
-
- return tps65912_vsel_to_uv_ldo(selector);
-}
-
/* Operations permitted on DCDCx */
static struct regulator_ops tps65912_ops_dcdc = {
.is_enabled = tps65912_reg_is_enabled,
@@ -469,9 +444,9 @@ static struct regulator_ops tps65912_ops_dcdc = {
.disable = tps65912_reg_disable,
.set_mode = tps65912_set_mode,
.get_mode = tps65912_get_mode,
- .get_voltage = tps65912_get_voltage_dcdc,
+ .get_voltage_sel = tps65912_get_voltage_sel,
.set_voltage_sel = tps65912_set_voltage_sel,
- .list_voltage = tps65912_list_voltage_dcdc,
+ .list_voltage = tps65912_list_voltage,
};
/* Operations permitted on LDOx */
@@ -479,14 +454,15 @@ static struct regulator_ops tps65912_ops_ldo = {
.is_enabled = tps65912_reg_is_enabled,
.enable = tps65912_reg_enable,
.disable = tps65912_reg_disable,
- .get_voltage = tps65912_get_voltage_ldo,
+ .get_voltage_sel = tps65912_get_voltage_sel,
.set_voltage_sel = tps65912_set_voltage_sel,
- .list_voltage = tps65912_list_voltage_ldo,
+ .list_voltage = tps65912_list_voltage,
};
static __devinit int tps65912_probe(struct platform_device *pdev)
{
struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
struct tps_info *info;
struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
@@ -500,7 +476,7 @@ static __devinit int tps65912_probe(struct platform_device *pdev)
reg_data = pmic_plat_data->tps65912_pmic_init_data;
- pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
@@ -524,8 +500,12 @@ static __devinit int tps65912_probe(struct platform_device *pdev)
pmic->desc[i].type = REGULATOR_VOLTAGE;
pmic->desc[i].owner = THIS_MODULE;
range = tps65912_get_range(pmic, i);
- rdev = regulator_register(&pmic->desc[i],
- tps65912->dev, reg_data, pmic, NULL);
+
+ config.dev = tps65912->dev;
+ config.init_data = reg_data;
+ config.driver_data = pmic;
+
+ rdev = regulator_register(&pmic->desc[i], &config);
if (IS_ERR(rdev)) {
dev_err(tps65912->dev,
"failed to register %s regulator\n",
@@ -542,8 +522,6 @@ static __devinit int tps65912_probe(struct platform_device *pdev)
err:
while (--i >= 0)
regulator_unregister(pmic->rdev[i]);
-
- kfree(pmic);
return err;
}
@@ -554,8 +532,6 @@ static int __devexit tps65912_remove(struct platform_device *pdev)
for (i = 0; i < TPS65912_NUM_REGULATOR; i++)
regulator_unregister(tps65912_reg->rdev[i]);
-
- kfree(tps65912_reg);
return 0;
}
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 9cdfc38..c739071 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -175,15 +174,14 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev)
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp = 0, val;
- if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
- grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
- if (grp < 0)
- return grp;
-
- if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) {
+ grp = twlreg_grp(rdev);
+ if (grp < 0)
+ return grp;
grp &= P1_GRP_6030;
- else
+ } else {
grp = 1;
+ }
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
val = TWL6030_CFG_STATE_APP(val);
@@ -197,7 +195,7 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
int grp;
int ret;
- grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ grp = twlreg_grp(rdev);
if (grp < 0)
return grp;
@@ -205,8 +203,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
- udelay(info->delay);
-
return ret;
}
@@ -217,17 +213,28 @@ static int twl6030reg_enable(struct regulator_dev *rdev)
int ret;
if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
- grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ grp = twlreg_grp(rdev);
if (grp < 0)
return grp;
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
grp << TWL6030_CFG_STATE_GRP_SHIFT |
TWL6030_CFG_STATE_ON);
+ return ret;
+}
- udelay(info->delay);
+static int twl4030reg_enable_time(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
- return ret;
+ return info->delay;
+}
+
+static int twl6030reg_enable_time(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+ return info->delay;
}
static int twl4030reg_disable(struct regulator_dev *rdev)
@@ -236,7 +243,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev)
int grp;
int ret;
- grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ grp = twlreg_grp(rdev);
if (grp < 0)
return grp;
@@ -348,7 +355,7 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
int val;
if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
- grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ grp = twlreg_grp(rdev);
if (grp < 0)
return grp;
@@ -388,14 +395,12 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
* VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
* TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
*/
-#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
-#define UNSUP_MASK 0x0000
-#else
#define UNSUP_MASK 0x8000
-#endif
#define UNSUP(x) (UNSUP_MASK | (x))
-#define IS_UNSUP(x) (UNSUP_MASK & (x))
+#define IS_UNSUP(info, x) \
+ ((UNSUP_MASK & (x)) && \
+ !((info)->features & TWL4030_ALLOW_UNSUPPORTED))
#define LDO_MV(x) (~UNSUP_MASK & (x))
@@ -469,35 +474,16 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
struct twlreg_info *info = rdev_get_drvdata(rdev);
int mV = info->table[index];
- return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
+ return IS_UNSUP(info, mV) ? 0 : (LDO_MV(mV) * 1000);
}
static int
-twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned *selector)
+twl4030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
- int vsel;
- for (vsel = 0; vsel < info->table_len; vsel++) {
- int mV = info->table[vsel];
- int uV;
-
- if (IS_UNSUP(mV))
- continue;
- uV = LDO_MV(mV) * 1000;
-
- /* REVISIT for VAUX2, first match may not be best/lowest */
-
- /* use the first in-range value */
- if (min_uV <= uV && uV <= max_uV) {
- *selector = vsel;
- return twlreg_write(info, TWL_MODULE_PM_RECEIVER,
- VREG_VOLTAGE, vsel);
- }
- }
-
- return -EDOM;
+ return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
+ selector);
}
static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
@@ -516,12 +502,13 @@ static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
static struct regulator_ops twl4030ldo_ops = {
.list_voltage = twl4030ldo_list_voltage,
- .set_voltage = twl4030ldo_set_voltage,
+ .set_voltage_sel = twl4030ldo_set_voltage_sel,
.get_voltage = twl4030ldo_get_voltage,
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
+ .enable_time = twl4030reg_enable_time,
.set_mode = twl4030reg_set_mode,
@@ -642,6 +629,7 @@ static struct regulator_ops twl6030ldo_ops = {
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
+ .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
@@ -675,6 +663,7 @@ static struct regulator_ops twl4030fixed_ops = {
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
+ .enable_time = twl4030reg_enable_time,
.set_mode = twl4030reg_set_mode,
@@ -689,6 +678,7 @@ static struct regulator_ops twl6030fixed_ops = {
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
+ .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
@@ -699,6 +689,7 @@ static struct regulator_ops twl6030_fixed_resource = {
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
+ .enable_time = twl6030reg_enable_time,
.get_status = twl6030reg_get_status,
};
@@ -806,10 +797,7 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
vsel = 0;
else if ((min_uV >= 600000) && (min_uV <= 1300000)) {
int calc_uV;
- vsel = (min_uV - 600000) / 125;
- if (vsel % 100)
- vsel += 100;
- vsel /= 100;
+ vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
vsel++;
calc_uV = twl6030smps_list_voltage(rdev, vsel);
if (calc_uV > max_uV)
@@ -836,10 +824,7 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
vsel = 0;
else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
int calc_uV;
- vsel = (min_uV - 700000) / 125;
- if (vsel % 100)
- vsel += 100;
- vsel /= 100;
+ vsel = DIV_ROUND_UP(min_uV - 700000, 12500);
vsel++;
calc_uV = twl6030smps_list_voltage(rdev, vsel);
if (calc_uV > max_uV)
@@ -862,24 +847,18 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
return -EINVAL;
break;
case SMPS_EXTENDED_EN:
- if (min_uV == 0)
+ if (min_uV == 0) {
vsel = 0;
- else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
- vsel = (min_uV - 1852000) / 386;
- if (vsel % 100)
- vsel += 100;
- vsel /= 100;
+ } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
+ vsel = DIV_ROUND_UP(min_uV - 1852000, 38600);
vsel++;
}
break;
case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
- if (min_uV == 0)
+ if (min_uV == 0) {
vsel = 0;
- else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
- vsel = (min_uV - 2161000) / 386;
- if (vsel % 100)
- vsel += 100;
- vsel /= 100;
+ } else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+ vsel = DIV_ROUND_UP(min_uV - 2161000, 38600);
vsel++;
}
break;
@@ -907,6 +886,7 @@ static struct regulator_ops twlsmps_ops = {
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
+ .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
@@ -1194,6 +1174,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
struct twl_regulator_driver_data *drvdata;
const struct of_device_id *match;
+ struct regulator_config config = { };
match = of_match_device(twl_of_match, &pdev->dev);
if (match) {
@@ -1207,10 +1188,12 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
initdata = pdev->dev.platform_data;
for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
info = twl_of_match[i].data;
- if (!info || info->desc.id != id)
- continue;
- break;
+ if (info && info->desc.id == id)
+ break;
}
+ if (i == ARRAY_SIZE(twl_of_match))
+ return -ENODEV;
+
drvdata = initdata->driver_data;
if (!drvdata)
return -EINVAL;
@@ -1273,8 +1256,12 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
break;
}
- rdev = regulator_register(&info->desc, &pdev->dev, initdata, info,
- pdev->dev.of_node);
+ config.dev = &pdev->dev;
+ config.init_data = initdata;
+ config.driver_data = info;
+ config.of_node = pdev->dev.of_node;
+
+ rdev = regulator_register(&info->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "can't register %s, %ld\n",
info->desc.name, PTR_ERR(rdev));
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
index 518667e..a7c8deb 100644
--- a/drivers/regulator/userspace-consumer.c
+++ b/drivers/regulator/userspace-consumer.c
@@ -115,7 +115,9 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
if (!pdata)
return -EINVAL;
- drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL);
+ drvdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct userspace_consumer_data),
+ GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
@@ -125,16 +127,16 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
mutex_init(&drvdata->lock);
- ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
- drvdata->supplies);
+ ret = devm_regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
+ drvdata->supplies);
if (ret) {
dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
- goto err_alloc_supplies;
+ return ret;
}
ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
if (ret != 0)
- goto err_create_attrs;
+ return ret;
if (pdata->init_on) {
ret = regulator_bulk_enable(drvdata->num_supplies,
@@ -154,11 +156,6 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
err_enable:
sysfs_remove_group(&pdev->dev.kobj, &attr_group);
-err_create_attrs:
- regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
-
-err_alloc_supplies:
- kfree(drvdata);
return ret;
}
@@ -171,9 +168,6 @@ static int regulator_userspace_consumer_remove(struct platform_device *pdev)
if (data->enabled)
regulator_bulk_disable(data->num_supplies, data->supplies);
- regulator_bulk_free(data->num_supplies, data->supplies);
- kfree(data);
-
return 0;
}
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index ee0b161..c038e74 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -121,7 +121,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
struct virtual_consumer_data *data = dev_get_drvdata(dev);
long val;
- if (strict_strtol(buf, 10, &val) != 0)
+ if (kstrtol(buf, 10, &val) != 0)
return count;
mutex_lock(&data->lock);
@@ -147,7 +147,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
struct virtual_consumer_data *data = dev_get_drvdata(dev);
long val;
- if (strict_strtol(buf, 10, &val) != 0)
+ if (kstrtol(buf, 10, &val) != 0)
return count;
mutex_lock(&data->lock);
@@ -173,7 +173,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
struct virtual_consumer_data *data = dev_get_drvdata(dev);
long val;
- if (strict_strtol(buf, 10, &val) != 0)
+ if (kstrtol(buf, 10, &val) != 0)
return count;
mutex_lock(&data->lock);
@@ -199,7 +199,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
struct virtual_consumer_data *data = dev_get_drvdata(dev);
long val;
- if (strict_strtol(buf, 10, &val) != 0)
+ if (kstrtol(buf, 10, &val) != 0)
return count;
mutex_lock(&data->lock);
@@ -291,18 +291,19 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev)
struct virtual_consumer_data *drvdata;
int ret;
- drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct virtual_consumer_data),
+ GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
mutex_init(&drvdata->lock);
- drvdata->regulator = regulator_get(&pdev->dev, reg_id);
+ drvdata->regulator = devm_regulator_get(&pdev->dev, reg_id);
if (IS_ERR(drvdata->regulator)) {
ret = PTR_ERR(drvdata->regulator);
dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n",
reg_id, ret);
- goto err;
+ return ret;
}
ret = sysfs_create_group(&pdev->dev.kobj,
@@ -310,7 +311,7 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev,
"Failed to create attribute group: %d\n", ret);
- goto err_regulator;
+ return ret;
}
drvdata->mode = regulator_get_mode(drvdata->regulator);
@@ -318,12 +319,6 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drvdata);
return 0;
-
-err_regulator:
- regulator_put(drvdata->regulator);
-err:
- kfree(drvdata);
- return ret;
}
static int __devexit regulator_virtual_remove(struct platform_device *pdev)
@@ -334,9 +329,6 @@ static int __devexit regulator_virtual_remove(struct platform_device *pdev)
if (drvdata->enabled)
regulator_disable(drvdata->regulator);
- regulator_put(drvdata->regulator);
-
- kfree(drvdata);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index ff810e7..a885911 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -35,7 +35,7 @@
#define WM831X_DCDC_MODE_IDLE 2
#define WM831X_DCDC_MODE_STANDBY 3
-#define WM831X_DCDC_MAX_NAME 6
+#define WM831X_DCDC_MAX_NAME 9
/* Register offsets in control block */
#define WM831X_DCDC_CONTROL_1 0
@@ -50,6 +50,7 @@
struct wm831x_dcdc {
char name[WM831X_DCDC_MAX_NAME];
+ char supply_name[WM831X_DCDC_MAX_NAME];
struct regulator_desc desc;
int base;
struct wm831x *wm831x;
@@ -60,41 +61,6 @@ struct wm831x_dcdc {
int dvs_vsel;
};
-static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- int mask = 1 << rdev_get_id(rdev);
- int reg;
-
- reg = wm831x_reg_read(wm831x, WM831X_DCDC_ENABLE);
- if (reg < 0)
- return reg;
-
- if (reg & mask)
- return 1;
- else
- return 0;
-}
-
-static int wm831x_dcdc_enable(struct regulator_dev *rdev)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- int mask = 1 << rdev_get_id(rdev);
-
- return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, mask);
-}
-
-static int wm831x_dcdc_disable(struct regulator_dev *rdev)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- int mask = 1 << rdev_get_id(rdev);
-
- return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, 0);
-}
-
static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev)
{
@@ -414,9 +380,9 @@ static struct regulator_ops wm831x_buckv_ops = {
.set_current_limit = wm831x_buckv_set_current_limit,
.get_current_limit = wm831x_buckv_get_current_limit,
- .is_enabled = wm831x_dcdc_is_enabled,
- .enable = wm831x_dcdc_enable,
- .disable = wm831x_dcdc_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_status = wm831x_dcdc_get_status,
.get_mode = wm831x_dcdc_get_mode,
.set_mode = wm831x_dcdc_set_mode,
@@ -437,23 +403,17 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
if (!pdata || !pdata->dvs_gpio)
return;
- ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
- if (ret < 0) {
- dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
- dcdc->name, ret);
- return;
- }
-
/* gpiolib won't let us read the GPIO status so pick the higher
* of the two existing voltages so we take it as platform data.
*/
dcdc->dvs_gpio_state = pdata->dvs_init_state;
- ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state);
+ ret = gpio_request_one(pdata->dvs_gpio,
+ dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0,
+ "DCDC DVS");
if (ret < 0) {
- dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n",
+ dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
dcdc->name, ret);
- gpio_free(pdata->dvs_gpio);
return;
}
@@ -498,6 +458,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id;
struct wm831x_dcdc *dcdc;
struct resource *res;
@@ -511,9 +472,6 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
- if (pdata == NULL || pdata->dcdc[id] == NULL)
- return -ENODEV;
-
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
if (dcdc == NULL) {
@@ -533,11 +491,18 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
dcdc->desc.name = dcdc->name;
+
+ snprintf(dcdc->supply_name, sizeof(dcdc->supply_name),
+ "DC%dVDD", id + 1);
+ dcdc->desc.supply_name = dcdc->supply_name;
+
dcdc->desc.id = id;
dcdc->desc.type = REGULATOR_VOLTAGE;
dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1;
dcdc->desc.ops = &wm831x_buckv_ops;
dcdc->desc.owner = THIS_MODULE;
+ dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
+ dcdc->desc.enable_mask = 1 << id;
ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
if (ret < 0) {
@@ -553,11 +518,16 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
}
dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
- if (pdata->dcdc[id])
+ if (pdata && pdata->dcdc[id])
wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
- dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc, NULL);
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->dcdc[id];
+ config.driver_data = dcdc;
+ config.regmap = wm831x->regmap;
+
+ dcdc->regulator = regulator_register(&dcdc->desc, &config);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -675,29 +645,15 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
- int val;
-
- val = wm831x_reg_read(wm831x, reg);
- if (val < 0)
- return val;
-
- return val & WM831X_DC3_ON_VSEL_MASK;
-}
-
static struct regulator_ops wm831x_buckp_ops = {
.set_voltage = wm831x_buckp_set_voltage,
- .get_voltage_sel = wm831x_buckp_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = wm831x_buckp_list_voltage,
.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
- .is_enabled = wm831x_dcdc_is_enabled,
- .enable = wm831x_dcdc_enable,
- .disable = wm831x_dcdc_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_status = wm831x_dcdc_get_status,
.get_mode = wm831x_dcdc_get_mode,
.set_mode = wm831x_dcdc_set_mode,
@@ -708,6 +664,7 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id;
struct wm831x_dcdc *dcdc;
struct resource *res;
@@ -721,9 +678,6 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
- if (pdata == NULL || pdata->dcdc[id] == NULL)
- return -ENODEV;
-
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
if (dcdc == NULL) {
@@ -743,14 +697,28 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
dcdc->desc.name = dcdc->name;
+
+ snprintf(dcdc->supply_name, sizeof(dcdc->supply_name),
+ "DC%dVDD", id + 1);
+ dcdc->desc.supply_name = dcdc->supply_name;
+
dcdc->desc.id = id;
dcdc->desc.type = REGULATOR_VOLTAGE;
dcdc->desc.n_voltages = WM831X_BUCKP_MAX_SELECTOR + 1;
dcdc->desc.ops = &wm831x_buckp_ops;
dcdc->desc.owner = THIS_MODULE;
-
- dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc, NULL);
+ dcdc->desc.vsel_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+ dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK;
+ dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
+ dcdc->desc.enable_mask = 1 << id;
+
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->dcdc[id];
+ config.driver_data = dcdc;
+ config.regmap = wm831x->regmap;
+
+ dcdc->regulator = regulator_register(&dcdc->desc, &config);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -832,15 +800,16 @@ static int wm831x_boostp_get_status(struct regulator_dev *rdev)
static struct regulator_ops wm831x_boostp_ops = {
.get_status = wm831x_boostp_get_status,
- .is_enabled = wm831x_dcdc_is_enabled,
- .enable = wm831x_dcdc_enable,
- .disable = wm831x_dcdc_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
struct wm831x_dcdc *dcdc;
struct resource *res;
@@ -851,7 +820,7 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
if (pdata == NULL || pdata->dcdc[id] == NULL)
return -ENODEV;
- dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL);
+ dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
if (dcdc == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
return -ENOMEM;
@@ -873,9 +842,16 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
dcdc->desc.type = REGULATOR_VOLTAGE;
dcdc->desc.ops = &wm831x_boostp_ops;
dcdc->desc.owner = THIS_MODULE;
+ dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
+ dcdc->desc.enable_mask = 1 << id;
- dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc, NULL);
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->dcdc[id];
+ config.driver_data = dcdc;
+ config.regmap = wm831x->regmap;
+
+ dcdc->regulator = regulator_register(&dcdc->desc, &config);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -900,7 +876,6 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
err_regulator:
regulator_unregister(dcdc->regulator);
err:
- kfree(dcdc);
return ret;
}
@@ -912,7 +887,6 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev)
free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
- kfree(dcdc);
return 0;
}
@@ -936,9 +910,9 @@ static struct platform_driver wm831x_boostp_driver = {
#define WM831X_EPE_BASE 6
static struct regulator_ops wm831x_epe_ops = {
- .is_enabled = wm831x_dcdc_is_enabled,
- .enable = wm831x_dcdc_enable,
- .disable = wm831x_dcdc_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_status = wm831x_dcdc_get_status,
};
@@ -946,16 +920,14 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id = pdev->id % ARRAY_SIZE(pdata->epe);
struct wm831x_dcdc *dcdc;
int ret;
dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);
- if (pdata == NULL || pdata->epe[id] == NULL)
- return -ENODEV;
-
- dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL);
+ dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
if (dcdc == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
return -ENOMEM;
@@ -972,9 +944,16 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev)
dcdc->desc.ops = &wm831x_epe_ops;
dcdc->desc.type = REGULATOR_VOLTAGE;
dcdc->desc.owner = THIS_MODULE;
+ dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
+ dcdc->desc.enable_mask = 1 << dcdc->desc.id;
+
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->epe[id];
+ config.driver_data = dcdc;
+ config.regmap = wm831x->regmap;
- dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->epe[id], dcdc, NULL);
+ dcdc->regulator = regulator_register(&dcdc->desc, &config);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register EPE%d: %d\n",
@@ -987,7 +966,6 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev)
return 0;
err:
- kfree(dcdc);
return ret;
}
@@ -996,9 +974,7 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
-
regulator_unregister(dcdc->regulator);
- kfree(dcdc);
return 0;
}
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index b414e09..b50ab77 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -154,6 +154,7 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev)
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
struct wm831x_isink *isink;
int id = pdev->id % ARRAY_SIZE(pdata->isink);
+ struct regulator_config config = { };
struct resource *res;
int ret, irq;
@@ -189,8 +190,11 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev)
isink->desc.type = REGULATOR_CURRENT;
isink->desc.owner = THIS_MODULE;
- isink->regulator = regulator_register(&isink->desc, &pdev->dev,
- pdata->isink[id], isink, NULL);
+ config.dev = pdev->dev.parent;
+ config.init_data = pdata->isink[id];
+ config.driver_data = isink;
+
+ isink->regulator = regulator_register(&isink->desc, &config);
if (IS_ERR(isink->regulator)) {
ret = PTR_ERR(isink->regulator);
dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n",
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 641e9f6..aa1f8b3 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -25,7 +25,7 @@
#include <linux/mfd/wm831x/regulator.h>
#include <linux/mfd/wm831x/pdata.h>
-#define WM831X_LDO_MAX_NAME 6
+#define WM831X_LDO_MAX_NAME 9
#define WM831X_LDO_CONTROL 0
#define WM831X_LDO_ON_CONTROL 1
@@ -36,6 +36,7 @@
struct wm831x_ldo {
char name[WM831X_LDO_MAX_NAME];
+ char supply_name[WM831X_LDO_MAX_NAME];
struct regulator_desc desc;
int base;
struct wm831x *wm831x;
@@ -46,41 +47,6 @@ struct wm831x_ldo {
* Shared
*/
-static int wm831x_ldo_is_enabled(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int mask = 1 << rdev_get_id(rdev);
- int reg;
-
- reg = wm831x_reg_read(wm831x, WM831X_LDO_ENABLE);
- if (reg < 0)
- return reg;
-
- if (reg & mask)
- return 1;
- else
- return 0;
-}
-
-static int wm831x_ldo_enable(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int mask = 1 << rdev_get_id(rdev);
-
- return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, mask);
-}
-
-static int wm831x_ldo_disable(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int mask = 1 << rdev_get_id(rdev);
-
- return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, 0);
-}
-
static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
{
struct wm831x_ldo *ldo = data;
@@ -105,7 +71,7 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
/* 0.9-1.6V in 50mV steps */
if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
return 900000 + (selector * 50000);
- /* 1.7-3.3V in 50mV steps */
+ /* 1.7-3.3V in 100mV steps */
if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
* 100000);
@@ -160,22 +126,6 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int reg = ldo->base + WM831X_LDO_ON_CONTROL;
- int ret;
-
- ret = wm831x_reg_read(wm831x, reg);
- if (ret < 0)
- return ret;
-
- ret &= WM831X_LDO1_ON_VSEL_MASK;
-
- return ret;
-}
-
static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
@@ -293,7 +243,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
static struct regulator_ops wm831x_gp_ldo_ops = {
.list_voltage = wm831x_gp_ldo_list_voltage,
- .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage = wm831x_gp_ldo_set_voltage,
.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
.get_mode = wm831x_gp_ldo_get_mode,
@@ -301,15 +251,16 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
.get_status = wm831x_gp_ldo_get_status,
.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
- .is_enabled = wm831x_ldo_is_enabled,
- .enable = wm831x_ldo_enable,
- .disable = wm831x_ldo_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
struct resource *res;
@@ -323,9 +274,6 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
- if (pdata == NULL || pdata->ldo[id] == NULL)
- return -ENODEV;
-
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
if (ldo == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
@@ -344,14 +292,28 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
ldo->desc.name = ldo->name;
+
+ snprintf(ldo->supply_name, sizeof(ldo->supply_name),
+ "LDO%dVDD", id + 1);
+ ldo->desc.supply_name = ldo->supply_name;
+
ldo->desc.id = id;
ldo->desc.type = REGULATOR_VOLTAGE;
ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
ldo->desc.ops = &wm831x_gp_ldo_ops;
ldo->desc.owner = THIS_MODULE;
-
- ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo, NULL);
+ ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+ ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
+ ldo->desc.enable_reg = WM831X_LDO_ENABLE;
+ ldo->desc.enable_mask = 1 << id;
+
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->ldo[id];
+ config.driver_data = ldo;
+ config.regmap = wm831x->regmap;
+
+ ldo->regulator = regulator_register(&ldo->desc, &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -414,7 +376,7 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
/* 1-1.6V in 50mV steps */
if (selector <= WM831X_ALDO_SELECTOR_LOW)
return 1000000 + (selector * 50000);
- /* 1.7-3.5V in 50mV steps */
+ /* 1.7-3.5V in 100mV steps */
if (selector <= WM831X_ALDO_MAX_SELECTOR)
return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
* 100000);
@@ -468,22 +430,6 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int reg = ldo->base + WM831X_LDO_ON_CONTROL;
- int ret;
-
- ret = wm831x_reg_read(wm831x, reg);
- if (ret < 0)
- return ret;
-
- ret &= WM831X_LDO7_ON_VSEL_MASK;
-
- return ret;
-}
-
static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
@@ -559,22 +505,23 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
static struct regulator_ops wm831x_aldo_ops = {
.list_voltage = wm831x_aldo_list_voltage,
- .get_voltage_sel = wm831x_aldo_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage = wm831x_aldo_set_voltage,
.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
.get_mode = wm831x_aldo_get_mode,
.set_mode = wm831x_aldo_set_mode,
.get_status = wm831x_aldo_get_status,
- .is_enabled = wm831x_ldo_is_enabled,
- .enable = wm831x_ldo_enable,
- .disable = wm831x_ldo_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
struct resource *res;
@@ -588,9 +535,6 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
- if (pdata == NULL || pdata->ldo[id] == NULL)
- return -ENODEV;
-
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
if (ldo == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
@@ -609,14 +553,28 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
ldo->desc.name = ldo->name;
+
+ snprintf(ldo->supply_name, sizeof(ldo->supply_name),
+ "LDO%dVDD", id + 1);
+ ldo->desc.supply_name = ldo->supply_name;
+
ldo->desc.id = id;
ldo->desc.type = REGULATOR_VOLTAGE;
ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
ldo->desc.ops = &wm831x_aldo_ops;
ldo->desc.owner = THIS_MODULE;
-
- ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo, NULL);
+ ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+ ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
+ ldo->desc.enable_reg = WM831X_LDO_ENABLE;
+ ldo->desc.enable_mask = 1 << id;
+
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->ldo[id];
+ config.driver_data = ldo;
+ config.regmap = wm831x->regmap;
+
+ ldo->regulator = regulator_register(&ldo->desc, &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -668,15 +626,6 @@ static struct platform_driver wm831x_aldo_driver = {
#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
-static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- /* 0.8-1.55V in 50mV steps */
- if (selector <= WM831X_ALIVE_LDO_MAX_SELECTOR)
- return 800000 + (selector * 50000);
- return -EINVAL;
-}
-
static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
int reg,
int min_uV, int max_uV,
@@ -688,7 +637,7 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
vsel = (min_uV - 800000) / 50000;
- ret = wm831x_alive_ldo_list_voltage(rdev, vsel);
+ ret = regulator_list_voltage_linear(rdev, vsel);
if (ret < 0)
return ret;
if (ret < min_uV || ret > max_uV)
@@ -720,22 +669,6 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
- int ret;
-
- ret = wm831x_reg_read(wm831x, reg);
- if (ret < 0)
- return ret;
-
- ret &= WM831X_LDO11_ON_VSEL_MASK;
-
- return ret;
-}
-
static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
@@ -754,21 +687,22 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
}
static struct regulator_ops wm831x_alive_ldo_ops = {
- .list_voltage = wm831x_alive_ldo_list_voltage,
- .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage = wm831x_alive_ldo_set_voltage,
.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
.get_status = wm831x_alive_ldo_get_status,
- .is_enabled = wm831x_ldo_is_enabled,
- .enable = wm831x_ldo_enable,
- .disable = wm831x_ldo_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
};
static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
struct resource *res;
@@ -783,9 +717,6 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
- if (pdata == NULL || pdata->ldo[id] == NULL)
- return -ENODEV;
-
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
if (ldo == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
@@ -804,14 +735,30 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
ldo->desc.name = ldo->name;
+
+ snprintf(ldo->supply_name, sizeof(ldo->supply_name),
+ "LDO%dVDD", id + 1);
+ ldo->desc.supply_name = ldo->supply_name;
+
ldo->desc.id = id;
ldo->desc.type = REGULATOR_VOLTAGE;
ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
ldo->desc.ops = &wm831x_alive_ldo_ops;
ldo->desc.owner = THIS_MODULE;
-
- ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo, NULL);
+ ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
+ ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK;
+ ldo->desc.enable_reg = WM831X_LDO_ENABLE;
+ ldo->desc.enable_mask = 1 << id;
+ ldo->desc.min_uV = 800000;
+ ldo->desc.uV_step = 50000;
+
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ config.init_data = pdata->ldo[id];
+ config.driver_data = ldo;
+ config.regmap = wm831x->regmap;
+
+ ldo->regulator = regulator_register(&ldo->desc, &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 05ecfb8..94e550d 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1269,7 +1269,7 @@ static struct regulator_ops wm8350_isink_ops = {
.enable_time = wm8350_isink_enable_time,
};
-static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
{
.name = "DCDC1",
.id = WM8350_DCDC_1,
@@ -1398,6 +1398,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data)
static int wm8350_regulator_probe(struct platform_device *pdev)
{
struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+ struct regulator_config config = { };
struct regulator_dev *rdev;
int ret;
u16 val;
@@ -1425,10 +1426,12 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
break;
}
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = dev_get_drvdata(&pdev->dev);
+
/* register regulator */
- rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
- pdev->dev.platform_data,
- dev_get_drvdata(&pdev->dev), NULL);
+ rdev = regulator_register(&wm8350_reg[pdev->id], &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n",
wm8350_reg[pdev->id].name);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 8477153..69a2b7c 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -19,31 +19,6 @@
#include <linux/regulator/driver.h>
#include <linux/mfd/wm8400-private.h>
-static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- u16 val;
-
- val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
- return (val & WM8400_LDO1_ENA) != 0;
-}
-
-static int wm8400_ldo_enable(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
-
- return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
- WM8400_LDO1_ENA, WM8400_LDO1_ENA);
-}
-
-static int wm8400_ldo_disable(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
-
- return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
- WM8400_LDO1_ENA, 0);
-}
-
static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
@@ -56,21 +31,9 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
return 1600000 + ((selector - 14) * 100000);
}
-static int wm8400_ldo_get_voltage_sel(struct regulator_dev *dev)
+static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- u16 val;
-
- val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
- val &= WM8400_LDO1_VSEL_MASK;
-
- return val;
-}
-
-static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
u16 val;
if (min_uV < 900000 || min_uV > 3300000)
@@ -94,92 +57,19 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
val += 0xf;
}
- *selector = val;
-
- return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
- WM8400_LDO1_VSEL_MASK, val);
+ return val;
}
static struct regulator_ops wm8400_ldo_ops = {
- .is_enabled = wm8400_ldo_is_enabled,
- .enable = wm8400_ldo_enable,
- .disable = wm8400_ldo_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.list_voltage = wm8400_ldo_list_voltage,
- .get_voltage_sel = wm8400_ldo_get_voltage_sel,
- .set_voltage = wm8400_ldo_set_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .map_voltage = wm8400_ldo_map_voltage,
};
-static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
- u16 val;
-
- val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
- return (val & WM8400_DC1_ENA) != 0;
-}
-
-static int wm8400_dcdc_enable(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
-
- return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
- WM8400_DC1_ENA, WM8400_DC1_ENA);
-}
-
-static int wm8400_dcdc_disable(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
-
- return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
- WM8400_DC1_ENA, 0);
-}
-
-static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- if (selector > WM8400_DC1_VSEL_MASK)
- return -EINVAL;
-
- return 850000 + (selector * 25000);
-}
-
-static int wm8400_dcdc_get_voltage_sel(struct regulator_dev *dev)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- u16 val;
- int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
-
- val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
- val &= WM8400_DC1_VSEL_MASK;
-
- return val;
-}
-
-static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct wm8400 *wm8400 = rdev_get_drvdata(dev);
- u16 val;
- int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
-
- if (min_uV < 850000)
- return -EINVAL;
-
- val = DIV_ROUND_UP(min_uV - 850000, 25000);
-
- if (850000 + (25000 * val) > max_uV)
- return -EINVAL;
- BUG_ON(850000 + (25000 * val) < min_uV);
-
- *selector = val;
-
- return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
- WM8400_DC1_VSEL_MASK, val);
-}
-
static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
@@ -258,12 +148,12 @@ static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
}
static struct regulator_ops wm8400_dcdc_ops = {
- .is_enabled = wm8400_dcdc_is_enabled,
- .enable = wm8400_dcdc_enable,
- .disable = wm8400_dcdc_disable,
- .list_voltage = wm8400_dcdc_list_voltage,
- .get_voltage_sel = wm8400_dcdc_get_voltage_sel,
- .set_voltage = wm8400_dcdc_set_voltage,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_mode = wm8400_dcdc_get_mode,
.set_mode = wm8400_dcdc_set_mode,
.get_optimum_mode = wm8400_dcdc_get_optimum_mode,
@@ -274,7 +164,11 @@ static struct regulator_desc regulators[] = {
.name = "LDO1",
.id = WM8400_LDO1,
.ops = &wm8400_ldo_ops,
+ .enable_reg = WM8400_LDO1_CONTROL,
+ .enable_mask = WM8400_LDO1_ENA,
.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
+ .vsel_reg = WM8400_LDO1_CONTROL,
+ .vsel_mask = WM8400_LDO1_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@@ -282,15 +176,23 @@ static struct regulator_desc regulators[] = {
.name = "LDO2",
.id = WM8400_LDO2,
.ops = &wm8400_ldo_ops,
+ .enable_reg = WM8400_LDO2_CONTROL,
+ .enable_mask = WM8400_LDO2_ENA,
.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
+ .vsel_reg = WM8400_LDO2_CONTROL,
+ .vsel_mask = WM8400_LDO2_VSEL_MASK,
.owner = THIS_MODULE,
},
{
.name = "LDO3",
.id = WM8400_LDO3,
.ops = &wm8400_ldo_ops,
+ .enable_reg = WM8400_LDO3_CONTROL,
+ .enable_mask = WM8400_LDO3_ENA,
.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
+ .vsel_reg = WM8400_LDO3_CONTROL,
+ .vsel_mask = WM8400_LDO3_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@@ -298,7 +200,11 @@ static struct regulator_desc regulators[] = {
.name = "LDO4",
.id = WM8400_LDO4,
.ops = &wm8400_ldo_ops,
+ .enable_reg = WM8400_LDO4_CONTROL,
+ .enable_mask = WM8400_LDO4_ENA,
.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
+ .vsel_reg = WM8400_LDO4_CONTROL,
+ .vsel_mask = WM8400_LDO4_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@@ -306,7 +212,13 @@ static struct regulator_desc regulators[] = {
.name = "DCDC1",
.id = WM8400_DCDC1,
.ops = &wm8400_dcdc_ops,
+ .enable_reg = WM8400_DCDC1_CONTROL_1,
+ .enable_mask = WM8400_DC1_ENA_MASK,
.n_voltages = WM8400_DC1_VSEL_MASK + 1,
+ .vsel_reg = WM8400_DCDC1_CONTROL_1,
+ .vsel_mask = WM8400_DC1_VSEL_MASK,
+ .min_uV = 850000,
+ .uV_step = 25000,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@@ -314,7 +226,13 @@ static struct regulator_desc regulators[] = {
.name = "DCDC2",
.id = WM8400_DCDC2,
.ops = &wm8400_dcdc_ops,
+ .enable_reg = WM8400_DCDC2_CONTROL_1,
+ .enable_mask = WM8400_DC1_ENA_MASK,
.n_voltages = WM8400_DC2_VSEL_MASK + 1,
+ .vsel_reg = WM8400_DCDC2_CONTROL_1,
+ .vsel_mask = WM8400_DC2_VSEL_MASK,
+ .min_uV = 850000,
+ .uV_step = 25000,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@@ -323,11 +241,15 @@ static struct regulator_desc regulators[] = {
static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
{
struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);
+ struct regulator_config config = { };
struct regulator_dev *rdev;
- rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, wm8400, NULL);
+ config.dev = &pdev->dev;
+ config.init_data = pdev->dev.platform_data;
+ config.driver_data = wm8400;
+ config.regmap = wm8400->regmap;
+ rdev = regulator_register(&regulators[pdev->id], &config);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 75ed402..9a99431 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -86,36 +86,6 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
return (selector * 100000) + 2400000;
}
-static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
- int val;
-
- val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1);
- if (val < 0)
- return val;
-
- return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
-}
-
-static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *s)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
- int selector, v;
-
- selector = (min_uV - 2400000) / 100000;
- v = wm8994_ldo1_list_voltage(rdev, selector);
- if (v < 0 || v > max_uV)
- return -EINVAL;
-
- *s = selector;
- selector <<= WM8994_LDO1_VSEL_SHIFT;
-
- return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1,
- WM8994_LDO1_VSEL_MASK, selector);
-}
-
static struct regulator_ops wm8994_ldo1_ops = {
.enable = wm8994_ldo_enable,
.disable = wm8994_ldo_disable,
@@ -123,8 +93,8 @@ static struct regulator_ops wm8994_ldo1_ops = {
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo1_list_voltage,
- .get_voltage_sel = wm8994_ldo1_get_voltage_sel,
- .set_voltage = wm8994_ldo1_set_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
};
static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
@@ -153,51 +123,6 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
}
}
-static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
- int val;
-
- val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2);
- if (val < 0)
- return val;
-
- return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
-}
-
-static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *s)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
- int selector, v;
-
- switch (ldo->wm8994->type) {
- case WM8994:
- selector = (min_uV - 900000) / 100000;
- break;
- case WM8958:
- selector = (min_uV - 1000000) / 100000;
- break;
- case WM1811:
- selector = (min_uV - 950000) / 100000;
- if (selector == 0)
- selector = 1;
- break;
- default:
- return -EINVAL;
- }
-
- v = wm8994_ldo2_list_voltage(rdev, selector);
- if (v < 0 || v > max_uV)
- return -EINVAL;
-
- *s = selector;
- selector <<= WM8994_LDO2_VSEL_SHIFT;
-
- return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
- WM8994_LDO2_VSEL_MASK, selector);
-}
-
static struct regulator_ops wm8994_ldo2_ops = {
.enable = wm8994_ldo_enable,
.disable = wm8994_ldo_disable,
@@ -205,16 +130,18 @@ static struct regulator_ops wm8994_ldo2_ops = {
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo2_list_voltage,
- .get_voltage_sel = wm8994_ldo2_get_voltage_sel,
- .set_voltage = wm8994_ldo2_set_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
};
-static struct regulator_desc wm8994_ldo_desc[] = {
+static const struct regulator_desc wm8994_ldo_desc[] = {
{
.name = "LDO1",
.id = 1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1,
+ .vsel_reg = WM8994_LDO_1,
+ .vsel_mask = WM8994_LDO1_VSEL_MASK,
.ops = &wm8994_ldo1_ops,
.owner = THIS_MODULE,
},
@@ -223,6 +150,8 @@ static struct regulator_desc wm8994_ldo_desc[] = {
.id = 2,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1,
+ .vsel_reg = WM8994_LDO_2,
+ .vsel_mask = WM8994_LDO2_VSEL_MASK,
.ops = &wm8994_ldo2_ops,
.owner = THIS_MODULE,
},
@@ -233,14 +162,12 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+ struct regulator_config config = { };
struct wm8994_ldo *ldo;
int ret;
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
- if (!pdata)
- return -ENODEV;
-
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
if (ldo == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
@@ -252,24 +179,22 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
ldo->enable = pdata->ldo[id].enable;
- ret = gpio_request(ldo->enable, "WM8994 LDO enable");
+ ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable");
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
ret);
goto err;
}
-
- ret = gpio_direction_output(ldo->enable, ldo->is_enabled);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to set GPIO up: %d\n",
- ret);
- goto err_gpio;
- }
} else
ldo->is_enabled = true;
- ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
- pdata->ldo[id].init_data, ldo, NULL);
+ config.dev = wm8994->dev;
+ config.driver_data = ldo;
+ config.regmap = wm8994->regmap;
+ if (pdata)
+ config.init_data = pdata->ldo[id].init_data;
+
+ ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index e756a0d..d6f8ada 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1105,8 +1105,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
goto out;
out:
- if (fw)
- release_firmware(fw);
+ release_firmware(fw);
/* allow rproc_unregister() contexts, if any, to proceed */
complete_all(&rproc->firmware_loading_complete);
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8c8377d..4161bfe 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -838,7 +838,7 @@ config RTC_DRV_AT32AP700X
config RTC_DRV_AT91RM9200
tristate "AT91RM9200 or some AT91SAM9 RTC"
- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Driver for the internal RTC (Realtime Clock) module found on
Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 684ef4b..f027c06 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -312,6 +312,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
int ret;
struct pl031_local *ldata;
struct rtc_class_ops *ops = id->data;
+ unsigned long time;
ret = amba_request_regions(adev, NULL);
if (ret)
@@ -343,6 +344,23 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
ldata->base + RTC_CR);
+ /*
+ * On ST PL031 variants, the RTC reset value does not provide correct
+ * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
+ */
+ if (ldata->hw_designer == AMBA_VENDOR_ST) {
+ if (readl(ldata->base + RTC_YDR) == 0x2000) {
+ time = readl(ldata->base + RTC_DR);
+ if ((time &
+ (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK))
+ == 0x02120000) {
+ time = time | (0x7 << RTC_WDAY_SHIFT);
+ writel(0x2000, ldata->base + RTC_YLR);
+ writel(time, ldata->base + RTC_LR);
+ }
+ }
+ }
+
ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 4f9f1dc..6c0116d 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/reboot.h>
+#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -44,14 +45,11 @@
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
#define RAW3215_FIXED 1 /* 3215 console device is not be freed */
-#define RAW3215_ACTIVE 2 /* set if the device is in use */
#define RAW3215_WORKING 4 /* set if a request is being worked on */
#define RAW3215_THROTTLED 8 /* set if reading is disabled */
#define RAW3215_STOPPED 16 /* set if writing is disabled */
-#define RAW3215_CLOSING 32 /* set while in close process */
#define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
-#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */
#define TAB_STOP_SIZE 8 /* tab stop size */
@@ -76,6 +74,7 @@ struct raw3215_req {
} __attribute__ ((aligned(8)));
struct raw3215_info {
+ struct tty_port port;
struct ccw_device *cdev; /* device for tty driver */
spinlock_t *lock; /* pointer to irq lock */
int flags; /* state flags */
@@ -84,7 +83,6 @@ struct raw3215_info {
int head; /* first free byte in output buffer */
int count; /* number of bytes in output buffer */
int written; /* number of bytes in write requests */
- struct tty_struct *tty; /* pointer to tty structure if present */
struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
if (raw->flags & RAW3215_TIMER_RUNS) {
del_timer(&raw->timer);
raw->flags &= ~RAW3215_TIMER_RUNS;
- if (!(raw->flags & RAW3215_FROZEN)) {
+ if (!(raw->port.flags & ASYNC_SUSPENDED)) {
raw3215_mk_write_req(raw);
raw3215_start_io(raw);
}
@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
*/
static inline void raw3215_try_io(struct raw3215_info *raw)
{
- if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
+ if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+ (raw->port.flags & ASYNC_SUSPENDED))
return;
if (raw->queued_read != NULL)
raw3215_start_io(raw);
@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
}
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
/* delay small writes */
- init_timer(&raw->timer);
raw->timer.expires = RAW3215_TIMEOUT + jiffies;
- raw->timer.data = (unsigned long) raw;
- raw->timer.function = raw3215_timeout;
add_timer(&raw->timer);
raw->flags |= RAW3215_TIMER_RUNS;
}
@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
static void raw3215_wakeup(unsigned long data)
{
struct raw3215_info *raw = (struct raw3215_info *) data;
- tty_wakeup(raw->tty);
+ struct tty_struct *tty;
+
+ tty = tty_port_tty_get(&raw->port);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
/*
* Try to start the next IO and wake up processes waiting on the tty.
*/
-static void raw3215_next_io(struct raw3215_info *raw)
+static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
{
raw3215_mk_write_req(raw);
raw3215_try_io(raw);
- if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
+ if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
tasklet_schedule(&raw->tlet);
}
@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw = dev_get_drvdata(&cdev->dev);
req = (struct raw3215_req *) intparm;
+ tty = tty_port_tty_get(&raw->port);
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
if (cstat != 0)
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
if (dstat & 0x01) { /* we got a unit exception */
dstat &= ~0x01; /* we can ignore it */
}
@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
break;
/* Attention interrupt, someone hit the enter key */
raw3215_mk_read_req(raw);
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
break;
case 0x08:
case 0x0C:
/* Channel end interrupt. */
if ((raw = req->info) == NULL)
- return; /* That shouldn't happen ... */
+ goto put_tty; /* That shouldn't happen ... */
if (req->type == RAW3215_READ) {
/* store residual count, then wait for device end */
req->residual = irb->scsw.cmd.count;
@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case 0x04:
/* Device end interrupt. */
if ((raw = req->info) == NULL)
- return; /* That shouldn't happen ... */
- if (req->type == RAW3215_READ && raw->tty != NULL) {
+ goto put_tty; /* That shouldn't happen ... */
+ if (req->type == RAW3215_READ && tty != NULL) {
unsigned int cchar;
- tty = raw->tty;
count = 160 - req->residual;
EBCASC(raw->inbuf, count);
cchar = ctrlchar_handle(raw->inbuf, count, tty);
@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case CTRLCHAR_CTRL:
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
- tty_flip_buffer_push(raw->tty);
+ tty_flip_buffer_push(tty);
break;
case CTRLCHAR_NONE:
@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
} else
count -= 2;
tty_insert_flip_string(tty, raw->inbuf, count);
- tty_flip_buffer_push(raw->tty);
+ tty_flip_buffer_push(tty);
break;
}
} else if (req->type == RAW3215_WRITE) {
@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->queued_read == NULL) {
wake_up_interruptible(&raw->empty_wait);
}
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
break;
default:
/* Strange interrupt, I'll do my best to clean up */
@@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
}
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
}
- return;
+put_tty:
+ tty_kref_put(tty);
}
/*
@@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
/* While console is frozen for suspend we have no other
* choice but to drop message from the buffer to make
* room for even more messages. */
- if (raw->flags & RAW3215_FROZEN) {
+ if (raw->port.flags & ASYNC_SUSPENDED) {
raw3215_drop_line(raw);
continue;
}
@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
{
unsigned long flags;
- if (raw->flags & RAW3215_ACTIVE)
+ if (raw->port.flags & ASYNC_INITIALIZED)
return 0;
raw->line_pos = 0;
- raw->flags |= RAW3215_ACTIVE;
+ raw->port.flags |= ASYNC_INITIALIZED;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
- if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
+ if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+ (raw->flags & RAW3215_FIXED))
return;
/* Wait for outstanding requests, then free irq */
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
if ((raw->flags & RAW3215_WORKING) ||
raw->queued_write != NULL ||
raw->queued_read != NULL) {
- raw->flags |= RAW3215_CLOSING;
+ raw->port.flags |= ASYNC_CLOSING;
add_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
- raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
+ raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
+static struct raw3215_info *raw3215_alloc_info(void)
+{
+ struct raw3215_info *info;
+
+ info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
+ if (!info)
+ return NULL;
+
+ info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+ info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!info->buffer || !info->inbuf) {
+ kfree(info);
+ return NULL;
+ }
+
+ setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
+ init_waitqueue_head(&info->empty_wait);
+ tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
+ tty_port_init(&info->port);
+
+ return info;
+}
+
+static void raw3215_free_info(struct raw3215_info *raw)
+{
+ kfree(raw->inbuf);
+ kfree(raw->buffer);
+ kfree(raw);
+}
+
static int raw3215_probe (struct ccw_device *cdev)
{
struct raw3215_info *raw;
@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
/* Console is special. */
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
return 0;
- raw = kmalloc(sizeof(struct raw3215_info) +
- RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
+
+ raw = raw3215_alloc_info();
if (raw == NULL)
return -ENOMEM;
+ raw->cdev = cdev;
+ dev_set_drvdata(&cdev->dev, raw);
+ cdev->handler = raw3215_irq;
+
spin_lock(&raw3215_device_lock);
for (line = 0; line < NR_3215; line++) {
if (!raw3215[line]) {
@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
}
spin_unlock(&raw3215_device_lock);
if (line == NR_3215) {
- kfree(raw);
+ raw3215_free_info(raw);
return -ENODEV;
}
- raw->cdev = cdev;
- raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
- memset(raw, 0, sizeof(struct raw3215_info));
- raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
- GFP_KERNEL|GFP_DMA);
- if (raw->buffer == NULL) {
- spin_lock(&raw3215_device_lock);
- raw3215[line] = NULL;
- spin_unlock(&raw3215_device_lock);
- kfree(raw);
- return -ENOMEM;
- }
- init_waitqueue_head(&raw->empty_wait);
- tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
-
- dev_set_drvdata(&cdev->dev, raw);
- cdev->handler = raw3215_irq;
-
return 0;
}
@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
dev_set_drvdata(&cdev->dev, NULL);
- kfree(raw->buffer);
- kfree(raw);
+ raw3215_free_info(raw);
}
}
@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
- raw->flags |= RAW3215_FROZEN;
+ raw->port.flags |= ASYNC_SUSPENDED;
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
return 0;
}
@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
/* Allow I/O again and flush output buffer. */
raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- raw->flags &= ~RAW3215_FROZEN;
+ raw->port.flags &= ~ASYNC_SUSPENDED;
raw->flags |= RAW3215_FLUSHING;
raw3215_try_io(raw);
raw->flags &= ~RAW3215_FLUSHING;
@@ -827,7 +844,7 @@ static void con3215_flush(void)
unsigned long flags;
raw = raw3215[0]; /* console 3215 is the first one */
- if (raw->flags & RAW3215_FROZEN)
+ if (raw->port.flags & ASYNC_SUSPENDED)
/* The console is still frozen for suspend. */
if (ccw_device_force_console())
/* Forcing didn't work, no panic message .. */
@@ -897,23 +914,16 @@ static int __init con3215_init(void)
if (IS_ERR(cdev))
return -ENODEV;
- raw3215[0] = raw = (struct raw3215_info *)
- kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
- raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
- raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+ raw3215[0] = raw = raw3215_alloc_info();
raw->cdev = cdev;
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED;
- init_waitqueue_head(&raw->empty_wait);
- tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
- kfree(raw->inbuf);
- kfree(raw->buffer);
- kfree(raw);
+ raw3215_free_info(raw);
raw3215[0] = NULL;
return -ENODEV;
}
@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
return -ENODEV;
tty->driver_data = raw;
- raw->tty = tty;
+ tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */
/*
@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
raw3215_shutdown(raw);
tasklet_kill(&raw->tlet);
tty->closing = 0;
- raw->tty = NULL;
+ tty_port_tty_set(&raw->port, NULL);
}
/*
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 8065881..7ef9cfd 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
if (ch == ' ' || ch == d)
return d;
- kbd_put_queue(kbd->tty, d);
+ kbd_put_queue(kbd->port, d);
return ch;
}
@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
{
if (kbd->diacr)
value = handle_diacr(kbd, value);
- kbd_put_queue(kbd->tty, value);
+ kbd_put_queue(kbd->port, value);
}
/*
@@ -239,7 +239,7 @@ static void
k_fn(struct kbd_data *kbd, unsigned char value)
{
if (kbd->func_table[value])
- kbd_puts_queue(kbd->tty, kbd->func_table[value]);
+ kbd_puts_queue(kbd->port, kbd->func_table[value]);
}
static void
@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
* but we need only 16 bits here
*/
static void
-to_utf8(struct tty_struct *tty, ushort c)
+to_utf8(struct tty_port *port, ushort c)
{
if (c < 0x80)
/* 0******* */
- kbd_put_queue(tty, c);
+ kbd_put_queue(port, c);
else if (c < 0x800) {
/* 110***** 10****** */
- kbd_put_queue(tty, 0xc0 | (c >> 6));
- kbd_put_queue(tty, 0x80 | (c & 0x3f));
+ kbd_put_queue(port, 0xc0 | (c >> 6));
+ kbd_put_queue(port, 0x80 | (c & 0x3f));
} else {
/* 1110**** 10****** 10****** */
- kbd_put_queue(tty, 0xe0 | (c >> 12));
- kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
- kbd_put_queue(tty, 0x80 | (c & 0x3f));
+ kbd_put_queue(port, 0xe0 | (c >> 12));
+ kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
+ kbd_put_queue(port, 0x80 | (c & 0x3f));
}
}
@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
unsigned short keysym;
unsigned char type, value;
- if (!kbd || !kbd->tty)
+ if (!kbd)
return;
if (keycode >= 384)
@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
#endif
(*k_handler[type])(kbd, value);
} else
- to_utf8(kbd->tty, keysym);
+ to_utf8(kbd->port, keysym);
}
/*
@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
{
+ struct tty_struct *tty;
void __user *argp;
unsigned int ct;
int perm;
@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
* To have permissions to do most of the vt ioctls, we either have
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
*/
- perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+ tty = tty_port_tty_get(kbd->port);
+ /* FIXME this test is pretty racy */
+ perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
+ tty_kref_put(tty);
switch (cmd) {
case KDGKBTYPE:
return put_user(KB_101, (char __user *)argp);
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 7e736aa..f682f4e 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
*/
struct kbd_data {
- struct tty_struct *tty;
+ struct tty_port *port;
unsigned short **key_maps;
char **func_table;
fn_handler_fn **fn_handler;
@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
* Helper Functions.
*/
static inline void
-kbd_put_queue(struct tty_struct *tty, int ch)
+kbd_put_queue(struct tty_port *port, int ch)
{
+ struct tty_struct *tty = tty_port_tty_get(port);
+ if (!tty)
+ return;
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
static inline void
-kbd_puts_queue(struct tty_struct *tty, char *cp)
+kbd_puts_queue(struct tty_port *port, char *cp)
{
+ struct tty_struct *tty = tty_port_tty_get(port);
+ if (!tty)
+ return;
while (*cp)
tty_insert_flip_char(tty, *cp++, 0);
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 231a1d8..3650636 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -352,7 +352,17 @@ out:
static int sclp_assign_storage(u16 rn)
{
- return do_assign_storage(0x000d0001, rn);
+ unsigned long long start, address;
+ int rc;
+
+ rc = do_assign_storage(0x000d0001, rn);
+ if (rc)
+ goto out;
+ start = address = rn2addr(rn);
+ for (; address < start + rzm; address += PAGE_SIZE)
+ page_set_storage_key(address, PAGE_DEFAULT_KEY, 0);
+out:
+ return rc;
}
static int sclp_unassign_storage(u16 rn)
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 40a9d69..e66a75b 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
/* Timer for delayed output of console messages. */
static struct timer_list sclp_tty_timer;
-static struct tty_struct *sclp_tty;
+static struct tty_port sclp_port;
static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
static unsigned short int sclp_tty_chars_count;
@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
static int
sclp_tty_open(struct tty_struct *tty, struct file *filp)
{
- sclp_tty = tty;
+ tty_port_tty_set(&sclp_port, tty);
tty->driver_data = NULL;
tty->low_latency = 0;
return 0;
@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
{
if (tty->count > 1)
return;
- sclp_tty = NULL;
+ tty_port_tty_set(&sclp_port, NULL);
}
/*
@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{
+ struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
/* check if the tty needs a wake up call */
- if (sclp_tty != NULL) {
- tty_wakeup(sclp_tty);
+ tty = tty_port_tty_get(&sclp_port);
+ if (tty != NULL) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
}
@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
static void
sclp_tty_input(unsigned char* buf, unsigned int count)
{
+ struct tty_struct *tty = tty_port_tty_get(&sclp_port);
unsigned int cchar;
/*
* If this tty driver is currently closed
* then throw the received input away.
*/
- if (sclp_tty == NULL)
+ if (tty == NULL)
return;
- cchar = ctrlchar_handle(buf, count, sclp_tty);
+ cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
break;
case CTRLCHAR_CTRL:
- tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
- tty_flip_buffer_push(sclp_tty);
+ tty_insert_flip_char(tty, cchar, TTY_NORMAL);
+ tty_flip_buffer_push(tty);
break;
case CTRLCHAR_NONE:
/* send (normal) input to line discipline */
@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
(strncmp((const char *) buf + count - 2, "^n", 2) &&
strncmp((const char *) buf + count - 2, "\252n", 2))) {
/* add the auto \n */
- tty_insert_flip_string(sclp_tty, buf, count);
- tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
+ tty_insert_flip_string(tty, buf, count);
+ tty_insert_flip_char(tty, '\n', TTY_NORMAL);
} else
- tty_insert_flip_string(sclp_tty, buf, count - 2);
- tty_flip_buffer_push(sclp_tty);
+ tty_insert_flip_string(tty, buf, count - 2);
+ tty_flip_buffer_push(tty);
break;
}
+ tty_kref_put(tty);
}
/*
@@ -543,7 +548,7 @@ sclp_tty_init(void)
sclp_tty_tolower = 1;
}
sclp_tty_chars_count = 0;
- sclp_tty = NULL;
+ tty_port_init(&sclp_port);
rc = sclp_register(&sclp_input_event);
if (rc) {
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index b635472..edfc0fd 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -34,7 +34,6 @@
#define SCLP_VT220_DEVICE_NAME "ttysclp"
#define SCLP_VT220_CONSOLE_NAME "ttyS"
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
-#define SCLP_VT220_BUF_SIZE 80
/* Representation of a single write request */
struct sclp_vt220_request {
@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
/* Structures and data needed to register tty driver */
static struct tty_driver *sclp_vt220_driver;
-/* The tty_struct that the kernel associated with us */
-static struct tty_struct *sclp_vt220_tty;
+static struct tty_port sclp_vt220_port;
/* Lock to protect internal data from concurrent access */
static spinlock_t sclp_vt220_lock;
@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
static void
sclp_vt220_process_queue(struct sclp_vt220_request *request)
{
+ struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
/* Check if the tty needs a wake up call */
- if (sclp_vt220_tty != NULL) {
- tty_wakeup(sclp_vt220_tty);
+ tty = tty_port_tty_get(&sclp_vt220_port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
}
@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
{
+ struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
char *buffer;
unsigned int count;
/* Ignore input if device is not open */
- if (sclp_vt220_tty == NULL)
+ if (tty == NULL)
return;
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
/* Send input to line discipline */
buffer++;
count--;
- tty_insert_flip_string(sclp_vt220_tty, buffer, count);
- tty_flip_buffer_push(sclp_vt220_tty);
+ tty_insert_flip_string(tty, buffer, count);
+ tty_flip_buffer_push(tty);
break;
}
+ tty_kref_put(tty);
}
/*
@@ -491,10 +494,7 @@ static int
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{
if (tty->count == 1) {
- sclp_vt220_tty = tty;
- tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
- if (tty->driver_data == NULL)
- return -ENOMEM;
+ tty_port_tty_set(&sclp_vt220_port, tty);
tty->low_latency = 0;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = 24;
@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
static void
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
{
- if (tty->count == 1) {
- sclp_vt220_tty = NULL;
- kfree(tty->driver_data);
- tty->driver_data = NULL;
- }
+ if (tty->count == 1)
+ tty_port_tty_set(&sclp_vt220_port, NULL);
}
/*
@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue);
init_timer(&sclp_vt220_timer);
+ tty_port_init(&sclp_vt220_port);
sclp_vt220_current_request = NULL;
sclp_vt220_buffered_chars = 0;
- sclp_vt220_tty = NULL;
sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 267b54e..bc6c7cf 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -154,12 +154,6 @@ struct tape_discipline {
struct tape_request *(*read_block)(struct tape_device *, size_t);
struct tape_request *(*write_block)(struct tape_device *, size_t);
void (*process_eov)(struct tape_device*);
-#ifdef CONFIG_S390_TAPE_BLOCK
- /* Block device stuff. */
- struct tape_request *(*bread)(struct tape_device *, struct request *);
- void (*check_locate)(struct tape_device *, struct tape_request *);
- void (*free_bread)(struct tape_request *);
-#endif
/* ioctl function for additional ioctls. */
int (*ioctl_fn)(struct tape_device *, unsigned int, unsigned long);
/* Array of tape commands with TAPE_NR_MTOPS entries */
@@ -182,26 +176,6 @@ struct tape_char_data {
int block_size; /* of size block_size. */
};
-#ifdef CONFIG_S390_TAPE_BLOCK
-/* Block Frontend Data */
-struct tape_blk_data
-{
- struct tape_device * device;
- /* Block device request queue. */
- struct request_queue * request_queue;
- spinlock_t request_queue_lock;
-
- /* Task to move entries from block request to CCS request queue. */
- struct work_struct requeue_task;
- atomic_t requeue_scheduled;
-
- /* Current position on the tape. */
- long block_position;
- int medium_changed;
- struct gendisk * disk;
-};
-#endif
-
/* Tape Info */
struct tape_device {
/* entry in tape_device_list */
@@ -248,10 +222,6 @@ struct tape_device {
/* Character device frontend data */
struct tape_char_data char_data;
-#ifdef CONFIG_S390_TAPE_BLOCK
- /* Block dev frontend data */
- struct tape_blk_data blk_data;
-#endif
/* Function to start or stop the next request later. */
struct delayed_work tape_dnr;
@@ -313,19 +283,6 @@ extern void tapechar_exit(void);
extern int tapechar_setup_device(struct tape_device *);
extern void tapechar_cleanup_device(struct tape_device *);
-/* Externals from tape_block.c */
-#ifdef CONFIG_S390_TAPE_BLOCK
-extern int tapeblock_init (void);
-extern void tapeblock_exit(void);
-extern int tapeblock_setup_device(struct tape_device *);
-extern void tapeblock_cleanup_device(struct tape_device *);
-#else
-static inline int tapeblock_init (void) {return 0;}
-static inline void tapeblock_exit (void) {;}
-static inline int tapeblock_setup_device(struct tape_device *t) {return 0;}
-static inline void tapeblock_cleanup_device (struct tape_device *t) {;}
-#endif
-
/* tape initialisation functions */
#ifdef CONFIG_PROC_FS
extern void tape_proc_init (void);
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 934ef33..b28de80 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -323,20 +323,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
inhibit_cu_recovery = (*device->modeset_byte & 0x80) ? 1 : 0;
sense = irb->ecw;
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK) {
- /*
- * Recovery for block device requests. Set the block_position
- * to something invalid and retry.
- */
- device->blk_data.block_position = -1;
- if (request->retries-- <= 0)
- return tape_34xx_erp_failed(request, -EIO);
- else
- return tape_34xx_erp_retry(request);
- }
-#endif
-
if (
sense[0] & SENSE_COMMAND_REJECT &&
sense[1] & SENSE_WRITE_PROTECT
@@ -1129,123 +1115,6 @@ tape_34xx_mtseek(struct tape_device *device, int mt_count)
return tape_do_io_free(device, request);
}
-#ifdef CONFIG_S390_TAPE_BLOCK
-/*
- * Tape block read for 34xx.
- */
-static struct tape_request *
-tape_34xx_bread(struct tape_device *device, struct request *req)
-{
- struct tape_request *request;
- struct ccw1 *ccw;
- int count = 0;
- unsigned off;
- char *dst;
- struct bio_vec *bv;
- struct req_iterator iter;
- struct tape_34xx_block_id * start_block;
-
- DBF_EVENT(6, "xBREDid:");
-
- /* Count the number of blocks for the request. */
- rq_for_each_segment(bv, req, iter)
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
-
- /* Allocate the ccw request. */
- request = tape_alloc_request(3+count+1, 8);
- if (IS_ERR(request))
- return request;
-
- /* Setup ccws. */
- request->op = TO_BLOCK;
- start_block = (struct tape_34xx_block_id *) request->cpdata;
- start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B;
- DBF_EVENT(6, "start_block = %i\n", start_block->block);
-
- ccw = request->cpaddr;
- ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte);
-
- /*
- * We always setup a nop after the mode set ccw. This slot is
- * used in tape_std_check_locate to insert a locate ccw if the
- * current tape position doesn't match the start block to be read.
- * The second nop will be filled with a read block id which is in
- * turn used by tape_34xx_free_bread to populate the segment bid
- * table.
- */
- ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
- ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
-
- rq_for_each_segment(bv, req, iter) {
- dst = kmap(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void*) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
- }
-
- ccw = tape_ccw_end(ccw, NOP, 0, NULL);
- DBF_EVENT(6, "xBREDccwg\n");
- return request;
-}
-
-static void
-tape_34xx_free_bread (struct tape_request *request)
-{
- struct ccw1* ccw;
-
- ccw = request->cpaddr;
- if ((ccw + 2)->cmd_code == READ_BLOCK_ID) {
- struct {
- struct tape_34xx_block_id cbid;
- struct tape_34xx_block_id dbid;
- } __attribute__ ((packed)) *rbi_data;
-
- rbi_data = request->cpdata;
-
- if (request->device)
- tape_34xx_add_sbid(request->device, rbi_data->cbid);
- }
-
- /* Last ccw is a nop and doesn't need clear_normalized_cda */
- for (; ccw->flags & CCW_FLAG_CC; ccw++)
- if (ccw->cmd_code == READ_FORWARD)
- clear_normalized_cda(ccw);
- tape_free_request(request);
-}
-
-/*
- * check_locate is called just before the tape request is passed to
- * the common io layer for execution. It has to check the current
- * tape position and insert a locate ccw if it doesn't match the
- * start block for the request.
- */
-static void
-tape_34xx_check_locate(struct tape_device *device, struct tape_request *request)
-{
- struct tape_34xx_block_id * start_block;
-
- start_block = (struct tape_34xx_block_id *) request->cpdata;
- if (start_block->block == device->blk_data.block_position)
- return;
-
- DBF_LH(4, "Block seek(%06d+%06d)\n", start_block->block, device->bof);
- start_block->wrap = 0;
- start_block->segment = 1;
- start_block->format = (*device->modeset_byte & 0x08) ?
- TAPE34XX_FMT_3480_XF :
- TAPE34XX_FMT_3480;
- start_block->block = start_block->block + device->bof;
- tape_34xx_merge_sbid(device, start_block);
- tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
- tape_ccw_cc(request->cpaddr + 2, READ_BLOCK_ID, 8, request->cpdata);
-}
-#endif
-
/*
* List of 3480/3490 magnetic tape commands.
*/
@@ -1295,11 +1164,6 @@ static struct tape_discipline tape_discipline_34xx = {
.irq = tape_34xx_irq,
.read_block = tape_std_read_block,
.write_block = tape_std_write_block,
-#ifdef CONFIG_S390_TAPE_BLOCK
- .bread = tape_34xx_bread,
- .free_bread = tape_34xx_free_bread,
- .check_locate = tape_34xx_check_locate,
-#endif
.ioctl_fn = tape_34xx_ioctl,
.mtop_array = tape_34xx_mtop
};
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 49c6aab..a5c6614 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -670,92 +670,6 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
return 0;
}
-#ifdef CONFIG_S390_TAPE_BLOCK
-/*
- * Tape Block READ
- */
-static struct tape_request *
-tape_3590_bread(struct tape_device *device, struct request *req)
-{
- struct tape_request *request;
- struct ccw1 *ccw;
- int count = 0, start_block;
- unsigned off;
- char *dst;
- struct bio_vec *bv;
- struct req_iterator iter;
-
- DBF_EVENT(6, "xBREDid:");
- start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B;
- DBF_EVENT(6, "start_block = %i\n", start_block);
-
- rq_for_each_segment(bv, req, iter)
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
-
- request = tape_alloc_request(2 + count + 1, 4);
- if (IS_ERR(request))
- return request;
- request->op = TO_BLOCK;
- *(__u32 *) request->cpdata = start_block;
- ccw = request->cpaddr;
- ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte);
-
- /*
- * We always setup a nop after the mode set ccw. This slot is
- * used in tape_std_check_locate to insert a locate ccw if the
- * current tape position doesn't match the start block to be read.
- */
- ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
-
- rq_for_each_segment(bv, req, iter) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void *) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
- BUG_ON(off > bv->bv_len);
- }
- ccw = tape_ccw_end(ccw, NOP, 0, NULL);
- DBF_EVENT(6, "xBREDccwg\n");
- return request;
-}
-
-static void
-tape_3590_free_bread(struct tape_request *request)
-{
- struct ccw1 *ccw;
-
- /* Last ccw is a nop and doesn't need clear_normalized_cda */
- for (ccw = request->cpaddr; ccw->flags & CCW_FLAG_CC; ccw++)
- if (ccw->cmd_code == READ_FORWARD)
- clear_normalized_cda(ccw);
- tape_free_request(request);
-}
-
-/*
- * check_locate is called just before the tape request is passed to
- * the common io layer for execution. It has to check the current
- * tape position and insert a locate ccw if it doesn't match the
- * start block for the request.
- */
-static void
-tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
-{
- __u32 *start_block;
-
- start_block = (__u32 *) request->cpdata;
- if (*start_block != device->blk_data.block_position) {
- /* Add the start offset of the file to get the real block. */
- *start_block += device->bof;
- tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
- }
-}
-#endif
-
static void tape_3590_med_state_set(struct tape_device *device,
struct tape_3590_med_sense *sense)
{
@@ -1423,20 +1337,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
{
struct tape_3590_sense *sense;
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK) {
- /*
- * Recovery for block device requests. Set the block_position
- * to something invalid and retry.
- */
- device->blk_data.block_position = -1;
- if (request->retries-- <= 0)
- return tape_3590_erp_failed(device, request, irb, -EIO);
- else
- return tape_3590_erp_retry(device, request, irb);
- }
-#endif
-
sense = (struct tape_3590_sense *) irb->ecw;
DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
@@ -1729,11 +1629,6 @@ static struct tape_discipline tape_discipline_3590 = {
.irq = tape_3590_irq,
.read_block = tape_std_read_block,
.write_block = tape_std_write_block,
-#ifdef CONFIG_S390_TAPE_BLOCK
- .bread = tape_3590_bread,
- .free_bread = tape_3590_free_bread,
- .check_locate = tape_3590_check_locate,
-#endif
.ioctl_fn = tape_3590_ioctl,
.mtop_array = tape_3590_mtop
};
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 87cd0ab..46886a7 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -161,11 +161,6 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
if (rc)
return rc;
-#ifdef CONFIG_S390_TAPE_BLOCK
- /* Changes position. */
- device->blk_data.medium_changed = 1;
-#endif
-
DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
/* Let the discipline build the ccw chain. */
request = device->discipline->read_block(device, block_size);
@@ -218,11 +213,6 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
if (rc)
return rc;
-#ifdef CONFIG_S390_TAPE_BLOCK
- /* Changes position. */
- device->blk_data.medium_changed = 1;
-#endif
-
DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size);
DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks);
/* Let the discipline build the ccw chain. */
@@ -379,9 +369,6 @@ __tapechar_ioctl(struct tape_device *device,
case MTBSFM:
case MTFSFM:
case MTSEEK:
-#ifdef CONFIG_S390_TAPE_BLOCK
- device->blk_data.medium_changed = 1;
-#endif
if (device->required_tapemarks)
tape_std_terminate_write(device);
default:
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index b3a3e8e..5856186 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -401,9 +401,6 @@ tape_generic_online(struct tape_device *device,
rc = tapechar_setup_device(device);
if (rc)
goto out_minor;
- rc = tapeblock_setup_device(device);
- if (rc)
- goto out_char;
tape_state_set(device, TS_UNUSED);
@@ -411,8 +408,6 @@ tape_generic_online(struct tape_device *device,
return 0;
-out_char:
- tapechar_cleanup_device(device);
out_minor:
tape_remove_minor(device);
out_discipline:
@@ -426,7 +421,6 @@ out:
static void
tape_cleanup_device(struct tape_device *device)
{
- tapeblock_cleanup_device(device);
tapechar_cleanup_device(device);
device->discipline->cleanup_device(device);
module_put(device->discipline->owner);
@@ -785,10 +779,6 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
{
int rc;
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK)
- device->discipline->check_locate(device, request);
-#endif
rc = ccw_device_start(
device->cdev,
request->cpaddr,
@@ -1253,7 +1243,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
}
/*
- * Tape device open function used by tape_char & tape_block frontends.
+ * Tape device open function used by tape_char frontend.
*/
int
tape_open(struct tape_device *device)
@@ -1283,7 +1273,7 @@ tape_open(struct tape_device *device)
}
/*
- * Tape device release function used by tape_char & tape_block frontends.
+ * Tape device release function used by tape_char frontend.
*/
int
tape_release(struct tape_device *device)
@@ -1344,7 +1334,6 @@ tape_init (void)
DBF_EVENT(3, "tape init\n");
tape_proc_init();
tapechar_init ();
- tapeblock_init ();
return 0;
}
@@ -1358,7 +1347,6 @@ tape_exit(void)
/* Get rid of the frontends */
tapechar_exit();
- tapeblock_exit();
tape_proc_cleanup();
debug_unregister (TAPE_DBF_AREA);
}
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index b43445a..10ec690 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -61,7 +61,7 @@ struct tty3270_line {
*/
struct tty3270 {
struct raw3270_view view;
- struct tty_struct *tty; /* Pointer to tty structure */
+ struct tty_port port;
void **freemem_pages; /* Array of pages used for freemem. */
struct list_head freemem; /* List of free memory for strings. */
@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
static void
tty3270_write_callback(struct raw3270_request *rq, void *data)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
- tp = (struct tty3270 *) rq->view;
if (rq->rc != 0) {
/* Write wasn't successful. Refresh all. */
tp->update_flags = TTY_UPDATE_ALL;
@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
static void
tty3270_rcl_backward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
struct string *s;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
if (tp->inattr == TF_INPUT) {
if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
static void
tty3270_exit_tty(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- tp = kbd->tty->driver_data;
raw3270_deactivate_view(&tp->view);
}
@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
static void
tty3270_scroll_forward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up - tp->view.rows + 2;
if (nr_up < 0)
@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
static void
tty3270_scroll_backward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up + tp->view.rows - 2;
if (nr_up + tp->view.rows - 2 > tp->nr_lines)
@@ -537,11 +532,10 @@ static void
tty3270_read_tasklet(struct raw3270_request *rrq)
{
static char kreset_data = TW_KR;
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
char *input;
int len;
- tp = (struct tty3270 *) rrq->view;
spin_lock_bh(&tp->view.lock);
/*
* Two AID keys are special: For 0x7d (enter) the input line
@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
raw3270_request_add_data(tp->kreset, &kreset_data, 1);
raw3270_start(&tp->view, tp->kreset);
- /* Emit input string. */
- if (tp->tty) {
- while (len-- > 0)
- kbd_keycode(tp->kbd, *input++);
- /* Emit keycode for AID byte. */
- kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
- }
+ while (len-- > 0)
+ kbd_keycode(tp->kbd, *input++);
+ /* Emit keycode for AID byte. */
+ kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
raw3270_request_reset(rrq);
xchg(&tp->read, rrq);
@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
static void
tty3270_read_callback(struct raw3270_request *rq, void *data)
{
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
raw3270_get_view(rq->view);
/* Schedule tasklet to pass input to tty. */
- tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
+ tasklet_schedule(&tp->readlet);
}
/*
@@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)
static int
tty3270_activate(struct raw3270_view *view)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
- tp = (struct tty3270 *) view;
tp->update_flags = TTY_UPDATE_ALL;
tty3270_set_timer(tp, 1);
return 0;
@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
static void
tty3270_deactivate(struct raw3270_view *view)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
- tp = (struct tty3270 *) view;
del_timer(&tp->timer);
}
@@ -690,6 +680,17 @@ tty3270_alloc_view(void)
if (!tp->freemem_pages)
goto out_tp;
INIT_LIST_HEAD(&tp->freemem);
+ INIT_LIST_HEAD(&tp->lines);
+ INIT_LIST_HEAD(&tp->update);
+ INIT_LIST_HEAD(&tp->rcl_lines);
+ tp->rcl_max = 20;
+ tty_port_init(&tp->port);
+ setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+ (unsigned long) tp);
+ tasklet_init(&tp->readlet,
+ (void (*)(unsigned long)) tty3270_read_tasklet,
+ (unsigned long) tp->read);
+
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *)
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
static void
tty3270_release(struct raw3270_view *view)
{
- struct tty3270 *tp;
- struct tty_struct *tty;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ struct tty_struct *tty = tty_port_tty_get(&tp->port);
- tp = (struct tty3270 *) view;
- tty = tp->tty;
if (tty) {
tty->driver_data = NULL;
- tp->tty = tp->kbd->tty = NULL;
+ tty_port_tty_set(&tp->port, NULL);
tty_hangup(tty);
raw3270_put_view(&tp->view);
+ tty_kref_put(tty);
}
}
@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
static void
tty3270_free(struct raw3270_view *view)
{
- tty3270_free_screen((struct tty3270 *) view);
- tty3270_free_view((struct tty3270 *) view);
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ tty3270_free_screen(tp);
+ tty3270_free_view(tp);
}
/*
@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
static void
tty3270_del_views(void)
{
- struct tty3270 *tp;
int i;
for (i = 0; i < tty3270_max_index; i++) {
- tp = (struct tty3270 *)
+ struct raw3270_view *view =
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
- if (!IS_ERR(tp))
- raw3270_del_view(&tp->view);
+ if (!IS_ERR(view))
+ raw3270_del_view(view);
}
}
@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
static int
tty3270_open(struct tty_struct *tty, struct file * filp)
{
+ struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;
if (tty->count > 1)
return 0;
/* Check if the tty3270 is already there. */
- tp = (struct tty3270 *)
- raw3270_find_view(&tty3270_fn,
+ view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
- if (!IS_ERR(tp)) {
+ if (!IS_ERR(view)) {
+ tp = container_of(view, struct tty3270, view);
tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;
tty->low_latency = 0;
- tp->tty = tty;
- tp->kbd->tty = tty;
+ /* why to reassign? */
+ tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
return 0;
}
@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty3270_max_index = tty->index + 1;
/* Quick exit if there is no device for tty->index. */
- if (PTR_ERR(tp) == -ENODEV)
+ if (PTR_ERR(view) == -ENODEV)
return -ENODEV;
/* Allocate tty3270 structure on first open. */
@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
if (IS_ERR(tp))
return PTR_ERR(tp);
- INIT_LIST_HEAD(&tp->lines);
- INIT_LIST_HEAD(&tp->update);
- INIT_LIST_HEAD(&tp->rcl_lines);
- tp->rcl_max = 20;
- setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
- (unsigned long) tp);
- tasklet_init(&tp->readlet,
- (void (*)(unsigned long)) tty3270_read_tasklet,
- (unsigned long) tp->read);
-
rc = raw3270_add_view(&tp->view, &tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
if (rc) {
@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
return rc;
}
- tp->tty = tty;
+ tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
for (i = 0; i < tp->view.rows - 2; i++)
tty3270_blank_line(tp);
- tp->kbd->tty = tty;
+ tp->kbd->port = &tp->port;
tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
static void
tty3270_close(struct tty_struct *tty, struct file * filp)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = tty->driver_data;
if (tty->count > 1)
return;
- tp = (struct tty3270 *) tty->driver_data;
if (tp) {
tty->driver_data = NULL;
- tp->tty = tp->kbd->tty = NULL;
+ tty_port_tty_set(&tp->port, NULL);
raw3270_put_view(&tp->view);
}
}
@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tty3270_lf(tp);
break;
case 'Z': /* Respond ID. */
- kbd_puts_queue(tp->tty, "\033[?6c");
+ kbd_puts_queue(&tp->port, "\033[?6c");
break;
case '7': /* Save cursor position. */
tp->saved_cx = tp->cx;
@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tp->esc_state = ESnormal;
if (ch == 'n' && !tp->esc_ques) {
if (tp->esc_par[0] == 5) /* Status report. */
- kbd_puts_queue(tp->tty, "\033[0n");
+ kbd_puts_queue(&tp->port, "\033[0n");
else if (tp->esc_par[0] == 6) { /* Cursor report. */
char buf[40];
sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
- kbd_puts_queue(tp->tty, buf);
+ kbd_puts_queue(&tp->port, buf);
}
return;
}
@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
* String write routine for 3270 ttys
*/
static void
-tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
+tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
+ const unsigned char *buf, int count)
{
int i_msg, i;
spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
+ for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) {
/* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]);
@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
if (!tp)
return 0;
if (tp->char_count > 0) {
- tty3270_do_write(tp, tp->char_buf, tp->char_count);
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0;
}
- tty3270_do_write(tp, buf, count);
+ tty3270_do_write(tp, tty, buf, count);
return count;
}
@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
if (!tp)
return;
if (tp->char_count > 0) {
- tty3270_do_write(tp, tp->char_buf, tp->char_count);
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0;
}
}
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 5f1dc6f..731470e 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -1,7 +1,7 @@
/*
* bus driver for ccwgroup
*
- * Copyright IBM Corp. 2002, 2009
+ * Copyright IBM Corp. 2002, 2012
*
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
@@ -15,10 +15,13 @@
#include <linux/ctype.h>
#include <linux/dcache.h>
+#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
-#define CCW_BUS_ID_SIZE 20
+#include "device.h"
+
+#define CCW_BUS_ID_SIZE 10
/* In Linux 2.4, we had a channel device layer called "chandev"
* that did all sorts of obscure stuff for networking devices.
@@ -27,19 +30,6 @@
* to devices that use multiple subchannels.
*/
-/* a device matches a driver if all its slave devices match the same
- * entry of the driver */
-static int ccwgroup_bus_match(struct device *dev, struct device_driver * drv)
-{
- struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
- struct ccwgroup_driver *gdrv = to_ccwgroupdrv(drv);
-
- if (gdev->creator_id == gdrv->driver_id)
- return 1;
-
- return 0;
-}
-
static struct bus_type ccwgroup_bus_type;
static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
@@ -254,9 +244,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
-static int __get_next_bus_id(const char **buf, char *bus_id)
+static int __get_next_id(const char **buf, struct ccw_dev_id *id)
{
- int rc, len;
+ unsigned int cssid, ssid, devno;
+ int ret = 0, len;
char *start, *end;
start = (char *)*buf;
@@ -271,49 +262,40 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
len = end - start + 1;
end++;
}
- if (len < CCW_BUS_ID_SIZE) {
- strlcpy(bus_id, start, len);
- rc = 0;
+ if (len <= CCW_BUS_ID_SIZE) {
+ if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3)
+ ret = -EINVAL;
} else
- rc = -EINVAL;
- *buf = end;
- return rc;
-}
-
-static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
-{
- int cssid, ssid, devno;
+ ret = -EINVAL;
- /* Must be of form %x.%x.%04x */
- if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
- return 0;
- return 1;
+ if (!ret) {
+ id->ssid = ssid;
+ id->devno = devno;
+ }
+ *buf = end;
+ return ret;
}
/**
- * ccwgroup_create_from_string() - create and register a ccw group device
- * @root: parent device for the new device
- * @creator_id: identifier of creating driver
- * @cdrv: ccw driver of slave devices
+ * ccwgroup_create_dev() - create and register a ccw group device
+ * @parent: parent device for the new device
+ * @gdrv: driver for the new group device
* @num_devices: number of slave devices
* @buf: buffer containing comma separated bus ids of slave devices
*
- * Create and register a new ccw group device as a child of @root. Slave
- * devices are obtained from the list of bus ids given in @buf and must all
- * belong to @cdrv.
+ * Create and register a new ccw group device as a child of @parent. Slave
+ * devices are obtained from the list of bus ids given in @buf.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
-int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
- struct ccw_driver *cdrv, int num_devices,
- const char *buf)
+int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
+ int num_devices, const char *buf)
{
struct ccwgroup_device *gdev;
+ struct ccw_dev_id dev_id;
int rc, i;
- char tmp_bus_id[CCW_BUS_ID_SIZE];
- const char *curr_buf;
gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
GFP_KERNEL);
@@ -323,29 +305,24 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
- gdev->creator_id = creator_id;
gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
- gdev->dev.parent = root;
+ gdev->dev.parent = parent;
gdev->dev.release = ccwgroup_release;
device_initialize(&gdev->dev);
- curr_buf = buf;
- for (i = 0; i < num_devices && curr_buf; i++) {
- rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
+ for (i = 0; i < num_devices && buf; i++) {
+ rc = __get_next_id(&buf, &dev_id);
if (rc != 0)
goto error;
- if (!__is_valid_bus_id(tmp_bus_id)) {
- rc = -EINVAL;
- goto error;
- }
- gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
+ gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id);
/*
* All devices have to be of the same type in
* order to be grouped.
*/
- if (!gdev->cdev[i]
- || gdev->cdev[i]->id.driver_info !=
+ if (!gdev->cdev[i] || !gdev->cdev[i]->drv ||
+ gdev->cdev[i]->drv != gdev->cdev[0]->drv ||
+ gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
rc = -EINVAL;
goto error;
@@ -361,18 +338,25 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
spin_unlock_irq(gdev->cdev[i]->ccwlock);
}
/* Check for sufficient number of bus ids. */
- if (i < num_devices && !curr_buf) {
+ if (i < num_devices) {
rc = -EINVAL;
goto error;
}
/* Check for trailing stuff. */
- if (i == num_devices && strlen(curr_buf) > 0) {
+ if (i == num_devices && strlen(buf) > 0) {
rc = -EINVAL;
goto error;
}
dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
gdev->dev.groups = ccwgroup_attr_groups;
+
+ if (gdrv) {
+ gdev->dev.driver = &gdrv->driver;
+ rc = gdrv->setup ? gdrv->setup(gdev) : 0;
+ if (rc)
+ goto error;
+ }
rc = device_add(&gdev->dev);
if (rc)
goto error;
@@ -397,7 +381,7 @@ error:
put_device(&gdev->dev);
return rc;
}
-EXPORT_SYMBOL(ccwgroup_create_from_string);
+EXPORT_SYMBOL(ccwgroup_create_dev);
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
void *data)
@@ -440,14 +424,6 @@ module_exit(cleanup_ccwgroup);
/************************** driver stuff ******************************/
-static int ccwgroup_probe(struct device *dev)
-{
- struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
- struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver);
-
- return gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
-}
-
static int ccwgroup_remove(struct device *dev)
{
struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
@@ -542,8 +518,6 @@ static const struct dev_pm_ops ccwgroup_pm_ops = {
static struct bus_type ccwgroup_bus_type = {
.name = "ccwgroup",
- .match = ccwgroup_bus_match,
- .probe = ccwgroup_probe,
.remove = ccwgroup_remove,
.shutdown = ccwgroup_shutdown,
.pm = &ccwgroup_pm_ops,
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index a49c46c..a6ddaed 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -656,51 +656,34 @@ static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
/*
- * Use cio_tpi to get a pending interrupt and call the interrupt handler.
- * Return non-zero if an interrupt was processed, zero otherwise.
+ * Use cio_tsch to update the subchannel status and call the interrupt handler
+ * if status had been pending. Called with the console_subchannel lock.
*/
-static int cio_tpi(void)
+static void cio_tsch(struct subchannel *sch)
{
- struct tpi_info *tpi_info;
- struct subchannel *sch;
struct irb *irb;
int irq_context;
- tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
- if (tpi(NULL) != 1)
- return 0;
- kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
- if (tpi_info->adapter_IO) {
- do_adapter_IO(tpi_info->isc);
- return 1;
- }
irb = (struct irb *)&S390_lowcore.irb;
/* Store interrupt response block to lowcore. */
- if (tsch(tpi_info->schid, irb) != 0) {
+ if (tsch(sch->schid, irb) != 0)
/* Not status pending or not operational. */
- kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
- return 1;
- }
- sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
- if (!sch) {
- kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
- return 1;
- }
+ return;
+ memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
+ /* Call interrupt handler with updated status. */
irq_context = in_interrupt();
- if (!irq_context)
+ if (!irq_context) {
local_bh_disable();
- irq_enter();
- spin_lock(sch->lock);
- memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
+ irq_enter();
+ }
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
else
kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
- spin_unlock(sch->lock);
- irq_exit();
- if (!irq_context)
+ if (!irq_context) {
+ irq_exit();
_local_bh_enable();
- return 1;
+ }
}
void *cio_get_console_priv(void)
@@ -712,34 +695,16 @@ void *cio_get_console_priv(void)
* busy wait for the next interrupt on the console
*/
void wait_cons_dev(void)
- __releases(console_subchannel.lock)
- __acquires(console_subchannel.lock)
{
- unsigned long cr6 __attribute__ ((aligned (8)));
- unsigned long save_cr6 __attribute__ ((aligned (8)));
-
- /*
- * before entering the spinlock we may already have
- * processed the interrupt on a different CPU...
- */
if (!console_subchannel_in_use)
return;
- /* disable all but the console isc */
- __ctl_store (save_cr6, 6, 6);
- cr6 = 1UL << (31 - CONSOLE_ISC);
- __ctl_load (cr6, 6, 6);
-
- do {
- spin_unlock(console_subchannel.lock);
- if (!cio_tpi())
- cpu_relax();
- spin_lock(console_subchannel.lock);
- } while (console_subchannel.schib.scsw.cmd.actl != 0);
- /*
- * restore previous isc value
- */
- __ctl_load (save_cr6, 6, 6);
+ while (1) {
+ cio_tsch(&console_subchannel);
+ if (console_subchannel.schib.scsw.cmd.actl == 0)
+ break;
+ udelay_simple(100);
+ }
}
static int
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 02d0152..f8f952d 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data)
return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
}
-static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
+/**
+ * get_ccwdev_by_dev_id() - obtain device from a ccw device id
+ * @dev_id: id of the device to be searched
+ *
+ * This function searches all devices attached to the ccw bus for a device
+ * matching @dev_id.
+ * Returns:
+ * If a device is found its reference count is increased and returned;
+ * else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
{
struct device *dev;
@@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
return dev ? to_ccwdev(dev) : NULL;
}
+EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id);
static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
{
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 179824b..6bace69 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *);
void ccw_device_schedule_sch_unregister(struct ccw_device *);
int ccw_purge_blacklisted(void);
void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
+struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id);
/* Function prototypes for device status and basic sense stuff. */
void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 35c685c..7493efa 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
" ipm %0\n"
" srl %0,28\n"
: "=d" (cc)
- : "d" (__fc), "d" (__schid), "d" (__mask) : "cc", "memory");
+ : "d" (__fc), "d" (__schid), "d" (__mask) : "cc");
return cc;
}
@@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer
* @fc: function code to perform
*
- * Returns cc or QDIO_ERROR_SIGA_ACCESS_EXCEPTION.
+ * Returns condition code.
* Note: For IQDC unicast queues only the highest priority queue is processed.
*/
static inline int do_siga_output(unsigned long schid, unsigned long mask,
@@ -85,18 +85,16 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask,
register unsigned long __schid asm("1") = schid;
register unsigned long __mask asm("2") = mask;
register unsigned long __aob asm("3") = aob;
- int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION;
+ int cc;
asm volatile(
" siga 0\n"
- "0: ipm %0\n"
+ " ipm %0\n"
" srl %0,28\n"
- "1:\n"
- EX_TABLE(0b, 1b)
- : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask),
- "+d" (__aob)
- : : "cc", "memory");
- *bb = ((unsigned int) __fc) >> 31;
+ : "=d" (cc), "+d" (__fc), "+d" (__aob)
+ : "d" (__schid), "d" (__mask)
+ : "cc");
+ *bb = __fc >> 31;
return cc;
}
@@ -167,7 +165,7 @@ again:
DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
- q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
+ q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE,
q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
@@ -215,7 +213,7 @@ again:
DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
- q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
+ q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE,
q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
@@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
cc = do_siga_sync(schid, output, input, fc);
if (unlikely(cc))
DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc);
- return cc;
+ return (cc) ? -EIO : 0;
}
static inline int qdio_siga_sync_q(struct qdio_q *q)
@@ -384,7 +382,7 @@ static inline int qdio_siga_input(struct qdio_q *q)
cc = do_siga_input(schid, q->mask, fc);
if (unlikely(cc))
DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc);
- return cc;
+ return (cc) ? -EIO : 0;
}
#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0)
@@ -443,7 +441,7 @@ static void process_buffer_error(struct qdio_q *q, int count)
unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT :
SLSB_P_OUTPUT_NOT_INIT;
- q->qdio_error |= QDIO_ERROR_SLSB_STATE;
+ q->qdio_error = QDIO_ERROR_SLSB_STATE;
/* special handling for no target buffer empty */
if ((!q->is_input_q &&
@@ -519,7 +517,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
int count, stop;
unsigned char state = 0;
- q->timestamp = get_clock_fast();
+ q->timestamp = get_clock();
/*
* Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q)
bufnr = get_inbound_buffer_frontier(q);
- if ((bufnr != q->last_move) || q->qdio_error) {
+ if (bufnr != q->last_move) {
q->last_move = bufnr;
if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR)
q->u.in.timestamp = get_clock();
@@ -790,7 +788,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
int count, stop;
unsigned char state = 0;
- q->timestamp = get_clock_fast();
+ q->timestamp = get_clock();
if (need_siga_sync(q))
if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
@@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
bufnr = get_outbound_buffer_frontier(q);
- if ((bufnr != q->last_move) || q->qdio_error) {
+ if (bufnr != q->last_move) {
q->last_move = bufnr;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
return 1;
@@ -894,13 +892,16 @@ retry:
goto retry;
}
DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr);
- cc |= QDIO_ERROR_SIGA_BUSY;
- } else
+ cc = -EBUSY;
+ } else {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
+ cc = -ENOBUFS;
+ }
break;
case 1:
case 3:
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
+ cc = -EIO;
break;
}
if (retries) {
@@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev,
}
count = sub_buf(q->first_to_check, q->first_to_kick);
- q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
+ q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE,
q->nr, q->first_to_kick, count, irq_ptr->int_parm);
no_handler:
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
@@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
"do%02x b:%02x c:%02x", callflags, bufnr, count);
if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)
- return -EBUSY;
+ return -EIO;
if (!count)
return 0;
if (callflags & QDIO_FLAG_SYNC_INPUT)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 7e9a72e..b987d46 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -215,7 +215,7 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind)
register struct ap_queue_status reg1_out asm ("1");
register void *reg2 asm ("2") = ind;
asm volatile(
- ".long 0xb2af0000" /* PQAP(RAPQ) */
+ ".long 0xb2af0000" /* PQAP(AQIC) */
: "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
:
: "cc" );
@@ -232,7 +232,7 @@ __ap_query_functions(ap_qid_t qid, unsigned int *functions)
register unsigned long reg2 asm ("2");
asm volatile(
- ".long 0xb2af0000\n"
+ ".long 0xb2af0000\n" /* PQAP(TAPQ) */
"0:\n"
EX_TABLE(0b, 0b)
: "+d" (reg0), "+d" (reg1), "=d" (reg2)
@@ -391,7 +391,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
reg0 |= 0x400000UL;
asm volatile (
- "0: .long 0xb2ad0042\n" /* DQAP */
+ "0: .long 0xb2ad0042\n" /* NQAP */
" brc 2,0b"
: "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
: "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
@@ -450,7 +450,7 @@ __ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
asm volatile(
- "0: .long 0xb2ae0064\n"
+ "0: .long 0xb2ae0064\n" /* DQAP */
" brc 6,0b\n"
: "+d" (reg0), "=d" (reg1), "+d" (reg2),
"+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
@@ -836,12 +836,12 @@ static void __ap_flush_queue(struct ap_device *ap_dev)
list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
list_del_init(&ap_msg->list);
ap_dev->pendingq_count--;
- ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
}
list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
list_del_init(&ap_msg->list);
ap_dev->requestq_count--;
- ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
}
}
@@ -1329,7 +1329,7 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
continue;
list_del_init(&ap_msg->list);
ap_dev->pendingq_count--;
- ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply);
+ ap_msg->receive(ap_dev, ap_msg, ap_dev->reply);
break;
}
if (ap_dev->queue_count > 0)
@@ -1450,10 +1450,10 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
return -EBUSY;
case AP_RESPONSE_REQ_FAC_NOT_INST:
case AP_RESPONSE_MESSAGE_TOO_BIG:
- ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
+ ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
return -EINVAL;
default: /* Device is gone. */
- ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
return -ENODEV;
}
} else {
@@ -1471,6 +1471,10 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
unsigned long flags;
int rc;
+ /* For asynchronous message handling a valid receive-callback
+ * is required. */
+ BUG_ON(!ap_msg->receive);
+
spin_lock_bh(&ap_dev->lock);
if (!ap_dev->unregistered) {
/* Make room on the queue by polling for finished requests. */
@@ -1482,7 +1486,7 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
if (rc == -ENODEV)
ap_dev->unregistered = 1;
} else {
- ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
rc = -ENODEV;
}
spin_unlock_bh(&ap_dev->lock);
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index d960a63..726fc65 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -136,9 +136,6 @@ struct ap_driver {
int (*probe)(struct ap_device *);
void (*remove)(struct ap_device *);
- /* receive is called from tasklet context */
- void (*receive)(struct ap_device *, struct ap_message *,
- struct ap_message *);
int request_timeout; /* request timeout in jiffies */
};
@@ -183,6 +180,9 @@ struct ap_message {
void *private; /* ap driver private pointer. */
unsigned int special:1; /* Used for special commands. */
+ /* receive is called from tasklet context */
+ void (*receive)(struct ap_device *, struct ap_message *,
+ struct ap_message *);
};
#define AP_DEVICE(dt) \
@@ -199,6 +199,7 @@ static inline void ap_init_message(struct ap_message *ap_msg)
ap_msg->psmid = 0;
ap_msg->length = 0;
ap_msg->special = 0;
+ ap_msg->receive = NULL;
}
/*
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 0842867..4681244 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -77,7 +77,6 @@ static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
static struct ap_driver zcrypt_cex2a_driver = {
.probe = zcrypt_cex2a_probe,
.remove = zcrypt_cex2a_remove,
- .receive = zcrypt_cex2a_receive,
.ids = zcrypt_cex2a_ids,
.request_timeout = CEX2A_CLEANUP_TIME,
};
@@ -349,6 +348,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_cex2a_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
@@ -390,6 +390,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_cex2a_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 0effca9..ad7951c 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -67,7 +67,6 @@ static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *,
static struct ap_driver zcrypt_pcica_driver = {
.probe = zcrypt_pcica_probe,
.remove = zcrypt_pcica_remove,
- .receive = zcrypt_pcica_receive,
.ids = zcrypt_pcica_ids,
.request_timeout = PCICA_CLEANUP_TIME,
};
@@ -284,6 +283,7 @@ static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcica_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
@@ -322,6 +322,7 @@ static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcica_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index f9523c0..e5dd335 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -79,7 +79,6 @@ static void zcrypt_pcicc_receive(struct ap_device *, struct ap_message *,
static struct ap_driver zcrypt_pcicc_driver = {
.probe = zcrypt_pcicc_probe,
.remove = zcrypt_pcicc_remove,
- .receive = zcrypt_pcicc_receive,
.ids = zcrypt_pcicc_ids,
.request_timeout = PCICC_CLEANUP_TIME,
};
@@ -488,6 +487,7 @@ static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev,
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcicc_receive;
ap_msg.length = PAGE_SIZE;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -527,6 +527,7 @@ static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcicc_receive;
ap_msg.length = PAGE_SIZE;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index cf1cbd4..f7cc434 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -89,7 +89,6 @@ static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
static struct ap_driver zcrypt_pcixcc_driver = {
.probe = zcrypt_pcixcc_probe,
.remove = zcrypt_pcixcc_remove,
- .receive = zcrypt_pcixcc_receive,
.ids = zcrypt_pcixcc_ids,
.request_timeout = PCIXCC_CLEANUP_TIME,
};
@@ -698,6 +697,7 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcixcc_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
@@ -738,6 +738,7 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcixcc_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
@@ -778,6 +779,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcixcc_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
@@ -818,6 +820,7 @@ static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev,
ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
+ ap_msg.receive = zcrypt_pcixcc_receive;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index b41fae3..6b1ff90 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -136,7 +136,6 @@ static inline void
claw_set_busy(struct net_device *dev)
{
((struct claw_privbk *)dev->ml_priv)->tbusy = 1;
- eieio();
}
static inline void
@@ -144,13 +143,11 @@ claw_clear_busy(struct net_device *dev)
{
clear_bit(0, &(((struct claw_privbk *) dev->ml_priv)->tbusy));
netif_wake_queue(dev);
- eieio();
}
static inline int
claw_check_busy(struct net_device *dev)
{
- eieio();
return ((struct claw_privbk *) dev->ml_priv)->tbusy;
}
@@ -233,8 +230,6 @@ static ssize_t claw_rbuff_show(struct device *dev,
static ssize_t claw_rbuff_write(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
-static int claw_add_files(struct device *dev);
-static void claw_remove_files(struct device *dev);
/* Functions for System Validate */
static int claw_process_control( struct net_device *dev, struct ccwbk * p_ccw);
@@ -267,12 +262,10 @@ static struct ccwgroup_driver claw_group_driver = {
.owner = THIS_MODULE,
.name = "claw",
},
- .max_slaves = 2,
- .driver_id = 0xC3D3C1E6,
- .probe = claw_probe,
- .remove = claw_remove_device,
- .set_online = claw_new_device,
- .set_offline = claw_shutdown_device,
+ .setup = claw_probe,
+ .remove = claw_remove_device,
+ .set_online = claw_new_device,
+ .set_offline = claw_shutdown_device,
.prepare = claw_pm_prepare,
};
@@ -293,30 +286,24 @@ static struct ccw_driver claw_ccw_driver = {
.int_class = IOINT_CLW,
};
-static ssize_t
-claw_driver_group_store(struct device_driver *ddrv, const char *buf,
- size_t count)
+static ssize_t claw_driver_group_store(struct device_driver *ddrv,
+ const char *buf, size_t count)
{
int err;
- err = ccwgroup_create_from_string(claw_root_dev,
- claw_group_driver.driver_id,
- &claw_ccw_driver, 2, buf);
+ err = ccwgroup_create_dev(claw_root_dev, &claw_group_driver, 2, buf);
return err ? err : count;
}
-
static DRIVER_ATTR(group, 0200, NULL, claw_driver_group_store);
-static struct attribute *claw_group_attrs[] = {
+static struct attribute *claw_drv_attrs[] = {
&driver_attr_group.attr,
NULL,
};
-
-static struct attribute_group claw_group_attr_group = {
- .attrs = claw_group_attrs,
+static struct attribute_group claw_drv_attr_group = {
+ .attrs = claw_drv_attrs,
};
-
-static const struct attribute_group *claw_group_attr_groups[] = {
- &claw_group_attr_group,
+static const struct attribute_group *claw_drv_attr_groups[] = {
+ &claw_drv_attr_group,
NULL,
};
@@ -324,60 +311,6 @@ static const struct attribute_group *claw_group_attr_groups[] = {
* Key functions
*/
-/*----------------------------------------------------------------*
- * claw_probe *
- * this function is called for each CLAW device. *
- *----------------------------------------------------------------*/
-static int
-claw_probe(struct ccwgroup_device *cgdev)
-{
- int rc;
- struct claw_privbk *privptr=NULL;
-
- CLAW_DBF_TEXT(2, setup, "probe");
- if (!get_device(&cgdev->dev))
- return -ENODEV;
- privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL);
- dev_set_drvdata(&cgdev->dev, privptr);
- if (privptr == NULL) {
- probe_error(cgdev);
- put_device(&cgdev->dev);
- CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM);
- return -ENOMEM;
- }
- privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
- privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
- if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
- probe_error(cgdev);
- put_device(&cgdev->dev);
- CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM);
- return -ENOMEM;
- }
- memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
- memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
- memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
- privptr->p_env->packing = 0;
- privptr->p_env->write_buffers = 5;
- privptr->p_env->read_buffers = 5;
- privptr->p_env->read_size = CLAW_FRAME_SIZE;
- privptr->p_env->write_size = CLAW_FRAME_SIZE;
- rc = claw_add_files(&cgdev->dev);
- if (rc) {
- probe_error(cgdev);
- put_device(&cgdev->dev);
- dev_err(&cgdev->dev, "Creating the /proc files for a new"
- " CLAW device failed\n");
- CLAW_DBF_TEXT_(2, setup, "probex%d", rc);
- return rc;
- }
- privptr->p_env->p_priv = privptr;
- cgdev->cdev[0]->handler = claw_irq_handler;
- cgdev->cdev[1]->handler = claw_irq_handler;
- CLAW_DBF_TEXT(2, setup, "prbext 0");
-
- return 0;
-} /* end of claw_probe */
-
/*-------------------------------------------------------------------*
* claw_tx *
*-------------------------------------------------------------------*/
@@ -3093,7 +3026,6 @@ claw_remove_device(struct ccwgroup_device *cgdev)
dev_info(&cgdev->dev, " will be removed.\n");
if (cgdev->state == CCWGROUP_ONLINE)
claw_shutdown_device(cgdev);
- claw_remove_files(&cgdev->dev);
kfree(priv->p_mtc_envelope);
priv->p_mtc_envelope=NULL;
kfree(priv->p_env);
@@ -3321,7 +3253,6 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr,
CLAW_DBF_TEXT_(2, setup, "RB=%d", p_env->read_buffers);
return count;
}
-
static DEVICE_ATTR(read_buffer, 0644, claw_rbuff_show, claw_rbuff_write);
static struct attribute *claw_attr[] = {
@@ -3332,40 +3263,73 @@ static struct attribute *claw_attr[] = {
&dev_attr_host_name.attr,
NULL,
};
-
static struct attribute_group claw_attr_group = {
.attrs = claw_attr,
};
+static const struct attribute_group *claw_attr_groups[] = {
+ &claw_attr_group,
+ NULL,
+};
+static const struct device_type claw_devtype = {
+ .name = "claw",
+ .groups = claw_attr_groups,
+};
-static int
-claw_add_files(struct device *dev)
+/*----------------------------------------------------------------*
+ * claw_probe *
+ * this function is called for each CLAW device. *
+ *----------------------------------------------------------------*/
+static int claw_probe(struct ccwgroup_device *cgdev)
{
- CLAW_DBF_TEXT(2, setup, "add_file");
- return sysfs_create_group(&dev->kobj, &claw_attr_group);
-}
+ struct claw_privbk *privptr = NULL;
-static void
-claw_remove_files(struct device *dev)
-{
- CLAW_DBF_TEXT(2, setup, "rem_file");
- sysfs_remove_group(&dev->kobj, &claw_attr_group);
-}
+ CLAW_DBF_TEXT(2, setup, "probe");
+ if (!get_device(&cgdev->dev))
+ return -ENODEV;
+ privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL);
+ dev_set_drvdata(&cgdev->dev, privptr);
+ if (privptr == NULL) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM);
+ return -ENOMEM;
+ }
+ privptr->p_mtc_envelope = kzalloc(MAX_ENVELOPE_SIZE, GFP_KERNEL);
+ privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
+ if ((privptr->p_mtc_envelope == NULL) || (privptr->p_env == NULL)) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM);
+ return -ENOMEM;
+ }
+ memcpy(privptr->p_env->adapter_name, WS_NAME_NOT_DEF, 8);
+ memcpy(privptr->p_env->host_name, WS_NAME_NOT_DEF, 8);
+ memcpy(privptr->p_env->api_type, WS_NAME_NOT_DEF, 8);
+ privptr->p_env->packing = 0;
+ privptr->p_env->write_buffers = 5;
+ privptr->p_env->read_buffers = 5;
+ privptr->p_env->read_size = CLAW_FRAME_SIZE;
+ privptr->p_env->write_size = CLAW_FRAME_SIZE;
+ privptr->p_env->p_priv = privptr;
+ cgdev->cdev[0]->handler = claw_irq_handler;
+ cgdev->cdev[1]->handler = claw_irq_handler;
+ cgdev->dev.type = &claw_devtype;
+ CLAW_DBF_TEXT(2, setup, "prbext 0");
+
+ return 0;
+} /* end of claw_probe */
/*--------------------------------------------------------------------*
* claw_init and cleanup *
*---------------------------------------------------------------------*/
-static void __exit
-claw_cleanup(void)
+static void __exit claw_cleanup(void)
{
- driver_remove_file(&claw_group_driver.driver,
- &driver_attr_group);
ccwgroup_driver_unregister(&claw_group_driver);
ccw_driver_unregister(&claw_ccw_driver);
root_device_unregister(claw_root_dev);
claw_unregister_debug_facility();
pr_info("Driver unloaded\n");
-
}
/**
@@ -3374,8 +3338,7 @@ claw_cleanup(void)
*
* @return 0 on success, !0 on error.
*/
-static int __init
-claw_init(void)
+static int __init claw_init(void)
{
int ret = 0;
@@ -3394,7 +3357,7 @@ claw_init(void)
ret = ccw_driver_register(&claw_ccw_driver);
if (ret)
goto ccw_err;
- claw_group_driver.driver.groups = claw_group_attr_groups;
+ claw_group_driver.driver.groups = claw_drv_attr_groups;
ret = ccwgroup_driver_register(&claw_group_driver);
if (ret)
goto ccwgroup_err;
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 11f3b07..3cd2554 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1296,6 +1296,11 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
}
+static const struct device_type ctcm_devtype = {
+ .name = "ctcm",
+ .groups = ctcm_attr_groups,
+};
+
/**
* Add ctcm specific attributes.
* Add ctcm private data.
@@ -1307,7 +1312,6 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
static int ctcm_probe_device(struct ccwgroup_device *cgdev)
{
struct ctcm_priv *priv;
- int rc;
CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO,
"%s %p",
@@ -1324,17 +1328,11 @@ static int ctcm_probe_device(struct ccwgroup_device *cgdev)
put_device(&cgdev->dev);
return -ENOMEM;
}
-
- rc = ctcm_add_files(&cgdev->dev);
- if (rc) {
- kfree(priv);
- put_device(&cgdev->dev);
- return rc;
- }
priv->buffer_size = CTCM_BUFSIZE_DEFAULT;
cgdev->cdev[0]->handler = ctcm_irq_handler;
cgdev->cdev[1]->handler = ctcm_irq_handler;
dev_set_drvdata(&cgdev->dev, priv);
+ cgdev->dev.type = &ctcm_devtype;
return 0;
}
@@ -1611,11 +1609,6 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
goto out_dev;
}
- if (ctcm_add_attributes(&cgdev->dev)) {
- result = -ENODEV;
- goto out_unregister;
- }
-
strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
dev_info(&dev->dev,
@@ -1629,8 +1622,6 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
priv->channel[CTCM_WRITE]->id, priv->protocol);
return 0;
-out_unregister:
- unregister_netdev(dev);
out_dev:
ctcm_free_netdevice(dev);
out_ccw2:
@@ -1669,7 +1660,6 @@ static int ctcm_shutdown_device(struct ccwgroup_device *cgdev)
/* Close the device */
ctcm_close(dev);
dev->flags &= ~IFF_RUNNING;
- ctcm_remove_attributes(&cgdev->dev);
channel_free(priv->channel[CTCM_READ]);
} else
dev = NULL;
@@ -1711,7 +1701,6 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev)
if (cgdev->state == CCWGROUP_ONLINE)
ctcm_shutdown_device(cgdev);
- ctcm_remove_files(&cgdev->dev);
dev_set_drvdata(&cgdev->dev, NULL);
kfree(priv);
put_device(&cgdev->dev);
@@ -1778,9 +1767,7 @@ static struct ccwgroup_driver ctcm_group_driver = {
.owner = THIS_MODULE,
.name = CTC_DRIVER_NAME,
},
- .max_slaves = 2,
- .driver_id = 0xC3E3C3D4, /* CTCM */
- .probe = ctcm_probe_device,
+ .setup = ctcm_probe_device,
.remove = ctcm_remove_device,
.set_online = ctcm_new_device,
.set_offline = ctcm_shutdown_device,
@@ -1789,31 +1776,25 @@ static struct ccwgroup_driver ctcm_group_driver = {
.restore = ctcm_pm_resume,
};
-static ssize_t
-ctcm_driver_group_store(struct device_driver *ddrv, const char *buf,
- size_t count)
+static ssize_t ctcm_driver_group_store(struct device_driver *ddrv,
+ const char *buf, size_t count)
{
int err;
- err = ccwgroup_create_from_string(ctcm_root_dev,
- ctcm_group_driver.driver_id,
- &ctcm_ccw_driver, 2, buf);
+ err = ccwgroup_create_dev(ctcm_root_dev, &ctcm_group_driver, 2, buf);
return err ? err : count;
}
-
static DRIVER_ATTR(group, 0200, NULL, ctcm_driver_group_store);
-static struct attribute *ctcm_group_attrs[] = {
+static struct attribute *ctcm_drv_attrs[] = {
&driver_attr_group.attr,
NULL,
};
-
-static struct attribute_group ctcm_group_attr_group = {
- .attrs = ctcm_group_attrs,
+static struct attribute_group ctcm_drv_attr_group = {
+ .attrs = ctcm_drv_attrs,
};
-
-static const struct attribute_group *ctcm_group_attr_groups[] = {
- &ctcm_group_attr_group,
+static const struct attribute_group *ctcm_drv_attr_groups[] = {
+ &ctcm_drv_attr_group,
NULL,
};
@@ -1829,7 +1810,6 @@ static const struct attribute_group *ctcm_group_attr_groups[] = {
*/
static void __exit ctcm_exit(void)
{
- driver_remove_file(&ctcm_group_driver.driver, &driver_attr_group);
ccwgroup_driver_unregister(&ctcm_group_driver);
ccw_driver_unregister(&ctcm_ccw_driver);
root_device_unregister(ctcm_root_dev);
@@ -1867,7 +1847,7 @@ static int __init ctcm_init(void)
ret = ccw_driver_register(&ctcm_ccw_driver);
if (ret)
goto ccw_err;
- ctcm_group_driver.driver.groups = ctcm_group_attr_groups;
+ ctcm_group_driver.driver.groups = ctcm_drv_attr_groups;
ret = ccwgroup_driver_register(&ctcm_group_driver);
if (ret)
goto ccwgroup_err;
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h
index 24d5215..b9056a5 100644
--- a/drivers/s390/net/ctcm_main.h
+++ b/drivers/s390/net/ctcm_main.h
@@ -225,13 +225,7 @@ struct ctcm_priv {
int ctcm_open(struct net_device *dev);
int ctcm_close(struct net_device *dev);
-/*
- * prototypes for non-static sysfs functions
- */
-int ctcm_add_attributes(struct device *dev);
-void ctcm_remove_attributes(struct device *dev);
-int ctcm_add_files(struct device *dev);
-void ctcm_remove_files(struct device *dev);
+extern const struct attribute_group *ctcm_attr_groups[];
/*
* Compatibility macros for busy handling
diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c
index 650aec1..0c27ae7 100644
--- a/drivers/s390/net/ctcm_sysfs.c
+++ b/drivers/s390/net/ctcm_sysfs.c
@@ -13,6 +13,7 @@
#define KMSG_COMPONENT "ctcm"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include "ctcm_main.h"
@@ -108,10 +109,12 @@ static void ctcm_print_statistics(struct ctcm_priv *priv)
}
static ssize_t stats_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
+ struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
struct ctcm_priv *priv = dev_get_drvdata(dev);
- if (!priv)
+
+ if (!priv || gdev->state != CCWGROUP_ONLINE)
return -ENODEV;
ctcm_print_statistics(priv);
return sprintf(buf, "0\n");
@@ -190,34 +193,14 @@ static struct attribute *ctcm_attr[] = {
&dev_attr_protocol.attr,
&dev_attr_type.attr,
&dev_attr_buffer.attr,
+ &dev_attr_stats.attr,
NULL,
};
static struct attribute_group ctcm_attr_group = {
.attrs = ctcm_attr,
};
-
-int ctcm_add_attributes(struct device *dev)
-{
- int rc;
-
- rc = device_create_file(dev, &dev_attr_stats);
-
- return rc;
-}
-
-void ctcm_remove_attributes(struct device *dev)
-{
- device_remove_file(dev, &dev_attr_stats);
-}
-
-int ctcm_add_files(struct device *dev)
-{
- return sysfs_create_group(&dev->kobj, &ctcm_attr_group);
-}
-
-void ctcm_remove_files(struct device *dev)
-{
- sysfs_remove_group(&dev->kobj, &ctcm_attr_group);
-}
-
+const struct attribute_group *ctcm_attr_groups[] = {
+ &ctcm_attr_group,
+ NULL,
+};
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 6056cf6..a3adf4b 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -2040,10 +2040,17 @@ static struct attribute * lcs_attrs[] = {
&dev_attr_recover.attr,
NULL,
};
-
static struct attribute_group lcs_attr_group = {
.attrs = lcs_attrs,
};
+static const struct attribute_group *lcs_attr_groups[] = {
+ &lcs_attr_group,
+ NULL,
+};
+static const struct device_type lcs_devtype = {
+ .name = "lcs",
+ .groups = lcs_attr_groups,
+};
/**
* lcs_probe_device is called on establishing a new ccwgroup_device.
@@ -2052,7 +2059,6 @@ static int
lcs_probe_device(struct ccwgroup_device *ccwgdev)
{
struct lcs_card *card;
- int ret;
if (!get_device(&ccwgdev->dev))
return -ENODEV;
@@ -2064,12 +2070,6 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
put_device(&ccwgdev->dev);
return -ENOMEM;
}
- ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group);
- if (ret) {
- lcs_free_card(card);
- put_device(&ccwgdev->dev);
- return ret;
- }
dev_set_drvdata(&ccwgdev->dev, card);
ccwgdev->cdev[0]->handler = lcs_irq;
ccwgdev->cdev[1]->handler = lcs_irq;
@@ -2078,7 +2078,9 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
card->thread_start_mask = 0;
card->thread_allowed_mask = 0;
card->thread_running_mask = 0;
- return 0;
+ ccwgdev->dev.type = &lcs_devtype;
+
+ return 0;
}
static int
@@ -2306,9 +2308,9 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
}
if (card->dev)
unregister_netdev(card->dev);
- sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);
lcs_cleanup_card(card);
lcs_free_card(card);
+ dev_set_drvdata(&ccwgdev->dev, NULL);
put_device(&ccwgdev->dev);
}
@@ -2393,9 +2395,7 @@ static struct ccwgroup_driver lcs_group_driver = {
.owner = THIS_MODULE,
.name = "lcs",
},
- .max_slaves = 2,
- .driver_id = 0xD3C3E2,
- .probe = lcs_probe_device,
+ .setup = lcs_probe_device,
.remove = lcs_remove_device,
.set_online = lcs_new_device,
.set_offline = lcs_shutdown_device,
@@ -2406,30 +2406,24 @@ static struct ccwgroup_driver lcs_group_driver = {
.restore = lcs_restore,
};
-static ssize_t
-lcs_driver_group_store(struct device_driver *ddrv, const char *buf,
- size_t count)
+static ssize_t lcs_driver_group_store(struct device_driver *ddrv,
+ const char *buf, size_t count)
{
int err;
- err = ccwgroup_create_from_string(lcs_root_dev,
- lcs_group_driver.driver_id,
- &lcs_ccw_driver, 2, buf);
+ err = ccwgroup_create_dev(lcs_root_dev, &lcs_group_driver, 2, buf);
return err ? err : count;
}
-
static DRIVER_ATTR(group, 0200, NULL, lcs_driver_group_store);
-static struct attribute *lcs_group_attrs[] = {
+static struct attribute *lcs_drv_attrs[] = {
&driver_attr_group.attr,
NULL,
};
-
-static struct attribute_group lcs_group_attr_group = {
- .attrs = lcs_group_attrs,
+static struct attribute_group lcs_drv_attr_group = {
+ .attrs = lcs_drv_attrs,
};
-
-static const struct attribute_group *lcs_group_attr_groups[] = {
- &lcs_group_attr_group,
+static const struct attribute_group *lcs_drv_attr_groups[] = {
+ &lcs_drv_attr_group,
NULL,
};
@@ -2453,7 +2447,7 @@ __init lcs_init_module(void)
rc = ccw_driver_register(&lcs_ccw_driver);
if (rc)
goto ccw_err;
- lcs_group_driver.driver.groups = lcs_group_attr_groups;
+ lcs_group_driver.driver.groups = lcs_drv_attr_groups;
rc = ccwgroup_driver_register(&lcs_group_driver);
if (rc)
goto ccwgroup_err;
@@ -2479,8 +2473,6 @@ __exit lcs_cleanup_module(void)
{
pr_info("Terminating lcs module.\n");
LCS_DBF_TEXT(0, trace, "cleanup");
- driver_remove_file(&lcs_group_driver.driver,
- &driver_attr_group);
ccwgroup_driver_unregister(&lcs_group_driver);
ccw_driver_unregister(&lcs_ccw_driver);
root_device_unregister(lcs_root_dev);
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 40285dc..06e8f31 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -707,7 +707,16 @@ struct qeth_discipline {
qdio_handler_t *input_handler;
qdio_handler_t *output_handler;
int (*recover)(void *ptr);
- struct ccwgroup_driver *ccwgdriver;
+ int (*setup) (struct ccwgroup_device *);
+ void (*remove) (struct ccwgroup_device *);
+ int (*set_online) (struct ccwgroup_device *);
+ int (*set_offline) (struct ccwgroup_device *);
+ void (*shutdown)(struct ccwgroup_device *);
+ int (*prepare) (struct ccwgroup_device *);
+ void (*complete) (struct ccwgroup_device *);
+ int (*freeze)(struct ccwgroup_device *);
+ int (*thaw) (struct ccwgroup_device *);
+ int (*restore)(struct ccwgroup_device *);
};
struct qeth_vlan_vid {
@@ -771,7 +780,7 @@ struct qeth_card {
struct qeth_perf_stats perf_stats;
int read_or_write_problem;
struct qeth_osn_info osn_info;
- struct qeth_discipline discipline;
+ struct qeth_discipline *discipline;
atomic_t force_alloc_skb;
struct service_level qeth_service_level;
struct qdio_ssqd_desc ssqd;
@@ -837,16 +846,15 @@ static inline int qeth_is_diagass_supported(struct qeth_card *card,
return card->info.diagass_support & (__u32)cmd;
}
-extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
-extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
+extern struct qeth_discipline qeth_l2_discipline;
+extern struct qeth_discipline qeth_l3_discipline;
+extern const struct attribute_group *qeth_generic_attr_groups[];
+extern const struct attribute_group *qeth_osn_attr_groups[];
+
const char *qeth_get_cardname_short(struct qeth_card *);
int qeth_realloc_buffer_pool(struct qeth_card *, int);
int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id);
void qeth_core_free_discipline(struct qeth_card *);
-int qeth_core_create_device_attributes(struct device *);
-void qeth_core_remove_device_attributes(struct device *);
-int qeth_core_create_osn_attributes(struct device *);
-void qeth_core_remove_osn_attributes(struct device *);
void qeth_buffer_reclaim_work(struct work_struct *);
/* exports for qeth discipline device drivers */
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index e000001..e118e1e 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1363,7 +1363,7 @@ static void qeth_start_kernel_thread(struct work_struct *work)
card->write.state != CH_STATE_UP)
return;
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) {
- ts = kthread_run(card->discipline.recover, (void *)card,
+ ts = kthread_run(card->discipline->recover, (void *)card,
"qeth_recover");
if (IS_ERR(ts)) {
qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
@@ -3337,7 +3337,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
if (rc) {
queue->card->stats.tx_errors += count;
/* ignore temporary SIGA errors without busy condition */
- if (rc == QDIO_ERROR_SIGA_TARGET)
+ if (rc == -ENOBUFS)
return;
QETH_CARD_TEXT(queue->card, 2, "flushbuf");
QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no);
@@ -3531,7 +3531,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
int i;
QETH_CARD_TEXT(card, 6, "qdouhdl");
- if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
+ if (qdio_error & QDIO_ERROR_FATAL) {
QETH_CARD_TEXT(card, 2, "achkcond");
netif_stop_queue(card->dev);
qeth_schedule_recovery(card);
@@ -4627,7 +4627,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
goto out_free_in_sbals;
}
for (i = 0; i < card->qdio.no_in_queues; ++i)
- queue_start_poll[i] = card->discipline.start_poll;
+ queue_start_poll[i] = card->discipline->start_poll;
qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll);
@@ -4651,8 +4651,8 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.qib_param_field = qib_param_field;
init_data.no_input_qs = card->qdio.no_in_queues;
init_data.no_output_qs = card->qdio.no_out_queues;
- init_data.input_handler = card->discipline.input_handler;
- init_data.output_handler = card->discipline.output_handler;
+ init_data.input_handler = card->discipline->input_handler;
+ init_data.output_handler = card->discipline->output_handler;
init_data.queue_start_poll_array = queue_start_poll;
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
@@ -4737,13 +4737,6 @@ static struct ccw_driver qeth_ccw_driver = {
.remove = ccwgroup_remove_ccwdev,
};
-static int qeth_core_driver_group(const char *buf, struct device *root_dev,
- unsigned long driver_id)
-{
- return ccwgroup_create_from_string(root_dev, driver_id,
- &qeth_ccw_driver, 3, buf);
-}
-
int qeth_core_hardsetup_card(struct qeth_card *card)
{
int retries = 0;
@@ -5040,17 +5033,15 @@ int qeth_core_load_discipline(struct qeth_card *card,
mutex_lock(&qeth_mod_mutex);
switch (discipline) {
case QETH_DISCIPLINE_LAYER3:
- card->discipline.ccwgdriver = try_then_request_module(
- symbol_get(qeth_l3_ccwgroup_driver),
- "qeth_l3");
+ card->discipline = try_then_request_module(
+ symbol_get(qeth_l3_discipline), "qeth_l3");
break;
case QETH_DISCIPLINE_LAYER2:
- card->discipline.ccwgdriver = try_then_request_module(
- symbol_get(qeth_l2_ccwgroup_driver),
- "qeth_l2");
+ card->discipline = try_then_request_module(
+ symbol_get(qeth_l2_discipline), "qeth_l2");
break;
}
- if (!card->discipline.ccwgdriver) {
+ if (!card->discipline) {
dev_err(&card->gdev->dev, "There is no kernel module to "
"support discipline %d\n", discipline);
rc = -EINVAL;
@@ -5062,12 +5053,21 @@ int qeth_core_load_discipline(struct qeth_card *card,
void qeth_core_free_discipline(struct qeth_card *card)
{
if (card->options.layer2)
- symbol_put(qeth_l2_ccwgroup_driver);
+ symbol_put(qeth_l2_discipline);
else
- symbol_put(qeth_l3_ccwgroup_driver);
- card->discipline.ccwgdriver = NULL;
+ symbol_put(qeth_l3_discipline);
+ card->discipline = NULL;
}
+static const struct device_type qeth_generic_devtype = {
+ .name = "qeth_generic",
+ .groups = qeth_generic_attr_groups,
+};
+static const struct device_type qeth_osn_devtype = {
+ .name = "qeth_osn",
+ .groups = qeth_osn_attr_groups,
+};
+
static int qeth_core_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card;
@@ -5122,18 +5122,17 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
}
if (card->info.type == QETH_CARD_TYPE_OSN)
- rc = qeth_core_create_osn_attributes(dev);
+ gdev->dev.type = &qeth_osn_devtype;
else
- rc = qeth_core_create_device_attributes(dev);
- if (rc)
- goto err_dbf;
+ gdev->dev.type = &qeth_generic_devtype;
+
switch (card->info.type) {
case QETH_CARD_TYPE_OSN:
case QETH_CARD_TYPE_OSM:
rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
if (rc)
- goto err_attr;
- rc = card->discipline.ccwgdriver->probe(card->gdev);
+ goto err_dbf;
+ rc = card->discipline->setup(card->gdev);
if (rc)
goto err_disc;
case QETH_CARD_TYPE_OSD:
@@ -5151,11 +5150,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
err_disc:
qeth_core_free_discipline(card);
-err_attr:
- if (card->info.type == QETH_CARD_TYPE_OSN)
- qeth_core_remove_osn_attributes(dev);
- else
- qeth_core_remove_device_attributes(dev);
err_dbf:
debug_unregister(card->debug);
err_card:
@@ -5172,14 +5166,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
QETH_DBF_TEXT(SETUP, 2, "removedv");
- if (card->info.type == QETH_CARD_TYPE_OSN) {
- qeth_core_remove_osn_attributes(&gdev->dev);
- } else {
- qeth_core_remove_device_attributes(&gdev->dev);
- }
-
- if (card->discipline.ccwgdriver) {
- card->discipline.ccwgdriver->remove(gdev);
+ if (card->discipline) {
+ card->discipline->remove(gdev);
qeth_core_free_discipline(card);
}
@@ -5199,7 +5187,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev)
int rc = 0;
int def_discipline;
- if (!card->discipline.ccwgdriver) {
+ if (!card->discipline) {
if (card->info.type == QETH_CARD_TYPE_IQD)
def_discipline = QETH_DISCIPLINE_LAYER3;
else
@@ -5207,11 +5195,11 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev)
rc = qeth_core_load_discipline(card, def_discipline);
if (rc)
goto err;
- rc = card->discipline.ccwgdriver->probe(card->gdev);
+ rc = card->discipline->setup(card->gdev);
if (rc)
goto err;
}
- rc = card->discipline.ccwgdriver->set_online(gdev);
+ rc = card->discipline->set_online(gdev);
err:
return rc;
}
@@ -5219,58 +5207,52 @@ err:
static int qeth_core_set_offline(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- return card->discipline.ccwgdriver->set_offline(gdev);
+ return card->discipline->set_offline(gdev);
}
static void qeth_core_shutdown(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->shutdown)
- card->discipline.ccwgdriver->shutdown(gdev);
+ if (card->discipline && card->discipline->shutdown)
+ card->discipline->shutdown(gdev);
}
static int qeth_core_prepare(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->prepare)
- return card->discipline.ccwgdriver->prepare(gdev);
+ if (card->discipline && card->discipline->prepare)
+ return card->discipline->prepare(gdev);
return 0;
}
static void qeth_core_complete(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->complete)
- card->discipline.ccwgdriver->complete(gdev);
+ if (card->discipline && card->discipline->complete)
+ card->discipline->complete(gdev);
}
static int qeth_core_freeze(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->freeze)
- return card->discipline.ccwgdriver->freeze(gdev);
+ if (card->discipline && card->discipline->freeze)
+ return card->discipline->freeze(gdev);
return 0;
}
static int qeth_core_thaw(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->thaw)
- return card->discipline.ccwgdriver->thaw(gdev);
+ if (card->discipline && card->discipline->thaw)
+ return card->discipline->thaw(gdev);
return 0;
}
static int qeth_core_restore(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline.ccwgdriver &&
- card->discipline.ccwgdriver->restore)
- return card->discipline.ccwgdriver->restore(gdev);
+ if (card->discipline && card->discipline->restore)
+ return card->discipline->restore(gdev);
return 0;
}
@@ -5279,8 +5261,7 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
.owner = THIS_MODULE,
.name = "qeth",
},
- .driver_id = 0xD8C5E3C8,
- .probe = qeth_core_probe_device,
+ .setup = qeth_core_probe_device,
.remove = qeth_core_remove_device,
.set_online = qeth_core_set_online,
.set_offline = qeth_core_set_offline,
@@ -5292,21 +5273,30 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
.restore = qeth_core_restore,
};
-static ssize_t
-qeth_core_driver_group_store(struct device_driver *ddrv, const char *buf,
- size_t count)
+static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv,
+ const char *buf, size_t count)
{
int err;
- err = qeth_core_driver_group(buf, qeth_core_root_dev,
- qeth_core_ccwgroup_driver.driver_id);
- if (err)
- return err;
- else
- return count;
-}
+ err = ccwgroup_create_dev(qeth_core_root_dev,
+ &qeth_core_ccwgroup_driver, 3, buf);
+
+ return err ? err : count;
+}
static DRIVER_ATTR(group, 0200, NULL, qeth_core_driver_group_store);
+static struct attribute *qeth_drv_attrs[] = {
+ &driver_attr_group.attr,
+ NULL,
+};
+static struct attribute_group qeth_drv_attr_group = {
+ .attrs = qeth_drv_attrs,
+};
+static const struct attribute_group *qeth_drv_attr_groups[] = {
+ &qeth_drv_attr_group,
+ NULL,
+};
+
static struct {
const char str[ETH_GSTRING_LEN];
} qeth_ethtool_stats_keys[] = {
@@ -5544,49 +5534,41 @@ static int __init qeth_core_init(void)
rc = qeth_register_dbf_views();
if (rc)
goto out_err;
- rc = ccw_driver_register(&qeth_ccw_driver);
- if (rc)
- goto ccw_err;
- rc = ccwgroup_driver_register(&qeth_core_ccwgroup_driver);
- if (rc)
- goto ccwgroup_err;
- rc = driver_create_file(&qeth_core_ccwgroup_driver.driver,
- &driver_attr_group);
- if (rc)
- goto driver_err;
qeth_core_root_dev = root_device_register("qeth");
rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0;
if (rc)
goto register_err;
-
qeth_core_header_cache = kmem_cache_create("qeth_hdr",
sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL);
if (!qeth_core_header_cache) {
rc = -ENOMEM;
goto slab_err;
}
-
qeth_qdio_outbuf_cache = kmem_cache_create("qeth_buf",
sizeof(struct qeth_qdio_out_buffer), 0, 0, NULL);
if (!qeth_qdio_outbuf_cache) {
rc = -ENOMEM;
goto cqslab_err;
}
+ rc = ccw_driver_register(&qeth_ccw_driver);
+ if (rc)
+ goto ccw_err;
+ qeth_core_ccwgroup_driver.driver.groups = qeth_drv_attr_groups;
+ rc = ccwgroup_driver_register(&qeth_core_ccwgroup_driver);
+ if (rc)
+ goto ccwgroup_err;
return 0;
+
+ccwgroup_err:
+ ccw_driver_unregister(&qeth_ccw_driver);
+ccw_err:
+ kmem_cache_destroy(qeth_qdio_outbuf_cache);
cqslab_err:
kmem_cache_destroy(qeth_core_header_cache);
slab_err:
root_device_unregister(qeth_core_root_dev);
register_err:
- driver_remove_file(&qeth_core_ccwgroup_driver.driver,
- &driver_attr_group);
-driver_err:
- ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
-ccwgroup_err:
- ccw_driver_unregister(&qeth_ccw_driver);
-ccw_err:
- QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc);
qeth_unregister_dbf_views();
out_err:
pr_err("Initializing the qeth device driver failed\n");
@@ -5595,13 +5577,11 @@ out_err:
static void __exit qeth_core_exit(void)
{
- root_device_unregister(qeth_core_root_dev);
- driver_remove_file(&qeth_core_ccwgroup_driver.driver,
- &driver_attr_group);
ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
ccw_driver_unregister(&qeth_ccw_driver);
kmem_cache_destroy(qeth_qdio_outbuf_cache);
kmem_cache_destroy(qeth_core_header_cache);
+ root_device_unregister(qeth_core_root_dev);
qeth_unregister_dbf_views();
pr_info("core functions removed\n");
}
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 0a8e86c..f163af5 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -434,8 +434,8 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
goto out;
else {
card->info.mac_bits = 0;
- if (card->discipline.ccwgdriver) {
- card->discipline.ccwgdriver->remove(card->gdev);
+ if (card->discipline) {
+ card->discipline->remove(card->gdev);
qeth_core_free_discipline(card);
}
}
@@ -444,7 +444,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
if (rc)
goto out;
- rc = card->discipline.ccwgdriver->probe(card->gdev);
+ rc = card->discipline->setup(card->gdev);
out:
mutex_unlock(&card->discipline_mutex);
return rc ? rc : count;
@@ -693,7 +693,6 @@ static struct attribute *qeth_blkt_device_attrs[] = {
&dev_attr_inter_jumbo.attr,
NULL,
};
-
static struct attribute_group qeth_device_blkt_group = {
.name = "blkt",
.attrs = qeth_blkt_device_attrs,
@@ -716,11 +715,16 @@ static struct attribute *qeth_device_attrs[] = {
&dev_attr_hw_trap.attr,
NULL,
};
-
static struct attribute_group qeth_device_attr_group = {
.attrs = qeth_device_attrs,
};
+const struct attribute_group *qeth_generic_attr_groups[] = {
+ &qeth_device_attr_group,
+ &qeth_device_blkt_group,
+ NULL,
+};
+
static struct attribute *qeth_osn_device_attrs[] = {
&dev_attr_state.attr,
&dev_attr_chpid.attr,
@@ -730,37 +734,10 @@ static struct attribute *qeth_osn_device_attrs[] = {
&dev_attr_recover.attr,
NULL,
};
-
static struct attribute_group qeth_osn_device_attr_group = {
.attrs = qeth_osn_device_attrs,
};
-
-int qeth_core_create_device_attributes(struct device *dev)
-{
- int ret;
- ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group);
- if (ret)
- return ret;
- ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group);
- if (ret)
- sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
-
- return 0;
-}
-
-void qeth_core_remove_device_attributes(struct device *dev)
-{
- sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
- sysfs_remove_group(&dev->kobj, &qeth_device_blkt_group);
-}
-
-int qeth_core_create_osn_attributes(struct device *dev)
-{
- return sysfs_create_group(&dev->kobj, &qeth_osn_device_attr_group);
-}
-
-void qeth_core_remove_osn_attributes(struct device *dev)
-{
- sysfs_remove_group(&dev->kobj, &qeth_osn_device_attr_group);
- return;
-}
+const struct attribute_group *qeth_osn_attr_groups[] = {
+ &qeth_osn_device_attr_group,
+ NULL,
+};
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0e7c29d..4269865 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -882,12 +882,6 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
INIT_LIST_HEAD(&card->mc_list);
card->options.layer2 = 1;
card->info.hwtrap = 0;
- card->discipline.start_poll = qeth_qdio_start_poll;
- card->discipline.input_handler = (qdio_handler_t *)
- qeth_qdio_input_handler;
- card->discipline.output_handler = (qdio_handler_t *)
- qeth_qdio_output_handler;
- card->discipline.recover = qeth_l2_recover;
return 0;
}
@@ -1227,8 +1221,12 @@ out:
return rc;
}
-struct ccwgroup_driver qeth_l2_ccwgroup_driver = {
- .probe = qeth_l2_probe_device,
+struct qeth_discipline qeth_l2_discipline = {
+ .start_poll = qeth_qdio_start_poll,
+ .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
+ .output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
+ .recover = qeth_l2_recover,
+ .setup = qeth_l2_probe_device,
.remove = qeth_l2_remove_device,
.set_online = qeth_l2_set_online,
.set_offline = qeth_l2_set_offline,
@@ -1237,7 +1235,7 @@ struct ccwgroup_driver qeth_l2_ccwgroup_driver = {
.thaw = qeth_l2_pm_resume,
.restore = qeth_l2_pm_resume,
};
-EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver);
+EXPORT_SYMBOL_GPL(qeth_l2_discipline);
static int qeth_osn_send_control_data(struct qeth_card *card, int len,
struct qeth_cmd_buffer *iob)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e7ad032..7be5e97 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3298,12 +3298,6 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
qeth_l3_create_device_attributes(&gdev->dev);
card->options.layer2 = 0;
card->info.hwtrap = 0;
- card->discipline.start_poll = qeth_qdio_start_poll;
- card->discipline.input_handler = (qdio_handler_t *)
- qeth_qdio_input_handler;
- card->discipline.output_handler = (qdio_handler_t *)
- qeth_qdio_output_handler;
- card->discipline.recover = qeth_l3_recover;
return 0;
}
@@ -3578,8 +3572,12 @@ out:
return rc;
}
-struct ccwgroup_driver qeth_l3_ccwgroup_driver = {
- .probe = qeth_l3_probe_device,
+struct qeth_discipline qeth_l3_discipline = {
+ .start_poll = qeth_qdio_start_poll,
+ .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
+ .output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
+ .recover = qeth_l3_recover,
+ .setup = qeth_l3_probe_device,
.remove = qeth_l3_remove_device,
.set_online = qeth_l3_set_online,
.set_offline = qeth_l3_set_offline,
@@ -3588,7 +3586,7 @@ struct ccwgroup_driver qeth_l3_ccwgroup_driver = {
.thaw = qeth_l3_pm_resume,
.restore = qeth_l3_pm_resume,
};
-EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver);
+EXPORT_SYMBOL_GPL(qeth_l3_discipline);
static int qeth_l3_ip_event(struct notifier_block *this,
unsigned long event, void *ptr)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 7a66d0e..e955978 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -408,6 +408,7 @@ config BLK_DEV_3W_XXXX_RAID
config SCSI_HPSA
tristate "HP Smart Array SCSI driver"
depends on PCI && SCSI
+ select CHECK_SIGNATURE
help
This driver supports HP Smart Array Controllers (circa 2009).
It is a SCSI alternative to the cciss driver, which is a block
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 2bee515..7628206 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -424,6 +424,8 @@ static int aac_src_deliver_message(struct fib *fib)
static int aac_src_ioremap(struct aac_dev *dev, u32 size)
{
if (!size) {
+ iounmap(dev->regs.src.bar1);
+ dev->regs.src.bar1 = NULL;
iounmap(dev->regs.src.bar0);
dev->base = dev->regs.src.bar0 = NULL;
return 0;
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 390168f..5fdca93 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1228,8 +1228,7 @@ static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
int asd_release_firmware(void)
{
- if (sequencer_fw)
- release_firmware(sequencer_fw);
+ release_firmware(sequencer_fw);
return 0;
}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 04a154f..df740cb 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -572,7 +572,7 @@ static void falcon_get_lock(void)
}
-int __init atari_scsi_detect(struct scsi_host_template *host)
+static int __init atari_scsi_detect(struct scsi_host_template *host)
{
static int called = 0;
struct Scsi_Host *instance;
@@ -724,7 +724,7 @@ int __init atari_scsi_detect(struct scsi_host_template *host)
return 1;
}
-int atari_scsi_release(struct Scsi_Host *sh)
+static int atari_scsi_release(struct Scsi_Host *sh)
{
if (IS_A_TT())
free_irq(IRQ_TT_MFP_SCSI, sh);
@@ -734,17 +734,21 @@ int atari_scsi_release(struct Scsi_Host *sh)
return 1;
}
-void __init atari_scsi_setup(char *str, int *ints)
+#ifndef MODULE
+static int __init atari_scsi_setup(char *str)
{
/* Format of atascsi parameter is:
* atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
* Defaults depend on TT or Falcon, hostid determined at run time.
* Negative values mean don't change.
*/
+ int ints[6];
+
+ get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] < 1) {
printk("atari_scsi_setup: no arguments!\n");
- return;
+ return 0;
}
if (ints[0] >= 1) {
@@ -777,9 +781,14 @@ void __init atari_scsi_setup(char *str, int *ints)
setup_use_tagged_queuing = !!ints[5];
}
#endif
+
+ return 1;
}
-int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
+__setup("atascsi=", atari_scsi_setup);
+#endif /* !MODULE */
+
+static int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
{
int rv;
struct NCR5380_hostdata *hostdata =
@@ -852,7 +861,7 @@ static void __init atari_scsi_reset_boot(void)
#endif
-const char *atari_scsi_info(struct Scsi_Host *host)
+static const char *atari_scsi_info(struct Scsi_Host *host)
{
/* atari_scsi_detect() is verbose enough... */
static const char string[] = "Atari native SCSI";
@@ -862,8 +871,9 @@ const char *atari_scsi_info(struct Scsi_Host *host)
#if defined(REAL_DMA)
-unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data,
- unsigned long count, int dir)
+static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
+ void *data, unsigned long count,
+ int dir)
{
unsigned long addr = virt_to_phys(data);
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index efadb8d..bd52df7 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -18,11 +18,6 @@
/* (I_HAVE_OVERRUNS stuff removed) */
#ifndef ASM
-int atari_scsi_detect (struct scsi_host_template *);
-const char *atari_scsi_info (struct Scsi_Host *);
-int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
-int atari_scsi_release (struct Scsi_Host *);
-
/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
* values should work, too; try it! (but cmd_per_lun costs memory!) */
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 1d7b976..a50b6a9 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -132,10 +132,6 @@ struct be_ctrl_info {
((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
-/* Byte offset into the page corresponding to given address */
-#define OFFSET_IN_PAGE(addr) \
- ((size_t)(addr) & (PAGE_SIZE_4K-1))
-
/* Returns bit offset within a DWORD of a bitfield */
#define AMAP_BIT_OFFSET(_struct, field) \
(((size_t)&(((_struct *)0)->field))%32)
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index cdb1536..d2e9e93 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -15,6 +15,8 @@
* Costa Mesa, CA 92626
*/
+#include <scsi/iscsi_proto.h>
+
#include "be.h"
#include "be_mgmt.h"
#include "be_main.h"
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 8b40a5b4..b0b36c6 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -23,7 +23,7 @@
* firmware in the BE. These requests are communicated to the processor
* using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one
* WRB inside a MAILBOX.
- * The commands are serviced by the ARM processor in the BladeEngine's MPU.
+ * The commands are serviced by the ARM processor in the OneConnect's MPU.
*/
struct be_sge {
u32 pa_lo;
@@ -163,7 +163,8 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3
#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7
#define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14
-#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17
+#define OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR 17
+#define OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR 18
#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21
#define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22
#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23
@@ -274,15 +275,15 @@ struct mgmt_conn_login_options {
struct mgmt_auth_method_format auth_data;
} __packed;
-struct ip_address_format {
+struct ip_addr_format {
u16 size_of_structure;
u8 reserved;
u8 ip_type;
- u8 ip_address[16];
+ u8 addr[16];
u32 rsvd0;
} __packed;
-struct mgmt_conn_info {
+struct mgmt_conn_info {
u32 connection_handle;
u32 connection_status;
u16 src_port;
@@ -290,9 +291,9 @@ struct mgmt_conn_info {
u16 dest_port_redirected;
u16 cid;
u32 estimated_throughput;
- struct ip_address_format src_ipaddr;
- struct ip_address_format dest_ipaddr;
- struct ip_address_format dest_ipaddr_redirected;
+ struct ip_addr_format src_ipaddr;
+ struct ip_addr_format dest_ipaddr;
+ struct ip_addr_format dest_ipaddr_redirected;
struct mgmt_conn_login_options negotiated_login_options;
} __packed;
@@ -322,43 +323,115 @@ struct mgmt_session_info {
struct mgmt_conn_info conn_list[1];
} __packed;
-struct be_cmd_req_get_session {
+struct be_cmd_get_session_req {
struct be_cmd_req_hdr hdr;
u32 session_handle;
} __packed;
-struct be_cmd_resp_get_session {
+struct be_cmd_get_session_resp {
struct be_cmd_resp_hdr hdr;
struct mgmt_session_info session_info;
} __packed;
struct mac_addr {
- u16 size_of_struct;
+ u16 size_of_structure;
u8 addr[ETH_ALEN];
} __packed;
-struct be_cmd_req_get_boot_target {
+struct be_cmd_get_boot_target_req {
struct be_cmd_req_hdr hdr;
} __packed;
-struct be_cmd_resp_get_boot_target {
+struct be_cmd_get_boot_target_resp {
struct be_cmd_resp_hdr hdr;
u32 boot_session_count;
int boot_session_handle;
};
-struct be_cmd_req_mac_query {
+struct be_cmd_mac_query_req {
struct be_cmd_req_hdr hdr;
u8 type;
u8 permanent;
u16 if_id;
} __packed;
-struct be_cmd_resp_mac_query {
+struct be_cmd_get_mac_resp {
struct be_cmd_resp_hdr hdr;
struct mac_addr mac;
};
+struct be_ip_addr_subnet_format {
+ u16 size_of_structure;
+ u8 ip_type;
+ u8 ipv6_prefix_length;
+ u8 addr[16];
+ u8 subnet_mask[16];
+ u32 rsvd0;
+} __packed;
+
+struct be_cmd_get_if_info_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_get_if_info_resp {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 vlan_priority;
+ u32 ip_addr_count;
+ u32 dhcp_state;
+ struct be_ip_addr_subnet_format ip_addr;
+} __packed;
+
+struct be_ip_addr_record {
+ u32 action;
+ u32 interface_hndl;
+ struct be_ip_addr_subnet_format ip_addr;
+ u32 status;
+} __packed;
+
+struct be_ip_addr_record_params {
+ u32 record_entry_count;
+ struct be_ip_addr_record ip_record;
+} __packed;
+
+struct be_cmd_set_ip_addr_req {
+ struct be_cmd_req_hdr hdr;
+ struct be_ip_addr_record_params ip_params;
+} __packed;
+
+
+struct be_cmd_set_dhcp_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+ u32 flags;
+ u32 retry_count;
+} __packed;
+
+struct be_cmd_rel_dhcp_req {
+ struct be_cmd_req_hdr hdr;
+ u32 interface_hndl;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_set_def_gateway_req {
+ struct be_cmd_req_hdr hdr;
+ u32 action;
+ struct ip_addr_format ip_addr;
+} __packed;
+
+struct be_cmd_get_def_gateway_req {
+ struct be_cmd_req_hdr hdr;
+ u32 ip_type;
+} __packed;
+
+struct be_cmd_get_def_gateway_resp {
+ struct be_cmd_req_hdr hdr;
+ struct ip_addr_format ip_addr;
+} __packed;
+
/******************** Create CQ ***************************/
/**
* Pseudo amap definition in which each bit of the actual structure is defined
@@ -489,7 +562,7 @@ struct be_cmd_req_modify_eq_delay {
#define ETH_ALEN 6
-struct be_cmd_req_get_mac_addr {
+struct be_cmd_get_nic_conf_req {
struct be_cmd_req_hdr hdr;
u32 nic_port_count;
u32 speed;
@@ -501,7 +574,7 @@ struct be_cmd_req_get_mac_addr {
u32 rsvd[23];
};
-struct be_cmd_resp_get_mac_addr {
+struct be_cmd_get_nic_conf_resp {
struct be_cmd_resp_hdr hdr;
u32 nic_port_count;
u32 speed;
@@ -513,6 +586,39 @@ struct be_cmd_resp_get_mac_addr {
u32 rsvd[23];
};
+#define BEISCSI_ALIAS_LEN 32
+
+struct be_cmd_hba_name {
+ struct be_cmd_req_hdr hdr;
+ u16 flags;
+ u16 rsvd0;
+ u8 initiator_name[ISCSI_NAME_LEN];
+ u8 initiator_alias[BEISCSI_ALIAS_LEN];
+} __packed;
+
+struct be_cmd_ntwk_link_status_req {
+ struct be_cmd_req_hdr hdr;
+ u32 rsvd0;
+} __packed;
+
+/*** Port Speed Values ***/
+#define BE2ISCSI_LINK_SPEED_ZERO 0x00
+#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
+#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
+#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
+#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
+struct be_cmd_ntwk_link_status_resp {
+ struct be_cmd_resp_hdr hdr;
+ u8 phys_port;
+ u8 mac_duplex;
+ u8 mac_speed;
+ u8 mac_fault;
+ u8 mgmt_mac_duplex;
+ u8 mgmt_mac_speed;
+ u16 qos_link_speed;
+ u32 logical_link_speed;
+} __packed;
+
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay);
@@ -530,11 +636,8 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
int be_poll_mcc(struct be_ctrl_info *ctrl);
int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
-unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba);
-unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba);
-unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd);
+unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
+unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
/*ISCSI Functuions */
@@ -715,7 +818,7 @@ struct be_eq_delay_params_in {
struct tcp_connect_and_offload_in {
struct be_cmd_req_hdr hdr;
- struct ip_address_format ip_address;
+ struct ip_addr_format ip_address;
u16 tcp_port;
u16 cid;
u16 cq_id;
@@ -792,13 +895,14 @@ struct be_fw_cfg {
u32 function_caps;
} __packed;
-struct be_all_if_id {
+struct be_cmd_get_all_if_id_req {
struct be_cmd_req_hdr hdr;
u32 if_count;
u32 if_hndl_list[1];
} __packed;
#define ISCSI_OPCODE_SCSI_DATA_OUT 5
+#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
#define OPCODE_COMMON_ISCSI_CLEANUP 59
#define OPCODE_COMMON_TCP_UPLOAD 56
@@ -810,6 +914,8 @@ struct be_all_if_id {
#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41
#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
#define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET 52
+#define OPCODE_COMMON_WRITE_FLASH 96
+#define OPCODE_COMMON_READ_FLASH 97
/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
#define CMD_ISCSI_COMMAND_INVALIDATE 1
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 33c8f09..43f3503 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -23,6 +23,8 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_netlink.h>
+#include <net/netlink.h>
#include <scsi/scsi.h>
#include "be_iscsi.h"
@@ -207,6 +209,301 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
}
+static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba)
+{
+ if (phba->ipv4_iface)
+ return 0;
+
+ phba->ipv4_iface = iscsi_create_iface(phba->shost,
+ &beiscsi_iscsi_transport,
+ ISCSI_IFACE_TYPE_IPV4,
+ 0, 0);
+ if (!phba->ipv4_iface) {
+ shost_printk(KERN_ERR, phba->shost, "Could not "
+ "create default IPv4 address.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba)
+{
+ if (phba->ipv6_iface)
+ return 0;
+
+ phba->ipv6_iface = iscsi_create_iface(phba->shost,
+ &beiscsi_iscsi_transport,
+ ISCSI_IFACE_TYPE_IPV6,
+ 0, 0);
+ if (!phba->ipv6_iface) {
+ shost_printk(KERN_ERR, phba->shost, "Could not "
+ "create default IPv6 address.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void beiscsi_create_def_ifaces(struct beiscsi_hba *phba)
+{
+ struct be_cmd_get_if_info_resp if_info;
+
+ if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info))
+ beiscsi_create_ipv4_iface(phba);
+
+ if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info))
+ beiscsi_create_ipv6_iface(phba);
+}
+
+void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba)
+{
+ if (phba->ipv6_iface)
+ iscsi_destroy_iface(phba->ipv6_iface);
+ if (phba->ipv4_iface)
+ iscsi_destroy_iface(phba->ipv4_iface);
+}
+
+static int
+beiscsi_set_static_ip(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_iface_param_info *iface_ip = NULL;
+ struct iscsi_iface_param_info *iface_subnet = NULL;
+ struct nlattr *nla;
+ int ret;
+
+
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
+ if (nla)
+ iface_ip = nla_data(nla);
+
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
+ if (nla)
+ iface_subnet = nla_data(nla);
+ break;
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ iface_ip = iface_param;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
+ if (nla)
+ iface_subnet = nla_data(nla);
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ iface_subnet = iface_param;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
+ if (nla)
+ iface_ip = nla_data(nla);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Unsupported param %d\n",
+ iface_param->param);
+ }
+
+ if (!iface_ip || !iface_subnet) {
+ shost_printk(KERN_ERR, shost, "IP and Subnet Mask required\n");
+ return -EINVAL;
+ }
+
+ ret = mgmt_set_ip(phba, iface_ip, iface_subnet,
+ ISCSI_BOOTPROTO_STATIC);
+
+ return ret;
+}
+
+static int
+beiscsi_set_ipv4(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ int ret = 0;
+
+ /* Check the param */
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IPV4_GW:
+ ret = mgmt_set_gateway(phba, iface_param);
+ break;
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
+ ret = mgmt_set_ip(phba, iface_param,
+ NULL, ISCSI_BOOTPROTO_DHCP);
+ else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
+ ret = beiscsi_set_static_ip(shost, iface_param,
+ data, dt_len);
+ else
+ shost_printk(KERN_ERR, shost, "Invalid BOOTPROTO: %d\n",
+ iface_param->value[0]);
+ break;
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
+ ret = beiscsi_create_ipv4_iface(phba);
+ else
+ iscsi_destroy_iface(phba->ipv4_iface);
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ ret = beiscsi_set_static_ip(shost, iface_param,
+ data, dt_len);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Param %d not supported\n",
+ iface_param->param);
+ }
+
+ return ret;
+}
+
+static int
+beiscsi_set_ipv6(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ int ret = 0;
+
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
+ ret = beiscsi_create_ipv6_iface(phba);
+ else {
+ iscsi_destroy_iface(phba->ipv6_iface);
+ ret = 0;
+ }
+ break;
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ ret = mgmt_set_ip(phba, iface_param, NULL,
+ ISCSI_BOOTPROTO_STATIC);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost, "Param %d not supported\n",
+ iface_param->param);
+ }
+
+ return ret;
+}
+
+int be2iscsi_iface_set_param(struct Scsi_Host *shost,
+ void *data, uint32_t dt_len)
+{
+ struct iscsi_iface_param_info *iface_param = NULL;
+ struct nlattr *attrib;
+ uint32_t rm_len = dt_len;
+ int ret = 0 ;
+
+ nla_for_each_attr(attrib, data, dt_len, rm_len) {
+ iface_param = nla_data(attrib);
+
+ if (iface_param->param_type != ISCSI_NET_PARAM)
+ continue;
+
+ /*
+ * BE2ISCSI only supports 1 interface
+ */
+ if (iface_param->iface_num) {
+ shost_printk(KERN_ERR, shost, "Invalid iface_num %d."
+ "Only iface_num 0 is supported.\n",
+ iface_param->iface_num);
+ return -EINVAL;
+ }
+
+ switch (iface_param->iface_type) {
+ case ISCSI_IFACE_TYPE_IPV4:
+ ret = beiscsi_set_ipv4(shost, iface_param,
+ data, dt_len);
+ break;
+ case ISCSI_IFACE_TYPE_IPV6:
+ ret = beiscsi_set_ipv6(shost, iface_param,
+ data, dt_len);
+ break;
+ default:
+ shost_printk(KERN_ERR, shost,
+ "Invalid iface type :%d passed\n",
+ iface_param->iface_type);
+ break;
+ }
+
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
+ struct iscsi_iface *iface, int param,
+ char *buf)
+{
+ struct be_cmd_get_if_info_resp if_info;
+ int len, ip_type = BE2_IPV4;
+
+ memset(&if_info, 0, sizeof(if_info));
+
+ if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
+ ip_type = BE2_IPV6;
+
+ len = mgmt_get_if_info(phba, ip_type, &if_info);
+ if (len)
+ return len;
+
+ switch (param) {
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ len = sprintf(buf, "%pI4\n", &if_info.ip_addr.addr);
+ break;
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ len = sprintf(buf, "%pI6\n", &if_info.ip_addr.addr);
+ break;
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ if (!if_info.dhcp_state)
+ len = sprintf(buf, "static");
+ else
+ len = sprintf(buf, "dhcp");
+ break;
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ return len;
+}
+
+int be2iscsi_iface_get_param(struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct be_cmd_get_def_gateway_resp gateway;
+ int len = -ENOSYS;
+
+ switch (param) {
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ len = be2iscsi_get_if_param(phba, iface, param, buf);
+ break;
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ len = sprintf(buf, "enabled");
+ break;
+ case ISCSI_NET_PARAM_IPV4_GW:
+ memset(&gateway, 0, sizeof(gateway));
+ len = mgmt_get_gateway(phba, BE2_IPV4, &gateway);
+ if (!len)
+ len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr);
+ break;
+ default:
+ len = -ENOSYS;
+ }
+
+ return len;
+}
+
/**
* beiscsi_ep_get_param - get the iscsi parameter
* @ep: pointer to iscsi ep
@@ -221,7 +518,7 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
int len = 0;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param);
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_get_param, param= %d\n", param);
switch (param) {
case ISCSI_PARAM_CONN_PORT:
@@ -279,6 +576,121 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
}
/**
+ * beiscsi_get_initname - Read Initiator Name from flash
+ * @buf: buffer bointer
+ * @phba: The device priv structure instance
+ *
+ * returns number of bytes
+ */
+static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
+{
+ int rc;
+ unsigned int tag, wrb_num;
+ unsigned short status, extd_status;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_hba_name *resp;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+
+ tag = be_cmd_get_initname(phba);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "Getting Initiator Name Failed\n");
+ return -EBUSY;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with "
+ "status = %d extd_status = %d\n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -EAGAIN;
+ }
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = embedded_payload(wrb);
+ rc = sprintf(buf, "%s\n", resp->initiator_name);
+ return rc;
+}
+
+/**
+ * beiscsi_get_port_state - Get the Port State
+ * @shost : pointer to scsi_host structure
+ *
+ * returns number of bytes
+ */
+static void beiscsi_get_port_state(struct Scsi_Host *shost)
+{
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_cls_host *ihost = shost->shost_data;
+
+ ihost->port_state = (phba->state == BE_ADAPTER_UP) ?
+ ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
+}
+
+/**
+ * beiscsi_get_port_speed - Get the Port Speed from Adapter
+ * @shost : pointer to scsi_host structure
+ *
+ * returns Success/Failure
+ */
+static int beiscsi_get_port_speed(struct Scsi_Host *shost)
+{
+ unsigned int tag, wrb_num;
+ unsigned short status, extd_status;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_ntwk_link_status_resp *resp;
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct iscsi_cls_host *ihost = shost->shost_data;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+
+ tag = be_cmd_get_port_speed(phba);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "Getting Port Speed Failed\n");
+ return -EBUSY;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with "
+ "status = %d extd_status = %d\n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -EAGAIN;
+ }
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = embedded_payload(wrb);
+
+ switch (resp->mac_speed) {
+ case BE2ISCSI_LINK_SPEED_10MBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_100MBPS:
+ ihost->port_speed = BE2ISCSI_LINK_SPEED_100MBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_1GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_10GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;
+ break;
+ default:
+ ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;
+ }
+ return 0;
+}
+
+/**
* beiscsi_get_host_param - get the iscsi parameter
* @shost: pointer to scsi_host structure
* @param: parameter type identifier
@@ -301,6 +713,27 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
return status;
}
break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ status = beiscsi_get_initname(buf, phba);
+ if (status < 0) {
+ SE_DEBUG(DBG_LVL_1,
+ "Retreiving Initiator Name Failed\n");
+ return status;
+ }
+ break;
+ case ISCSI_HOST_PARAM_PORT_STATE:
+ beiscsi_get_port_state(shost);
+ status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
+ break;
+ case ISCSI_HOST_PARAM_PORT_SPEED:
+ status = beiscsi_get_port_speed(shost);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1,
+ "Retreiving Port Speed Failed\n");
+ return status;
+ }
+ status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
+ break;
default:
return iscsi_host_get_param(shost, param, buf);
}
@@ -309,46 +742,21 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)
{
- struct be_cmd_resp_get_mac_addr *resp;
- struct be_mcc_wrb *wrb;
- unsigned int tag, wrb_num;
- unsigned short status, extd_status;
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_cmd_get_nic_conf_resp resp;
int rc;
- if (phba->read_mac_address)
- return sysfs_format_mac(buf, phba->mac_address,
- ETH_ALEN);
+ if (strlen(phba->mac_address))
+ return strlcpy(buf, phba->mac_address, PAGE_SIZE);
- tag = be_cmd_get_mac_addr(phba);
- if (!tag) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
- return -EBUSY;
- } else
- wait_event_interruptible(phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag]);
+ memset(&resp, 0, sizeof(resp));
+ rc = mgmt_get_nic_conf(phba, &resp);
+ if (rc)
+ return rc;
- wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
- extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
- status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
- if (status || extd_status) {
- SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr"
- " status = %d extd_status = %d\n",
- status, extd_status);
- free_mcc_tag(&phba->ctrl, tag);
- return -EAGAIN;
- }
- wrb = queue_get_wrb(mccq, wrb_num);
- free_mcc_tag(&phba->ctrl, tag);
- resp = embedded_payload(wrb);
- memcpy(phba->mac_address, resp->mac_address, ETH_ALEN);
- rc = sysfs_format_mac(buf, phba->mac_address,
- ETH_ALEN);
- phba->read_mac_address = 1;
- return rc;
+ memcpy(phba->mac_address, resp.mac_address, ETH_ALEN);
+ return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
}
-
/**
* beiscsi_conn_get_stats - get the iscsi stats
* @cls_conn: pointer to iscsi cls conn
@@ -736,11 +1144,24 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
umode_t be2iscsi_attr_is_visible(int param_type, int param)
{
switch (param_type) {
+ case ISCSI_NET_PARAM:
+ switch (param) {
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ case ISCSI_NET_PARAM_IPV4_ADDR:
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+ case ISCSI_NET_PARAM_IPV4_GW:
+ case ISCSI_NET_PARAM_IPV6_ADDR:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
case ISCSI_HOST_PARAM:
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
- case ISCSI_HOST_PARAM_IPADDRESS:
case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ case ISCSI_HOST_PARAM_PORT_STATE:
+ case ISCSI_HOST_PARAM_PORT_SPEED:
return S_IRUGO;
default:
return 0;
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 5c45be1..8b826fc 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -25,6 +25,21 @@
#define BE2_IPV4 0x1
#define BE2_IPV6 0x10
+#define BE2_DHCP_V4 0x05
+
+#define NON_BLOCKING 0x0
+#define BLOCKING 0x1
+
+void beiscsi_create_def_ifaces(struct beiscsi_hba *phba);
+
+void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba);
+
+int be2iscsi_iface_get_param(struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf);
+
+int be2iscsi_iface_set_param(struct Scsi_Host *shost,
+ void *data, uint32_t count);
umode_t be2iscsi_attr_is_visible(int param_type, int param);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 375756f..0b1d99c 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -28,8 +28,11 @@
#include <linux/semaphore.h>
#include <linux/iscsi_boot_sysfs.h>
#include <linux/module.h>
+#include <linux/bsg-lib.h>
#include <scsi/libiscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
+#include <scsi/scsi_netlink.h>
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_cmnd.h>
@@ -48,7 +51,8 @@ static unsigned int num_hba = 0;
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
-MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_VERSION(BUILD_STR);
+MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");
module_param(be_iopoll_budget, int, 0);
module_param(enable_msix, int, 0);
@@ -147,15 +151,15 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
- int rc = FAILED;
/* invalidate iocbs */
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
spin_lock_bh(&session->lock);
- if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
- goto unlock;
-
+ if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
+ spin_unlock_bh(&session->lock);
+ return FAILED;
+ }
conn = session->leadconn;
beiscsi_conn = conn->dd_data;
phba = beiscsi_conn->phba;
@@ -208,9 +212,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
-unlock:
- spin_unlock_bh(&session->lock);
- return rc;
}
static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
@@ -230,10 +231,10 @@ static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
case ISCSI_BOOT_TGT_IP_ADDR:
if (boot_conn->dest_ipaddr.ip_type == 0x1)
rc = sprintf(buf, "%pI4\n",
- (char *)&boot_conn->dest_ipaddr.ip_address);
+ (char *)&boot_conn->dest_ipaddr.addr);
else
rc = sprintf(str, "%pI6\n",
- (char *)&boot_conn->dest_ipaddr.ip_address);
+ (char *)&boot_conn->dest_ipaddr.addr);
break;
case ISCSI_BOOT_TGT_PORT:
rc = sprintf(str, "%d\n", boot_conn->dest_port);
@@ -311,12 +312,8 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf)
rc = sprintf(str, "0\n");
break;
case ISCSI_BOOT_ETH_MAC:
- rc = beiscsi_get_macaddr(buf, phba);
- if (rc < 0) {
- SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n");
- return rc;
- }
- break;
+ rc = beiscsi_get_macaddr(str, phba);
+ break;
default:
rc = -ENOSYS;
break;
@@ -394,7 +391,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
static struct scsi_host_template beiscsi_sht = {
.module = THIS_MODULE,
- .name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
+ .name = "Emulex 10Gbe open-iscsi Initiator Driver",
.proc_name = DRV_NAME,
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
@@ -409,6 +406,8 @@ static struct scsi_host_template beiscsi_sht = {
.max_sectors = BEISCSI_MAX_SECTORS,
.cmd_per_lun = BEISCSI_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
+
};
static struct scsi_transport_template *beiscsi_scsi_transport;
@@ -435,6 +434,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
phba->shost = shost;
phba->pcidev = pci_dev_get(pcidev);
pci_set_drvdata(pcidev, phba);
+ phba->interface_handle = 0xFFFFFFFF;
if (iscsi_host_add(shost, &phba->pcidev->dev))
goto free_devices;
@@ -544,8 +544,7 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
&mbox_mem_alloc->dma);
if (!mbox_mem_alloc->va) {
beiscsi_unmap_pci_function(phba);
- status = -ENOMEM;
- return status;
+ return -ENOMEM;
}
mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
@@ -1252,9 +1251,9 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
task = pwrb_handle->pio_handle;
io_task = task->dd_data;
- spin_lock(&phba->mgmt_sgl_lock);
+ spin_lock_bh(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->mgmt_sgl_lock);
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
spin_lock_bh(&session->lock);
free_wrb_handle(phba, pwrb_context, pwrb_handle);
spin_unlock_bh(&session->lock);
@@ -1370,8 +1369,6 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
struct be_bus_address phys_addr;
struct list_head *pbusy_list;
struct async_pdu_handle *pasync_handle = NULL;
- int buffer_len = 0;
- unsigned char buffer_index = -1;
unsigned char is_header = 0;
phys_addr.u.a32.address_lo =
@@ -1392,22 +1389,11 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1,
(pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
index) / 32] & PDUCQE_INDEX_MASK));
-
- buffer_len = (unsigned int)(phys_addr.u.a64.address -
- pasync_ctx->async_header.pa_base.u.a64.address);
-
- buffer_index = buffer_len /
- pasync_ctx->async_header.buffer_size;
-
break;
case UNSOL_DATA_NOTIFY:
pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe->
dw[offsetof(struct amap_i_t_dpdu_cqe,
index) / 32] & PDUCQE_INDEX_MASK));
- buffer_len = (unsigned long)(phys_addr.u.a64.address -
- pasync_ctx->async_data.pa_base.u.
- a64.address);
- buffer_index = buffer_len / pasync_ctx->async_data.buffer_size;
break;
default:
pbusy_list = NULL;
@@ -1418,11 +1404,9 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
return NULL;
}
- WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries));
WARN_ON(list_empty(pbusy_list));
list_for_each_entry(pasync_handle, pbusy_list, link) {
- WARN_ON(pasync_handle->consumed);
- if (pasync_handle->index == buffer_index)
+ if (pasync_handle->pa.u.a64.address == phys_addr.u.a64.address)
break;
}
@@ -1449,15 +1433,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
unsigned int num_entries, writables = 0;
unsigned int *pep_read_ptr, *pwritables;
-
+ num_entries = pasync_ctx->num_entries;
if (is_header) {
pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr;
pwritables = &pasync_ctx->async_header.writables;
- num_entries = pasync_ctx->async_header.num_entries;
} else {
pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr;
pwritables = &pasync_ctx->async_data.writables;
- num_entries = pasync_ctx->async_data.num_entries;
}
while ((*pep_read_ptr) != cq_index) {
@@ -1491,14 +1473,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
return 0;
}
-static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
+static void hwi_free_async_msg(struct beiscsi_hba *phba,
unsigned int cri)
{
struct hwi_controller *phwi_ctrlr;
struct hwi_async_pdu_context *pasync_ctx;
struct async_pdu_handle *pasync_handle, *tmp_handle;
struct list_head *plist;
- unsigned int i = 0;
phwi_ctrlr = phba->phwi_ctrlr;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
@@ -1508,23 +1489,20 @@ static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
list_del(&pasync_handle->link);
- if (i == 0) {
+ if (pasync_handle->is_header) {
list_add_tail(&pasync_handle->link,
&pasync_ctx->async_header.free_list);
pasync_ctx->async_header.free_entries++;
- i++;
} else {
list_add_tail(&pasync_handle->link,
&pasync_ctx->async_data.free_list);
pasync_ctx->async_data.free_entries++;
- i++;
}
}
INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list);
pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0;
pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
- return 0;
}
static struct phys_addr *
@@ -1557,16 +1535,15 @@ static void hwi_post_async_buffers(struct beiscsi_hba *phba,
phwi_ctrlr = phba->phwi_ctrlr;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+ num_entries = pasync_ctx->num_entries;
if (is_header) {
- num_entries = pasync_ctx->async_header.num_entries;
writables = min(pasync_ctx->async_header.writables,
pasync_ctx->async_header.free_entries);
pfree_link = pasync_ctx->async_header.free_list.next;
host_write_num = pasync_ctx->async_header.host_write_ptr;
ring_id = phwi_ctrlr->default_pdu_hdr.id;
} else {
- num_entries = pasync_ctx->async_data.num_entries;
writables = min(pasync_ctx->async_data.writables,
pasync_ctx->async_data.free_entries);
pfree_link = pasync_ctx->async_data.free_list.next;
@@ -1673,7 +1650,7 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
}
memcpy(pfirst_buffer + offset,
pasync_handle->pbuffer, buf_len);
- offset = buf_len;
+ offset += buf_len;
}
index++;
}
@@ -1682,10 +1659,9 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
(beiscsi_conn->beiscsi_conn_cid -
phba->fw_config.iscsi_cid_start),
phdr, hdr_len, pfirst_buffer,
- buf_len);
+ offset);
- if (status == 0)
- hwi_free_async_msg(phba, cri);
+ hwi_free_async_msg(phba, cri);
return 0;
}
@@ -2229,7 +2205,7 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
struct mem_array *mem_arr, *mem_arr_orig;
unsigned int i, j, alloc_size, curr_alloc_size;
- phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
+ phba->phwi_ctrlr = kzalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
if (!phba->phwi_ctrlr)
return -ENOMEM;
@@ -2349,27 +2325,21 @@ static void iscsi_init_global_templates(struct beiscsi_hba *phba)
AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0);
}
-static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
+static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
{
struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb;
- struct wrb_handle *pwrb_handle;
+ struct wrb_handle *pwrb_handle = NULL;
struct hwi_controller *phwi_ctrlr;
struct hwi_wrb_context *pwrb_context;
- struct iscsi_wrb *pwrb;
- unsigned int num_cxn_wrbh;
- unsigned int num_cxn_wrb, j, idx, index;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int num_cxn_wrbh = 0;
+ unsigned int num_cxn_wrb = 0, j, idx = 0, index;
mem_descr_wrbh = phba->init_mem;
mem_descr_wrbh += HWI_MEM_WRBH;
mem_descr_wrb = phba->init_mem;
mem_descr_wrb += HWI_MEM_WRB;
-
- idx = 0;
- pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address;
- num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
- ((sizeof(struct wrb_handle)) *
- phba->params.wrbs_per_cxn));
phwi_ctrlr = phba->phwi_ctrlr;
for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
@@ -2377,12 +2347,32 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_context->pwrb_handle_base =
kzalloc(sizeof(struct wrb_handle *) *
phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (!pwrb_context->pwrb_handle_base) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ goto init_wrb_hndl_failed;
+ }
pwrb_context->pwrb_handle_basestd =
kzalloc(sizeof(struct wrb_handle *) *
phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (!pwrb_context->pwrb_handle_basestd) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ goto init_wrb_hndl_failed;
+ }
+ if (!num_cxn_wrbh) {
+ pwrb_handle =
+ mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ idx++;
+ }
+ pwrb_context->alloc_index = 0;
+ pwrb_context->wrb_handles_available = 0;
+ pwrb_context->free_index = 0;
+
if (num_cxn_wrbh) {
- pwrb_context->alloc_index = 0;
- pwrb_context->wrb_handles_available = 0;
for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
pwrb_context->pwrb_handle_base[j] = pwrb_handle;
pwrb_context->pwrb_handle_basestd[j] =
@@ -2391,49 +2381,21 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
pwrb_handle->wrb_index = j;
pwrb_handle++;
}
- pwrb_context->free_index = 0;
- num_cxn_wrbh--;
- } else {
- idx++;
- pwrb_handle =
- mem_descr_wrbh->mem_array[idx].virtual_address;
- num_cxn_wrbh =
- ((mem_descr_wrbh->mem_array[idx].size) /
- ((sizeof(struct wrb_handle)) *
- phba->params.wrbs_per_cxn));
- pwrb_context->alloc_index = 0;
- for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
- pwrb_context->pwrb_handle_base[j] = pwrb_handle;
- pwrb_context->pwrb_handle_basestd[j] =
- pwrb_handle;
- pwrb_context->wrb_handles_available++;
- pwrb_handle->wrb_index = j;
- pwrb_handle++;
- }
- pwrb_context->free_index = 0;
num_cxn_wrbh--;
}
}
idx = 0;
- pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
- num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
- ((sizeof(struct iscsi_wrb) *
- phba->params.wrbs_per_cxn));
for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
pwrb_context = &phwi_ctrlr->wrb_context[index];
- if (num_cxn_wrb) {
- for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
- pwrb_handle = pwrb_context->pwrb_handle_base[j];
- pwrb_handle->pwrb = pwrb;
- pwrb++;
- }
- num_cxn_wrb--;
- } else {
- idx++;
+ if (!num_cxn_wrb) {
pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
- ((sizeof(struct iscsi_wrb) *
- phba->params.wrbs_per_cxn));
+ ((sizeof(struct iscsi_wrb) *
+ phba->params.wrbs_per_cxn));
+ idx++;
+ }
+
+ if (num_cxn_wrb) {
for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
pwrb_handle = pwrb_context->pwrb_handle_base[j];
pwrb_handle->pwrb = pwrb;
@@ -2442,6 +2404,14 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
num_cxn_wrb--;
}
}
+ return 0;
+init_wrb_hndl_failed:
+ for (j = index; j > 0; j--) {
+ pwrb_context = &phwi_ctrlr->wrb_context[j];
+ kfree(pwrb_context->pwrb_handle_base);
+ kfree(pwrb_context->pwrb_handle_basestd);
+ }
+ return -ENOMEM;
}
static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
@@ -2450,7 +2420,7 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
struct hba_parameters *p = &phba->params;
struct hwi_async_pdu_context *pasync_ctx;
struct async_pdu_handle *pasync_header_h, *pasync_data_h;
- unsigned int index;
+ unsigned int index, idx, num_per_mem, num_async_data;
struct be_mem_descriptor *mem_descr;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
@@ -2462,10 +2432,8 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx;
memset(pasync_ctx, 0, sizeof(*pasync_ctx));
- pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl;
- pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz;
- pasync_ctx->async_data.buffer_size = p->defpdu_data_sz;
- pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->buffer_size = p->defpdu_hdr_sz;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_BUF;
@@ -2510,19 +2478,6 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_header.writables = 0;
INIT_LIST_HEAD(&pasync_ctx->async_header.free_list);
- mem_descr = (struct be_mem_descriptor *)phba->init_mem;
- mem_descr += HWI_MEM_ASYNC_DATA_BUF;
- if (mem_descr->mem_array[0].virtual_address) {
- SE_DEBUG(DBG_LVL_8,
- "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
- "va=%p\n", mem_descr->mem_array[0].virtual_address);
- } else
- shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address\n");
- pasync_ctx->async_data.va_base =
- mem_descr->mem_array[0].virtual_address;
- pasync_ctx->async_data.pa_base.u.a64.address =
- mem_descr->mem_array[0].bus_address.u.a64.address;
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_RING;
@@ -2553,6 +2508,25 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_data_h =
(struct async_pdu_handle *)pasync_ctx->async_data.handle_base;
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address\n");
+ idx = 0;
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[idx].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[idx].bus_address.u.a64.address;
+
+ num_async_data = ((mem_descr->mem_array[idx].size) /
+ phba->params.defpdu_data_sz);
+ num_per_mem = 0;
+
for (index = 0; index < p->asyncpdus_per_ctrl; index++) {
pasync_header_h->cri = -1;
pasync_header_h->index = (char)index;
@@ -2578,14 +2552,29 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_data_h->cri = -1;
pasync_data_h->index = (char)index;
INIT_LIST_HEAD(&pasync_data_h->link);
+
+ if (!num_async_data) {
+ num_per_mem = 0;
+ idx++;
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[idx].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[idx].
+ bus_address.u.a64.address;
+
+ num_async_data = ((mem_descr->mem_array[idx].size) /
+ phba->params.defpdu_data_sz);
+ }
pasync_data_h->pbuffer =
(void *)((unsigned long)
(pasync_ctx->async_data.va_base) +
- (p->defpdu_data_sz * index));
+ (p->defpdu_data_sz * num_per_mem));
pasync_data_h->pa.u.a64.address =
pasync_ctx->async_data.pa_base.u.a64.address +
- (p->defpdu_data_sz * index);
+ (p->defpdu_data_sz * num_per_mem);
+ num_per_mem++;
+ num_async_data--;
list_add_tail(&pasync_data_h->link,
&pasync_ctx->async_data.free_list);
@@ -2913,9 +2902,11 @@ beiscsi_post_pages(struct beiscsi_hba *phba)
static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
- if (mem->va)
+ if (mem->va) {
pci_free_consistent(phba->pcidev, mem->size,
mem->va, mem->dma);
+ mem->va = NULL;
+ }
}
static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q,
@@ -3215,7 +3206,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
error:
shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed");
hwi_cleanup(phba);
- return -ENOMEM;
+ return status;
}
static int hwi_init_controller(struct beiscsi_hba *phba)
@@ -3236,7 +3227,9 @@ static int hwi_init_controller(struct beiscsi_hba *phba)
}
iscsi_init_global_templates(phba);
- beiscsi_init_wrb_handle(phba);
+ if (beiscsi_init_wrb_handle(phba))
+ return -ENOMEM;
+
hwi_init_async_pdu_ctx(phba);
if (hwi_init_port(phba) != 0) {
shost_printk(KERN_ERR, phba->shost,
@@ -3288,7 +3281,7 @@ static int beiscsi_init_controller(struct beiscsi_hba *phba)
free_init:
beiscsi_free_mem(phba);
- return -ENOMEM;
+ return ret;
}
static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
@@ -3475,8 +3468,8 @@ static void hwi_disable_intr(struct beiscsi_hba *phba)
static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
{
- struct be_cmd_resp_get_boot_target *boot_resp;
- struct be_cmd_resp_get_session *session_resp;
+ struct be_cmd_get_boot_target_resp *boot_resp;
+ struct be_cmd_get_session_resp *session_resp;
struct be_mcc_wrb *wrb;
struct be_dma_mem nonemb_cmd;
unsigned int tag, wrb_num;
@@ -3484,9 +3477,9 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
int ret = -ENOMEM;
- tag = beiscsi_get_boot_target(phba);
+ tag = mgmt_get_boot_target(phba);
if (!tag) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+ SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed\n");
return -EAGAIN;
} else
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
@@ -3496,7 +3489,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
if (status || extd_status) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+ SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed"
" status = %d extd_status = %d\n",
status, extd_status);
free_mcc_tag(&phba->ctrl, tag);
@@ -3522,8 +3515,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
}
memset(nonemb_cmd.va, 0, sizeof(*session_resp));
- tag = beiscsi_get_session_info(phba,
- boot_resp->boot_session_handle, &nonemb_cmd);
+ tag = mgmt_get_session_info(phba, boot_resp->boot_session_handle,
+ &nonemb_cmd);
if (!tag) {
SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info"
" Failed\n");
@@ -3696,6 +3689,57 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
kfree(phba->ep_array);
}
+static void beiscsi_cleanup_task(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid
+ - phba->fw_config.iscsi_cid_start];
+
+ if (io_task->cmd_bhs) {
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ io_task->cmd_bhs = NULL;
+ }
+
+ if (task->sc) {
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context,
+ io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->io_sgl_lock);
+ free_io_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->io_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ } else {
+ if (!beiscsi_conn->login_in_progress) {
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context,
+ io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba,
+ io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ }
+ }
+}
+
void
beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_offload_params *params)
@@ -3704,12 +3748,19 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct iscsi_target_context_update_wrb *pwrb = NULL;
struct be_mem_descriptor *mem_descr;
struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_task *task = beiscsi_conn->task;
+ struct iscsi_session *session = task->conn->session;
u32 doorbell = 0;
/*
* We can always use 0 here because it is reserved by libiscsi for
* login/startup related tasks.
*/
+ beiscsi_conn->login_in_progress = 0;
+ spin_lock_bh(&session->lock);
+ beiscsi_cleanup_task(task);
+ spin_unlock_bh(&session->lock);
+
pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid -
phba->fw_config.iscsi_cid_start));
pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
@@ -3823,7 +3874,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
task->hdr_max = sizeof(struct be_cmd_bhs);
io_task->psgl_handle = NULL;
- io_task->psgl_handle = NULL;
+ io_task->pwrb_handle = NULL;
if (task->sc) {
spin_lock(&phba->io_sgl_lock);
@@ -3865,6 +3916,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->pwrb_handle =
beiscsi_conn->plogin_wrb_handle;
}
+ beiscsi_conn->task = task;
} else {
spin_lock(&phba->mgmt_sgl_lock);
io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
@@ -3907,53 +3959,11 @@ free_hndls:
io_task->pwrb_handle = NULL;
pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
io_task->bhs_pa.u.a64.address);
+ io_task->cmd_bhs = NULL;
SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n");
return -ENOMEM;
}
-static void beiscsi_cleanup_task(struct iscsi_task *task)
-{
- struct beiscsi_io_task *io_task = task->dd_data;
- struct iscsi_conn *conn = task->conn;
- struct beiscsi_conn *beiscsi_conn = conn->dd_data;
- struct beiscsi_hba *phba = beiscsi_conn->phba;
- struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
- struct hwi_wrb_context *pwrb_context;
- struct hwi_controller *phwi_ctrlr;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid
- - phba->fw_config.iscsi_cid_start];
- if (io_task->pwrb_handle) {
- free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
- io_task->pwrb_handle = NULL;
- }
-
- if (io_task->cmd_bhs) {
- pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
- io_task->bhs_pa.u.a64.address);
- }
-
- if (task->sc) {
- if (io_task->psgl_handle) {
- spin_lock(&phba->io_sgl_lock);
- free_io_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->io_sgl_lock);
- io_task->psgl_handle = NULL;
- }
- } else {
- if (task->hdr &&
- ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN))
- return;
- if (io_task->psgl_handle) {
- spin_lock(&phba->mgmt_sgl_lock);
- free_mgmt_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->mgmt_sgl_lock);
- io_task->psgl_handle = NULL;
- }
- }
-}
-
static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
unsigned int num_sg, unsigned int xferlen,
unsigned int writedir)
@@ -3993,7 +4003,8 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
&io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun));
AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb,
- cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun));
+ cpu_to_be16(*(unsigned short *)
+ &io_task->cmd_bhs->iscsi_hdr.lun));
AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen);
AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
io_task->pwrb_handle->wrb_index);
@@ -4126,6 +4137,76 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
}
+/**
+ * beiscsi_bsg_request - handle bsg request from ISCSI transport
+ * @job: job to handle
+ */
+static int beiscsi_bsg_request(struct bsg_job *job)
+{
+ struct Scsi_Host *shost;
+ struct beiscsi_hba *phba;
+ struct iscsi_bsg_request *bsg_req = job->request;
+ int rc = -EINVAL;
+ unsigned int tag;
+ struct be_dma_mem nonemb_cmd;
+ struct be_cmd_resp_hdr *resp;
+ struct iscsi_bsg_reply *bsg_reply = job->reply;
+ unsigned short status, extd_status;
+
+ shost = iscsi_job_to_shost(job);
+ phba = iscsi_host_priv(shost);
+
+ switch (bsg_req->msgcode) {
+ case ISCSI_BSG_HST_VENDOR:
+ nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ job->request_payload.payload_len,
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for "
+ "beiscsi_bsg_request\n");
+ return -EIO;
+ }
+ tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job,
+ &nonemb_cmd);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return -EAGAIN;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va;
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ nonemb_cmd.va, (resp->response_length
+ + sizeof(*resp)));
+ bsg_reply->reply_payload_rcv_len = resp->response_length;
+ bsg_reply->result = status;
+ bsg_job_done(job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+ " status = %d extd_status = %d\n",
+ status, extd_status);
+ return -EIO;
+ }
+ break;
+
+ default:
+ SE_DEBUG(DBG_LVL_1, "Unsupported bsg command: 0x%x\n",
+ bsg_req->msgcode);
+ break;
+ }
+
+ return rc;
+}
+
static void beiscsi_quiesce(struct beiscsi_hba *phba)
{
struct hwi_controller *phwi_ctrlr;
@@ -4183,6 +4264,7 @@ static void beiscsi_remove(struct pci_dev *pcidev)
return;
}
+ beiscsi_destroy_def_ifaces(phba);
beiscsi_quiesce(phba);
iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
@@ -4267,8 +4349,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
phba->num_cpus = num_cpus;
SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus);
- if (enable_msix)
+ if (enable_msix) {
beiscsi_msix_enable(phba);
+ if (!phba->msix_enabled)
+ phba->num_cpus = 1;
+ }
ret = be_ctrl_init(phba, pcidev);
if (ret) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
@@ -4366,8 +4451,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
* iscsi boot.
*/
shost_printk(KERN_ERR, phba->shost, "Could not set up "
- "iSCSI boot info.");
+ "iSCSI boot info.\n");
+ beiscsi_create_def_ifaces(phba);
SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n");
return 0;
@@ -4418,6 +4504,8 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.bind_conn = beiscsi_conn_bind,
.destroy_conn = iscsi_conn_teardown,
.attr_is_visible = be2iscsi_attr_is_visible,
+ .set_iface_param = be2iscsi_iface_set_param,
+ .get_iface_param = be2iscsi_iface_get_param,
.set_param = beiscsi_set_param,
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
@@ -4435,6 +4523,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.ep_poll = beiscsi_ep_poll,
.ep_disconnect = beiscsi_ep_disconnect,
.session_recovery_timedout = iscsi_session_recovery_timedout,
+ .bsg_request = beiscsi_bsg_request,
};
static struct pci_driver beiscsi_pci_driver = {
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index b4a06d5..40fea6e 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -34,9 +34,9 @@
#include "be.h"
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "4.1.239.0"
-#define BE_NAME "ServerEngines BladeEngine2" \
- "Linux iSCSI Driver version" BUILD_STR
+#define BUILD_STR "4.2.162.0"
+#define BE_NAME "Emulex OneConnect" \
+ "Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
#define BE_VENDOR_ID 0x19A2
@@ -316,6 +316,8 @@ struct beiscsi_hba {
struct iscsi_endpoint **ep_array;
struct iscsi_boot_kset *boot_kset;
struct Scsi_Host *shost;
+ struct iscsi_iface *ipv4_iface;
+ struct iscsi_iface *ipv6_iface;
struct {
/**
* group together since they are used most frequently
@@ -345,7 +347,7 @@ struct beiscsi_hba {
struct work_struct work_cqs; /* The work being queued */
struct be_ctrl_info ctrl;
unsigned int generation;
- unsigned int read_mac_address;
+ unsigned int interface_handle;
struct mgmt_session_info boot_sess;
struct invalidate_command_table inv_tbl[128];
@@ -525,8 +527,6 @@ struct hwi_async_pdu_context {
unsigned int free_entries;
unsigned int busy_entries;
- unsigned int buffer_size;
- unsigned int num_entries;
struct list_head free_list;
} async_header;
@@ -543,11 +543,12 @@ struct hwi_async_pdu_context {
unsigned int free_entries;
unsigned int busy_entries;
- unsigned int buffer_size;
struct list_head free_list;
- unsigned int num_entries;
} async_data;
+ unsigned int buffer_size;
+ unsigned int num_entries;
+
/**
* This is a varying size list! Do not add anything
* after this entry!!
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 44762cf..01bb04c 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -17,15 +17,17 @@
* Costa Mesa, CA 92626
*/
+#include <linux/bsg-lib.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
#include "be_mgmt.h"
#include "be_iscsi.h"
-#include <scsi/scsi_transport_iscsi.h>
-unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba)
+unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
- struct be_cmd_req_get_mac_addr *req;
+ struct be_cmd_get_boot_target_req *req;
unsigned int tag = 0;
SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n");
@@ -42,22 +44,22 @@ unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba)
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
- sizeof(*req));
+ sizeof(struct be_cmd_get_boot_target_resp));
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
return tag;
}
-unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd)
+unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
+ u32 boot_session_handle,
+ struct be_dma_mem *nonemb_cmd)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
unsigned int tag = 0;
- struct be_cmd_req_get_session *req;
- struct be_cmd_resp_get_session *resp;
+ struct be_cmd_get_session_req *req;
+ struct be_cmd_get_session_resp *resp;
struct be_sge *sge;
SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n");
@@ -187,6 +189,72 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
return status;
}
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba,
+ struct bsg_job *job,
+ struct be_dma_mem *nonemb_cmd)
+{
+ struct be_cmd_resp_hdr *resp;
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+ struct be_sge *mcc_sge = nonembedded_sgl(wrb);
+ unsigned int tag = 0;
+ struct iscsi_bsg_request *bsg_req = job->request;
+ struct be_bsg_vendor_cmd *req = nonemb_cmd->va;
+ unsigned short region, sector_size, sector, offset;
+
+ nonemb_cmd->size = job->request_payload.payload_len;
+ memset(nonemb_cmd->va, 0, nonemb_cmd->size);
+ resp = nonemb_cmd->va;
+ region = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
+ sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+ sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3];
+ offset = bsg_req->rqst_data.h_vendor.vendor_cmd[4];
+ req->region = region;
+ req->sector = sector;
+ req->offset = offset;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
+ case BEISCSI_WRITE_FLASH:
+ offset = sector * sector_size + offset;
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_WRITE_FLASH, sizeof(*req));
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ nonemb_cmd->va + offset, job->request_len);
+ break;
+ case BEISCSI_READ_FLASH:
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_READ_FLASH, sizeof(*req));
+ break;
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unsupported cmd = 0x%x\n\n", bsg_req->rqst_data.
+ h_vendor.vendor_cmd[0]);
+ spin_unlock(&ctrl->mbox_lock);
+ return -ENOSYS;
+ }
+
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
+ job->request_payload.sg_cnt);
+ mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
+ wrb->tag0 |= tag;
+
+ be_mcc_notify(phba);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+}
+
int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
@@ -328,7 +396,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr *dst_addr,
struct beiscsi_endpoint *beiscsi_ep,
struct be_dma_mem *nonemb_cmd)
-
{
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
@@ -374,17 +441,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
if (dst_addr->sa_family == PF_INET) {
__be32 s_addr = daddr_in->sin_addr.s_addr;
req->ip_address.ip_type = BE2_IPV4;
- req->ip_address.ip_address[0] = s_addr & 0x000000ff;
- req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8;
- req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16;
- req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24;
+ req->ip_address.addr[0] = s_addr & 0x000000ff;
+ req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8;
+ req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16;
+ req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24;
req->tcp_port = ntohs(daddr_in->sin_port);
beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
beiscsi_ep->ip_type = BE2_IPV4;
} else if (dst_addr->sa_family == PF_INET6) {
req->ip_address.ip_type = BE2_IPV6;
- memcpy(&req->ip_address.ip_address,
+ memcpy(&req->ip_address.addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
req->tcp_port = ntohs(daddr_in6->sin6_port);
beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
@@ -419,14 +486,399 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
return tag;
}
-unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba)
+unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_req_get_mac_addr *req;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb);
+ struct be_cmd_get_all_if_id_req *pbe_allid = req;
+ int status = 0;
+
+ memset(wrb, 0, sizeof(*wrb));
+
+ spin_lock(&ctrl->mbox_lock);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
+ sizeof(*req));
+ status = be_mbox_notify(ctrl);
+ if (!status)
+ phba->interface_handle = pbe_allid->if_hndl_list[0];
+ else {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed in mgmt_get_all_if_id\n");
+ }
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
+ struct be_dma_mem *nonemb_cmd, void *resp_buf,
+ int resp_buf_len)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+ unsigned short status, extd_status;
+ struct be_sge *sge;
+ unsigned int tag;
+ int rc = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ rc = -ENOMEM;
+ goto free_cmd;
+ }
+ memset(wrb, 0, sizeof(*wrb));
+ wrb->tag0 |= tag;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
+
+ be_mcc_notify(phba);
+ spin_unlock(&ctrl->mbox_lock);
+
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1,
+ "mgmt_exec_nonemb_cmd Failed status = %d"
+ "extd_status = %d\n", status, extd_status);
+ rc = -EIO;
+ goto free_tag;
+ }
+
+ if (resp_buf)
+ memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
+
+free_tag:
+ free_mcc_tag(&phba->ctrl, tag);
+free_cmd:
+ pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
+ nonemb_cmd->va, nonemb_cmd->dma);
+ return rc;
+}
+
+static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd,
+ int iscsi_cmd, int size)
+{
+ cmd->va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(size),
+ &cmd->dma);
+ if (!cmd->va) {
+ SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for if info\n");
+ return -ENOMEM;
+ }
+ memset(cmd->va, 0, sizeof(size));
+ cmd->size = size;
+ be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size);
+ return 0;
+}
+
+static int
+mgmt_static_ip_modify(struct beiscsi_hba *phba,
+ struct be_cmd_get_if_info_resp *if_info,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t ip_action)
+{
+ struct be_cmd_set_ip_addr_req *req;
+ struct be_dma_mem nonemb_cmd;
+ uint32_t ip_type;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
+ sizeof(*req));
+ if (rc)
+ return rc;
+
+ ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ BE2_IPV6 : BE2_IPV4 ;
+
+ req = nonemb_cmd.va;
+ req->ip_params.record_entry_count = 1;
+ req->ip_params.ip_record.action = ip_action;
+ req->ip_params.ip_record.interface_hndl =
+ phba->interface_handle;
+ req->ip_params.ip_record.ip_addr.size_of_structure =
+ sizeof(struct be_ip_addr_subnet_format);
+ req->ip_params.ip_record.ip_addr.ip_type = ip_type;
+
+ if (ip_action == IP_ACTION_ADD) {
+ memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value,
+ ip_param->len);
+
+ if (subnet_param)
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ subnet_param->value, subnet_param->len);
+ } else {
+ memcpy(req->ip_params.ip_record.ip_addr.addr,
+ if_info->ip_addr.addr, ip_param->len);
+
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ if_info->ip_addr.subnet_mask, ip_param->len);
+ }
+
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0)
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Modify existing IP Address\n");
+ return rc;
+}
+
+static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr,
+ uint32_t gtway_action, uint32_t param_len)
+{
+ struct be_cmd_set_def_gateway_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rt_val;
+
+
+ rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY,
+ sizeof(*req));
+ if (rt_val)
+ return rt_val;
+
+ req = nonemb_cmd.va;
+ req->action = gtway_action;
+ req->ip_addr.ip_type = BE2_IPV4;
+
+ memcpy(req->ip_addr.addr, gt_addr, param_len);
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+}
+
+int mgmt_set_ip(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t boot_proto)
+{
+ struct be_cmd_get_def_gateway_resp gtway_addr_set;
+ struct be_cmd_get_if_info_resp if_info;
+ struct be_cmd_set_dhcp_req *dhcpreq;
+ struct be_cmd_rel_dhcp_req *reldhcp;
+ struct be_dma_mem nonemb_cmd;
+ uint8_t *gtway_addr;
+ uint32_t ip_type;
+ int rc;
+
+ if (mgmt_get_all_if_id(phba))
+ return -EIO;
+
+ memset(&if_info, 0, sizeof(if_info));
+ ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ BE2_IPV6 : BE2_IPV4 ;
+
+ rc = mgmt_get_if_info(phba, ip_type, &if_info);
+ if (rc)
+ return rc;
+
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ if (if_info.dhcp_state) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "DHCP Already Enabled\n");
+ return 0;
+ }
+ /* The ip_param->len is 1 in DHCP case. Setting
+ proper IP len as this it is used while
+ freeing the Static IP.
+ */
+ ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
+ IP_V6_LEN : IP_V4_LEN;
+
+ } else {
+ if (if_info.dhcp_state) {
+
+ memset(&if_info, 0, sizeof(if_info));
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR,
+ sizeof(*reldhcp));
+
+ if (rc)
+ return rc;
+
+ reldhcp = nonemb_cmd.va;
+ reldhcp->interface_hndl = phba->interface_handle;
+ reldhcp->ip_type = ip_type;
+
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Delete existing dhcp\n");
+ return rc;
+ }
+ }
+ }
+
+ /* Delete the Static IP Set */
+ if (if_info.ip_addr.addr[0]) {
+ rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL,
+ IP_ACTION_DEL);
+ if (rc)
+ return rc;
+ }
+
+ /* Delete the Gateway settings if mode change is to DHCP */
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
+ rc = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
+ if (rc) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Get Gateway Addr\n");
+ return rc;
+ }
+
+ if (gtway_addr_set.ip_addr.addr[0]) {
+ gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
+ rc = mgmt_modify_gateway(phba, gtway_addr,
+ IP_ACTION_DEL, IP_V4_LEN);
+
+ if (rc) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to clear Gateway Addr Set\n");
+ return rc;
+ }
+ }
+ }
+
+ /* Set Adapter to DHCP/Static Mode */
+ if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR,
+ sizeof(*dhcpreq));
+ if (rc)
+ return rc;
+
+ dhcpreq = nonemb_cmd.va;
+ dhcpreq->flags = BLOCKING;
+ dhcpreq->retry_count = 1;
+ dhcpreq->interface_hndl = phba->interface_handle;
+ dhcpreq->ip_type = BE2_DHCP_V4;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ } else {
+ return mgmt_static_ip_modify(phba, &if_info, ip_param,
+ subnet_param, IP_ACTION_ADD);
+ }
+
+ return rc;
+}
+
+int mgmt_set_gateway(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *gateway_param)
+{
+ struct be_cmd_get_def_gateway_resp gtway_addr_set;
+ uint8_t *gtway_addr;
+ int rt_val;
+
+ memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
+ rt_val = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
+ if (rt_val) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Get Gateway Addr\n");
+ return rt_val;
+ }
+
+ if (gtway_addr_set.ip_addr.addr[0]) {
+ gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
+ rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL,
+ gateway_param->len);
+ if (rt_val) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to clear Gateway Addr Set\n");
+ return rt_val;
+ }
+ }
+
+ gtway_addr = (uint8_t *)&gateway_param->value;
+ rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD,
+ gateway_param->len);
+
+ if (rt_val)
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed to Set Gateway Addr\n");
+
+ return rt_val;
+}
+
+int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_def_gateway_resp *gateway)
+{
+ struct be_cmd_get_def_gateway_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY,
+ sizeof(*gateway));
+ if (rc)
+ return rc;
+
+ req = nonemb_cmd.va;
+ req->ip_type = ip_type;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway,
+ sizeof(*gateway));
+}
+
+int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp *if_info)
+{
+ struct be_cmd_get_if_info_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ if (mgmt_get_all_if_id(phba))
+ return -EIO;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO,
+ sizeof(*if_info));
+ if (rc)
+ return rc;
+
+ req = nonemb_cmd.va;
+ req->interface_hndl = phba->interface_handle;
+ req->ip_type = ip_type;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info,
+ sizeof(*if_info));
+}
+
+int mgmt_get_nic_conf(struct beiscsi_hba *phba,
+ struct be_cmd_get_nic_conf_resp *nic)
+{
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
+ sizeof(*nic));
+ if (rc)
+ return rc;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, nic, sizeof(*nic));
+}
+
+
+
+unsigned int be_cmd_get_initname(struct beiscsi_hba *phba)
+{
unsigned int tag = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_hba_name *req;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
- SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n");
spin_lock(&ctrl->mbox_lock);
tag = alloc_mcc_tag(phba);
if (!tag) {
@@ -438,12 +890,38 @@ unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba)
req = embedded_payload(wrb);
wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
- OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
- sizeof(*req));
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_CFG_GET_HBA_NAME,
+ sizeof(*req));
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
return tag;
}
+unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba)
+{
+ unsigned int tag = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_ntwk_link_status_req *req;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ spin_lock(&ctrl->mbox_lock);
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+
+ wrb = wrb_from_mccq(phba);
+ req = embedded_payload(wrb);
+ wrb->tag0 |= tag;
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY,
+ sizeof(*req));
+
+ be_mcc_notify(phba);
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 0842882..5c2e376 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -20,11 +20,16 @@
#ifndef _BEISCSI_MGMT_
#define _BEISCSI_MGMT_
-#include <linux/types.h>
-#include <linux/list.h>
+#include <scsi/scsi_bsg_iscsi.h>
#include "be_iscsi.h"
#include "be_main.h"
+#define IP_ACTION_ADD 0x01
+#define IP_ACTION_DEL 0x02
+
+#define IP_V6_LEN 16
+#define IP_V4_LEN 4
+
/**
* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field
@@ -98,6 +103,10 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct invalidate_command_table *inv_tbl,
unsigned int num_invalidate, unsigned int cid,
struct be_dma_mem *nonemb_cmd);
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba,
+ struct bsg_job *job,
+ struct be_dma_mem *nonemb_cmd);
struct iscsi_invalidate_connection_params_in {
struct be_cmd_req_hdr hdr;
@@ -204,6 +213,13 @@ struct be_mgmt_controller_attributes_resp {
struct mgmt_controller_attributes params;
} __packed;
+struct be_bsg_vendor_cmd {
+ struct be_cmd_req_hdr hdr;
+ unsigned short region;
+ unsigned short offset;
+ unsigned short sector;
+} __packed;
+
/* configuration management */
#define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws)
@@ -219,12 +235,15 @@ struct be_mgmt_controller_attributes_resp {
/* the CMD_RESPONSE_HEADER */
#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\
- pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
bus_address.u.a32.address_lo; \
- pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
bus_address.u.a32.address_hi; \
}
+#define BEISCSI_WRITE_FLASH 0
+#define BEISCSI_READ_FLASH 1
+
struct beiscsi_endpoint {
struct beiscsi_hba *phba;
struct beiscsi_sess *sess;
@@ -248,4 +267,27 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short issue_reset,
unsigned short savecfg_flag);
+int mgmt_set_ip(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *ip_param,
+ struct iscsi_iface_param_info *subnet_param,
+ uint32_t boot_proto);
+
+unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba);
+
+unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
+ u32 boot_session_handle,
+ struct be_dma_mem *nonemb_cmd);
+
+int mgmt_get_nic_conf(struct beiscsi_hba *phba,
+ struct be_cmd_get_nic_conf_resp *mac);
+
+int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp *if_info);
+
+int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_def_gateway_resp *gateway);
+
+int mgmt_set_gateway(struct beiscsi_hba *phba,
+ struct iscsi_iface_param_info *gateway_param);
+
#endif
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index e75e07d..51c9e13 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -799,9 +799,6 @@ struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad,
enum bfa_lport_role roles,
struct bfad_vf_s *vf_drv,
struct bfad_vport_s *vp_drv);
-void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
- struct bfad_vf_s *vf_drv,
- struct bfad_vport_s *vp_drv);
/*
* vport callbacks
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 5d2a130..937000d 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -616,7 +616,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
__port_action[port->fabric->fab_type].online(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port online: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE);
@@ -639,12 +639,12 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
if (bfa_sm_cmp_state(port->fabric,
bfa_fcs_fabric_sm_online) == BFA_TRUE) {
- BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
} else {
- BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Logical port taken offline: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE);
@@ -709,14 +709,10 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);
/* Base port will be deleted by the OS driver */
- if (port->vport) {
- bfa_fcb_lport_delete(port->fcs->bfad, port->port_cfg.roles,
- port->fabric->vf_drv,
- port->vport ? port->vport->vport_drv : NULL);
+ if (port->vport)
bfa_fcs_vport_delete_comp(port->vport);
- } else {
+ else
bfa_wc_down(&port->fabric->wc);
- }
}
@@ -5714,17 +5710,23 @@ bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
(struct bfad_vport_s *)vport->vport_drv;
bfa_fcs_fabric_delvport(__vport_fabric(vport), vport);
+ bfa_lps_delete(vport->lps);
- if (vport_drv->comp_del)
+ if (vport_drv->comp_del) {
complete(vport_drv->comp_del);
- else
- kfree(vport_drv);
+ return;
+ }
- bfa_lps_delete(vport->lps);
+ /*
+ * We queue the vport delete work to the IM work_q from here.
+ * The memory for the bfad_vport_s is freed from the FC function
+ * template vport_delete entry point.
+ */
+ if (vport_drv)
+ bfad_im_port_delete(vport_drv->drv_port.bfad,
+ &vport_drv->drv_port);
}
-
-
/*
* fcs_vport_public FCS virtual port public interfaces
*/
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 404fd10..2e4b0be 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -456,23 +456,6 @@ bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port,
return port_drv;
}
-void
-bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
- struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
-{
- struct bfad_port_s *port_drv;
-
- /* this will be only called from rmmod context */
- if (vp_drv && !vp_drv->comp_del) {
- port_drv = (vp_drv) ? (&(vp_drv)->drv_port) :
- ((vf_drv) ? (&(vf_drv)->base_port) :
- (&(bfad)->pport));
- bfa_trc(bfad, roles);
- if (roles & BFA_LPORT_ROLE_FCP_IM)
- bfad_im_port_delete(bfad, port_drv);
- }
-}
-
/*
* FCS RPORT alloc callback, after successful PLOGI by FCS
*/
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 7b1ecd2..8b6c6bf 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -497,6 +497,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
if (im_port->flags & BFAD_PORT_DELETE) {
bfad_scsi_host_free(bfad, im_port);
list_del(&vport->list_entry);
+ kfree(vport);
return 0;
}
@@ -758,25 +759,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
else if (!strcmp(model, "Brocade-804"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 8Gbps FC HBA for HP Bladesystem C-class");
- else if (!strcmp(model, "Brocade-902") ||
- !strcmp(model, "Brocade-1741"))
+ else if (!strcmp(model, "Brocade-1741"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 10Gbps CNA for Dell M-Series Blade Servers");
- else if (strstr(model, "Brocade-1560")) {
- if (nports == 1)
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA");
- else
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA");
- } else if (strstr(model, "Brocade-1710")) {
- if (nports == 1)
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
- else
- snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
- } else if (strstr(model, "Brocade-1860")) {
+ else if (strstr(model, "Brocade-1860")) {
if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Brocade 10Gbps single port CNA");
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 495a841..25093a0 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index 72118db..dc0a08e 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 0bd70e8..0c53c28 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index f9d6f41..ece47e5 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 4927cca..8b68167 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.7.0.3"
-#define DRV_MODULE_RELDATE "Jun 15, 2011"
+#define DRV_MODULE_VERSION "2.7.2.2"
+#define DRV_MODULE_RELDATE "Apr 25, 2012"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 1a44b45..f8d516b 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2011 Broadcom Corporation
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -2244,6 +2244,7 @@ static struct scsi_host_template bnx2i_host_template = {
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_recover_target,
.change_queue_depth = iscsi_change_queue_depth,
+ .target_alloc = iscsi_target_alloc,
.can_queue = 2048,
.max_sectors = 127,
.cmd_per_lun = 128,
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index 83a77f7..c61cf7a 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,6 +1,6 @@
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2011 Broadcom Corporation
+ * Copyright (c) 2004 - 2012 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 04c5cea..fda9cde 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -55,11 +55,16 @@
#define ALUA_FAILOVER_TIMEOUT (60 * HZ)
#define ALUA_FAILOVER_RETRIES 5
+/* flags passed from user level */
+#define ALUA_OPTIMIZE_STPG 1
+
struct alua_dh_data {
int group_id;
int rel_port;
int tpgs;
int state;
+ int pref;
+ unsigned flags; /* used for optimizing STPG */
unsigned char inq[ALUA_INQUIRY_SIZE];
unsigned char *buff;
int bufflen;
@@ -554,14 +559,16 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
if (h->group_id == (ucp[2] << 8) + ucp[3]) {
h->state = ucp[0] & 0x0f;
+ h->pref = ucp[0] >> 7;
valid_states = ucp[1];
}
off = 8 + (ucp[7] * 4);
}
sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n",
+ "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
+ h->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -621,6 +628,37 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
out:
return err;
}
+/*
+ * alua_set_params - set/unset the optimize flag
+ * @sdev: device on the path to be activated
+ * params - parameters in the following format
+ * "no_of_params\0param1\0param2\0param3\0...\0"
+ * For example, to set the flag pass the following parameters
+ * from multipath.conf
+ * hardware_handler "2 alua 1"
+ */
+static int alua_set_params(struct scsi_device *sdev, const char *params)
+{
+ struct alua_dh_data *h = get_alua_data(sdev);
+ unsigned int optimize = 0, argc;
+ const char *p = params;
+ int result = SCSI_DH_OK;
+
+ if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
+ return -EINVAL;
+
+ while (*p++)
+ ;
+ if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
+ return -EINVAL;
+
+ if (optimize)
+ h->flags |= ALUA_OPTIMIZE_STPG;
+ else
+ h->flags &= ~ALUA_OPTIMIZE_STPG;
+
+ return result;
+}
/*
* alua_activate - activate a path
@@ -637,14 +675,37 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = get_alua_data(sdev);
int err = SCSI_DH_OK;
+ int stpg = 0;
err = alua_rtpg(sdev, h);
if (err != SCSI_DH_OK)
goto out;
- if (h->tpgs & TPGS_MODE_EXPLICIT &&
- h->state != TPGS_STATE_OPTIMIZED &&
- h->state != TPGS_STATE_LBA_DEPENDENT) {
+ if (h->tpgs & TPGS_MODE_EXPLICIT) {
+ switch (h->state) {
+ case TPGS_STATE_NONOPTIMIZED:
+ stpg = 1;
+ if ((h->flags & ALUA_OPTIMIZE_STPG) &&
+ (!h->pref) &&
+ (h->tpgs & TPGS_MODE_IMPLICIT))
+ stpg = 0;
+ break;
+ case TPGS_STATE_STANDBY:
+ stpg = 1;
+ break;
+ case TPGS_STATE_UNAVAILABLE:
+ case TPGS_STATE_OFFLINE:
+ err = SCSI_DH_IO;
+ break;
+ case TPGS_STATE_TRANSITIONING:
+ err = SCSI_DH_RETRY;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (stpg) {
h->callback_fn = fn;
h->callback_data = data;
err = submit_stpg(h);
@@ -698,6 +759,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+ .set_params = alua_set_params,
.match = alua_match,
};
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 394ed9e7..34552bf 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1000,7 +1000,7 @@ static int esp_check_spur_intr(struct esp *esp)
static void esp_schedule_reset(struct esp *esp)
{
- esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+ esp_log_reset("ESP: esp_schedule_reset() from %pf\n",
__builtin_return_address(0));
esp->flags |= ESP_FLAG_RESETTING;
esp_event(esp, ESP_EVENT_RESET);
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 335e851..76e3d0b 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -411,20 +411,18 @@ out:
}
/**
- * fcoe_interface_cleanup() - Clean up a FCoE interface
+ * fcoe_interface_remove() - remove FCoE interface from netdev
* @fcoe: The FCoE interface to be cleaned up
*
* Caller must be holding the RTNL mutex
*/
-static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
+static void fcoe_interface_remove(struct fcoe_interface *fcoe)
{
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = &fcoe->ctlr;
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
- rtnl_lock();
-
/*
* Don't listen for Ethernet packets anymore.
* synchronize_net() ensures that the packet handlers are not running
@@ -453,12 +451,28 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
" specific feature for LLD.\n");
}
+ fcoe->removed = 1;
+}
+
+
+/**
+ * fcoe_interface_cleanup() - Clean up a FCoE interface
+ * @fcoe: The FCoE interface to be cleaned up
+ */
+static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
+{
+ struct net_device *netdev = fcoe->netdev;
+ struct fcoe_ctlr *fip = &fcoe->ctlr;
+ rtnl_lock();
+ if (!fcoe->removed)
+ fcoe_interface_remove(fcoe);
rtnl_unlock();
/* Release the self-reference taken during fcoe_interface_create() */
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(fip);
+ scsi_host_put(fcoe->ctlr.lp->host);
kfree(fcoe);
dev_put(netdev);
module_put(THIS_MODULE);
@@ -522,13 +536,11 @@ static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr)
struct fcoe_port *port = lport_priv(lport);
struct fcoe_interface *fcoe = port->priv;
- rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(fcoe->netdev, port->data_src_addr);
if (!is_zero_ether_addr(addr))
dev_uc_add(fcoe->netdev, addr);
memcpy(port->data_src_addr, addr, ETH_ALEN);
- rtnl_unlock();
}
/**
@@ -941,6 +953,10 @@ static void fcoe_if_destroy(struct fc_lport *lport)
rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(netdev, port->data_src_addr);
+ if (lport->vport)
+ synchronize_net();
+ else
+ fcoe_interface_remove(fcoe);
rtnl_unlock();
/* Free queued packets for the per-CPU receive threads */
@@ -959,8 +975,12 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Free memory used by statistical counters */
fc_lport_free_stats(lport);
- /* Release the Scsi_Host */
- scsi_host_put(lport->host);
+ /*
+ * Release the Scsi_Host for vport but hold on to
+ * master lport until it fcoe interface fully cleaned-up.
+ */
+ if (lport->vport)
+ scsi_host_put(lport->host);
}
/**
@@ -2274,10 +2294,9 @@ static void fcoe_percpu_clean(struct fc_lport *lport)
continue;
skb = dev_alloc_skb(0);
- if (!skb) {
- spin_unlock_bh(&pp->fcoe_rx_list.lock);
+ if (!skb)
continue;
- }
+
skb->destructor = fcoe_percpu_flush_done;
spin_lock_bh(&pp->fcoe_rx_list.lock);
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index 3c2733a..96ac938 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -71,7 +71,8 @@ do { \
* @ctlr: The FCoE controller (for FIP)
* @oem: The offload exchange manager for all local port
* instances associated with this port
- * This structure is 1:1 with a net devive.
+ * @removed: Indicates fcoe interface removed from net device
+ * This structure is 1:1 with a net device.
*/
struct fcoe_interface {
struct list_head list;
@@ -81,6 +82,7 @@ struct fcoe_interface {
struct packet_type fip_packet_type;
struct fcoe_ctlr ctlr;
struct fc_exch_mgr *oem;
+ u8 removed;
};
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 249a106..5a4c725 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1883,7 +1883,13 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
frame = (struct fip_frame *)skb->data;
memset(frame, 0, len);
memcpy(frame->eth.h_dest, dest, ETH_ALEN);
- memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+
+ if (sub == FIP_SC_VN_BEACON) {
+ hton24(frame->eth.h_source, FIP_VN_FC_MAP);
+ hton24(frame->eth.h_source + 3, fip->port_id);
+ } else {
+ memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+ }
frame->eth.h_proto = htons(ETH_P_FIP);
frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 500e20d..796482b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -159,6 +159,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev,
int qdepth, int reason);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
+static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
static int hpsa_slave_alloc(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
@@ -171,7 +172,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
static void calc_bucket_map(int *bucket, int num_buckets,
int nsgs, int *bucket_map);
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
-static inline u32 next_command(struct ctlr_info *h);
+static inline u32 next_command(struct ctlr_info *h, u8 q);
static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
u64 *cfg_offset);
@@ -180,6 +181,7 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
void __iomem *vaddr, int wait_for_ready);
+static inline void finish_cmd(struct CommandList *c);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
@@ -234,6 +236,16 @@ static int check_for_unit_attention(struct ctlr_info *h,
return 1;
}
+static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
+{
+ if (c->err_info->CommandStatus != CMD_TARGET_STATUS ||
+ (c->err_info->ScsiStatus != SAM_STAT_BUSY &&
+ c->err_info->ScsiStatus != SAM_STAT_TASK_SET_FULL))
+ return 0;
+ dev_warn(&h->pdev->dev, HPSA "device busy");
+ return 1;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -368,7 +380,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
}
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
- "UNKNOWN"
+ "1(ADM)", "UNKNOWN"
};
#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
@@ -497,6 +509,7 @@ static struct scsi_host_template hpsa_driver_template = {
.change_queue_depth = hpsa_change_queue_depth,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
+ .eh_abort_handler = hpsa_eh_abort_handler,
.eh_device_reset_handler = hpsa_eh_device_reset_handler,
.ioctl = hpsa_ioctl,
.slave_alloc = hpsa_slave_alloc,
@@ -516,24 +529,28 @@ static inline void addQ(struct list_head *list, struct CommandList *c)
list_add_tail(&c->list, list);
}
-static inline u32 next_command(struct ctlr_info *h)
+static inline u32 next_command(struct ctlr_info *h, u8 q)
{
u32 a;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags;
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
- return h->access.command_completed(h);
+ return h->access.command_completed(h, q);
- if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
- a = *(h->reply_pool_head); /* Next cmd in ring buffer */
- (h->reply_pool_head)++;
+ if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ a = rq->head[rq->current_entry];
+ rq->current_entry++;
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
} else {
a = FIFO_EMPTY;
}
/* Check for wraparound */
- if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
- h->reply_pool_head = h->reply_pool;
- h->reply_pool_wraparound ^= 1;
+ if (rq->current_entry == h->max_commands) {
+ rq->current_entry = 0;
+ rq->wraparound ^= 1;
}
return a;
}
@@ -544,8 +561,41 @@ static inline u32 next_command(struct ctlr_info *h)
*/
static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
{
- if (likely(h->transMethod & CFGTBL_Trans_Performant))
+ if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+ if (likely(h->msix_vector))
+ c->Header.ReplyQueue =
+ smp_processor_id() % h->nreply_queues;
+ }
+}
+
+static int is_firmware_flash_cmd(u8 *cdb)
+{
+ return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
+}
+
+/*
+ * During firmware flash, the heartbeat register may not update as frequently
+ * as it should. So we dial down lockup detection during firmware flash. and
+ * dial it back up when firmware flash completes.
+ */
+#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
+#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
+static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (!is_firmware_flash_cmd(c->Request.CDB))
+ return;
+ atomic_inc(&h->firmware_flash_in_progress);
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
+}
+
+static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (is_firmware_flash_cmd(c->Request.CDB) &&
+ atomic_dec_and_test(&h->firmware_flash_in_progress))
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
}
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
@@ -554,11 +604,12 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
unsigned long flags;
set_performant_mode(h, c);
+ dial_down_lockup_detection_during_fw_flash(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
h->Qdepth++;
- start_io(h);
spin_unlock_irqrestore(&h->lock, flags);
+ start_io(h);
}
static inline void removeQ(struct CommandList *c)
@@ -1193,7 +1244,7 @@ static void complete_scsi_command(struct CommandList *cp)
break;
}
/* Must be some other type of check condition */
- dev_warn(&h->pdev->dev, "cp %p has check condition: "
+ dev_dbg(&h->pdev->dev, "cp %p has check condition: "
"unknown type: "
"Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
"Returning result: 0x%x, "
@@ -1370,16 +1421,24 @@ static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h,
}
}
+#define MAX_DRIVER_CMD_RETRIES 25
static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
struct CommandList *c, int data_direction)
{
- int retry_count = 0;
+ int backoff_time = 10, retry_count = 0;
do {
memset(c->err_info, 0, sizeof(*c->err_info));
hpsa_scsi_do_simple_cmd_core(h, c);
retry_count++;
- } while (check_for_unit_attention(h, c) && retry_count <= 3);
+ if (retry_count > 3) {
+ msleep(backoff_time);
+ if (backoff_time < 1000)
+ backoff_time *= 2;
+ }
+ } while ((check_for_unit_attention(h, c) ||
+ check_for_busy(h, c)) &&
+ retry_count <= MAX_DRIVER_CMD_RETRIES);
hpsa_pci_unmap(h->pdev, c, 1, data_direction);
}
@@ -2065,9 +2124,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
done(cmd);
return 0;
}
- /* Need a lock as this is being allocated from the pool */
- c = cmd_alloc(h);
spin_unlock_irqrestore(&h->lock, flags);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2334,6 +2392,261 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
return FAILED;
}
+static void swizzle_abort_tag(u8 *tag)
+{
+ u8 original_tag[8];
+
+ memcpy(original_tag, tag, 8);
+ tag[0] = original_tag[3];
+ tag[1] = original_tag[2];
+ tag[2] = original_tag[1];
+ tag[3] = original_tag[0];
+ tag[4] = original_tag[7];
+ tag[5] = original_tag[6];
+ tag[6] = original_tag[5];
+ tag[7] = original_tag[4];
+}
+
+static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
+ struct CommandList *abort, int swizzle)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+
+ fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG);
+ if (swizzle)
+ swizzle_abort_tag(&c->Request.CDB[4]);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
+ __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
+ /* no unmap needed here because no data xfer. */
+
+ ei = c->err_info;
+ switch (ei->CommandStatus) {
+ case CMD_SUCCESS:
+ break;
+ case CMD_UNABORTABLE: /* Very common, don't make noise. */
+ rc = -1;
+ break;
+ default:
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
+ __func__, abort->Header.Tag.upper,
+ abort->Header.Tag.lower);
+ hpsa_scsi_interpret_error(c);
+ rc = -1;
+ break;
+ }
+ cmd_special_free(h, c);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
+ abort->Header.Tag.upper, abort->Header.Tag.lower);
+ return rc;
+}
+
+/*
+ * hpsa_find_cmd_in_queue
+ *
+ * Used to determine whether a command (find) is still present
+ * in queue_head. Optionally excludes the last element of queue_head.
+ *
+ * This is used to avoid unnecessary aborts. Commands in h->reqQ have
+ * not yet been submitted, and so can be aborted by the driver without
+ * sending an abort to the hardware.
+ *
+ * Returns pointer to command if found in queue, NULL otherwise.
+ */
+static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
+ struct scsi_cmnd *find, struct list_head *queue_head)
+{
+ unsigned long flags;
+ struct CommandList *c = NULL; /* ptr into cmpQ */
+
+ if (!find)
+ return 0;
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, queue_head, list) {
+ if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */
+ continue;
+ if (c->scsi_cmd == find) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return c;
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return NULL;
+}
+
+static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
+ u8 *tag, struct list_head *queue_head)
+{
+ unsigned long flags;
+ struct CommandList *c;
+
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, queue_head, list) {
+ if (memcmp(&c->Header.Tag, tag, 8) != 0)
+ continue;
+ spin_unlock_irqrestore(&h->lock, flags);
+ return c;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return NULL;
+}
+
+/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
+ * tell which kind we're dealing with, so we send the abort both ways. There
+ * shouldn't be any collisions between swizzled and unswizzled tags due to the
+ * way we construct our tags but we check anyway in case the assumptions which
+ * make this true someday become false.
+ */
+static int hpsa_send_abort_both_ways(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct CommandList *abort)
+{
+ u8 swizzled_tag[8];
+ struct CommandList *c;
+ int rc = 0, rc2 = 0;
+
+ /* we do not expect to find the swizzled tag in our queue, but
+ * check anyway just to be sure the assumptions which make this
+ * the case haven't become wrong.
+ */
+ memcpy(swizzled_tag, &abort->Request.CDB[4], 8);
+ swizzle_abort_tag(swizzled_tag);
+ c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ);
+ if (c != NULL) {
+ dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n");
+ return hpsa_send_abort(h, scsi3addr, abort, 0);
+ }
+ rc = hpsa_send_abort(h, scsi3addr, abort, 0);
+
+ /* if the command is still in our queue, we can't conclude that it was
+ * aborted (it might have just completed normally) but in any case
+ * we don't need to try to abort it another way.
+ */
+ c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ);
+ if (c)
+ rc2 = hpsa_send_abort(h, scsi3addr, abort, 1);
+ return rc && rc2;
+}
+
+/* Send an abort for the specified command.
+ * If the device and controller support it,
+ * send a task abort request.
+ */
+static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
+{
+
+ int i, rc;
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+ struct CommandList *abort; /* pointer to command to be aborted */
+ struct CommandList *found;
+ struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
+ char msg[256]; /* For debug messaging. */
+ int ml = 0;
+
+ /* Find the controller of the command to be aborted */
+ h = sdev_to_hba(sc->device);
+ if (WARN(h == NULL,
+ "ABORT REQUEST FAILED, Controller lookup failed.\n"))
+ return FAILED;
+
+ /* Check that controller supports some kind of task abort */
+ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) &&
+ !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
+ return FAILED;
+
+ memset(msg, 0, sizeof(msg));
+ ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%d ",
+ h->scsi_host->host_no, sc->device->channel,
+ sc->device->id, sc->device->lun);
+
+ /* Find the device of the command to be aborted */
+ dev = sc->device->hostdata;
+ if (!dev) {
+ dev_err(&h->pdev->dev, "%s FAILED, Device lookup failed.\n",
+ msg);
+ return FAILED;
+ }
+
+ /* Get SCSI command to be aborted */
+ abort = (struct CommandList *) sc->host_scribble;
+ if (abort == NULL) {
+ dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n",
+ msg);
+ return FAILED;
+ }
+
+ ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
+ abort->Header.Tag.upper, abort->Header.Tag.lower);
+ as = (struct scsi_cmnd *) abort->scsi_cmd;
+ if (as != NULL)
+ ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
+ as->cmnd[0], as->serial_number);
+ dev_dbg(&h->pdev->dev, "%s\n", msg);
+ dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n",
+ h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
+
+ /* Search reqQ to See if command is queued but not submitted,
+ * if so, complete the command with aborted status and remove
+ * it from the reqQ.
+ */
+ found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ);
+ if (found) {
+ found->err_info->CommandStatus = CMD_ABORTED;
+ finish_cmd(found);
+ dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n",
+ msg);
+ return SUCCESS;
+ }
+
+ /* not in reqQ, if also not in cmpQ, must have already completed */
+ found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
+ if (!found) {
+ dev_dbg(&h->pdev->dev, "%s Request FAILED (not known to driver).\n",
+ msg);
+ return SUCCESS;
+ }
+
+ /*
+ * Command is in flight, or possibly already completed
+ * by the firmware (but not to the scsi mid layer) but we can't
+ * distinguish which. Send the abort down.
+ */
+ rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort);
+ if (rc != 0) {
+ dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg);
+ dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n",
+ h->scsi_host->host_no,
+ dev->bus, dev->target, dev->lun);
+ return FAILED;
+ }
+ dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg);
+
+ /* If the abort(s) above completed and actually aborted the
+ * command, then the command to be aborted should already be
+ * completed. If not, wait around a bit more to see if they
+ * manage to complete normally.
+ */
+#define ABORT_COMPLETE_WAIT_SECS 30
+ for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
+ found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
+ if (!found)
+ return SUCCESS;
+ msleep(100);
+ }
+ dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
+ msg, ABORT_COMPLETE_WAIT_SECS);
+ return FAILED;
+}
+
+
/*
* For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
@@ -2346,14 +2659,21 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
int i;
union u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
+ unsigned long flags;
+ spin_lock_irqsave(&h->lock, flags);
do {
i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
- if (i == h->nr_cmds)
+ if (i == h->nr_cmds) {
+ spin_unlock_irqrestore(&h->lock, flags);
return NULL;
+ }
} while (test_and_set_bit
(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
+ h->nr_allocs++;
+ spin_unlock_irqrestore(&h->lock, flags);
+
c = h->cmd_pool + i;
memset(c, 0, sizeof(*c));
cmd_dma_handle = h->cmd_pool_dhandle
@@ -2362,7 +2682,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
memset(c->err_info, 0, sizeof(*c->err_info));
err_dma_handle = h->errinfo_pool_dhandle
+ i * sizeof(*c->err_info);
- h->nr_allocs++;
c->cmdindex = i;
@@ -2418,11 +2737,14 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
static void cmd_free(struct ctlr_info *h, struct CommandList *c)
{
int i;
+ unsigned long flags;
i = c - h->cmd_pool;
+ spin_lock_irqsave(&h->lock, flags);
clear_bit(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG));
h->nr_frees++;
+ spin_unlock_irqrestore(&h->lock, flags);
}
static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
@@ -2866,6 +3188,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
int cmd_type)
{
int pci_dir = XFER_NONE;
+ struct CommandList *a; /* for commands to be aborted */
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
@@ -2949,8 +3272,35 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[5] = 0x00;
c->Request.CDB[6] = 0x00;
c->Request.CDB[7] = 0x00;
+ break;
+ case HPSA_ABORT_MSG:
+ a = buff; /* point to command to be aborted */
+ dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n",
+ a->Header.Tag.upper, a->Header.Tag.lower,
+ c->Header.Tag.upper, c->Header.Tag.lower);
+ c->Request.CDBLen = 16;
+ c->Request.Type.Type = TYPE_MSG;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_WRITE;
+ c->Request.Timeout = 0; /* Don't time out */
+ c->Request.CDB[0] = HPSA_TASK_MANAGEMENT;
+ c->Request.CDB[1] = HPSA_TMF_ABORT_TASK;
+ c->Request.CDB[2] = 0x00; /* reserved */
+ c->Request.CDB[3] = 0x00; /* reserved */
+ /* Tag to abort goes in CDB[4]-CDB[11] */
+ c->Request.CDB[4] = a->Header.Tag.lower & 0xFF;
+ c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF;
+ c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF;
+ c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF;
+ c->Request.CDB[8] = a->Header.Tag.upper & 0xFF;
+ c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF;
+ c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF;
+ c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF;
+ c->Request.CDB[12] = 0x00; /* reserved */
+ c->Request.CDB[13] = 0x00; /* reserved */
+ c->Request.CDB[14] = 0x00; /* reserved */
+ c->Request.CDB[15] = 0x00; /* reserved */
break;
-
default:
dev_warn(&h->pdev->dev, "unknown message type %d\n",
cmd);
@@ -2998,7 +3348,9 @@ static void __iomem *remap_pci_mem(ulong base, ulong size)
static void start_io(struct ctlr_info *h)
{
struct CommandList *c;
+ unsigned long flags;
+ spin_lock_irqsave(&h->lock, flags);
while (!list_empty(&h->reqQ)) {
c = list_entry(h->reqQ.next, struct CommandList, list);
/* can't do anything if fifo is full */
@@ -3011,17 +3363,28 @@ static void start_io(struct ctlr_info *h)
removeQ(c);
h->Qdepth--;
- /* Tell the controller execute command */
- h->access.submit_command(h, c);
-
/* Put job onto the completed Q */
addQ(&h->cmpQ, c);
+
+ /* Must increment commands_outstanding before unlocking
+ * and submitting to avoid race checking for fifo full
+ * condition.
+ */
+ h->commands_outstanding++;
+ if (h->commands_outstanding > h->max_outstanding)
+ h->max_outstanding = h->commands_outstanding;
+
+ /* Tell the controller execute command */
+ spin_unlock_irqrestore(&h->lock, flags);
+ h->access.submit_command(h, c);
+ spin_lock_irqsave(&h->lock, flags);
}
+ spin_unlock_irqrestore(&h->lock, flags);
}
-static inline unsigned long get_next_completion(struct ctlr_info *h)
+static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q)
{
- return h->access.command_completed(h);
+ return h->access.command_completed(h, q);
}
static inline bool interrupt_pending(struct ctlr_info *h)
@@ -3045,9 +3408,14 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
return 0;
}
-static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
+static inline void finish_cmd(struct CommandList *c)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->h->lock, flags);
removeQ(c);
+ spin_unlock_irqrestore(&c->h->lock, flags);
+ dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
if (likely(c->cmd_type == CMD_SCSI))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
@@ -3075,36 +3443,38 @@ static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
}
/* process completion of an indexed ("direct lookup") command */
-static inline u32 process_indexed_cmd(struct ctlr_info *h,
+static inline void process_indexed_cmd(struct ctlr_info *h,
u32 raw_tag)
{
u32 tag_index;
struct CommandList *c;
tag_index = hpsa_tag_to_index(raw_tag);
- if (bad_tag(h, tag_index, raw_tag))
- return next_command(h);
- c = h->cmd_pool + tag_index;
- finish_cmd(c, raw_tag);
- return next_command(h);
+ if (!bad_tag(h, tag_index, raw_tag)) {
+ c = h->cmd_pool + tag_index;
+ finish_cmd(c);
+ }
}
/* process completion of a non-indexed command */
-static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
+static inline void process_nonindexed_cmd(struct ctlr_info *h,
u32 raw_tag)
{
u32 tag;
struct CommandList *c = NULL;
+ unsigned long flags;
tag = hpsa_tag_discard_error_bits(h, raw_tag);
+ spin_lock_irqsave(&h->lock, flags);
list_for_each_entry(c, &h->cmpQ, list) {
if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
- finish_cmd(c, raw_tag);
- return next_command(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+ finish_cmd(c);
+ return;
}
}
+ spin_unlock_irqrestore(&h->lock, flags);
bad_tag(h, h->nr_cmds + 1, raw_tag);
- return next_command(h);
}
/* Some controllers, like p400, will give us one interrupt
@@ -3126,10 +3496,20 @@ static int ignore_bogus_interrupt(struct ctlr_info *h)
return 1;
}
-static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id)
+/*
+ * Convert &h->q[x] (passed to interrupt handlers) back to h.
+ * Relies on (h-q[x] == x) being true for x such that
+ * 0 <= x < MAX_REPLY_QUEUES.
+ */
+static struct ctlr_info *queue_to_hba(u8 *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ return container_of((queue - *queue), struct ctlr_info, q[0]);
+}
+
+static irqreturn_t hpsa_intx_discard_completions(int irq, void *queue)
+{
+ struct ctlr_info *h = queue_to_hba(queue);
+ u8 q = *(u8 *) queue;
u32 raw_tag;
if (ignore_bogus_interrupt(h))
@@ -3137,74 +3517,68 @@ static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id)
if (interrupt_not_for_us(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
while (interrupt_pending(h)) {
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY)
- raw_tag = next_command(h);
+ raw_tag = next_command(h, q);
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id)
+static irqreturn_t hpsa_msix_discard_completions(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba(queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
if (ignore_bogus_interrupt(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY)
- raw_tag = next_command(h);
- spin_unlock_irqrestore(&h->lock, flags);
+ raw_tag = next_command(h, q);
return IRQ_HANDLED;
}
-static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba((u8 *) queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
if (interrupt_not_for_us(h))
return IRQ_NONE;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
while (interrupt_pending(h)) {
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (hpsa_tag_contains_index(raw_tag))
- raw_tag = process_indexed_cmd(h, raw_tag);
+ if (likely(hpsa_tag_contains_index(raw_tag)))
+ process_indexed_cmd(h, raw_tag);
else
- raw_tag = process_nonindexed_cmd(h, raw_tag);
+ process_nonindexed_cmd(h, raw_tag);
+ raw_tag = next_command(h, q);
}
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_msi(int irq, void *queue)
{
- struct ctlr_info *h = dev_id;
- unsigned long flags;
+ struct ctlr_info *h = queue_to_hba(queue);
u32 raw_tag;
+ u8 q = *(u8 *) queue;
- spin_lock_irqsave(&h->lock, flags);
h->last_intr_timestamp = get_jiffies_64();
- raw_tag = get_next_completion(h);
+ raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (hpsa_tag_contains_index(raw_tag))
- raw_tag = process_indexed_cmd(h, raw_tag);
+ if (likely(hpsa_tag_contains_index(raw_tag)))
+ process_indexed_cmd(h, raw_tag);
else
- raw_tag = process_nonindexed_cmd(h, raw_tag);
+ process_nonindexed_cmd(h, raw_tag);
+ raw_tag = next_command(h, q);
}
- spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
@@ -3638,10 +4012,13 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
{
#ifdef CONFIG_PCI_MSI
- int err;
- struct msix_entry hpsa_msix_entries[4] = { {0, 0}, {0, 1},
- {0, 2}, {0, 3}
- };
+ int err, i;
+ struct msix_entry hpsa_msix_entries[MAX_REPLY_QUEUES];
+
+ for (i = 0; i < MAX_REPLY_QUEUES; i++) {
+ hpsa_msix_entries[i].vector = 0;
+ hpsa_msix_entries[i].entry = i;
+ }
/* Some boards advertise MSI but don't really support it */
if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
@@ -3649,12 +4026,11 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
dev_info(&h->pdev->dev, "MSIX\n");
- err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries,
+ MAX_REPLY_QUEUES);
if (!err) {
- h->intr[0] = hpsa_msix_entries[0].vector;
- h->intr[1] = hpsa_msix_entries[1].vector;
- h->intr[2] = hpsa_msix_entries[2].vector;
- h->intr[3] = hpsa_msix_entries[3].vector;
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ h->intr[i] = hpsa_msix_entries[i].vector;
h->msix_vector = 1;
return;
}
@@ -3705,14 +4081,6 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
}
-static inline bool hpsa_board_disabled(struct pci_dev *pdev)
-{
- u16 command;
-
- (void) pci_read_config_word(pdev, PCI_COMMAND, &command);
- return ((command & PCI_COMMAND_MEMORY) == 0);
-}
-
static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar)
{
@@ -3838,14 +4206,14 @@ static void __devinit hpsa_find_board_params(struct ctlr_info *h)
h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
}
+
+ /* Find out what task management functions are supported and cache */
+ h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
}
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
{
- if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
- (readb(&h->cfgtable->Signature[1]) != 'I') ||
- (readb(&h->cfgtable->Signature[2]) != 'S') ||
- (readb(&h->cfgtable->Signature[3]) != 'S')) {
+ if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
return false;
}
@@ -3932,11 +4300,6 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
- if (hpsa_board_disabled(h->pdev)) {
- dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
- return -ENODEV;
- }
-
pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
@@ -3946,6 +4309,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
return err;
}
+ /* Enable bus mastering (pci_disable_device may disable this) */
+ pci_set_master(h->pdev);
+
err = pci_request_regions(h->pdev, HPSA);
if (err) {
dev_err(&h->pdev->dev,
@@ -3987,10 +4353,7 @@ err_out_free_res:
iounmap(h->cfgtable);
if (h->vaddr)
iounmap(h->vaddr);
- /*
- * Deliberately omit pci_disable_device(): it does something nasty to
- * Smart Array controllers that pci_enable_device does not undo
- */
+ pci_disable_device(h->pdev);
pci_release_regions(h->pdev);
return err;
}
@@ -4081,14 +4444,33 @@ static int hpsa_request_irq(struct ctlr_info *h,
irqreturn_t (*msixhandler)(int, void *),
irqreturn_t (*intxhandler)(int, void *))
{
- int rc;
+ int rc, i;
- if (h->msix_vector || h->msi_vector)
- rc = request_irq(h->intr[h->intr_mode], msixhandler,
- 0, h->devname, h);
- else
- rc = request_irq(h->intr[h->intr_mode], intxhandler,
- IRQF_SHARED, h->devname, h);
+ /*
+ * initialize h->q[x] = x so that interrupt handlers know which
+ * queue to process.
+ */
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ h->q[i] = (u8) i;
+
+ if (h->intr_mode == PERF_MODE_INT && h->msix_vector) {
+ /* If performant mode and MSI-X, use multiple reply queues */
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ rc = request_irq(h->intr[i], msixhandler,
+ 0, h->devname,
+ &h->q[i]);
+ } else {
+ /* Use single reply pool */
+ if (h->msix_vector || h->msi_vector) {
+ rc = request_irq(h->intr[h->intr_mode],
+ msixhandler, 0, h->devname,
+ &h->q[h->intr_mode]);
+ } else {
+ rc = request_irq(h->intr[h->intr_mode],
+ intxhandler, IRQF_SHARED, h->devname,
+ &h->q[h->intr_mode]);
+ }
+ }
if (rc) {
dev_err(&h->pdev->dev, "unable to get irq %d for %s\n",
h->intr[h->intr_mode], h->devname);
@@ -4121,15 +4503,38 @@ static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h)
return 0;
}
-static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
+static void free_irqs(struct ctlr_info *h)
{
- free_irq(h->intr[h->intr_mode], h);
+ int i;
+
+ if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) {
+ /* Single reply queue, only one irq to free */
+ i = h->intr_mode;
+ free_irq(h->intr[i], &h->q[i]);
+ return;
+ }
+
+ for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ free_irq(h->intr[i], &h->q[i]);
+}
+
+static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h)
+{
+ free_irqs(h);
#ifdef CONFIG_PCI_MSI
- if (h->msix_vector)
- pci_disable_msix(h->pdev);
- else if (h->msi_vector)
- pci_disable_msi(h->pdev);
+ if (h->msix_vector) {
+ if (h->pdev->msix_enabled)
+ pci_disable_msix(h->pdev);
+ } else if (h->msi_vector) {
+ if (h->pdev->msi_enabled)
+ pci_disable_msi(h->pdev);
+ }
#endif /* CONFIG_PCI_MSI */
+}
+
+static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
+{
+ hpsa_free_irqs_and_disable_msix(h);
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
kfree(h->blockFetchTable);
@@ -4165,7 +4570,7 @@ static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)
while (!list_empty(list)) {
c = list_entry(list->next, struct CommandList, list);
c->err_info->CommandStatus = CMD_HARDWARE_ERR;
- finish_cmd(c, c->Header.Tag.lower);
+ finish_cmd(c);
}
}
@@ -4188,9 +4593,6 @@ static void controller_lockup_detected(struct ctlr_info *h)
spin_unlock_irqrestore(&h->lock, flags);
}
-#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ)
-#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2)
-
static void detect_controller_lockup(struct ctlr_info *h)
{
u64 now;
@@ -4201,7 +4603,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
now = get_jiffies_64();
/* If we've received an interrupt recently, we're ok. */
if (time_after64(h->last_intr_timestamp +
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+ (h->heartbeat_sample_interval), now))
return;
/*
@@ -4210,7 +4612,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
* otherwise don't care about signals in this thread.
*/
if (time_after64(h->last_heartbeat_timestamp +
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
+ (h->heartbeat_sample_interval), now))
return;
/* If heartbeat has not changed since we last looked, we're not ok. */
@@ -4252,6 +4654,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h)
{
unsigned long flags;
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
spin_lock_irqsave(&lockup_detector_lock, flags);
list_add_tail(&h->lockup_list, &hpsa_ctlr_list);
spin_unlock_irqrestore(&lockup_detector_lock, flags);
@@ -4391,7 +4794,7 @@ reinit_after_soft_reset:
spin_lock_irqsave(&h->lock, flags);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags);
- free_irq(h->intr[h->intr_mode], h);
+ free_irqs(h);
rc = hpsa_request_irq(h, hpsa_msix_discard_completions,
hpsa_intx_discard_completions);
if (rc) {
@@ -4441,7 +4844,7 @@ reinit_after_soft_reset:
clean4:
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
- free_irq(h->intr[h->intr_mode], h);
+ free_irqs(h);
clean2:
clean1:
kfree(h);
@@ -4484,13 +4887,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
*/
hpsa_flush_cache(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- free_irq(h->intr[h->intr_mode], h);
-#ifdef CONFIG_PCI_MSI
- if (h->msix_vector)
- pci_disable_msix(h->pdev);
- else if (h->msi_vector)
- pci_disable_msi(h->pdev);
-#endif /* CONFIG_PCI_MSI */
+ hpsa_free_irqs_and_disable_msix(h);
}
static void __devexit hpsa_free_device_info(struct ctlr_info *h)
@@ -4529,10 +4926,7 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
kfree(h->hba_inquiry_data);
- /*
- * Deliberately omit pci_disable_device(): it does something nasty to
- * Smart Array controllers that pci_enable_device does not undo
- */
+ pci_disable_device(pdev);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
kfree(h);
@@ -4627,11 +5021,8 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
* 10 = 6 s/g entry or 24k
*/
- h->reply_pool_wraparound = 1; /* spec: init to 1 */
-
/* Controller spec: zero out this buffer. */
memset(h->reply_pool, 0, h->reply_pool_size);
- h->reply_pool_head = h->reply_pool;
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
@@ -4641,12 +5032,19 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
/* size of controller ring buffer */
writel(h->max_commands, &h->transtable->RepQSize);
- writel(1, &h->transtable->RepQCount);
+ writel(h->nreply_queues, &h->transtable->RepQCount);
writel(0, &h->transtable->RepQCtrAddrLow32);
writel(0, &h->transtable->RepQCtrAddrHigh32);
- writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
- writel(0, &h->transtable->RepQAddr0High32);
- writel(CFGTBL_Trans_Performant | use_short_tags,
+
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(0, &h->transtable->RepQAddr[i].upper);
+ writel(h->reply_pool_dhandle +
+ (h->max_commands * sizeof(u64) * i),
+ &h->transtable->RepQAddr[i].lower);
+ }
+
+ writel(CFGTBL_Trans_Performant | use_short_tags |
+ CFGTBL_Trans_enable_directed_msix,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
@@ -4664,6 +5062,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
+ int i;
if (hpsa_simple_mode)
return;
@@ -4672,12 +5071,20 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
if (!(trans_support & PERFORMANT_MODE))
return;
+ h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1;
hpsa_get_max_perf_mode_cmds(h);
/* Performant mode ring buffer and supporting data structures */
- h->reply_pool_size = h->max_commands * sizeof(u64);
+ h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues;
h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
&(h->reply_pool_dhandle));
+ for (i = 0; i < h->nreply_queues; i++) {
+ h->reply_queue[i].head = &h->reply_pool[h->max_commands * i];
+ h->reply_queue[i].size = h->max_commands;
+ h->reply_queue[i].wraparound = 1; /* spec: init to 1 */
+ h->reply_queue[i].current_entry = 0;
+ }
+
/* Need a block fetch table for performant mode */
h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *
sizeof(u32)), GFP_KERNEL);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 7b28d54..9816479 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -34,7 +34,7 @@ struct access_method {
void (*set_intr_mask)(struct ctlr_info *h, unsigned long val);
unsigned long (*fifo_full)(struct ctlr_info *h);
bool (*intr_pending)(struct ctlr_info *h);
- unsigned long (*command_completed)(struct ctlr_info *h);
+ unsigned long (*command_completed)(struct ctlr_info *h, u8 q);
};
struct hpsa_scsi_dev_t {
@@ -48,6 +48,13 @@ struct hpsa_scsi_dev_t {
unsigned char raid_level; /* from inquiry page 0xC1 */
};
+struct reply_pool {
+ u64 *head;
+ size_t size;
+ u8 wraparound;
+ u32 current_entry;
+};
+
struct ctlr_info {
int ctlr;
char devname[8];
@@ -68,7 +75,7 @@ struct ctlr_info {
# define DOORBELL_INT 1
# define SIMPLE_MODE_INT 2
# define MEMQ_MODE_INT 3
- unsigned int intr[4];
+ unsigned int intr[MAX_REPLY_QUEUES];
unsigned int msix_vector;
unsigned int msi_vector;
int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
@@ -78,7 +85,6 @@ struct ctlr_info {
struct list_head reqQ;
struct list_head cmpQ;
unsigned int Qdepth;
- unsigned int maxQsinceinit;
unsigned int maxSG;
spinlock_t lock;
int maxsgentries;
@@ -111,20 +117,45 @@ struct ctlr_info {
unsigned long transMethod;
/*
- * Performant mode completion buffer
+ * Performant mode completion buffers
*/
u64 *reply_pool;
- dma_addr_t reply_pool_dhandle;
- u64 *reply_pool_head;
size_t reply_pool_size;
- unsigned char reply_pool_wraparound;
+ struct reply_pool reply_queue[MAX_REPLY_QUEUES];
+ u8 nreply_queues;
+ dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
unsigned char *hba_inquiry_data;
u64 last_intr_timestamp;
u32 last_heartbeat;
u64 last_heartbeat_timestamp;
+ u32 heartbeat_sample_interval;
+ atomic_t firmware_flash_in_progress;
u32 lockup_detected;
struct list_head lockup_list;
+ /* Address of h->q[x] is passed to intr handler to know which queue */
+ u8 q[MAX_REPLY_QUEUES];
+ u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */
+#define HPSATMF_BITS_SUPPORTED (1 << 0)
+#define HPSATMF_PHYS_LUN_RESET (1 << 1)
+#define HPSATMF_PHYS_NEX_RESET (1 << 2)
+#define HPSATMF_PHYS_TASK_ABORT (1 << 3)
+#define HPSATMF_PHYS_TSET_ABORT (1 << 4)
+#define HPSATMF_PHYS_CLEAR_ACA (1 << 5)
+#define HPSATMF_PHYS_CLEAR_TSET (1 << 6)
+#define HPSATMF_PHYS_QRY_TASK (1 << 7)
+#define HPSATMF_PHYS_QRY_TSET (1 << 8)
+#define HPSATMF_PHYS_QRY_ASYNC (1 << 9)
+#define HPSATMF_MASK_SUPPORTED (1 << 16)
+#define HPSATMF_LOG_LUN_RESET (1 << 17)
+#define HPSATMF_LOG_NEX_RESET (1 << 18)
+#define HPSATMF_LOG_TASK_ABORT (1 << 19)
+#define HPSATMF_LOG_TSET_ABORT (1 << 20)
+#define HPSATMF_LOG_CLEAR_ACA (1 << 21)
+#define HPSATMF_LOG_CLEAR_TSET (1 << 22)
+#define HPSATMF_LOG_QRY_TASK (1 << 23)
+#define HPSATMF_LOG_QRY_TSET (1 << 24)
+#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
@@ -216,9 +247,6 @@ static void SA5_submit_command(struct ctlr_info *h,
c->Header.Tag.lower);
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
- h->commands_outstanding++;
- if (h->commands_outstanding > h->max_outstanding)
- h->max_outstanding = h->commands_outstanding;
}
/*
@@ -254,16 +282,17 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)
}
}
-static unsigned long SA5_performant_completed(struct ctlr_info *h)
+static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
{
- unsigned long register_value = FIFO_EMPTY;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags, register_value = FIFO_EMPTY;
- /* flush the controller write of the reply queue by reading
- * outbound doorbell status register.
- */
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
/* msi auto clears the interrupt pending bit. */
if (!(h->msi_vector || h->msix_vector)) {
+ /* flush the controller write of the reply queue by reading
+ * outbound doorbell status register.
+ */
+ register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
/* Do a read in order to flush the write to the controller
* (as per spec.)
@@ -271,19 +300,20 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h)
register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
}
- if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
- register_value = *(h->reply_pool_head);
- (h->reply_pool_head)++;
+ if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ register_value = rq->head[rq->current_entry];
+ rq->current_entry++;
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
} else {
register_value = FIFO_EMPTY;
}
/* Check for wraparound */
- if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
- h->reply_pool_head = h->reply_pool;
- h->reply_pool_wraparound ^= 1;
+ if (rq->current_entry == h->max_commands) {
+ rq->current_entry = 0;
+ rq->wraparound ^= 1;
}
-
return register_value;
}
@@ -303,13 +333,18 @@ static unsigned long SA5_fifo_full(struct ctlr_info *h)
* returns value read from hardware.
* returns FIFO_EMPTY if there is nothing to read
*/
-static unsigned long SA5_completed(struct ctlr_info *h)
+static unsigned long SA5_completed(struct ctlr_info *h,
+ __attribute__((unused)) u8 q)
{
unsigned long register_value
= readl(h->vaddr + SA5_REPLY_PORT_OFFSET);
+ unsigned long flags;
- if (register_value != FIFO_EMPTY)
+ if (register_value != FIFO_EMPTY) {
+ spin_lock_irqsave(&h->lock, flags);
h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
+ }
#ifdef HPSA_DEBUG
if (register_value != FIFO_EMPTY)
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 8049815..a894f2e 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -82,6 +82,29 @@
#define TYPE_CMD 0x00
#define TYPE_MSG 0x01
+/* Message Types */
+#define HPSA_TASK_MANAGEMENT 0x00
+#define HPSA_RESET 0x01
+#define HPSA_SCAN 0x02
+#define HPSA_NOOP 0x03
+
+#define HPSA_CTLR_RESET_TYPE 0x00
+#define HPSA_BUS_RESET_TYPE 0x01
+#define HPSA_TARGET_RESET_TYPE 0x03
+#define HPSA_LUN_RESET_TYPE 0x04
+#define HPSA_NEXUS_RESET_TYPE 0x05
+
+/* Task Management Functions */
+#define HPSA_TMF_ABORT_TASK 0x00
+#define HPSA_TMF_ABORT_TASK_SET 0x01
+#define HPSA_TMF_CLEAR_ACA 0x02
+#define HPSA_TMF_CLEAR_TASK_SET 0x03
+#define HPSA_TMF_QUERY_TASK 0x04
+#define HPSA_TMF_QUERY_TASK_SET 0x05
+#define HPSA_TMF_QUERY_ASYNCEVENT 0x06
+
+
+
/* config space register offsets */
#define CFG_VENDORID 0x00
#define CFG_DEVICEID 0x02
@@ -106,6 +129,7 @@
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
#define CFGTBL_Trans_use_short_tags 0x20000000l
+#define CFGTBL_Trans_enable_directed_msix (1 << 30)
#define CFGTBL_BusType_Ultra2 0x00000001l
#define CFGTBL_BusType_Ultra3 0x00000002l
@@ -162,6 +186,7 @@ struct SenseSubsystem_info {
#define BMIC_WRITE 0x27
#define BMIC_CACHE_FLUSH 0xc2
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
+#define BMIC_FLASH_FIRMWARE 0xF7
/* Command List Structure */
union SCSI3Addr {
@@ -337,11 +362,17 @@ struct CfgTable {
u32 MaxPhysicalDevices;
u32 MaxPhysicalDrivesPerLogicalUnit;
u32 MaxPerformantModeCommands;
- u8 reserved[0x78 - 0x58];
+ u32 MaxBlockFetch;
+ u32 PowerConservationSupport;
+ u32 PowerConservationEnable;
+ u32 TMFSupportFlags;
+ u8 TMFTagMask[8];
+ u8 reserved[0x78 - 0x70];
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
#define MISC_FW_DOORBELL_RESET2 (0x010)
u8 driver_version[32];
+
};
#define NUM_BLOCKFETCH_ENTRIES 8
@@ -351,8 +382,8 @@ struct TransTable_struct {
u32 RepQCount;
u32 RepQCtrAddrLow32;
u32 RepQCtrAddrHigh32;
- u32 RepQAddr0Low32;
- u32 RepQAddr0High32;
+#define MAX_REPLY_QUEUES 8
+ struct vals32 RepQAddr[MAX_REPLY_QUEUES];
};
struct hpsa_pci_info {
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index d4bf9c1..45385f5 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -192,22 +192,27 @@ static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost)
static bool sci_controller_isr(struct isci_host *ihost)
{
- if (sci_controller_completion_queue_has_entries(ihost)) {
+ if (sci_controller_completion_queue_has_entries(ihost))
return true;
- } else {
- /*
- * we have a spurious interrupt it could be that we have already
- * emptied the completion queue from a previous interrupt */
- writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
- /*
- * There is a race in the hardware that could cause us not to be notified
- * of an interrupt completion if we do not take this step. We will mask
- * then unmask the interrupts so if there is another interrupt pending
- * the clearing of the interrupt source we get the next interrupt message. */
+ /* we have a spurious interrupt it could be that we have already
+ * emptied the completion queue from a previous interrupt
+ * FIXME: really!?
+ */
+ writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
+
+ /* There is a race in the hardware that could cause us not to be
+ * notified of an interrupt completion if we do not take this
+ * step. We will mask then unmask the interrupts so if there is
+ * another interrupt pending the clearing of the interrupt
+ * source we get the next interrupt message.
+ */
+ spin_lock(&ihost->scic_lock);
+ if (test_bit(IHOST_IRQ_ENABLED, &ihost->flags)) {
writel(0xFF000000, &ihost->smu_registers->interrupt_mask);
writel(0, &ihost->smu_registers->interrupt_mask);
}
+ spin_unlock(&ihost->scic_lock);
return false;
}
@@ -642,7 +647,6 @@ static void isci_host_start_complete(struct isci_host *ihost, enum sci_status co
if (completion_status != SCI_SUCCESS)
dev_info(&ihost->pdev->dev,
"controller start timed out, continuing...\n");
- isci_host_change_state(ihost, isci_ready);
clear_bit(IHOST_START_PENDING, &ihost->flags);
wake_up(&ihost->eventq);
}
@@ -657,12 +661,7 @@ int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
sas_drain_work(ha);
- dev_dbg(&ihost->pdev->dev,
- "%s: ihost->status = %d, time = %ld\n",
- __func__, isci_host_get_state(ihost), time);
-
return 1;
-
}
/**
@@ -704,14 +703,15 @@ static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost)
static void sci_controller_enable_interrupts(struct isci_host *ihost)
{
- BUG_ON(ihost->smu_registers == NULL);
+ set_bit(IHOST_IRQ_ENABLED, &ihost->flags);
writel(0, &ihost->smu_registers->interrupt_mask);
}
void sci_controller_disable_interrupts(struct isci_host *ihost)
{
- BUG_ON(ihost->smu_registers == NULL);
+ clear_bit(IHOST_IRQ_ENABLED, &ihost->flags);
writel(0xffffffff, &ihost->smu_registers->interrupt_mask);
+ readl(&ihost->smu_registers->interrupt_mask); /* flush */
}
static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost)
@@ -822,7 +822,7 @@ static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *
&ihost->scu_registers->sdma.unsolicited_frame_put_pointer);
}
-static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
+void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
{
if (ihost->sm.current_state_id == SCIC_STARTING) {
/*
@@ -849,6 +849,7 @@ static bool is_phy_starting(struct isci_phy *iphy)
case SCI_PHY_SUB_AWAIT_SATA_POWER:
case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
+ case SCI_PHY_SUB_AWAIT_OSSP_EN:
case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
case SCI_PHY_SUB_FINAL:
return true;
@@ -857,6 +858,39 @@ static bool is_phy_starting(struct isci_phy *iphy)
}
}
+bool is_controller_start_complete(struct isci_host *ihost)
+{
+ int i;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ struct isci_phy *iphy = &ihost->phys[i];
+ u32 state = iphy->sm.current_state_id;
+
+ /* in apc mode we need to check every phy, in
+ * mpc mode we only need to check phys that have
+ * been configured into a port
+ */
+ if (is_port_config_apc(ihost))
+ /* pass */;
+ else if (!phy_get_non_dummy_port(iphy))
+ continue;
+
+ /* The controller start operation is complete iff:
+ * - all links have been given an opportunity to start
+ * - have no indication of a connected device
+ * - have an indication of a connected device and it has
+ * finished the link training process.
+ */
+ if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
+ (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
+ (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
+ (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask))
+ return false;
+ }
+
+ return true;
+}
+
/**
* sci_controller_start_next_phy - start phy
* @scic: controller
@@ -877,36 +911,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
return status;
if (ihost->next_phy_to_start >= SCI_MAX_PHYS) {
- bool is_controller_start_complete = true;
- u32 state;
- u8 index;
-
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- iphy = &ihost->phys[index];
- state = iphy->sm.current_state_id;
-
- if (!phy_get_non_dummy_port(iphy))
- continue;
-
- /* The controller start operation is complete iff:
- * - all links have been given an opportunity to start
- * - have no indication of a connected device
- * - have an indication of a connected device and it has
- * finished the link training process.
- */
- if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
- (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
- (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
- (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) {
- is_controller_start_complete = false;
- break;
- }
- }
-
- /*
- * The controller has successfully finished the start process.
- * Inform the SCI Core user and transition to the READY state. */
- if (is_controller_start_complete == true) {
+ if (is_controller_start_complete(ihost)) {
sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
sci_del_timer(&ihost->phy_timer);
ihost->phy_startup_timer_pending = false;
@@ -987,9 +992,8 @@ static enum sci_status sci_controller_start(struct isci_host *ihost,
u16 index;
if (ihost->sm.current_state_id != SCIC_INITIALIZED) {
- dev_warn(&ihost->pdev->dev,
- "SCIC Controller start operation requested in "
- "invalid state\n");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
@@ -1053,9 +1057,8 @@ void isci_host_scan_start(struct Scsi_Host *shost)
spin_unlock_irq(&ihost->scic_lock);
}
-static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status)
+static void isci_host_stop_complete(struct isci_host *ihost)
{
- isci_host_change_state(ihost, isci_stopped);
sci_controller_disable_interrupts(ihost);
clear_bit(IHOST_STOP_PENDING, &ihost->flags);
wake_up(&ihost->eventq);
@@ -1074,6 +1077,32 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
writel(0, &ihost->smu_registers->interrupt_mask);
}
+void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task)
+{
+ task->lldd_task = NULL;
+ if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags) &&
+ !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (test_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags)) {
+ /* Normal notification (task_done) */
+ dev_dbg(&ihost->pdev->dev,
+ "%s: Normal - ireq/task = %p/%p\n",
+ __func__, ireq, task);
+
+ task->task_done(task);
+ } else {
+ dev_dbg(&ihost->pdev->dev,
+ "%s: Error - ireq/task = %p/%p\n",
+ __func__, ireq, task);
+
+ sas_task_abort(task);
+ }
+ }
+ if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+ wake_up_all(&ihost->eventq);
+
+ if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags))
+ isci_free_tag(ihost, ireq->io_tag);
+}
/**
* isci_host_completion_routine() - This function is the delayed service
* routine that calls the sci core library's completion handler. It's
@@ -1082,107 +1111,15 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
* @data: This parameter specifies the ISCI host object
*
*/
-static void isci_host_completion_routine(unsigned long data)
+void isci_host_completion_routine(unsigned long data)
{
struct isci_host *ihost = (struct isci_host *)data;
- struct list_head completed_request_list;
- struct list_head errored_request_list;
- struct list_head *current_position;
- struct list_head *next_position;
- struct isci_request *request;
- struct isci_request *next_request;
- struct sas_task *task;
u16 active;
- INIT_LIST_HEAD(&completed_request_list);
- INIT_LIST_HEAD(&errored_request_list);
-
spin_lock_irq(&ihost->scic_lock);
-
sci_controller_completion_handler(ihost);
-
- /* Take the lists of completed I/Os from the host. */
-
- list_splice_init(&ihost->requests_to_complete,
- &completed_request_list);
-
- /* Take the list of errored I/Os from the host. */
- list_splice_init(&ihost->requests_to_errorback,
- &errored_request_list);
-
spin_unlock_irq(&ihost->scic_lock);
- /* Process any completions in the lists. */
- list_for_each_safe(current_position, next_position,
- &completed_request_list) {
-
- request = list_entry(current_position, struct isci_request,
- completed_node);
- task = isci_request_access_task(request);
-
- /* Normal notification (task_done) */
- dev_dbg(&ihost->pdev->dev,
- "%s: Normal - request/task = %p/%p\n",
- __func__,
- request,
- task);
-
- /* Return the task to libsas */
- if (task != NULL) {
-
- task->lldd_task = NULL;
- if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-
- /* If the task is already in the abort path,
- * the task_done callback cannot be called.
- */
- task->task_done(task);
- }
- }
-
- spin_lock_irq(&ihost->scic_lock);
- isci_free_tag(ihost, request->io_tag);
- spin_unlock_irq(&ihost->scic_lock);
- }
- list_for_each_entry_safe(request, next_request, &errored_request_list,
- completed_node) {
-
- task = isci_request_access_task(request);
-
- /* Use sas_task_abort */
- dev_warn(&ihost->pdev->dev,
- "%s: Error - request/task = %p/%p\n",
- __func__,
- request,
- task);
-
- if (task != NULL) {
-
- /* Put the task into the abort path if it's not there
- * already.
- */
- if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED))
- sas_task_abort(task);
-
- } else {
- /* This is a case where the request has completed with a
- * status such that it needed further target servicing,
- * but the sas_task reference has already been removed
- * from the request. Since it was errored, it was not
- * being aborted, so there is nothing to do except free
- * it.
- */
-
- spin_lock_irq(&ihost->scic_lock);
- /* Remove the request from the remote device's list
- * of pending requests.
- */
- list_del_init(&request->dev_node);
- isci_free_tag(ihost, request->io_tag);
- spin_unlock_irq(&ihost->scic_lock);
- }
- }
-
/* the coalesence timeout doubles at each encoding step, so
* update it based on the ilog2 value of the outstanding requests
*/
@@ -1213,9 +1150,8 @@ static void isci_host_completion_routine(unsigned long data)
static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout)
{
if (ihost->sm.current_state_id != SCIC_READY) {
- dev_warn(&ihost->pdev->dev,
- "SCIC Controller stop operation requested in "
- "invalid state\n");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
@@ -1241,7 +1177,7 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost)
switch (ihost->sm.current_state_id) {
case SCIC_RESET:
case SCIC_READY:
- case SCIC_STOPPED:
+ case SCIC_STOPPING:
case SCIC_FAILED:
/*
* The reset operation is not a graceful cleanup, just
@@ -1250,13 +1186,50 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost)
sci_change_state(&ihost->sm, SCIC_RESETTING);
return SCI_SUCCESS;
default:
- dev_warn(&ihost->pdev->dev,
- "SCIC Controller reset operation requested in "
- "invalid state\n");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
}
+static enum sci_status sci_controller_stop_phys(struct isci_host *ihost)
+{
+ u32 index;
+ enum sci_status status;
+ enum sci_status phy_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ phy_status = sci_phy_stop(&ihost->phys[index]);
+
+ if (phy_status != SCI_SUCCESS &&
+ phy_status != SCI_FAILURE_INVALID_STATE) {
+ status = SCI_FAILURE;
+
+ dev_warn(&ihost->pdev->dev,
+ "%s: Controller stop operation failed to stop "
+ "phy %d because of status %d.\n",
+ __func__,
+ ihost->phys[index].phy_index, phy_status);
+ }
+ }
+
+ return status;
+}
+
+
+/**
+ * isci_host_deinit - shutdown frame reception and dma
+ * @ihost: host to take down
+ *
+ * This is called in either the driver shutdown or the suspend path. In
+ * the shutdown case libsas went through port teardown and normal device
+ * removal (i.e. physical links stayed up to service scsi_device removal
+ * commands). In the suspend case we disable the hardware without
+ * notifying libsas of the link down events since we want libsas to
+ * remember the domain across the suspend/resume cycle
+ */
void isci_host_deinit(struct isci_host *ihost)
{
int i;
@@ -1265,17 +1238,6 @@ void isci_host_deinit(struct isci_host *ihost)
for (i = 0; i < isci_gpio_count(ihost); i++)
writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
- isci_host_change_state(ihost, isci_stopping);
- for (i = 0; i < SCI_MAX_PORTS; i++) {
- struct isci_port *iport = &ihost->ports[i];
- struct isci_remote_device *idev, *d;
-
- list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) {
- if (test_bit(IDEV_ALLOCATED, &idev->flags))
- isci_remote_device_stop(ihost, idev);
- }
- }
-
set_bit(IHOST_STOP_PENDING, &ihost->flags);
spin_lock_irq(&ihost->scic_lock);
@@ -1284,12 +1246,21 @@ void isci_host_deinit(struct isci_host *ihost)
wait_for_stop(ihost);
+ /* phy stop is after controller stop to allow port and device to
+ * go idle before shutting down the phys, but the expectation is
+ * that i/o has been shut off well before we reach this
+ * function.
+ */
+ sci_controller_stop_phys(ihost);
+
/* disable sgpio: where the above wait should give time for the
* enclosure to sample the gpios going inactive
*/
writel(0, &ihost->scu_registers->peg0.sgpio.interface_control);
+ spin_lock_irq(&ihost->scic_lock);
sci_controller_reset(ihost);
+ spin_unlock_irq(&ihost->scic_lock);
/* Cancel any/all outstanding port timers */
for (i = 0; i < ihost->logical_port_entries; i++) {
@@ -1328,29 +1299,6 @@ static void __iomem *smu_base(struct isci_host *isci_host)
return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
}
-static void isci_user_parameters_get(struct sci_user_parameters *u)
-{
- int i;
-
- for (i = 0; i < SCI_MAX_PHYS; i++) {
- struct sci_phy_user_params *u_phy = &u->phys[i];
-
- u_phy->max_speed_generation = phy_gen;
-
- /* we are not exporting these for now */
- u_phy->align_insertion_frequency = 0x7f;
- u_phy->in_connection_align_insertion_frequency = 0xff;
- u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
- }
-
- u->stp_inactivity_timeout = stp_inactive_to;
- u->ssp_inactivity_timeout = ssp_inactive_to;
- u->stp_max_occupancy_timeout = stp_max_occ_to;
- u->ssp_max_occupancy_timeout = ssp_max_occ_to;
- u->no_outbound_task_timeout = no_outbound_task_to;
- u->max_concurr_spinup = max_concurr_spinup;
-}
-
static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm)
{
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
@@ -1510,32 +1458,6 @@ static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm)
sci_controller_set_interrupt_coalescence(ihost, 0, 0);
}
-static enum sci_status sci_controller_stop_phys(struct isci_host *ihost)
-{
- u32 index;
- enum sci_status status;
- enum sci_status phy_status;
-
- status = SCI_SUCCESS;
-
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- phy_status = sci_phy_stop(&ihost->phys[index]);
-
- if (phy_status != SCI_SUCCESS &&
- phy_status != SCI_FAILURE_INVALID_STATE) {
- status = SCI_FAILURE;
-
- dev_warn(&ihost->pdev->dev,
- "%s: Controller stop operation failed to stop "
- "phy %d because of status %d.\n",
- __func__,
- ihost->phys[index].phy_index, phy_status);
- }
- }
-
- return status;
-}
-
static enum sci_status sci_controller_stop_ports(struct isci_host *ihost)
{
u32 index;
@@ -1595,10 +1517,11 @@ static void sci_controller_stopping_state_enter(struct sci_base_state_machine *s
{
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
- /* Stop all of the components for this controller */
- sci_controller_stop_phys(ihost);
- sci_controller_stop_ports(ihost);
sci_controller_stop_devices(ihost);
+ sci_controller_stop_ports(ihost);
+
+ if (!sci_controller_has_remote_devices_stopping(ihost))
+ isci_host_stop_complete(ihost);
}
static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm)
@@ -1624,6 +1547,9 @@ static void sci_controller_reset_hardware(struct isci_host *ihost)
/* The write to the UFQGP clears the UFQPR */
writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
+
+ /* clear all interrupts */
+ writel(~SMU_INTERRUPT_STATUS_RESERVED_MASK, &ihost->smu_registers->interrupt_status);
}
static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm)
@@ -1655,59 +1581,9 @@ static const struct sci_base_state sci_controller_state_table[] = {
.enter_state = sci_controller_stopping_state_enter,
.exit_state = sci_controller_stopping_state_exit,
},
- [SCIC_STOPPED] = {},
[SCIC_FAILED] = {}
};
-static void sci_controller_set_default_config_parameters(struct isci_host *ihost)
-{
- /* these defaults are overridden by the platform / firmware */
- u16 index;
-
- /* Default to APC mode. */
- ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
-
- /* Default to APC mode. */
- ihost->oem_parameters.controller.max_concurr_spin_up = 1;
-
- /* Default to no SSC operation. */
- ihost->oem_parameters.controller.do_enable_ssc = false;
-
- /* Default to short cables on all phys. */
- ihost->oem_parameters.controller.cable_selection_mask = 0;
-
- /* Initialize all of the port parameter information to narrow ports. */
- for (index = 0; index < SCI_MAX_PORTS; index++) {
- ihost->oem_parameters.ports[index].phy_mask = 0;
- }
-
- /* Initialize all of the phy parameter information. */
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- /* Default to 3G (i.e. Gen 2). */
- ihost->user_parameters.phys[index].max_speed_generation =
- SCIC_SDS_PARM_GEN2_SPEED;
-
- /* the frequencies cannot be 0 */
- ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f;
- ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff;
- ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
-
- /*
- * Previous Vitesse based expanders had a arbitration issue that
- * is worked around by having the upper 32-bits of SAS address
- * with a value greater then the Vitesse company identifier.
- * Hence, usage of 0x5FCFFFFF. */
- ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id;
- ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF;
- }
-
- ihost->user_parameters.stp_inactivity_timeout = 5;
- ihost->user_parameters.ssp_inactivity_timeout = 5;
- ihost->user_parameters.stp_max_occupancy_timeout = 5;
- ihost->user_parameters.ssp_max_occupancy_timeout = 20;
- ihost->user_parameters.no_outbound_task_timeout = 2;
-}
-
static void controller_timeout(unsigned long data)
{
struct sci_timer *tmr = (struct sci_timer *)data;
@@ -1724,7 +1600,7 @@ static void controller_timeout(unsigned long data)
sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT);
else if (sm->current_state_id == SCIC_STOPPING) {
sci_change_state(sm, SCIC_FAILED);
- isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT);
+ isci_host_stop_complete(ihost);
} else /* / @todo Now what do we want to do in this case? */
dev_err(&ihost->pdev->dev,
"%s: Controller timer fired when controller was not "
@@ -1764,9 +1640,6 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost,
sci_init_timer(&ihost->timer, controller_timeout);
- /* Initialize the User and OEM parameters to default values. */
- sci_controller_set_default_config_parameters(ihost);
-
return sci_controller_reset(ihost);
}
@@ -1846,27 +1719,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version)
return 0;
}
-static enum sci_status sci_oem_parameters_set(struct isci_host *ihost)
-{
- u32 state = ihost->sm.current_state_id;
- struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
- if (state == SCIC_RESET ||
- state == SCIC_INITIALIZING ||
- state == SCIC_INITIALIZED) {
- u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version :
- ISCI_ROM_VER_1_0;
-
- if (sci_oem_parameters_validate(&ihost->oem_parameters,
- oem_version))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- return SCI_SUCCESS;
- }
-
- return SCI_FAILURE_INVALID_STATE;
-}
-
static u8 max_spin_up(struct isci_host *ihost)
{
if (ihost->user_parameters.max_concurr_spinup)
@@ -1914,7 +1766,7 @@ static void power_control_timeout(unsigned long data)
ihost->power_control.phys_granted_power++;
sci_phy_consume_power_handler(iphy);
- if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ if (iphy->protocol == SAS_PROTOCOL_SSP) {
u8 j;
for (j = 0; j < SCI_MAX_PHYS; j++) {
@@ -1988,7 +1840,7 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost,
sizeof(current_phy->frame_rcvd.iaf.sas_addr));
if (current_phy->sm.current_state_id == SCI_PHY_READY &&
- current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
+ current_phy->protocol == SAS_PROTOCOL_SSP &&
other == 0) {
sci_phy_consume_power_handler(iphy);
break;
@@ -2279,9 +2131,8 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost)
unsigned long i, state, val;
if (ihost->sm.current_state_id != SCIC_RESET) {
- dev_warn(&ihost->pdev->dev,
- "SCIC Controller initialize operation requested "
- "in invalid state\n");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
@@ -2384,96 +2235,76 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost)
return result;
}
-static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
- struct sci_user_parameters *sci_parms)
-{
- u32 state = ihost->sm.current_state_id;
-
- if (state == SCIC_RESET ||
- state == SCIC_INITIALIZING ||
- state == SCIC_INITIALIZED) {
- u16 index;
-
- /*
- * Validate the user parameters. If they are not legal, then
- * return a failure.
- */
- for (index = 0; index < SCI_MAX_PHYS; index++) {
- struct sci_phy_user_params *user_phy;
-
- user_phy = &sci_parms->phys[index];
-
- if (!((user_phy->max_speed_generation <=
- SCIC_SDS_PARM_MAX_SPEED) &&
- (user_phy->max_speed_generation >
- SCIC_SDS_PARM_NO_SPEED)))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- if (user_phy->in_connection_align_insertion_frequency <
- 3)
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- if ((user_phy->in_connection_align_insertion_frequency <
- 3) ||
- (user_phy->align_insertion_frequency == 0) ||
- (user_phy->
- notify_enable_spin_up_insertion_frequency ==
- 0))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
- }
-
- if ((sci_parms->stp_inactivity_timeout == 0) ||
- (sci_parms->ssp_inactivity_timeout == 0) ||
- (sci_parms->stp_max_occupancy_timeout == 0) ||
- (sci_parms->ssp_max_occupancy_timeout == 0) ||
- (sci_parms->no_outbound_task_timeout == 0))
- return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
- memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
-
- return SCI_SUCCESS;
- }
-
- return SCI_FAILURE_INVALID_STATE;
-}
-
-static int sci_controller_mem_init(struct isci_host *ihost)
+static int sci_controller_dma_alloc(struct isci_host *ihost)
{
struct device *dev = &ihost->pdev->dev;
- dma_addr_t dma;
size_t size;
- int err;
+ int i;
+
+ /* detect re-initialization */
+ if (ihost->completion_queue)
+ return 0;
size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32);
- ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ ihost->completion_queue = dmam_alloc_coherent(dev, size, &ihost->cq_dma,
+ GFP_KERNEL);
if (!ihost->completion_queue)
return -ENOMEM;
- writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper);
-
size = ihost->remote_node_entries * sizeof(union scu_remote_node_context);
- ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma,
+ ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &ihost->rnc_dma,
GFP_KERNEL);
+
if (!ihost->remote_node_context_table)
return -ENOMEM;
- writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper);
-
size = ihost->task_context_entries * sizeof(struct scu_task_context),
- ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ ihost->task_context_table = dmam_alloc_coherent(dev, size, &ihost->tc_dma,
+ GFP_KERNEL);
if (!ihost->task_context_table)
return -ENOMEM;
- ihost->task_context_dma = dma;
- writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower);
- writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper);
+ size = SCI_UFI_TOTAL_SIZE;
+ ihost->ufi_buf = dmam_alloc_coherent(dev, size, &ihost->ufi_dma, GFP_KERNEL);
+ if (!ihost->ufi_buf)
+ return -ENOMEM;
+
+ for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+ struct isci_request *ireq;
+ dma_addr_t dma;
+
+ ireq = dmam_alloc_coherent(dev, sizeof(*ireq), &dma, GFP_KERNEL);
+ if (!ireq)
+ return -ENOMEM;
+
+ ireq->tc = &ihost->task_context_table[i];
+ ireq->owning_controller = ihost;
+ ireq->request_daddr = dma;
+ ireq->isci_host = ihost;
+ ihost->reqs[i] = ireq;
+ }
+
+ return 0;
+}
+
+static int sci_controller_mem_init(struct isci_host *ihost)
+{
+ int err = sci_controller_dma_alloc(ihost);
- err = sci_unsolicited_frame_control_construct(ihost);
if (err)
return err;
+ writel(lower_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_lower);
+ writel(upper_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_upper);
+
+ writel(lower_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_lower);
+ writel(upper_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_upper);
+
+ writel(lower_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_lower);
+ writel(upper_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_upper);
+
+ sci_unsolicited_frame_control_construct(ihost);
+
/*
* Inform the silicon as to the location of the UF headers and
* address table.
@@ -2491,22 +2322,22 @@ static int sci_controller_mem_init(struct isci_host *ihost)
return 0;
}
+/**
+ * isci_host_init - (re-)initialize hardware and internal (private) state
+ * @ihost: host to init
+ *
+ * Any public facing objects (like asd_sas_port, and asd_sas_phys), or
+ * one-time initialization objects like locks and waitqueues, are
+ * not touched (they are initialized in isci_host_alloc)
+ */
int isci_host_init(struct isci_host *ihost)
{
- int err = 0, i;
+ int i, err;
enum sci_status status;
- struct sci_user_parameters sci_user_params;
- struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
- spin_lock_init(&ihost->state_lock);
- spin_lock_init(&ihost->scic_lock);
- init_waitqueue_head(&ihost->eventq);
-
- isci_host_change_state(ihost, isci_starting);
-
- status = sci_controller_construct(ihost, scu_base(ihost),
- smu_base(ihost));
+ spin_lock_irq(&ihost->scic_lock);
+ status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost));
+ spin_unlock_irq(&ihost->scic_lock);
if (status != SCI_SUCCESS) {
dev_err(&ihost->pdev->dev,
"%s: sci_controller_construct failed - status = %x\n",
@@ -2515,48 +2346,6 @@ int isci_host_init(struct isci_host *ihost)
return -ENODEV;
}
- ihost->sas_ha.dev = &ihost->pdev->dev;
- ihost->sas_ha.lldd_ha = ihost;
-
- /*
- * grab initial values stored in the controller object for OEM and USER
- * parameters
- */
- isci_user_parameters_get(&sci_user_params);
- status = sci_user_parameters_set(ihost, &sci_user_params);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "%s: sci_user_parameters_set failed\n",
- __func__);
- return -ENODEV;
- }
-
- /* grab any OEM parameters specified in orom */
- if (pci_info->orom) {
- status = isci_parse_oem_parameters(&ihost->oem_parameters,
- pci_info->orom,
- ihost->id);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "parsing firmware oem parameters failed\n");
- return -EINVAL;
- }
- }
-
- status = sci_oem_parameters_set(ihost);
- if (status != SCI_SUCCESS) {
- dev_warn(&ihost->pdev->dev,
- "%s: sci_oem_parameters_set failed\n",
- __func__);
- return -ENODEV;
- }
-
- tasklet_init(&ihost->completion_tasklet,
- isci_host_completion_routine, (unsigned long)ihost);
-
- INIT_LIST_HEAD(&ihost->requests_to_complete);
- INIT_LIST_HEAD(&ihost->requests_to_errorback);
-
spin_lock_irq(&ihost->scic_lock);
status = sci_controller_initialize(ihost);
spin_unlock_irq(&ihost->scic_lock);
@@ -2572,43 +2361,12 @@ int isci_host_init(struct isci_host *ihost)
if (err)
return err;
- for (i = 0; i < SCI_MAX_PORTS; i++)
- isci_port_init(&ihost->ports[i], ihost, i);
-
- for (i = 0; i < SCI_MAX_PHYS; i++)
- isci_phy_init(&ihost->phys[i], ihost, i);
-
/* enable sgpio */
writel(1, &ihost->scu_registers->peg0.sgpio.interface_control);
for (i = 0; i < isci_gpio_count(ihost); i++)
writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code);
- for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
- struct isci_remote_device *idev = &ihost->devices[i];
-
- INIT_LIST_HEAD(&idev->reqs_in_process);
- INIT_LIST_HEAD(&idev->node);
- }
-
- for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
- struct isci_request *ireq;
- dma_addr_t dma;
-
- ireq = dmam_alloc_coherent(&ihost->pdev->dev,
- sizeof(struct isci_request), &dma,
- GFP_KERNEL);
- if (!ireq)
- return -ENOMEM;
-
- ireq->tc = &ihost->task_context_table[i];
- ireq->owning_controller = ihost;
- spin_lock_init(&ireq->state_lock);
- ireq->request_daddr = dma;
- ireq->isci_host = ihost;
- ihost->reqs[i] = ireq;
- }
-
return 0;
}
@@ -2654,7 +2412,7 @@ void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
}
}
-static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost)
+bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost)
{
u32 index;
@@ -2680,7 +2438,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost,
}
if (!sci_controller_has_remote_devices_stopping(ihost))
- sci_change_state(&ihost->sm, SCIC_STOPPED);
+ isci_host_stop_complete(ihost);
}
void sci_controller_post_request(struct isci_host *ihost, u32 request)
@@ -2842,7 +2600,8 @@ enum sci_status sci_controller_start_io(struct isci_host *ihost,
enum sci_status status;
if (ihost->sm.current_state_id != SCIC_READY) {
- dev_warn(&ihost->pdev->dev, "invalid state to start I/O");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
@@ -2866,22 +2625,26 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
enum sci_status status;
if (ihost->sm.current_state_id != SCIC_READY) {
- dev_warn(&ihost->pdev->dev,
- "invalid state to terminate request\n");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
-
status = sci_io_request_terminate(ireq);
- if (status != SCI_SUCCESS)
- return status;
- /*
- * Utilize the original post context command and or in the POST_TC_ABORT
- * request sub-type.
- */
- sci_controller_post_request(ihost,
- ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
- return SCI_SUCCESS;
+ dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n",
+ __func__, status, ireq, ireq->flags);
+
+ if ((status == SCI_SUCCESS) &&
+ !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
+ !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
+ /* Utilize the original post context command and or in the
+ * POST_TC_ABORT request sub-type.
+ */
+ sci_controller_post_request(
+ ihost, ireq->post_context |
+ SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
+ }
+ return status;
}
/**
@@ -2915,7 +2678,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost,
clear_bit(IREQ_ACTIVE, &ireq->flags);
return SCI_SUCCESS;
default:
- dev_warn(&ihost->pdev->dev, "invalid state to complete I/O");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
@@ -2926,7 +2690,8 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq)
struct isci_host *ihost = ireq->owning_controller;
if (ihost->sm.current_state_id != SCIC_READY) {
- dev_warn(&ihost->pdev->dev, "invalid state to continue I/O");
+ dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+ __func__, ihost->sm.current_state_id);
return SCI_FAILURE_INVALID_STATE;
}
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index adbad69..9ab58e0 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -55,6 +55,7 @@
#ifndef _SCI_HOST_H_
#define _SCI_HOST_H_
+#include <scsi/sas_ata.h>
#include "remote_device.h"
#include "phy.h"
#include "isci.h"
@@ -108,6 +109,8 @@ struct sci_port_configuration_agent;
typedef void (*port_config_fn)(struct isci_host *,
struct sci_port_configuration_agent *,
struct isci_port *, struct isci_phy *);
+bool is_port_config_apc(struct isci_host *ihost);
+bool is_controller_start_complete(struct isci_host *ihost);
struct sci_port_configuration_agent {
u16 phy_configured_mask;
@@ -157,13 +160,17 @@ struct isci_host {
struct sci_power_control power_control;
u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
struct scu_task_context *task_context_table;
- dma_addr_t task_context_dma;
+ dma_addr_t tc_dma;
union scu_remote_node_context *remote_node_context_table;
+ dma_addr_t rnc_dma;
u32 *completion_queue;
+ dma_addr_t cq_dma;
u32 completion_queue_get;
u32 logical_port_entries;
u32 remote_node_entries;
u32 task_context_entries;
+ void *ufi_buf;
+ dma_addr_t ufi_dma;
struct sci_unsolicited_frame_control uf_control;
/* phy startup */
@@ -190,17 +197,13 @@ struct isci_host {
struct asd_sas_port sas_ports[SCI_MAX_PORTS];
struct sas_ha_struct sas_ha;
- spinlock_t state_lock;
struct pci_dev *pdev;
- enum isci_status status;
#define IHOST_START_PENDING 0
#define IHOST_STOP_PENDING 1
+ #define IHOST_IRQ_ENABLED 2
unsigned long flags;
wait_queue_head_t eventq;
- struct Scsi_Host *shost;
struct tasklet_struct completion_tasklet;
- struct list_head requests_to_complete;
- struct list_head requests_to_errorback;
spinlock_t scic_lock;
struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
@@ -274,13 +277,6 @@ enum sci_controller_states {
SCIC_STOPPING,
/**
- * This state indicates that the controller has successfully been stopped.
- * In this state no new IO operations are permitted.
- * This state is entered from the STOPPING state.
- */
- SCIC_STOPPED,
-
- /**
* This state indicates that the controller could not successfully be
* initialized. In this state no new IO operations are permitted.
* This state is entered from the INITIALIZING state.
@@ -309,32 +305,16 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
return pci_get_drvdata(pdev);
}
+static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
+{
+ return ihost->sas_ha.core.shost;
+}
+
#define for_each_isci_host(id, ihost, pdev) \
for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
ihost = to_pci_info(pdev)->hosts[++id])
-static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
-{
- return isci_host->status;
-}
-
-static inline void isci_host_change_state(struct isci_host *isci_host,
- enum isci_status status)
-{
- unsigned long flags;
-
- dev_dbg(&isci_host->pdev->dev,
- "%s: isci_host = %p, state = 0x%x",
- __func__,
- isci_host,
- status);
- spin_lock_irqsave(&isci_host->state_lock, flags);
- isci_host->status = status;
- spin_unlock_irqrestore(&isci_host->state_lock, flags);
-
-}
-
static inline void wait_for_start(struct isci_host *ihost)
{
wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags));
@@ -360,6 +340,11 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
return dev->port->ha->lldd_ha;
}
+static inline struct isci_host *idev_to_ihost(struct isci_remote_device *idev)
+{
+ return dev_to_ihost(idev->domain_dev);
+}
+
/* we always use protocol engine group zero */
#define ISCI_PEG 0
@@ -378,8 +363,7 @@ static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
{
struct domain_device *dev = idev->domain_dev;
- if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
- !idev->is_direct_attached)
+ if (dev_is_sata(dev) && dev->parent)
return SCU_STP_REMOTE_NODE_COUNT;
return SCU_SSP_REMOTE_NODE_COUNT;
}
@@ -475,36 +459,17 @@ void sci_controller_free_remote_node_context(
struct isci_remote_device *idev,
u16 node_id);
-struct isci_request *sci_request_by_tag(struct isci_host *ihost,
- u16 io_tag);
-
-void sci_controller_power_control_queue_insert(
- struct isci_host *ihost,
- struct isci_phy *iphy);
-
-void sci_controller_power_control_queue_remove(
- struct isci_host *ihost,
- struct isci_phy *iphy);
-
-void sci_controller_link_up(
- struct isci_host *ihost,
- struct isci_port *iport,
- struct isci_phy *iphy);
-
-void sci_controller_link_down(
- struct isci_host *ihost,
- struct isci_port *iport,
- struct isci_phy *iphy);
-
-void sci_controller_remote_device_stopped(
- struct isci_host *ihost,
- struct isci_remote_device *idev);
-
-void sci_controller_copy_task_context(
- struct isci_host *ihost,
- struct isci_request *ireq);
-
-void sci_controller_register_setup(struct isci_host *ihost);
+struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag);
+void sci_controller_power_control_queue_insert(struct isci_host *ihost,
+ struct isci_phy *iphy);
+void sci_controller_power_control_queue_remove(struct isci_host *ihost,
+ struct isci_phy *iphy);
+void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport,
+ struct isci_phy *iphy);
+void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
+ struct isci_phy *iphy);
+void sci_controller_remote_device_stopped(struct isci_host *ihost,
+ struct isci_remote_device *idev);
enum sci_status sci_controller_continue_io(struct isci_request *ireq);
int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
@@ -512,29 +477,14 @@ void isci_host_scan_start(struct Scsi_Host *);
u16 isci_alloc_tag(struct isci_host *ihost);
enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
void isci_tci_free(struct isci_host *ihost, u16 tci);
+void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task);
int isci_host_init(struct isci_host *);
-
-void isci_host_init_controller_names(
- struct isci_host *isci_host,
- unsigned int controller_idx);
-
-void isci_host_deinit(
- struct isci_host *);
-
-void isci_host_port_link_up(
- struct isci_host *,
- struct isci_port *,
- struct isci_phy *);
-int isci_host_dev_found(struct domain_device *);
-
-void isci_host_remote_device_start_complete(
- struct isci_host *,
- struct isci_remote_device *,
- enum sci_status);
-
-void sci_controller_disable_interrupts(
- struct isci_host *ihost);
+void isci_host_completion_routine(unsigned long data);
+void isci_host_deinit(struct isci_host *);
+void sci_controller_disable_interrupts(struct isci_host *ihost);
+bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost);
+void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status);
enum sci_status sci_controller_start_io(
struct isci_host *ihost,
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 5137db5..47e28b5 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -271,13 +271,12 @@ static void isci_unregister(struct isci_host *isci_host)
if (!isci_host)
return;
- shost = isci_host->shost;
-
sas_unregister_ha(&isci_host->sas_ha);
- sas_remove_host(isci_host->shost);
- scsi_remove_host(isci_host->shost);
- scsi_host_put(isci_host->shost);
+ shost = to_shost(isci_host);
+ sas_remove_host(shost);
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
}
static int __devinit isci_pci_init(struct pci_dev *pdev)
@@ -397,38 +396,199 @@ static int isci_setup_interrupts(struct pci_dev *pdev)
return err;
}
+static void isci_user_parameters_get(struct sci_user_parameters *u)
+{
+ int i;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ struct sci_phy_user_params *u_phy = &u->phys[i];
+
+ u_phy->max_speed_generation = phy_gen;
+
+ /* we are not exporting these for now */
+ u_phy->align_insertion_frequency = 0x7f;
+ u_phy->in_connection_align_insertion_frequency = 0xff;
+ u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
+ }
+
+ u->stp_inactivity_timeout = stp_inactive_to;
+ u->ssp_inactivity_timeout = ssp_inactive_to;
+ u->stp_max_occupancy_timeout = stp_max_occ_to;
+ u->ssp_max_occupancy_timeout = ssp_max_occ_to;
+ u->no_outbound_task_timeout = no_outbound_task_to;
+ u->max_concurr_spinup = max_concurr_spinup;
+}
+
+static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
+ struct sci_user_parameters *sci_parms)
+{
+ u16 index;
+
+ /*
+ * Validate the user parameters. If they are not legal, then
+ * return a failure.
+ */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ struct sci_phy_user_params *u;
+
+ u = &sci_parms->phys[index];
+
+ if (!((u->max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED) &&
+ (u->max_speed_generation > SCIC_SDS_PARM_NO_SPEED)))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (u->in_connection_align_insertion_frequency < 3)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if ((u->in_connection_align_insertion_frequency < 3) ||
+ (u->align_insertion_frequency == 0) ||
+ (u->notify_enable_spin_up_insertion_frequency == 0))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if ((sci_parms->stp_inactivity_timeout == 0) ||
+ (sci_parms->ssp_inactivity_timeout == 0) ||
+ (sci_parms->stp_max_occupancy_timeout == 0) ||
+ (sci_parms->ssp_max_occupancy_timeout == 0) ||
+ (sci_parms->no_outbound_task_timeout == 0))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
+
+ return SCI_SUCCESS;
+}
+
+static void sci_oem_defaults(struct isci_host *ihost)
+{
+ /* these defaults are overridden by the platform / firmware */
+ struct sci_user_parameters *user = &ihost->user_parameters;
+ struct sci_oem_params *oem = &ihost->oem_parameters;
+ int i;
+
+ /* Default to APC mode. */
+ oem->controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+ /* Default to APC mode. */
+ oem->controller.max_concurr_spin_up = 1;
+
+ /* Default to no SSC operation. */
+ oem->controller.do_enable_ssc = false;
+
+ /* Default to short cables on all phys. */
+ oem->controller.cable_selection_mask = 0;
+
+ /* Initialize all of the port parameter information to narrow ports. */
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ oem->ports[i].phy_mask = 0;
+
+ /* Initialize all of the phy parameter information. */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ /* Default to 3G (i.e. Gen 2). */
+ user->phys[i].max_speed_generation = SCIC_SDS_PARM_GEN2_SPEED;
+
+ /* the frequencies cannot be 0 */
+ user->phys[i].align_insertion_frequency = 0x7f;
+ user->phys[i].in_connection_align_insertion_frequency = 0xff;
+ user->phys[i].notify_enable_spin_up_insertion_frequency = 0x33;
+
+ /* Previous Vitesse based expanders had a arbitration issue that
+ * is worked around by having the upper 32-bits of SAS address
+ * with a value greater then the Vitesse company identifier.
+ * Hence, usage of 0x5FCFFFFF.
+ */
+ oem->phys[i].sas_address.low = 0x1 + ihost->id;
+ oem->phys[i].sas_address.high = 0x5FCFFFFF;
+ }
+
+ user->stp_inactivity_timeout = 5;
+ user->ssp_inactivity_timeout = 5;
+ user->stp_max_occupancy_timeout = 5;
+ user->ssp_max_occupancy_timeout = 20;
+ user->no_outbound_task_timeout = 2;
+}
+
static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
{
- struct isci_host *isci_host;
+ struct isci_orom *orom = to_pci_info(pdev)->orom;
+ struct sci_user_parameters sci_user_params;
+ u8 oem_version = ISCI_ROM_VER_1_0;
+ struct isci_host *ihost;
struct Scsi_Host *shost;
- int err;
+ int err, i;
- isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
- if (!isci_host)
+ ihost = devm_kzalloc(&pdev->dev, sizeof(*ihost), GFP_KERNEL);
+ if (!ihost)
return NULL;
- isci_host->pdev = pdev;
- isci_host->id = id;
+ ihost->pdev = pdev;
+ ihost->id = id;
+ spin_lock_init(&ihost->scic_lock);
+ init_waitqueue_head(&ihost->eventq);
+ ihost->sas_ha.dev = &ihost->pdev->dev;
+ ihost->sas_ha.lldd_ha = ihost;
+ tasklet_init(&ihost->completion_tasklet,
+ isci_host_completion_routine, (unsigned long)ihost);
+
+ /* validate module parameters */
+ /* TODO: kill struct sci_user_parameters and reference directly */
+ sci_oem_defaults(ihost);
+ isci_user_parameters_get(&sci_user_params);
+ if (sci_user_parameters_set(ihost, &sci_user_params)) {
+ dev_warn(&pdev->dev,
+ "%s: sci_user_parameters_set failed\n", __func__);
+ return NULL;
+ }
+
+ /* sanity check platform (or 'firmware') oem parameters */
+ if (orom) {
+ if (id < 0 || id >= SCI_MAX_CONTROLLERS || id > orom->hdr.num_elements) {
+ dev_warn(&pdev->dev, "parsing firmware oem parameters failed\n");
+ return NULL;
+ }
+ ihost->oem_parameters = orom->ctrl[id];
+ oem_version = orom->hdr.version;
+ }
+
+ /* validate oem parameters (platform, firmware, or built-in defaults) */
+ if (sci_oem_parameters_validate(&ihost->oem_parameters, oem_version)) {
+ dev_warn(&pdev->dev, "oem parameter validation failed\n");
+ return NULL;
+ }
+
+ for (i = 0; i < SCI_MAX_PORTS; i++) {
+ struct isci_port *iport = &ihost->ports[i];
+
+ INIT_LIST_HEAD(&iport->remote_dev_list);
+ iport->isci_host = ihost;
+ }
+
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ isci_phy_init(&ihost->phys[i], ihost, i);
+
+ for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
+ struct isci_remote_device *idev = &ihost->devices[i];
+
+ INIT_LIST_HEAD(&idev->node);
+ }
shost = scsi_host_alloc(&isci_sht, sizeof(void *));
if (!shost)
return NULL;
- isci_host->shost = shost;
dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
"{%s, %s, %s, %s}\n",
- (is_cable_select_overridden() ? "* " : ""), isci_host->id,
- lookup_cable_names(decode_cable_selection(isci_host, 3)),
- lookup_cable_names(decode_cable_selection(isci_host, 2)),
- lookup_cable_names(decode_cable_selection(isci_host, 1)),
- lookup_cable_names(decode_cable_selection(isci_host, 0)));
+ (is_cable_select_overridden() ? "* " : ""), ihost->id,
+ lookup_cable_names(decode_cable_selection(ihost, 3)),
+ lookup_cable_names(decode_cable_selection(ihost, 2)),
+ lookup_cable_names(decode_cable_selection(ihost, 1)),
+ lookup_cable_names(decode_cable_selection(ihost, 0)));
- err = isci_host_init(isci_host);
+ err = isci_host_init(ihost);
if (err)
goto err_shost;
- SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
- isci_host->sas_ha.core.shost = shost;
+ SHOST_TO_SAS_HA(shost) = &ihost->sas_ha;
+ ihost->sas_ha.core.shost = shost;
shost->transportt = isci_transport_template;
shost->max_id = ~0;
@@ -439,11 +599,11 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
if (err)
goto err_shost;
- err = isci_register_sas_ha(isci_host);
+ err = isci_register_sas_ha(ihost);
if (err)
goto err_shost_remove;
- return isci_host;
+ return ihost;
err_shost_remove:
scsi_remove_host(shost);
@@ -476,7 +636,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
if (!orom)
orom = isci_request_oprom(pdev);
- for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) {
+ for (i = 0; orom && i < num_controllers(pdev); i++) {
if (sci_oem_parameters_validate(&orom->ctrl[i],
orom->hdr.version)) {
dev_warn(&pdev->dev,
@@ -525,11 +685,11 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
pci_info->hosts[i] = h;
/* turn on DIF support */
- scsi_host_set_prot(h->shost,
+ scsi_host_set_prot(to_shost(h),
SHOST_DIF_TYPE1_PROTECTION |
SHOST_DIF_TYPE2_PROTECTION |
SHOST_DIF_TYPE3_PROTECTION);
- scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
+ scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC);
}
err = isci_setup_interrupts(pdev);
@@ -537,7 +697,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
goto err_host_alloc;
for_each_isci_host(i, isci_host, pdev)
- scsi_scan_host(isci_host->shost);
+ scsi_scan_host(to_shost(isci_host));
return 0;
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index fab3586..18f43d4 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -580,7 +580,7 @@ static void sci_phy_start_sas_link_training(struct isci_phy *iphy)
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN);
- iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS;
+ iphy->protocol = SAS_PROTOCOL_SSP;
}
static void sci_phy_start_sata_link_training(struct isci_phy *iphy)
@@ -591,7 +591,7 @@ static void sci_phy_start_sata_link_training(struct isci_phy *iphy)
*/
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER);
- iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+ iphy->protocol = SAS_PROTOCOL_SATA;
}
/**
@@ -668,6 +668,19 @@ static const char *phy_event_name(u32 event_code)
phy_to_host(iphy)->id, iphy->phy_index, \
phy_state_name(state), phy_event_name(code), code)
+
+void scu_link_layer_set_txcomsas_timeout(struct isci_phy *iphy, u32 timeout)
+{
+ u32 val;
+
+ /* Extend timeout */
+ val = readl(&iphy->link_layer_registers->transmit_comsas_signal);
+ val &= ~SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK);
+ val |= SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, timeout);
+
+ writel(val, &iphy->link_layer_registers->transmit_comsas_signal);
+}
+
enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
{
enum sci_phy_states state = iphy->sm.current_state_id;
@@ -683,6 +696,13 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
sci_phy_start_sata_link_training(iphy);
iphy->is_in_link_training = true;
break;
+ case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+ /* Extend timeout value */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+ /* Start the oob/sn state machine over again */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
default:
phy_event_dbg(iphy, state, event_code);
return SCI_FAILURE;
@@ -717,9 +737,19 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
sci_phy_start_sata_link_training(iphy);
break;
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
+ case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+ /* Extend the timeout value */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+ /* Start the oob/sn state machine over again */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
default:
phy_event_warn(iphy, state, event_code);
return SCI_FAILURE;
@@ -740,7 +770,14 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
sci_phy_start_sata_link_training(iphy);
break;
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+ /* Extend the timeout value */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+ /* Start the oob/sn state machine over again */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
case SCU_EVENT_LINK_FAILURE:
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
case SCU_EVENT_HARD_RESET_RECEIVED:
/* Start the oob/sn state machine over again */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
@@ -753,6 +790,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
case SCI_PHY_SUB_AWAIT_SAS_POWER:
switch (scu_get_event_code(event_code)) {
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
@@ -764,6 +804,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
case SCI_PHY_SUB_AWAIT_SATA_POWER:
switch (scu_get_event_code(event_code)) {
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
@@ -788,6 +831,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
switch (scu_get_event_code(event_code)) {
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
@@ -797,7 +843,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
*/
break;
case SCU_EVENT_SATA_PHY_DETECTED:
- iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+ iphy->protocol = SAS_PROTOCOL_SATA;
/* We have received the SATA PHY notification change state */
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN);
@@ -836,6 +882,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
SCI_PHY_SUB_AWAIT_SIG_FIS_UF);
break;
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
@@ -859,6 +908,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
break;
case SCU_EVENT_LINK_FAILURE:
+ /* Change the timeout value to default */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
@@ -871,16 +923,26 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
case SCI_PHY_READY:
switch (scu_get_event_code(event_code)) {
case SCU_EVENT_LINK_FAILURE:
+ /* Set default timeout */
+ scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
break;
case SCU_EVENT_BROADCAST_CHANGE:
+ case SCU_EVENT_BROADCAST_SES:
+ case SCU_EVENT_BROADCAST_RESERVED0:
+ case SCU_EVENT_BROADCAST_RESERVED1:
+ case SCU_EVENT_BROADCAST_EXPANDER:
+ case SCU_EVENT_BROADCAST_AEN:
/* Broadcast change received. Notify the port. */
if (phy_get_non_dummy_port(iphy) != NULL)
sci_port_broadcast_change_received(iphy->owning_port, iphy);
else
iphy->bcn_received_while_port_unassigned = true;
break;
+ case SCU_EVENT_BROADCAST_RESERVED3:
+ case SCU_EVENT_BROADCAST_RESERVED4:
default:
phy_event_warn(iphy, state, event_code);
return SCI_FAILURE_INVALID_STATE;
@@ -1215,7 +1277,7 @@ static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm)
scu_link_layer_start_oob(iphy);
/* We don't know what kind of phy we are going to be just yet */
- iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+ iphy->protocol = SAS_PROTOCOL_NONE;
iphy->bcn_received_while_port_unassigned = false;
if (iphy->sm.previous_state_id == SCI_PHY_READY)
@@ -1250,7 +1312,7 @@ static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm)
*/
sci_port_deactivate_phy(iphy->owning_port, iphy, false);
- if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ if (iphy->protocol == SAS_PROTOCOL_SSP) {
scu_link_layer_tx_hard_reset(iphy);
} else {
/* The SCU does not need to have a discrete reset state so
@@ -1316,7 +1378,7 @@ void sci_phy_construct(struct isci_phy *iphy,
iphy->owning_port = iport;
iphy->phy_index = phy_index;
iphy->bcn_received_while_port_unassigned = false;
- iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+ iphy->protocol = SAS_PROTOCOL_NONE;
iphy->link_layer_registers = NULL;
iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN;
@@ -1380,12 +1442,14 @@ int isci_phy_control(struct asd_sas_phy *sas_phy,
switch (func) {
case PHY_FUNC_DISABLE:
spin_lock_irqsave(&ihost->scic_lock, flags);
+ scu_link_layer_start_oob(iphy);
sci_phy_stop(iphy);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
break;
case PHY_FUNC_LINK_RESET:
spin_lock_irqsave(&ihost->scic_lock, flags);
+ scu_link_layer_start_oob(iphy);
sci_phy_stop(iphy);
sci_phy_start(iphy);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
diff --git a/drivers/scsi/isci/phy.h b/drivers/scsi/isci/phy.h
index 0e45833..45fecfa 100644
--- a/drivers/scsi/isci/phy.h
+++ b/drivers/scsi/isci/phy.h
@@ -76,13 +76,6 @@
*/
#define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT 250
-enum sci_phy_protocol {
- SCIC_SDS_PHY_PROTOCOL_UNKNOWN,
- SCIC_SDS_PHY_PROTOCOL_SAS,
- SCIC_SDS_PHY_PROTOCOL_SATA,
- SCIC_SDS_MAX_PHY_PROTOCOLS
-};
-
/**
* isci_phy - hba local phy infrastructure
* @sm:
@@ -95,7 +88,7 @@ struct isci_phy {
struct sci_base_state_machine sm;
struct isci_port *owning_port;
enum sas_linkrate max_negotiated_speed;
- enum sci_phy_protocol protocol;
+ enum sas_protocol protocol;
u8 phy_index;
bool bcn_received_while_port_unassigned;
bool is_in_link_training;
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 5fada73..2fb85bf 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -184,7 +184,7 @@ static void isci_port_link_up(struct isci_host *isci_host,
sci_port_get_properties(iport, &properties);
- if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
+ if (iphy->protocol == SAS_PROTOCOL_SATA) {
u64 attached_sas_address;
iphy->sas_phy.oob_mode = SATA_OOB_MODE;
@@ -204,7 +204,7 @@ static void isci_port_link_up(struct isci_host *isci_host,
memcpy(&iphy->sas_phy.attached_sas_addr,
&attached_sas_address, sizeof(attached_sas_address));
- } else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ } else if (iphy->protocol == SAS_PROTOCOL_SSP) {
iphy->sas_phy.oob_mode = SAS_OOB_MODE;
iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame);
@@ -251,10 +251,10 @@ static void isci_port_link_down(struct isci_host *isci_host,
if (isci_phy->sas_phy.port &&
isci_phy->sas_phy.port->num_phys == 1) {
/* change the state for all devices on this port. The
- * next task sent to this device will be returned as
- * SAS_TASK_UNDELIVERED, and the scsi mid layer will
- * remove the target
- */
+ * next task sent to this device will be returned as
+ * SAS_TASK_UNDELIVERED, and the scsi mid layer will
+ * remove the target
+ */
list_for_each_entry(isci_device,
&isci_port->remote_dev_list,
node) {
@@ -517,7 +517,7 @@ void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_a
*/
iphy = sci_port_get_a_connected_phy(iport);
if (iphy) {
- if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) {
+ if (iphy->protocol != SAS_PROTOCOL_SATA) {
sci_phy_get_attached_sas_address(iphy, sas);
} else {
sci_phy_get_sas_address(iphy, sas);
@@ -624,7 +624,7 @@ static void sci_port_activate_phy(struct isci_port *iport,
{
struct isci_host *ihost = iport->owning_controller;
- if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME))
+ if (iphy->protocol != SAS_PROTOCOL_SATA && (flags & PF_RESUME))
sci_phy_resume(iphy);
iport->active_phy_mask |= 1 << iphy->phy_index;
@@ -751,12 +751,10 @@ static bool sci_port_is_wide(struct isci_port *iport)
* wide ports and direct attached phys. Since there are no wide ported SATA
* devices this could become an invalid port configuration.
*/
-bool sci_port_link_detected(
- struct isci_port *iport,
- struct isci_phy *iphy)
+bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy)
{
if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) &&
- (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) {
+ (iphy->protocol == SAS_PROTOCOL_SATA)) {
if (sci_port_is_wide(iport)) {
sci_port_invalid_link_up(iport, iphy);
return false;
@@ -1201,6 +1199,8 @@ enum sci_status sci_port_add_phy(struct isci_port *iport,
enum sci_status status;
enum sci_port_states state;
+ sci_port_bcn_enable(iport);
+
state = iport->sm.current_state_id;
switch (state) {
case SCI_PORT_STOPPED: {
@@ -1548,6 +1548,29 @@ static void sci_port_failed_state_enter(struct sci_base_state_machine *sm)
isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT);
}
+void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout)
+{
+ int phy_index;
+ u32 phy_mask = iport->active_phy_mask;
+
+ if (timeout)
+ ++iport->hang_detect_users;
+ else if (iport->hang_detect_users > 1)
+ --iport->hang_detect_users;
+ else
+ iport->hang_detect_users = 0;
+
+ if (timeout || (iport->hang_detect_users == 0)) {
+ for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
+ if ((phy_mask >> phy_index) & 1) {
+ writel(timeout,
+ &iport->phy_table[phy_index]
+ ->link_layer_registers
+ ->link_layer_hang_detection_timeout);
+ }
+ }
+ }
+}
/* --------------------------------------------------------------------------- */
static const struct sci_base_state sci_port_state_table[] = {
@@ -1596,6 +1619,7 @@ void sci_port_construct(struct isci_port *iport, u8 index,
iport->started_request_count = 0;
iport->assigned_device_count = 0;
+ iport->hang_detect_users = 0;
iport->reserved_rni = SCU_DUMMY_INDEX;
iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG;
@@ -1608,13 +1632,6 @@ void sci_port_construct(struct isci_port *iport, u8 index,
iport->phy_table[index] = NULL;
}
-void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index)
-{
- INIT_LIST_HEAD(&iport->remote_dev_list);
- INIT_LIST_HEAD(&iport->domain_dev_list);
- iport->isci_host = ihost;
-}
-
void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy)
{
struct isci_host *ihost = iport->owning_controller;
@@ -1671,17 +1688,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
__func__, iport, status);
}
-
- /* If the hard reset for the port has failed, consider this
- * the same as link failures on all phys in the port.
- */
- if (ret != TMF_RESP_FUNC_COMPLETE) {
-
- dev_err(&ihost->pdev->dev,
- "%s: iport = %p; hard reset failed "
- "(0x%x) - driving explicit link fail for all phys\n",
- __func__, iport, iport->hard_reset_status);
- }
return ret;
}
@@ -1740,7 +1746,7 @@ void isci_port_formed(struct asd_sas_phy *phy)
struct isci_host *ihost = phy->ha->lldd_ha;
struct isci_phy *iphy = to_iphy(phy);
struct asd_sas_port *port = phy->port;
- struct isci_port *iport;
+ struct isci_port *iport = NULL;
unsigned long flags;
int i;
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index 6b56240..861e8f7 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -97,7 +97,6 @@ enum isci_status {
struct isci_port {
struct isci_host *isci_host;
struct list_head remote_dev_list;
- struct list_head domain_dev_list;
#define IPORT_RESET_PENDING 0
unsigned long state;
enum sci_status hard_reset_status;
@@ -112,6 +111,7 @@ struct isci_port {
u16 reserved_tag;
u32 started_request_count;
u32 assigned_device_count;
+ u32 hang_detect_users;
u32 not_ready_reason;
struct isci_phy *phy_table[SCI_MAX_PHYS];
struct isci_host *owning_controller;
@@ -270,14 +270,13 @@ void sci_port_get_attached_sas_address(
struct isci_port *iport,
struct sci_sas_address *sas_address);
+void sci_port_set_hang_detection_timeout(
+ struct isci_port *isci_port,
+ u32 timeout);
+
void isci_port_formed(struct asd_sas_phy *);
void isci_port_deformed(struct asd_sas_phy *);
-void isci_port_init(
- struct isci_port *port,
- struct isci_host *host,
- int index);
-
int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
struct isci_phy *iphy);
int isci_ata_check_ready(struct domain_device *dev);
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 6d1e954..cd962da 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -57,7 +57,7 @@
#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10)
#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10)
-#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250)
+#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (1000)
enum SCIC_SDS_APC_ACTIVITY {
SCIC_SDS_APC_SKIP_PHY,
@@ -472,13 +472,9 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
* down event or a link up event where we can not yet tell to which a phy
* belongs.
*/
-static void sci_apc_agent_start_timer(
- struct sci_port_configuration_agent *port_agent,
- u32 timeout)
+static void sci_apc_agent_start_timer(struct sci_port_configuration_agent *port_agent,
+ u32 timeout)
{
- if (port_agent->timer_pending)
- sci_del_timer(&port_agent->timer);
-
port_agent->timer_pending = true;
sci_mod_timer(&port_agent->timer, timeout);
}
@@ -697,6 +693,9 @@ static void apc_agent_timeout(unsigned long data)
&ihost->phys[index], false);
}
+ if (is_controller_start_complete(ihost))
+ sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
+
done:
spin_unlock_irqrestore(&ihost->scic_lock, flags);
}
@@ -732,6 +731,11 @@ void sci_port_configuration_agent_construct(
}
}
+bool is_port_config_apc(struct isci_host *ihost)
+{
+ return ihost->port_agent.link_up_handler == sci_apc_agent_link_up;
+}
+
enum sci_status sci_port_configuration_agent_initialize(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent)
diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c
index 9b8117b..4d95654 100644
--- a/drivers/scsi/isci/probe_roms.c
+++ b/drivers/scsi/isci/probe_roms.c
@@ -112,18 +112,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
return rom;
}
-enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
- struct isci_orom *orom, int scu_index)
-{
- /* check for valid inputs */
- if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS ||
- scu_index > orom->hdr.num_elements || !oem)
- return -EINVAL;
-
- *oem = orom->ctrl[scu_index];
- return 0;
-}
-
struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
{
struct isci_orom *orom = NULL, *data;
diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h
index bb0e9d4..e08b578 100644
--- a/drivers/scsi/isci/probe_roms.h
+++ b/drivers/scsi/isci/probe_roms.h
@@ -156,8 +156,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version);
struct isci_orom;
struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
-enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
- struct isci_orom *orom, int scu_index);
struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
struct isci_orom *isci_get_efi_var(struct pci_dev *pdev);
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index 7eb0ccd..97f3ceb 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -1239,6 +1239,14 @@ struct scu_transport_layer_registers {
#define SCU_SAS_LLCTL_GEN_BIT(name) \
SCU_GEN_BIT(SCU_SAS_LINK_LAYER_CONTROL_ ## name)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT (0xF0)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED (0x1FF)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_SHIFT (0)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK (0x3FF)
+
+#define SCU_SAS_LLTXCOMSAS_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_LINK_LAYER_TXCOMSAS_ ## name, value)
+
/* #define SCU_FRXHECR_DCNT_OFFSET 0x00B0 */
#define SCU_PSZGCR_OFFSET 0x00E4
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 8f501b0..c3aa6c5 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -72,46 +72,11 @@ const char *dev_state_name(enum sci_remote_device_states state)
}
#undef C
-/**
- * isci_remote_device_not_ready() - This function is called by the ihost when
- * the remote device is not ready. We mark the isci device as ready (not
- * "ready_for_io") and signal the waiting proccess.
- * @isci_host: This parameter specifies the isci host object.
- * @isci_device: This parameter specifies the remote device
- *
- * sci_lock is held on entrance to this function.
- */
-static void isci_remote_device_not_ready(struct isci_host *ihost,
- struct isci_remote_device *idev, u32 reason)
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+ enum sci_remote_node_suspension_reasons reason)
{
- struct isci_request *ireq;
-
- dev_dbg(&ihost->pdev->dev,
- "%s: isci_device = %p\n", __func__, idev);
-
- switch (reason) {
- case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
- set_bit(IDEV_GONE, &idev->flags);
- break;
- case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
- set_bit(IDEV_IO_NCQERROR, &idev->flags);
-
- /* Kill all outstanding requests for the device. */
- list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) {
-
- dev_dbg(&ihost->pdev->dev,
- "%s: isci_device = %p request = %p\n",
- __func__, idev, ireq);
-
- sci_controller_terminate_request(ihost,
- idev,
- ireq);
- }
- /* Fall through into the default case... */
- default:
- clear_bit(IDEV_IO_READY, &idev->flags);
- break;
- }
+ return sci_remote_node_context_suspend(&idev->rnc, reason,
+ SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
}
/**
@@ -133,18 +98,29 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
wake_up(&ihost->eventq);
}
-/* called once the remote node context is ready to be freed.
- * The remote device can now report that its stop operation is complete. none
- */
-static void rnc_destruct_done(void *_dev)
+static enum sci_status sci_remote_device_terminate_req(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ int check_abort,
+ struct isci_request *ireq)
{
- struct isci_remote_device *idev = _dev;
+ if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
+ (ireq->target_device != idev) ||
+ (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags)))
+ return SCI_SUCCESS;
- BUG_ON(idev->started_request_count != 0);
- sci_change_state(&idev->sm, SCI_DEV_STOPPED);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
+ __func__, idev, idev->flags, ireq, ireq->target_device);
+
+ set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
+
+ return sci_controller_terminate_request(ihost, idev, ireq);
}
-static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev)
+static enum sci_status sci_remote_device_terminate_reqs_checkabort(
+ struct isci_remote_device *idev,
+ int chk)
{
struct isci_host *ihost = idev->owning_port->owning_controller;
enum sci_status status = SCI_SUCCESS;
@@ -154,18 +130,210 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
struct isci_request *ireq = ihost->reqs[i];
enum sci_status s;
- if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
- ireq->target_device != idev)
- continue;
-
- s = sci_controller_terminate_request(ihost, idev, ireq);
+ s = sci_remote_device_terminate_req(ihost, idev, chk, ireq);
if (s != SCI_SUCCESS)
status = s;
}
+ return status;
+}
+
+static bool isci_compare_suspendcount(
+ struct isci_remote_device *idev,
+ u32 localcount)
+{
+ smp_rmb();
+
+ /* Check for a change in the suspend count, or the RNC
+ * being destroyed.
+ */
+ return (localcount != idev->rnc.suspend_count)
+ || sci_remote_node_context_is_being_destroyed(&idev->rnc);
+}
+
+static bool isci_check_reqterm(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq,
+ u32 localcount)
+{
+ unsigned long flags;
+ bool res;
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ res = isci_compare_suspendcount(idev, localcount)
+ && !test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return res;
+}
+
+static bool isci_check_devempty(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u32 localcount)
+{
+ unsigned long flags;
+ bool res;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ res = isci_compare_suspendcount(idev, localcount)
+ && idev->started_request_count == 0;
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return res;
+}
+
+enum sci_status isci_remote_device_terminate_requests(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ enum sci_status status = SCI_SUCCESS;
+ unsigned long flags;
+ u32 rnc_suspend_count;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
+ if (isci_get_device(idev) == NULL) {
+ dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n",
+ __func__, idev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ status = SCI_FAILURE;
+ } else {
+ /* If already suspended, don't wait for another suspension. */
+ smp_rmb();
+ rnc_suspend_count
+ = sci_remote_node_context_is_suspended(&idev->rnc)
+ ? 0 : idev->rnc.suspend_count;
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: idev=%p, ireq=%p; started_request_count=%d, "
+ "rnc_suspend_count=%d, rnc.suspend_count=%d"
+ "about to wait\n",
+ __func__, idev, ireq, idev->started_request_count,
+ rnc_suspend_count, idev->rnc.suspend_count);
+
+ #define MAX_SUSPEND_MSECS 10000
+ if (ireq) {
+ /* Terminate a specific TC. */
+ set_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
+ sci_remote_device_terminate_req(ihost, idev, 0, ireq);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ if (!wait_event_timeout(ihost->eventq,
+ isci_check_reqterm(ihost, idev, ireq,
+ rnc_suspend_count),
+ msecs_to_jiffies(MAX_SUSPEND_MSECS))) {
+
+ dev_warn(&ihost->pdev->dev, "%s host%d timeout single\n",
+ __func__, ihost->id);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: ******* Timeout waiting for "
+ "suspend; idev=%p, current state %s; "
+ "started_request_count=%d, flags=%lx\n\t"
+ "rnc_suspend_count=%d, rnc.suspend_count=%d "
+ "RNC: current state %s, current "
+ "suspend_type %x dest state %d;\n"
+ "ireq=%p, ireq->flags = %lx\n",
+ __func__, idev,
+ dev_state_name(idev->sm.current_state_id),
+ idev->started_request_count, idev->flags,
+ rnc_suspend_count, idev->rnc.suspend_count,
+ rnc_state_name(idev->rnc.sm.current_state_id),
+ idev->rnc.suspend_type,
+ idev->rnc.destination_state,
+ ireq, ireq->flags);
+ }
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
+ if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+ isci_free_tag(ihost, ireq->io_tag);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ } else {
+ /* Terminate all TCs. */
+ sci_remote_device_terminate_requests(idev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ if (!wait_event_timeout(ihost->eventq,
+ isci_check_devempty(ihost, idev,
+ rnc_suspend_count),
+ msecs_to_jiffies(MAX_SUSPEND_MSECS))) {
+
+ dev_warn(&ihost->pdev->dev, "%s host%d timeout all\n",
+ __func__, ihost->id);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: ******* Timeout waiting for "
+ "suspend; idev=%p, current state %s; "
+ "started_request_count=%d, flags=%lx\n\t"
+ "rnc_suspend_count=%d, "
+ "RNC: current state %s, "
+ "rnc.suspend_count=%d, current "
+ "suspend_type %x dest state %d\n",
+ __func__, idev,
+ dev_state_name(idev->sm.current_state_id),
+ idev->started_request_count, idev->flags,
+ rnc_suspend_count,
+ rnc_state_name(idev->rnc.sm.current_state_id),
+ idev->rnc.suspend_count,
+ idev->rnc.suspend_type,
+ idev->rnc.destination_state);
+ }
+ }
+ dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
+ __func__, idev);
+ isci_put_device(idev);
+ }
return status;
}
+/**
+* isci_remote_device_not_ready() - This function is called by the ihost when
+* the remote device is not ready. We mark the isci device as ready (not
+* "ready_for_io") and signal the waiting proccess.
+* @isci_host: This parameter specifies the isci host object.
+* @isci_device: This parameter specifies the remote device
+*
+* sci_lock is held on entrance to this function.
+*/
+static void isci_remote_device_not_ready(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u32 reason)
+{
+ dev_dbg(&ihost->pdev->dev,
+ "%s: isci_device = %p; reason = %d\n", __func__, idev, reason);
+
+ switch (reason) {
+ case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
+ set_bit(IDEV_IO_NCQERROR, &idev->flags);
+
+ /* Suspend the remote device so the I/O can be terminated. */
+ sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
+
+ /* Kill all outstanding requests for the device. */
+ sci_remote_device_terminate_requests(idev);
+
+ /* Fall through into the default case... */
+ default:
+ clear_bit(IDEV_IO_READY, &idev->flags);
+ break;
+ }
+}
+
+/* called once the remote node context is ready to be freed.
+ * The remote device can now report that its stop operation is complete. none
+ */
+static void rnc_destruct_done(void *_dev)
+{
+ struct isci_remote_device *idev = _dev;
+
+ BUG_ON(idev->started_request_count != 0);
+ sci_change_state(&idev->sm, SCI_DEV_STOPPED);
+}
+
+enum sci_status sci_remote_device_terminate_requests(
+ struct isci_remote_device *idev)
+{
+ return sci_remote_device_terminate_reqs_checkabort(idev, 0);
+}
+
enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
u32 timeout)
{
@@ -201,13 +369,16 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
case SCI_SMP_DEV_IDLE:
case SCI_SMP_DEV_CMD:
sci_change_state(sm, SCI_DEV_STOPPING);
- if (idev->started_request_count == 0) {
+ if (idev->started_request_count == 0)
sci_remote_node_context_destruct(&idev->rnc,
- rnc_destruct_done, idev);
- return SCI_SUCCESS;
- } else
- return sci_remote_device_terminate_requests(idev);
- break;
+ rnc_destruct_done,
+ idev);
+ else {
+ sci_remote_device_suspend(
+ idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
+ sci_remote_device_terminate_requests(idev);
+ }
+ return SCI_SUCCESS;
case SCI_DEV_STOPPING:
/* All requests should have been terminated, but if there is an
* attempt to stop a device already in the stopping state, then
@@ -265,22 +436,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
return SCI_SUCCESS;
}
-enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
- u32 suspend_type)
-{
- struct sci_base_state_machine *sm = &idev->sm;
- enum sci_remote_device_states state = sm->current_state_id;
-
- if (state != SCI_STP_DEV_CMD) {
- dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
- __func__, dev_state_name(state));
- return SCI_FAILURE_INVALID_STATE;
- }
-
- return sci_remote_node_context_suspend(&idev->rnc,
- suspend_type, NULL, NULL);
-}
-
enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
u32 frame_index)
{
@@ -412,9 +567,9 @@ static void atapi_remote_device_resume_done(void *_dev)
enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
u32 event_code)
{
+ enum sci_status status;
struct sci_base_state_machine *sm = &idev->sm;
enum sci_remote_device_states state = sm->current_state_id;
- enum sci_status status;
switch (scu_get_event_type(event_code)) {
case SCU_EVENT_TYPE_RNC_OPS_MISC:
@@ -427,9 +582,7 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
status = SCI_SUCCESS;
/* Suspend the associated RNC */
- sci_remote_node_context_suspend(&idev->rnc,
- SCI_SOFTWARE_SUSPENSION,
- NULL, NULL);
+ sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
dev_dbg(scirdev_to_dev(idev),
"%s: device: %p event code: %x: %s\n",
@@ -455,6 +608,10 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
if (status != SCI_SUCCESS)
return status;
+ /* Decode device-specific states that may require an RNC resume during
+ * normal operation. When the abort path is active, these resumes are
+ * managed when the abort path exits.
+ */
if (state == SCI_STP_DEV_ATAPI_ERROR) {
/* For ATAPI error state resume the RNC right away. */
if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
@@ -743,10 +900,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
if (status != SCI_SUCCESS)
return status;
- status = sci_remote_node_context_start_task(&idev->rnc, ireq);
- if (status != SCI_SUCCESS)
- goto out;
-
status = sci_request_start(ireq);
if (status != SCI_SUCCESS)
goto out;
@@ -765,11 +918,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
* the correct action when the remote node context is suspended
* and later resumed.
*/
- sci_remote_node_context_suspend(&idev->rnc,
- SCI_SOFTWARE_SUSPENSION, NULL, NULL);
- sci_remote_node_context_resume(&idev->rnc,
- sci_remote_device_continue_request,
- idev);
+ sci_remote_device_suspend(idev,
+ SCI_SW_SUSPEND_LINKHANG_DETECT);
+
+ status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+ sci_remote_device_continue_request, idev);
out:
sci_remote_device_start_request(idev, ireq, status);
@@ -783,7 +936,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
if (status != SCI_SUCCESS)
return status;
- status = sci_remote_node_context_start_task(&idev->rnc, ireq);
+ /* Resume the RNC as needed: */
+ status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+ NULL, NULL);
if (status != SCI_SUCCESS)
break;
@@ -892,7 +1047,7 @@ static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_
* here should go through isci_remote_device_nuke_requests.
* If we hit this condition, we will need a way to complete
* io requests in process */
- BUG_ON(!list_empty(&idev->reqs_in_process));
+ BUG_ON(idev->started_request_count > 0);
sci_remote_device_destruct(idev);
list_del_init(&idev->node);
@@ -954,14 +1109,21 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm
static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm)
{
struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+ struct isci_host *ihost = idev->owning_port->owning_controller;
- sci_remote_node_context_suspend(
- &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: isci_device = %p\n", __func__, idev);
+
+ sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
}
static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm)
{
struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+ struct isci_host *ihost = idev->owning_port->owning_controller;
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: isci_device = %p\n", __func__, idev);
sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
}
@@ -1113,33 +1275,20 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport,
{
enum sci_status status;
struct sci_port_properties properties;
- struct domain_device *dev = idev->domain_dev;
sci_remote_device_construct(iport, idev);
- /*
- * This information is request to determine how many remote node context
- * entries will be needed to store the remote node.
- */
- idev->is_direct_attached = true;
-
sci_port_get_properties(iport, &properties);
/* Get accurate port width from port's phy mask for a DA device. */
idev->device_port_width = hweight32(properties.phy_mask);
status = sci_controller_allocate_remote_node_context(iport->owning_controller,
- idev,
- &idev->rnc.remote_node_index);
+ idev,
+ &idev->rnc.remote_node_index);
if (status != SCI_SUCCESS)
return status;
- if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV ||
- (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev))
- /* pass */;
- else
- return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
-
idev->connection_rate = sci_port_get_max_allowed_speed(iport);
return SCI_SUCCESS;
@@ -1171,19 +1320,13 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
if (status != SCI_SUCCESS)
return status;
- if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV ||
- (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev))
- /* pass */;
- else
- return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
-
- /*
- * For SAS-2 the physical link rate is actually a logical link
+ /* For SAS-2 the physical link rate is actually a logical link
* rate that incorporates multiplexing. The SCU doesn't
* incorporate multiplexing and for the purposes of the
* connection the logical link rate is that same as the
* physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay
- * one another, so this code works for both situations. */
+ * one another, so this code works for both situations.
+ */
idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport),
dev->linkrate);
@@ -1193,6 +1336,105 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
return SCI_SUCCESS;
}
+enum sci_status sci_remote_device_resume(
+ struct isci_remote_device *idev,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ enum sci_status status;
+
+ status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p);
+ if (status != SCI_SUCCESS)
+ dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n",
+ __func__, status);
+ return status;
+}
+
+static void isci_remote_device_resume_from_abort_complete(void *cbparam)
+{
+ struct isci_remote_device *idev = cbparam;
+ struct isci_host *ihost = idev->owning_port->owning_controller;
+ scics_sds_remote_node_context_callback abort_resume_cb =
+ idev->abort_resume_cb;
+
+ dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n",
+ __func__, abort_resume_cb);
+
+ if (abort_resume_cb != NULL) {
+ idev->abort_resume_cb = NULL;
+ abort_resume_cb(idev->abort_resume_cbparam);
+ }
+ clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+ wake_up(&ihost->eventq);
+}
+
+static bool isci_remote_device_test_resume_done(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ unsigned long flags;
+ bool done;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ done = !test_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags)
+ || test_bit(IDEV_STOP_PENDING, &idev->flags)
+ || sci_remote_node_context_is_being_destroyed(&idev->rnc);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return done;
+}
+
+void isci_remote_device_wait_for_resume_from_abort(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ dev_dbg(&ihost->pdev->dev, "%s: starting resume wait: %p\n",
+ __func__, idev);
+
+ #define MAX_RESUME_MSECS 10000
+ if (!wait_event_timeout(ihost->eventq,
+ isci_remote_device_test_resume_done(ihost, idev),
+ msecs_to_jiffies(MAX_RESUME_MSECS))) {
+
+ dev_warn(&ihost->pdev->dev, "%s: #### Timeout waiting for "
+ "resume: %p\n", __func__, idev);
+ }
+ clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+
+ dev_dbg(&ihost->pdev->dev, "%s: resume wait done: %p\n",
+ __func__, idev);
+}
+
+enum sci_status isci_remote_device_resume_from_abort(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ unsigned long flags;
+ enum sci_status status = SCI_SUCCESS;
+ int destroyed;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ /* Preserve any current resume callbacks, for instance from other
+ * resumptions.
+ */
+ idev->abort_resume_cb = idev->rnc.user_callback;
+ idev->abort_resume_cbparam = idev->rnc.user_cookie;
+ set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+ clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
+ destroyed = sci_remote_node_context_is_being_destroyed(&idev->rnc);
+ if (!destroyed)
+ status = sci_remote_device_resume(
+ idev, isci_remote_device_resume_from_abort_complete,
+ idev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ if (!destroyed && (status == SCI_SUCCESS))
+ isci_remote_device_wait_for_resume_from_abort(ihost, idev);
+ else
+ clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+
+ return status;
+}
+
/**
* sci_remote_device_start() - This method will start the supplied remote
* device. This method enables normal IO requests to flow through to the
@@ -1207,7 +1449,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
* the device when there have been no phys added to it.
*/
static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
- u32 timeout)
+ u32 timeout)
{
struct sci_base_state_machine *sm = &idev->sm;
enum sci_remote_device_states state = sm->current_state_id;
@@ -1219,9 +1461,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
return SCI_FAILURE_INVALID_STATE;
}
- status = sci_remote_node_context_resume(&idev->rnc,
- remote_device_resume_done,
- idev);
+ status = sci_remote_device_resume(idev, remote_device_resume_done,
+ idev);
if (status != SCI_SUCCESS)
return status;
@@ -1259,20 +1500,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
return status;
}
-void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev)
-{
- DECLARE_COMPLETION_ONSTACK(aborted_task_completion);
-
- dev_dbg(&ihost->pdev->dev,
- "%s: idev = %p\n", __func__, idev);
-
- /* Cleanup all requests pending for this device. */
- isci_terminate_pending_requests(ihost, idev);
-
- dev_dbg(&ihost->pdev->dev,
- "%s: idev = %p, done\n", __func__, idev);
-}
-
/**
* This function builds the isci_remote_device when a libsas dev_found message
* is received.
@@ -1297,10 +1524,6 @@ isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport)
dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__);
return NULL;
}
-
- if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n"))
- return NULL;
-
if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n"))
return NULL;
@@ -1342,14 +1565,8 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem
spin_lock_irqsave(&ihost->scic_lock, flags);
idev->domain_dev->lldd_dev = NULL; /* disable new lookups */
set_bit(IDEV_GONE, &idev->flags);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- /* Kill all outstanding requests. */
- isci_remote_device_nuke_requests(ihost, idev);
set_bit(IDEV_STOP_PENDING, &idev->flags);
-
- spin_lock_irqsave(&ihost->scic_lock, flags);
status = sci_remote_device_stop(idev, 50);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -1359,6 +1576,9 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem
else
wait_for_device_stop(ihost, idev);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: isci_device = %p, waiting done.\n", __func__, idev);
+
return status;
}
@@ -1434,3 +1654,73 @@ int isci_remote_device_found(struct domain_device *dev)
return status == SCI_SUCCESS ? 0 : -ENODEV;
}
+
+enum sci_status isci_remote_device_suspend_terminate(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ unsigned long flags;
+ enum sci_status status;
+
+ /* Put the device into suspension. */
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
+ sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ /* Terminate and wait for the completions. */
+ status = isci_remote_device_terminate_requests(ihost, idev, ireq);
+ if (status != SCI_SUCCESS)
+ dev_dbg(&ihost->pdev->dev,
+ "%s: isci_remote_device_terminate_requests(%p) "
+ "returned %d!\n",
+ __func__, idev, status);
+
+ /* NOTE: RNC resumption is left to the caller! */
+ return status;
+}
+
+int isci_remote_device_is_safe_to_abort(
+ struct isci_remote_device *idev)
+{
+ return sci_remote_node_context_is_safe_to_abort(&idev->rnc);
+}
+
+enum sci_status sci_remote_device_abort_requests_pending_abort(
+ struct isci_remote_device *idev)
+{
+ return sci_remote_device_terminate_reqs_checkabort(idev, 1);
+}
+
+enum sci_status isci_remote_device_reset_complete(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ unsigned long flags;
+ enum sci_status status;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ status = sci_remote_device_reset_complete(idev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return status;
+}
+
+void isci_dev_set_hang_detection_timeout(
+ struct isci_remote_device *idev,
+ u32 timeout)
+{
+ if (dev_is_sata(idev->domain_dev)) {
+ if (timeout) {
+ if (test_and_set_bit(IDEV_RNC_LLHANG_ENABLED,
+ &idev->flags))
+ return; /* Already enabled. */
+ } else if (!test_and_clear_bit(IDEV_RNC_LLHANG_ENABLED,
+ &idev->flags))
+ return; /* Not enabled. */
+
+ sci_port_set_hang_detection_timeout(idev->owning_port,
+ timeout);
+ }
+}
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 58637ee..7674caa 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -85,27 +85,38 @@ struct isci_remote_device {
#define IDEV_GONE 3
#define IDEV_IO_READY 4
#define IDEV_IO_NCQERROR 5
+ #define IDEV_RNC_LLHANG_ENABLED 6
+ #define IDEV_ABORT_PATH_ACTIVE 7
+ #define IDEV_ABORT_PATH_RESUME_PENDING 8
unsigned long flags;
struct kref kref;
struct isci_port *isci_port;
struct domain_device *domain_dev;
struct list_head node;
- struct list_head reqs_in_process;
struct sci_base_state_machine sm;
u32 device_port_width;
enum sas_linkrate connection_rate;
- bool is_direct_attached;
struct isci_port *owning_port;
struct sci_remote_node_context rnc;
/* XXX unify with device reference counting and delete */
u32 started_request_count;
struct isci_request *working_request;
u32 not_ready_reason;
+ scics_sds_remote_node_context_callback abort_resume_cb;
+ void *abort_resume_cbparam;
};
#define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000
/* device reference routines must be called under sci_lock */
+static inline struct isci_remote_device *isci_get_device(
+ struct isci_remote_device *idev)
+{
+ if (idev)
+ kref_get(&idev->kref);
+ return idev;
+}
+
static inline struct isci_remote_device *isci_lookup_device(struct domain_device *dev)
{
struct isci_remote_device *idev = dev->lldd_dev;
@@ -302,6 +313,8 @@ static inline void sci_remote_device_decrement_request_count(struct isci_remote_
idev->started_request_count--;
}
+void isci_dev_set_hang_detection_timeout(struct isci_remote_device *idev, u32 timeout);
+
enum sci_status sci_remote_device_frame_handler(
struct isci_remote_device *idev,
u32 frame_index);
@@ -325,12 +338,50 @@ enum sci_status sci_remote_device_complete_io(
struct isci_remote_device *idev,
struct isci_request *ireq);
-enum sci_status sci_remote_device_suspend(
- struct isci_remote_device *idev,
- u32 suspend_type);
-
void sci_remote_device_post_request(
struct isci_remote_device *idev,
u32 request);
+enum sci_status sci_remote_device_terminate_requests(
+ struct isci_remote_device *idev);
+
+int isci_remote_device_is_safe_to_abort(
+ struct isci_remote_device *idev);
+
+enum sci_status
+sci_remote_device_abort_requests_pending_abort(
+ struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev);
+
+enum sci_status sci_remote_device_resume(
+ struct isci_remote_device *idev,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p);
+
+enum sci_status isci_remote_device_resume_from_abort(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_reset(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_reset_complete(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend_terminate(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+
+enum sci_status isci_remote_device_terminate_requests(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+ enum sci_remote_node_suspension_reasons reason);
#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 3a94634..1910100 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -52,7 +52,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+#include <scsi/sas_ata.h>
#include "host.h"
#include "isci.h"
#include "remote_device.h"
@@ -90,6 +90,15 @@ bool sci_remote_node_context_is_ready(
return false;
}
+bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc)
+{
+ u32 current_state = sci_rnc->sm.current_state_id;
+
+ if (current_state == SCI_RNC_TX_RX_SUSPENDED)
+ return true;
+ return false;
+}
+
static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id)
{
if (id < ihost->remote_node_entries &&
@@ -131,7 +140,7 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
rnc->ssp.arbitration_wait_time = 0;
- if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+ if (dev_is_sata(dev)) {
rnc->ssp.connection_occupancy_timeout =
ihost->user_parameters.stp_max_occupancy_timeout;
rnc->ssp.connection_inactivity_timeout =
@@ -151,7 +160,6 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
rnc->ssp.oaf_source_zone_group = 0;
rnc->ssp.oaf_more_compatibility_features = 0;
}
-
/**
*
* @sci_rnc:
@@ -165,23 +173,30 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
static void sci_remote_node_context_setup_to_resume(
struct sci_remote_node_context *sci_rnc,
scics_sds_remote_node_context_callback callback,
- void *callback_parameter)
+ void *callback_parameter,
+ enum sci_remote_node_context_destination_state dest_param)
{
- if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
- sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY;
- sci_rnc->user_callback = callback;
- sci_rnc->user_cookie = callback_parameter;
+ if (sci_rnc->destination_state != RNC_DEST_FINAL) {
+ sci_rnc->destination_state = dest_param;
+ if (callback != NULL) {
+ sci_rnc->user_callback = callback;
+ sci_rnc->user_cookie = callback_parameter;
+ }
}
}
-static void sci_remote_node_context_setup_to_destory(
+static void sci_remote_node_context_setup_to_destroy(
struct sci_remote_node_context *sci_rnc,
scics_sds_remote_node_context_callback callback,
void *callback_parameter)
{
- sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL;
+ struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc));
+
+ sci_rnc->destination_state = RNC_DEST_FINAL;
sci_rnc->user_callback = callback;
sci_rnc->user_cookie = callback_parameter;
+
+ wake_up(&ihost->eventq);
}
/**
@@ -203,9 +218,19 @@ static void sci_remote_node_context_notify_user(
static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)
{
- if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY)
+ switch (rnc->destination_state) {
+ case RNC_DEST_READY:
+ case RNC_DEST_SUSPENDED_RESUME:
+ rnc->destination_state = RNC_DEST_READY;
+ /* Fall through... */
+ case RNC_DEST_FINAL:
sci_remote_node_context_resume(rnc, rnc->user_callback,
- rnc->user_cookie);
+ rnc->user_cookie);
+ break;
+ default:
+ rnc->destination_state = RNC_DEST_UNSPECIFIED;
+ break;
+ }
}
static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)
@@ -219,13 +244,12 @@ static void sci_remote_node_context_validate_context_buffer(struct sci_remote_no
rnc_buffer->ssp.is_valid = true;
- if (!idev->is_direct_attached &&
- (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) {
+ if (dev_is_sata(dev) && dev->parent) {
sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96);
} else {
sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32);
- if (idev->is_direct_attached)
+ if (!dev->parent)
sci_port_setup_transports(idev->owning_port,
sci_rnc->remote_node_index);
}
@@ -248,13 +272,18 @@ static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_
static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm)
{
struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+ struct isci_remote_device *idev = rnc_to_dev(rnc);
+ struct isci_host *ihost = idev->owning_port->owning_controller;
/* Check to see if we have gotten back to the initial state because
* someone requested to destroy the remote node context object.
*/
if (sm->previous_state_id == SCI_RNC_INVALIDATING) {
- rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+ rnc->destination_state = RNC_DEST_UNSPECIFIED;
sci_remote_node_context_notify_user(rnc);
+
+ smp_wmb();
+ wake_up(&ihost->eventq);
}
}
@@ -269,6 +298,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta
{
struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+ /* Terminate all outstanding requests. */
+ sci_remote_device_terminate_requests(rnc_to_dev(rnc));
sci_remote_node_context_invalidate_context_buffer(rnc);
}
@@ -287,10 +318,8 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m
* resume because of a target reset we also need to update
* the STPTLDARNI register with the RNi of the device
*/
- if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
- idev->is_direct_attached)
- sci_port_setup_transports(idev->owning_port,
- rnc->remote_node_index);
+ if (dev_is_sata(dev) && !dev->parent)
+ sci_port_setup_transports(idev->owning_port, rnc->remote_node_index);
sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME);
}
@@ -298,10 +327,22 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m
static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm)
{
struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+ enum sci_remote_node_context_destination_state dest_select;
+ int tell_user = 1;
+
+ dest_select = rnc->destination_state;
+ rnc->destination_state = RNC_DEST_UNSPECIFIED;
- rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+ if ((dest_select == RNC_DEST_SUSPENDED) ||
+ (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
+ sci_remote_node_context_suspend(
+ rnc, rnc->suspend_reason,
+ SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
- if (rnc->user_callback)
+ if (dest_select == RNC_DEST_SUSPENDED_RESUME)
+ tell_user = 0; /* Wait until ready again. */
+ }
+ if (tell_user)
sci_remote_node_context_notify_user(rnc);
}
@@ -315,10 +356,34 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta
static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
{
struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+ struct isci_remote_device *idev = rnc_to_dev(rnc);
+ struct isci_host *ihost = idev->owning_port->owning_controller;
+ u32 new_count = rnc->suspend_count + 1;
+
+ if (new_count == 0)
+ rnc->suspend_count = 1;
+ else
+ rnc->suspend_count = new_count;
+ smp_wmb();
+ /* Terminate outstanding requests pending abort. */
+ sci_remote_device_abort_requests_pending_abort(idev);
+
+ wake_up(&ihost->eventq);
sci_remote_node_context_continue_state_transitions(rnc);
}
+static void sci_remote_node_context_await_suspend_state_exit(
+ struct sci_base_state_machine *sm)
+{
+ struct sci_remote_node_context *rnc
+ = container_of(sm, typeof(*rnc), sm);
+ struct isci_remote_device *idev = rnc_to_dev(rnc);
+
+ if (dev_is_sata(idev->domain_dev))
+ isci_dev_set_hang_detection_timeout(idev, 0);
+}
+
static const struct sci_base_state sci_remote_node_context_state_table[] = {
[SCI_RNC_INITIAL] = {
.enter_state = sci_remote_node_context_initial_state_enter,
@@ -341,7 +406,9 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
[SCI_RNC_TX_RX_SUSPENDED] = {
.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
},
- [SCI_RNC_AWAIT_SUSPENSION] = { },
+ [SCI_RNC_AWAIT_SUSPENSION] = {
+ .exit_state = sci_remote_node_context_await_suspend_state_exit,
+ },
};
void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
@@ -350,7 +417,7 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
memset(rnc, 0, sizeof(struct sci_remote_node_context));
rnc->remote_node_index = remote_node_index;
- rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+ rnc->destination_state = RNC_DEST_UNSPECIFIED;
sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL);
}
@@ -359,6 +426,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
u32 event_code)
{
enum scis_sds_remote_node_context_states state;
+ u32 next_state;
state = sci_rnc->sm.current_state_id;
switch (state) {
@@ -373,18 +441,18 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
break;
case SCI_RNC_INVALIDATING:
if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
- if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL)
- state = SCI_RNC_INITIAL;
+ if (sci_rnc->destination_state == RNC_DEST_FINAL)
+ next_state = SCI_RNC_INITIAL;
else
- state = SCI_RNC_POSTING;
- sci_change_state(&sci_rnc->sm, state);
+ next_state = SCI_RNC_POSTING;
+ sci_change_state(&sci_rnc->sm, next_state);
} else {
switch (scu_get_event_type(event_code)) {
case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
/* We really dont care if the hardware is going to suspend
* the device since it's being invalidated anyway */
- dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
"%s: SCIC Remote Node Context 0x%p was "
"suspeneded by hardware while being "
"invalidated.\n", __func__, sci_rnc);
@@ -403,7 +471,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
/* We really dont care if the hardware is going to suspend
* the device since it's being resumed anyway */
- dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
"%s: SCIC Remote Node Context 0x%p was "
"suspeneded by hardware while being resumed.\n",
__func__, sci_rnc);
@@ -417,11 +485,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
switch (scu_get_event_type(event_code)) {
case SCU_EVENT_TL_RNC_SUSPEND_TX:
sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
- sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+ sci_rnc->suspend_type = scu_get_event_type(event_code);
break;
case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
- sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+ sci_rnc->suspend_type = scu_get_event_type(event_code);
break;
default:
goto out;
@@ -430,27 +498,29 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
case SCI_RNC_AWAIT_SUSPENSION:
switch (scu_get_event_type(event_code)) {
case SCU_EVENT_TL_RNC_SUSPEND_TX:
- sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
- sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+ next_state = SCI_RNC_TX_SUSPENDED;
break;
case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
- sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
- sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+ next_state = SCI_RNC_TX_RX_SUSPENDED;
break;
default:
goto out;
}
+ if (sci_rnc->suspend_type == scu_get_event_type(event_code))
+ sci_change_state(&sci_rnc->sm, next_state);
break;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state: %s\n", __func__,
+ rnc_state_name(state));
return SCI_FAILURE_INVALID_STATE;
}
return SCI_SUCCESS;
out:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: code: %#x state: %d\n", __func__, event_code, state);
+ "%s: code: %#x state: %s\n", __func__, event_code,
+ rnc_state_name(state));
return SCI_FAILURE;
}
@@ -464,20 +534,23 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
state = sci_rnc->sm.current_state_id;
switch (state) {
case SCI_RNC_INVALIDATING:
- sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p);
+ sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
return SCI_SUCCESS;
case SCI_RNC_POSTING:
case SCI_RNC_RESUMING:
case SCI_RNC_READY:
case SCI_RNC_TX_SUSPENDED:
case SCI_RNC_TX_RX_SUSPENDED:
- case SCI_RNC_AWAIT_SUSPENSION:
- sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p);
+ sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
return SCI_SUCCESS;
+ case SCI_RNC_AWAIT_SUSPENSION:
+ sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
+ return SCI_SUCCESS;
case SCI_RNC_INITIAL:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state: %s\n", __func__,
+ rnc_state_name(state));
/* We have decided that the destruct request on the remote node context
* can not fail since it is either in the initial/destroyed state or is
* can be destroyed.
@@ -485,35 +558,101 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
return SCI_SUCCESS;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state %s\n", __func__,
+ rnc_state_name(state));
return SCI_FAILURE_INVALID_STATE;
}
}
-enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
- u32 suspend_type,
- scics_sds_remote_node_context_callback cb_fn,
- void *cb_p)
+enum sci_status sci_remote_node_context_suspend(
+ struct sci_remote_node_context *sci_rnc,
+ enum sci_remote_node_suspension_reasons suspend_reason,
+ u32 suspend_type)
{
- enum scis_sds_remote_node_context_states state;
+ enum scis_sds_remote_node_context_states state
+ = sci_rnc->sm.current_state_id;
+ struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
+ enum sci_status status = SCI_FAILURE_INVALID_STATE;
+ enum sci_remote_node_context_destination_state dest_param =
+ RNC_DEST_UNSPECIFIED;
+
+ dev_dbg(scirdev_to_dev(idev),
+ "%s: current state %s, current suspend_type %x dest state %d,"
+ " arg suspend_reason %d, arg suspend_type %x",
+ __func__, rnc_state_name(state), sci_rnc->suspend_type,
+ sci_rnc->destination_state, suspend_reason,
+ suspend_type);
+
+ /* Disable automatic state continuations if explicitly suspending. */
+ if ((suspend_reason == SCI_HW_SUSPEND) ||
+ (sci_rnc->destination_state == RNC_DEST_FINAL))
+ dest_param = sci_rnc->destination_state;
- state = sci_rnc->sm.current_state_id;
- if (state != SCI_RNC_READY) {
+ switch (state) {
+ case SCI_RNC_READY:
+ break;
+ case SCI_RNC_INVALIDATING:
+ if (sci_rnc->destination_state == RNC_DEST_FINAL) {
+ dev_warn(scirdev_to_dev(idev),
+ "%s: already destroying %p\n",
+ __func__, sci_rnc);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+ /* Fall through and handle like SCI_RNC_POSTING */
+ case SCI_RNC_RESUMING:
+ /* Fall through and handle like SCI_RNC_POSTING */
+ case SCI_RNC_POSTING:
+ /* Set the destination state to AWAIT - this signals the
+ * entry into the SCI_RNC_READY state that a suspension
+ * needs to be done immediately.
+ */
+ if (sci_rnc->destination_state != RNC_DEST_FINAL)
+ sci_rnc->destination_state = RNC_DEST_SUSPENDED;
+ sci_rnc->suspend_type = suspend_type;
+ sci_rnc->suspend_reason = suspend_reason;
+ return SCI_SUCCESS;
+
+ case SCI_RNC_TX_SUSPENDED:
+ if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
+ status = SCI_SUCCESS;
+ break;
+ case SCI_RNC_TX_RX_SUSPENDED:
+ if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+ status = SCI_SUCCESS;
+ break;
+ case SCI_RNC_AWAIT_SUSPENSION:
+ if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+ || (suspend_type == sci_rnc->suspend_type))
+ return SCI_SUCCESS;
+ break;
+ default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state %s\n", __func__,
+ rnc_state_name(state));
return SCI_FAILURE_INVALID_STATE;
}
+ sci_rnc->destination_state = dest_param;
+ sci_rnc->suspend_type = suspend_type;
+ sci_rnc->suspend_reason = suspend_reason;
+
+ if (status == SCI_SUCCESS) { /* Already in the destination state? */
+ struct isci_host *ihost = idev->owning_port->owning_controller;
+
+ wake_up_all(&ihost->eventq); /* Let observers look. */
+ return SCI_SUCCESS;
+ }
+ if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) ||
+ (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) {
- sci_rnc->user_callback = cb_fn;
- sci_rnc->user_cookie = cb_p;
- sci_rnc->suspension_code = suspend_type;
+ if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)
+ isci_dev_set_hang_detection_timeout(idev, 0x00000001);
- if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
- sci_remote_device_post_request(rnc_to_dev(sci_rnc),
- SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
+ sci_remote_device_post_request(
+ idev, SCI_SOFTWARE_SUSPEND_CMD);
}
+ if (state != SCI_RNC_AWAIT_SUSPENSION)
+ sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
- sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
return SCI_SUCCESS;
}
@@ -522,56 +661,86 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
void *cb_p)
{
enum scis_sds_remote_node_context_states state;
+ struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
state = sci_rnc->sm.current_state_id;
+ dev_dbg(scirdev_to_dev(idev),
+ "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; "
+ "dev resume path %s\n",
+ __func__, rnc_state_name(state), cb_fn, cb_p,
+ sci_rnc->destination_state,
+ test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)
+ ? "<abort active>" : "<normal>");
+
switch (state) {
case SCI_RNC_INITIAL:
if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
return SCI_FAILURE_INVALID_STATE;
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
- sci_remote_node_context_construct_buffer(sci_rnc);
- sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+ sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
+ RNC_DEST_READY);
+ if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
+ sci_remote_node_context_construct_buffer(sci_rnc);
+ sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+ }
return SCI_SUCCESS;
+
case SCI_RNC_POSTING:
case SCI_RNC_INVALIDATING:
case SCI_RNC_RESUMING:
- if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY)
- return SCI_FAILURE_INVALID_STATE;
-
- sci_rnc->user_callback = cb_fn;
- sci_rnc->user_cookie = cb_p;
+ /* We are still waiting to post when a resume was
+ * requested.
+ */
+ switch (sci_rnc->destination_state) {
+ case RNC_DEST_SUSPENDED:
+ case RNC_DEST_SUSPENDED_RESUME:
+ /* Previously waiting to suspend after posting.
+ * Now continue onto resumption.
+ */
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p,
+ RNC_DEST_SUSPENDED_RESUME);
+ break;
+ default:
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p,
+ RNC_DEST_READY);
+ break;
+ }
return SCI_SUCCESS;
- case SCI_RNC_TX_SUSPENDED: {
- struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
- struct domain_device *dev = idev->domain_dev;
-
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
-
- /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
- if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev))
- sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
- else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
- if (idev->is_direct_attached) {
- /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
- sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
- } else {
- sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
+
+ case SCI_RNC_TX_SUSPENDED:
+ case SCI_RNC_TX_RX_SUSPENDED:
+ {
+ struct domain_device *dev = idev->domain_dev;
+ /* If this is an expander attached SATA device we must
+ * invalidate and repost the RNC since this is the only
+ * way to clear the TCi to NCQ tag mapping table for
+ * the RNi. All other device types we can just resume.
+ */
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
+
+ if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
+ if ((dev_is_sata(dev) && dev->parent) ||
+ (sci_rnc->destination_state == RNC_DEST_FINAL))
+ sci_change_state(&sci_rnc->sm,
+ SCI_RNC_INVALIDATING);
+ else
+ sci_change_state(&sci_rnc->sm,
+ SCI_RNC_RESUMING);
}
- } else
- return SCI_FAILURE;
+ }
return SCI_SUCCESS;
- }
- case SCI_RNC_TX_RX_SUSPENDED:
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
- sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
- return SCI_FAILURE_INVALID_STATE;
+
case SCI_RNC_AWAIT_SUSPENSION:
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME);
return SCI_SUCCESS;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state %s\n", __func__,
+ rnc_state_name(state));
return SCI_FAILURE_INVALID_STATE;
}
}
@@ -590,35 +759,51 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
case SCI_RNC_TX_RX_SUSPENDED:
case SCI_RNC_AWAIT_SUSPENSION:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: invalid state %d\n", __func__, state);
+ "%s: invalid state %s\n", __func__,
+ rnc_state_name(state));
return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
default:
- break;
+ dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ "%s: invalid state %s\n", __func__,
+ rnc_state_name(state));
+ return SCI_FAILURE_INVALID_STATE;
}
- dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: requested to start IO while still resuming, %d\n",
- __func__, state);
- return SCI_FAILURE_INVALID_STATE;
}
-enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
- struct isci_request *ireq)
+enum sci_status sci_remote_node_context_start_task(
+ struct sci_remote_node_context *sci_rnc,
+ struct isci_request *ireq,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ enum sci_status status = sci_remote_node_context_resume(sci_rnc,
+ cb_fn, cb_p);
+ if (status != SCI_SUCCESS)
+ dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ "%s: resume failed: %d\n", __func__, status);
+ return status;
+}
+
+int sci_remote_node_context_is_safe_to_abort(
+ struct sci_remote_node_context *sci_rnc)
{
enum scis_sds_remote_node_context_states state;
state = sci_rnc->sm.current_state_id;
switch (state) {
+ case SCI_RNC_INVALIDATING:
+ case SCI_RNC_TX_RX_SUSPENDED:
+ return 1;
+ case SCI_RNC_POSTING:
case SCI_RNC_RESUMING:
case SCI_RNC_READY:
- case SCI_RNC_AWAIT_SUSPENSION:
- return SCI_SUCCESS;
case SCI_RNC_TX_SUSPENDED:
- case SCI_RNC_TX_RX_SUSPENDED:
- sci_remote_node_context_resume(sci_rnc, NULL, NULL);
- return SCI_SUCCESS;
+ case SCI_RNC_AWAIT_SUSPENSION:
+ case SCI_RNC_INITIAL:
+ return 0;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
"%s: invalid state %d\n", __func__, state);
- return SCI_FAILURE_INVALID_STATE;
+ return 0;
}
}
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index a241e0f..a703b9c 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -75,8 +75,13 @@
*/
#define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX 0x0FFF
-#define SCU_HARDWARE_SUSPENSION (0)
-#define SCI_SOFTWARE_SUSPENSION (1)
+enum sci_remote_node_suspension_reasons {
+ SCI_HW_SUSPEND,
+ SCI_SW_SUSPEND_NORMAL,
+ SCI_SW_SUSPEND_LINKHANG_DETECT
+};
+#define SCI_SOFTWARE_SUSPEND_CMD SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX
+#define SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT SCU_EVENT_TL_RNC_SUSPEND_TX_RX
struct isci_request;
struct isci_remote_device;
@@ -137,9 +142,13 @@ const char *rnc_state_name(enum scis_sds_remote_node_context_states state);
* node context.
*/
enum sci_remote_node_context_destination_state {
- SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED,
- SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY,
- SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL
+ RNC_DEST_UNSPECIFIED,
+ RNC_DEST_READY,
+ RNC_DEST_FINAL,
+ RNC_DEST_SUSPENDED, /* Set when suspend during post/invalidate */
+ RNC_DEST_SUSPENDED_RESUME /* Set when a resume was done during posting
+ * or invalidating and already suspending.
+ */
};
/**
@@ -156,10 +165,12 @@ struct sci_remote_node_context {
u16 remote_node_index;
/**
- * This field is the recored suspension code or the reason for the remote node
+ * This field is the recored suspension type of the remote node
* context suspension.
*/
- u32 suspension_code;
+ u32 suspend_type;
+ enum sci_remote_node_suspension_reasons suspend_reason;
+ u32 suspend_count;
/**
* This field is true if the remote node context is resuming from its current
@@ -193,6 +204,8 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
bool sci_remote_node_context_is_ready(
struct sci_remote_node_context *sci_rnc);
+bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc);
+
enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc,
u32 event_code);
enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc,
@@ -200,14 +213,24 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
void *callback_parameter);
enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
u32 suspend_type,
- scics_sds_remote_node_context_callback cb_fn,
- void *cb_p);
+ u32 suspension_code);
enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
scics_sds_remote_node_context_callback cb_fn,
void *cb_p);
enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
- struct isci_request *ireq);
+ struct isci_request *ireq,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p);
enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
struct isci_request *ireq);
+int sci_remote_node_context_is_safe_to_abort(
+ struct sci_remote_node_context *sci_rnc);
+static inline bool sci_remote_node_context_is_being_destroyed(
+ struct sci_remote_node_context *sci_rnc)
+{
+ return (sci_rnc->destination_state == RNC_DEST_FINAL)
+ || ((sci_rnc->sm.current_state_id == SCI_RNC_INITIAL)
+ && (sci_rnc->destination_state == RNC_DEST_UNSPECIFIED));
+}
#endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 2def1e3..7a0431c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -92,11 +92,11 @@ static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost,
if (idx == 0) {
offset = (void *) &ireq->tc->sgl_pair_ab -
(void *) &ihost->task_context_table[0];
- return ihost->task_context_dma + offset;
+ return ihost->tc_dma + offset;
} else if (idx == 1) {
offset = (void *) &ireq->tc->sgl_pair_cd -
(void *) &ihost->task_context_table[0];
- return ihost->task_context_dma + offset;
+ return ihost->tc_dma + offset;
}
return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]);
@@ -730,7 +730,7 @@ static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *i
{
struct sas_task *task = isci_request_access_task(ireq);
- ireq->protocol = SCIC_SSP_PROTOCOL;
+ ireq->protocol = SAS_PROTOCOL_SSP;
scu_ssp_io_request_construct_task_context(ireq,
task->data_dir,
@@ -763,7 +763,7 @@ static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *
bool copy = false;
struct sas_task *task = isci_request_access_task(ireq);
- ireq->protocol = SCIC_STP_PROTOCOL;
+ ireq->protocol = SAS_PROTOCOL_STP;
copy = (task->data_dir == DMA_NONE) ? false : true;
@@ -863,6 +863,8 @@ sci_io_request_terminate(struct isci_request *ireq)
switch (state) {
case SCI_REQ_CONSTRUCTED:
+ /* Set to make sure no HW terminate posting is done: */
+ set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags);
ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
@@ -883,8 +885,7 @@ sci_io_request_terminate(struct isci_request *ireq)
case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
case SCI_REQ_ATAPI_WAIT_D2H:
case SCI_REQ_ATAPI_WAIT_TC_COMP:
- sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
- return SCI_SUCCESS;
+ /* Fall through and change state to ABORTING... */
case SCI_REQ_TASK_WAIT_TC_RESP:
/* The task frame was already confirmed to have been
* sent by the SCU HW. Since the state machine is
@@ -893,20 +894,21 @@ sci_io_request_terminate(struct isci_request *ireq)
* and don't wait for the task response.
*/
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
- sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
- return SCI_SUCCESS;
+ /* Fall through and handle like ABORTING... */
case SCI_REQ_ABORTING:
- /* If a request has a termination requested twice, return
- * a failure indication, since HW confirmation of the first
- * abort is still outstanding.
+ if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
+ set_bit(IREQ_PENDING_ABORT, &ireq->flags);
+ else
+ clear_bit(IREQ_PENDING_ABORT, &ireq->flags);
+ /* If the request is only waiting on the remote device
+ * suspension, return SUCCESS so the caller will wait too.
*/
+ return SCI_SUCCESS;
case SCI_REQ_COMPLETED:
default:
dev_warn(&ireq->owning_controller->pdev->dev,
"%s: SCIC IO Request requested to abort while in wrong "
- "state %d\n",
- __func__,
- ireq->sm.current_state_id);
+ "state %d\n", __func__, ireq->sm.current_state_id);
break;
}
@@ -1070,7 +1072,7 @@ request_started_state_tc_event(struct isci_request *ireq,
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS):
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR):
- if (ireq->protocol == SCIC_STP_PROTOCOL) {
+ if (ireq->protocol == SAS_PROTOCOL_STP) {
ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
SCU_COMPLETION_TL_STATUS_SHIFT;
ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
@@ -2117,7 +2119,7 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
*/
if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
sci_remote_device_suspend(ireq->target_device,
- SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
+ SCI_SW_SUSPEND_NORMAL);
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
@@ -2138,13 +2140,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
/* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR
* - this comes only for B0
*/
- case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN):
- case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
- case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR):
- case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR):
- sci_remote_device_suspend(ireq->target_device,
- SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
- /* Fall through to the default case */
default:
/* All other completion status cause the IO to be complete. */
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
@@ -2262,15 +2257,151 @@ static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ire
return status;
}
+static int sci_request_smp_completion_status_is_tx_suspend(
+ unsigned int completion_status)
+{
+ switch (completion_status) {
+ case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+ case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+ return 1;
+ }
+ return 0;
+}
+
+static int sci_request_smp_completion_status_is_tx_rx_suspend(
+ unsigned int completion_status)
+{
+ return 0; /* There are no Tx/Rx SMP suspend conditions. */
+}
+
+static int sci_request_ssp_completion_status_is_tx_suspend(
+ unsigned int completion_status)
+{
+ switch (completion_status) {
+ case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+ case SCU_TASK_DONE_LF_ERR:
+ case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+ case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+ case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+ case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+ case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+ return 1;
+ }
+ return 0;
+}
+
+static int sci_request_ssp_completion_status_is_tx_rx_suspend(
+ unsigned int completion_status)
+{
+ return 0; /* There are no Tx/Rx SSP suspend conditions. */
+}
+
+static int sci_request_stpsata_completion_status_is_tx_suspend(
+ unsigned int completion_status)
+{
+ switch (completion_status) {
+ case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+ case SCU_TASK_DONE_LL_R_ERR:
+ case SCU_TASK_DONE_LL_PERR:
+ case SCU_TASK_DONE_REG_ERR:
+ case SCU_TASK_DONE_SDB_ERR:
+ case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+ case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+ case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+ case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+ case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+ case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+ case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+ return 1;
+ }
+ return 0;
+}
+
+
+static int sci_request_stpsata_completion_status_is_tx_rx_suspend(
+ unsigned int completion_status)
+{
+ switch (completion_status) {
+ case SCU_TASK_DONE_LF_ERR:
+ case SCU_TASK_DONE_LL_SY_TERM:
+ case SCU_TASK_DONE_LL_LF_TERM:
+ case SCU_TASK_DONE_BREAK_RCVD:
+ case SCU_TASK_DONE_INV_FIS_LEN:
+ case SCU_TASK_DONE_UNEXP_FIS:
+ case SCU_TASK_DONE_UNEXP_SDBFIS:
+ case SCU_TASK_DONE_MAX_PLD_ERR:
+ return 1;
+ }
+ return 0;
+}
+
+static void sci_request_handle_suspending_completions(
+ struct isci_request *ireq,
+ u32 completion_code)
+{
+ int is_tx = 0;
+ int is_tx_rx = 0;
+
+ switch (ireq->protocol) {
+ case SAS_PROTOCOL_SMP:
+ is_tx = sci_request_smp_completion_status_is_tx_suspend(
+ completion_code);
+ is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend(
+ completion_code);
+ break;
+ case SAS_PROTOCOL_SSP:
+ is_tx = sci_request_ssp_completion_status_is_tx_suspend(
+ completion_code);
+ is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend(
+ completion_code);
+ break;
+ case SAS_PROTOCOL_STP:
+ is_tx = sci_request_stpsata_completion_status_is_tx_suspend(
+ completion_code);
+ is_tx_rx =
+ sci_request_stpsata_completion_status_is_tx_rx_suspend(
+ completion_code);
+ break;
+ default:
+ dev_warn(&ireq->isci_host->pdev->dev,
+ "%s: request %p has no valid protocol\n",
+ __func__, ireq);
+ break;
+ }
+ if (is_tx || is_tx_rx) {
+ BUG_ON(is_tx && is_tx_rx);
+
+ sci_remote_node_context_suspend(
+ &ireq->target_device->rnc,
+ SCI_HW_SUSPEND,
+ (is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
+ : SCU_EVENT_TL_RNC_SUSPEND_TX);
+ }
+}
+
enum sci_status
sci_io_request_tc_completion(struct isci_request *ireq,
- u32 completion_code)
+ u32 completion_code)
{
enum sci_base_request_states state;
struct isci_host *ihost = ireq->owning_controller;
state = ireq->sm.current_state_id;
+ /* Decode those completions that signal upcoming suspension events. */
+ sci_request_handle_suspending_completions(
+ ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code));
+
switch (state) {
case SCI_REQ_STARTED:
return request_started_state_tc_event(ireq, completion_code);
@@ -2362,9 +2493,6 @@ static void isci_request_process_response_iu(
* @request: This parameter is the completed isci_request object.
* @response_ptr: This parameter specifies the service response for the I/O.
* @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- * the LLDD with respect to completing this request or forcing an abort
- * condition on the I/O.
* @open_rej_reason: This parameter specifies the encoded reason for the
* abandon-class reject.
*
@@ -2375,14 +2503,12 @@ static void isci_request_set_open_reject_status(
struct sas_task *task,
enum service_response *response_ptr,
enum exec_status *status_ptr,
- enum isci_completion_selection *complete_to_host_ptr,
enum sas_open_rej_reason open_rej_reason)
{
/* Task in the target is done. */
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*response_ptr = SAS_TASK_UNDELIVERED;
*status_ptr = SAS_OPEN_REJECT;
- *complete_to_host_ptr = isci_perform_normal_io_completion;
task->task_status.open_rej_reason = open_rej_reason;
}
@@ -2392,9 +2518,6 @@ static void isci_request_set_open_reject_status(
* @request: This parameter is the completed isci_request object.
* @response_ptr: This parameter specifies the service response for the I/O.
* @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- * the LLDD with respect to completing this request or forcing an abort
- * condition on the I/O.
*
* none.
*/
@@ -2403,8 +2526,7 @@ static void isci_request_handle_controller_specific_errors(
struct isci_request *request,
struct sas_task *task,
enum service_response *response_ptr,
- enum exec_status *status_ptr,
- enum isci_completion_selection *complete_to_host_ptr)
+ enum exec_status *status_ptr)
{
unsigned int cstatus;
@@ -2445,9 +2567,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAS_ABORTED_TASK;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
- *complete_to_host_ptr =
- isci_perform_normal_io_completion;
} else {
/* Task in the target is not done. */
*response_ptr = SAS_TASK_UNDELIVERED;
@@ -2458,9 +2577,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAM_STAT_TASK_ABORTED;
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
- *complete_to_host_ptr =
- isci_perform_error_io_completion;
}
break;
@@ -2489,8 +2605,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAS_ABORTED_TASK;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
- *complete_to_host_ptr = isci_perform_normal_io_completion;
break;
@@ -2501,7 +2615,7 @@ static void isci_request_handle_controller_specific_errors(
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_WRONG_DEST);
+ SAS_OREJ_WRONG_DEST);
break;
case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
@@ -2511,56 +2625,56 @@ static void isci_request_handle_controller_specific_errors(
*/
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_RESV_AB0);
+ SAS_OREJ_RESV_AB0);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_RESV_AB1);
+ SAS_OREJ_RESV_AB1);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_RESV_AB2);
+ SAS_OREJ_RESV_AB2);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_RESV_AB3);
+ SAS_OREJ_RESV_AB3);
break;
case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_BAD_DEST);
+ SAS_OREJ_BAD_DEST);
break;
case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_STP_NORES);
+ SAS_OREJ_STP_NORES);
break;
case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_EPROTO);
+ SAS_OREJ_EPROTO);
break;
case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
- complete_to_host_ptr, SAS_OREJ_CONN_RATE);
+ SAS_OREJ_CONN_RATE);
break;
case SCU_TASK_DONE_LL_R_ERR:
@@ -2592,95 +2706,12 @@ static void isci_request_handle_controller_specific_errors(
*response_ptr = SAS_TASK_UNDELIVERED;
*status_ptr = SAM_STAT_TASK_ABORTED;
- if (task->task_proto == SAS_PROTOCOL_SMP) {
+ if (task->task_proto == SAS_PROTOCOL_SMP)
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
- *complete_to_host_ptr = isci_perform_normal_io_completion;
- } else {
+ else
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
- *complete_to_host_ptr = isci_perform_error_io_completion;
- }
- break;
- }
-}
-
-/**
- * isci_task_save_for_upper_layer_completion() - This function saves the
- * request for later completion to the upper layer driver.
- * @host: This parameter is a pointer to the host on which the the request
- * should be queued (either as an error or success).
- * @request: This parameter is the completed request.
- * @response: This parameter is the response code for the completed task.
- * @status: This parameter is the status code for the completed task.
- *
- * none.
- */
-static void isci_task_save_for_upper_layer_completion(
- struct isci_host *host,
- struct isci_request *request,
- enum service_response response,
- enum exec_status status,
- enum isci_completion_selection task_notification_selection)
-{
- struct sas_task *task = isci_request_access_task(request);
-
- task_notification_selection
- = isci_task_set_completion_status(task, response, status,
- task_notification_selection);
-
- /* Tasks aborted specifically by a call to the lldd_abort_task
- * function should not be completed to the host in the regular path.
- */
- switch (task_notification_selection) {
-
- case isci_perform_normal_io_completion:
- /* Normal notification (task_done) */
-
- /* Add to the completed list. */
- list_add(&request->completed_node,
- &host->requests_to_complete);
-
- /* Take the request off the device's pending request list. */
- list_del_init(&request->dev_node);
- break;
-
- case isci_perform_aborted_io_completion:
- /* No notification to libsas because this request is
- * already in the abort path.
- */
- /* Wake up whatever process was waiting for this
- * request to complete.
- */
- WARN_ON(request->io_request_completion == NULL);
-
- if (request->io_request_completion != NULL) {
-
- /* Signal whoever is waiting that this
- * request is complete.
- */
- complete(request->io_request_completion);
- }
- break;
-
- case isci_perform_error_io_completion:
- /* Use sas_task_abort */
- /* Add to the aborted list. */
- list_add(&request->completed_node,
- &host->requests_to_errorback);
- break;
-
- default:
- /* Add to the error to libsas list. */
- list_add(&request->completed_node,
- &host->requests_to_errorback);
break;
}
- dev_dbg(&host->pdev->dev,
- "%s: %d - task = %p, response=%d (%d), status=%d (%d)\n",
- __func__, task_notification_selection, task,
- (task) ? task->task_status.resp : 0, response,
- (task) ? task->task_status.stat : 0, status);
}
static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
@@ -2715,295 +2746,164 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
struct isci_remote_device *idev = request->target_device;
enum service_response response = SAS_TASK_UNDELIVERED;
enum exec_status status = SAS_ABORTED_TASK;
- enum isci_request_status request_status;
- enum isci_completion_selection complete_to_host
- = isci_perform_normal_io_completion;
dev_dbg(&ihost->pdev->dev,
- "%s: request = %p, task = %p,\n"
+ "%s: request = %p, task = %p, "
"task->data_dir = %d completion_status = 0x%x\n",
- __func__,
- request,
- task,
- task->data_dir,
- completion_status);
+ __func__, request, task, task->data_dir, completion_status);
- spin_lock(&request->state_lock);
- request_status = request->status;
+ /* The request is done from an SCU HW perspective. */
- /* Decode the request status. Note that if the request has been
- * aborted by a task management function, we don't care
- * what the status is.
- */
- switch (request_status) {
-
- case aborted:
- /* "aborted" indicates that the request was aborted by a task
- * management function, since once a task management request is
- * perfomed by the device, the request only completes because
- * of the subsequent driver terminate.
- *
- * Aborted also means an external thread is explicitly managing
- * this request, so that we do not complete it up the stack.
- *
- * The target is still there (since the TMF was successful).
- */
- set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- response = SAS_TASK_COMPLETE;
+ /* This is an active request being completed from the core. */
+ switch (completion_status) {
- /* See if the device has been/is being stopped. Note
- * that we ignore the quiesce state, since we are
- * concerned about the actual device state.
- */
- if (!idev)
- status = SAS_DEVICE_UNKNOWN;
- else
- status = SAS_ABORTED_TASK;
+ case SCI_IO_FAILURE_RESPONSE_VALID:
+ dev_dbg(&ihost->pdev->dev,
+ "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
+ __func__, request, task);
+
+ if (sas_protocol_ata(task->task_proto)) {
+ isci_process_stp_response(task, &request->stp.rsp);
+ } else if (SAS_PROTOCOL_SSP == task->task_proto) {
+
+ /* crack the iu response buffer. */
+ resp_iu = &request->ssp.rsp;
+ isci_request_process_response_iu(task, resp_iu,
+ &ihost->pdev->dev);
+
+ } else if (SAS_PROTOCOL_SMP == task->task_proto) {
+
+ dev_err(&ihost->pdev->dev,
+ "%s: SCI_IO_FAILURE_RESPONSE_VALID: "
+ "SAS_PROTOCOL_SMP protocol\n",
+ __func__);
- complete_to_host = isci_perform_aborted_io_completion;
- /* This was an aborted request. */
+ } else
+ dev_err(&ihost->pdev->dev,
+ "%s: unknown protocol\n", __func__);
- spin_unlock(&request->state_lock);
+ /* use the task status set in the task struct by the
+ * isci_request_process_response_iu call.
+ */
+ set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+ response = task->task_status.resp;
+ status = task->task_status.stat;
break;
- case aborting:
- /* aborting means that the task management function tried and
- * failed to abort the request. We need to note the request
- * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the
- * target as down.
- *
- * Aborting also means an external thread is explicitly managing
- * this request, so that we do not complete it up the stack.
- */
+ case SCI_IO_SUCCESS:
+ case SCI_IO_SUCCESS_IO_DONE_EARLY:
+
+ response = SAS_TASK_COMPLETE;
+ status = SAM_STAT_GOOD;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- response = SAS_TASK_UNDELIVERED;
- if (!idev)
- /* The device has been /is being stopped. Note that
- * we ignore the quiesce state, since we are
- * concerned about the actual device state.
- */
- status = SAS_DEVICE_UNKNOWN;
- else
- status = SAS_PHY_DOWN;
+ if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
- complete_to_host = isci_perform_aborted_io_completion;
+ /* This was an SSP / STP / SATA transfer.
+ * There is a possibility that less data than
+ * the maximum was transferred.
+ */
+ u32 transferred_length = sci_req_tx_bytes(request);
- /* This was an aborted request. */
+ task->task_status.residual
+ = task->total_xfer_len - transferred_length;
+
+ /* If there were residual bytes, call this an
+ * underrun.
+ */
+ if (task->task_status.residual != 0)
+ status = SAS_DATA_UNDERRUN;
- spin_unlock(&request->state_lock);
+ dev_dbg(&ihost->pdev->dev,
+ "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
+ __func__, status);
+
+ } else
+ dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n",
+ __func__);
break;
- case terminating:
+ case SCI_IO_FAILURE_TERMINATED:
- /* This was an terminated request. This happens when
- * the I/O is being terminated because of an action on
- * the device (reset, tear down, etc.), and the I/O needs
- * to be completed up the stack.
- */
+ dev_dbg(&ihost->pdev->dev,
+ "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
+ __func__, request, task);
+
+ /* The request was terminated explicitly. */
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_UNDELIVERED;
/* See if the device has been/is being stopped. Note
- * that we ignore the quiesce state, since we are
- * concerned about the actual device state.
- */
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
if (!idev)
status = SAS_DEVICE_UNKNOWN;
else
status = SAS_ABORTED_TASK;
-
- complete_to_host = isci_perform_aborted_io_completion;
-
- /* This was a terminated request. */
-
- spin_unlock(&request->state_lock);
break;
- case dead:
- /* This was a terminated request that timed-out during the
- * termination process. There is no task to complete to
- * libsas.
- */
- complete_to_host = isci_perform_normal_io_completion;
- spin_unlock(&request->state_lock);
- break;
+ case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
- default:
-
- /* The request is done from an SCU HW perspective. */
- request->status = completed;
-
- spin_unlock(&request->state_lock);
-
- /* This is an active request being completed from the core. */
- switch (completion_status) {
-
- case SCI_IO_FAILURE_RESPONSE_VALID:
- dev_dbg(&ihost->pdev->dev,
- "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
- __func__,
- request,
- task);
-
- if (sas_protocol_ata(task->task_proto)) {
- isci_process_stp_response(task, &request->stp.rsp);
- } else if (SAS_PROTOCOL_SSP == task->task_proto) {
-
- /* crack the iu response buffer. */
- resp_iu = &request->ssp.rsp;
- isci_request_process_response_iu(task, resp_iu,
- &ihost->pdev->dev);
-
- } else if (SAS_PROTOCOL_SMP == task->task_proto) {
-
- dev_err(&ihost->pdev->dev,
- "%s: SCI_IO_FAILURE_RESPONSE_VALID: "
- "SAS_PROTOCOL_SMP protocol\n",
- __func__);
-
- } else
- dev_err(&ihost->pdev->dev,
- "%s: unknown protocol\n", __func__);
-
- /* use the task status set in the task struct by the
- * isci_request_process_response_iu call.
- */
- set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- response = task->task_status.resp;
- status = task->task_status.stat;
- break;
+ isci_request_handle_controller_specific_errors(idev, request,
+ task, &response,
+ &status);
+ break;
- case SCI_IO_SUCCESS:
- case SCI_IO_SUCCESS_IO_DONE_EARLY:
+ case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
+ /* This is a special case, in that the I/O completion
+ * is telling us that the device needs a reset.
+ * In order for the device reset condition to be
+ * noticed, the I/O has to be handled in the error
+ * handler. Set the reset flag and cause the
+ * SCSI error thread to be scheduled.
+ */
+ spin_lock_irqsave(&task->task_state_lock, task_flags);
+ task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, task_flags);
- response = SAS_TASK_COMPLETE;
- status = SAM_STAT_GOOD;
- set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+ /* Fail the I/O. */
+ response = SAS_TASK_UNDELIVERED;
+ status = SAM_STAT_TASK_ABORTED;
- if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
+ clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+ break;
- /* This was an SSP / STP / SATA transfer.
- * There is a possibility that less data than
- * the maximum was transferred.
- */
- u32 transferred_length = sci_req_tx_bytes(request);
+ case SCI_FAILURE_RETRY_REQUIRED:
- task->task_status.residual
- = task->total_xfer_len - transferred_length;
+ /* Fail the I/O so it can be retried. */
+ response = SAS_TASK_UNDELIVERED;
+ if (!idev)
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
- /* If there were residual bytes, call this an
- * underrun.
- */
- if (task->task_status.residual != 0)
- status = SAS_DATA_UNDERRUN;
+ set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+ break;
- dev_dbg(&ihost->pdev->dev,
- "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
- __func__,
- status);
- } else
- dev_dbg(&ihost->pdev->dev,
- "%s: SCI_IO_SUCCESS\n",
- __func__);
+ default:
+ /* Catch any otherwise unhandled error codes here. */
+ dev_dbg(&ihost->pdev->dev,
+ "%s: invalid completion code: 0x%x - "
+ "isci_request = %p\n",
+ __func__, completion_status, request);
- break;
+ response = SAS_TASK_UNDELIVERED;
- case SCI_IO_FAILURE_TERMINATED:
- dev_dbg(&ihost->pdev->dev,
- "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
- __func__,
- request,
- task);
+ /* See if the device has been/is being stopped. Note
+ * that we ignore the quiesce state, since we are
+ * concerned about the actual device state.
+ */
+ if (!idev)
+ status = SAS_DEVICE_UNKNOWN;
+ else
+ status = SAS_ABORTED_TASK;
- /* The request was terminated explicitly. No handling
- * is needed in the SCSI error handler path.
- */
+ if (SAS_PROTOCOL_SMP == task->task_proto)
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- response = SAS_TASK_UNDELIVERED;
-
- /* See if the device has been/is being stopped. Note
- * that we ignore the quiesce state, since we are
- * concerned about the actual device state.
- */
- if (!idev)
- status = SAS_DEVICE_UNKNOWN;
- else
- status = SAS_ABORTED_TASK;
-
- complete_to_host = isci_perform_normal_io_completion;
- break;
-
- case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
-
- isci_request_handle_controller_specific_errors(
- idev, request, task, &response, &status,
- &complete_to_host);
-
- break;
-
- case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
- /* This is a special case, in that the I/O completion
- * is telling us that the device needs a reset.
- * In order for the device reset condition to be
- * noticed, the I/O has to be handled in the error
- * handler. Set the reset flag and cause the
- * SCSI error thread to be scheduled.
- */
- spin_lock_irqsave(&task->task_state_lock, task_flags);
- task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
- spin_unlock_irqrestore(&task->task_state_lock, task_flags);
-
- /* Fail the I/O. */
- response = SAS_TASK_UNDELIVERED;
- status = SAM_STAT_TASK_ABORTED;
-
- complete_to_host = isci_perform_error_io_completion;
+ else
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- break;
-
- case SCI_FAILURE_RETRY_REQUIRED:
-
- /* Fail the I/O so it can be retried. */
- response = SAS_TASK_UNDELIVERED;
- if (!idev)
- status = SAS_DEVICE_UNKNOWN;
- else
- status = SAS_ABORTED_TASK;
-
- complete_to_host = isci_perform_normal_io_completion;
- set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- break;
-
-
- default:
- /* Catch any otherwise unhandled error codes here. */
- dev_dbg(&ihost->pdev->dev,
- "%s: invalid completion code: 0x%x - "
- "isci_request = %p\n",
- __func__, completion_status, request);
-
- response = SAS_TASK_UNDELIVERED;
-
- /* See if the device has been/is being stopped. Note
- * that we ignore the quiesce state, since we are
- * concerned about the actual device state.
- */
- if (!idev)
- status = SAS_DEVICE_UNKNOWN;
- else
- status = SAS_ABORTED_TASK;
-
- if (SAS_PROTOCOL_SMP == task->task_proto) {
- set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- complete_to_host = isci_perform_normal_io_completion;
- } else {
- clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
- complete_to_host = isci_perform_error_io_completion;
- }
- break;
- }
break;
}
@@ -3038,10 +2938,18 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
break;
}
- /* Put the completed request on the correct list */
- isci_task_save_for_upper_layer_completion(ihost, request, response,
- status, complete_to_host
- );
+ spin_lock_irqsave(&task->task_state_lock, task_flags);
+
+ task->task_status.resp = response;
+ task->task_status.stat = status;
+
+ if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) {
+ /* Normal notification (task_done) */
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+ SAS_TASK_STATE_PENDING);
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, task_flags);
/* complete the io request to the core. */
sci_controller_complete_io(ihost, request->target_device, request);
@@ -3051,6 +2959,8 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
* task to recognize the already completed case.
*/
set_bit(IREQ_TERMINATED, &request->flags);
+
+ ireq_done(ihost, request, task);
}
static void sci_request_started_state_enter(struct sci_base_state_machine *sm)
@@ -3169,7 +3079,7 @@ sci_general_request_construct(struct isci_host *ihost,
sci_init_sm(&ireq->sm, sci_request_state_table, SCI_REQ_INIT);
ireq->target_device = idev;
- ireq->protocol = SCIC_NO_PROTOCOL;
+ ireq->protocol = SAS_PROTOCOL_NONE;
ireq->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX;
ireq->sci_status = SCI_SUCCESS;
@@ -3193,7 +3103,7 @@ sci_io_request_construct(struct isci_host *ihost,
if (dev->dev_type == SAS_END_DEV)
/* pass */;
- else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
+ else if (dev_is_sata(dev))
memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
else if (dev_is_expander(dev))
/* pass */;
@@ -3215,10 +3125,15 @@ enum sci_status sci_task_request_construct(struct isci_host *ihost,
/* Build the common part of the request */
sci_general_request_construct(ihost, idev, ireq);
- if (dev->dev_type == SAS_END_DEV ||
- dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+ if (dev->dev_type == SAS_END_DEV || dev_is_sata(dev)) {
set_bit(IREQ_TMF, &ireq->flags);
memset(ireq->tc, 0, sizeof(struct scu_task_context));
+
+ /* Set the protocol indicator. */
+ if (dev_is_sata(dev))
+ ireq->protocol = SAS_PROTOCOL_STP;
+ else
+ ireq->protocol = SAS_PROTOCOL_SSP;
} else
status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
@@ -3311,7 +3226,7 @@ sci_io_request_construct_smp(struct device *dev,
if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
return SCI_FAILURE;
- ireq->protocol = SCIC_SMP_PROTOCOL;
+ ireq->protocol = SAS_PROTOCOL_SMP;
/* byte swap the smp request. */
@@ -3496,9 +3411,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
ireq->io_request_completion = NULL;
ireq->flags = 0;
ireq->num_sg_entries = 0;
- INIT_LIST_HEAD(&ireq->completed_node);
- INIT_LIST_HEAD(&ireq->dev_node);
- isci_request_change_state(ireq, allocated);
return ireq;
}
@@ -3582,26 +3494,15 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
spin_unlock_irqrestore(&ihost->scic_lock, flags);
return status;
}
-
/* Either I/O started OK, or the core has signaled that
* the device needs a target reset.
- *
- * In either case, hold onto the I/O for later.
- *
- * Update it's status and add it to the list in the
- * remote device object.
*/
- list_add(&ireq->dev_node, &idev->reqs_in_process);
-
- if (status == SCI_SUCCESS) {
- isci_request_change_state(ireq, started);
- } else {
+ if (status != SCI_SUCCESS) {
/* The request did not really start in the
* hardware, so clear the request handle
* here so no terminations will be done.
*/
set_bit(IREQ_TERMINATED, &ireq->flags);
- isci_request_change_state(ireq, completed);
}
spin_unlock_irqrestore(&ihost->scic_lock, flags);
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 057f237..aff9531 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -61,30 +61,6 @@
#include "scu_task_context.h"
/**
- * struct isci_request_status - This enum defines the possible states of an I/O
- * request.
- *
- *
- */
-enum isci_request_status {
- unallocated = 0x00,
- allocated = 0x01,
- started = 0x02,
- completed = 0x03,
- aborting = 0x04,
- aborted = 0x05,
- terminating = 0x06,
- dead = 0x07
-};
-
-enum sci_request_protocol {
- SCIC_NO_PROTOCOL,
- SCIC_SMP_PROTOCOL,
- SCIC_SSP_PROTOCOL,
- SCIC_STP_PROTOCOL
-}; /* XXX remove me, use sas_task.{dev|task_proto} instead */;
-
-/**
* isci_stp_request - extra request infrastructure to handle pio/atapi protocol
* @pio_len - number of bytes requested at PIO setup
* @status - pio setup ending status value to tell us if we need
@@ -104,11 +80,14 @@ struct isci_stp_request {
};
struct isci_request {
- enum isci_request_status status;
#define IREQ_COMPLETE_IN_TARGET 0
#define IREQ_TERMINATED 1
#define IREQ_TMF 2
#define IREQ_ACTIVE 3
+ #define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
+ #define IREQ_TC_ABORT_POSTED 5
+ #define IREQ_ABORT_PATH_ACTIVE 6
+ #define IREQ_NO_AUTO_FREE_TAG 7 /* Set when being explicitly managed */
unsigned long flags;
/* XXX kill ttype and ttype_ptr, allocate full sas_task */
union ttype_ptr_union {
@@ -116,11 +95,6 @@ struct isci_request {
struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */
} ttype_ptr;
struct isci_host *isci_host;
- /* For use in the requests_to_{complete|abort} lists: */
- struct list_head completed_node;
- /* For use in the reqs_in_process list: */
- struct list_head dev_node;
- spinlock_t state_lock;
dma_addr_t request_daddr;
dma_addr_t zero_scatter_daddr;
unsigned int num_sg_entries;
@@ -140,7 +114,7 @@ struct isci_request {
struct isci_host *owning_controller;
struct isci_remote_device *target_device;
u16 io_tag;
- enum sci_request_protocol protocol;
+ enum sas_protocol protocol;
u32 scu_status; /* hardware result */
u32 sci_status; /* upper layer disposition */
u32 post_context;
@@ -309,92 +283,6 @@ sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr)
return ireq->request_daddr + (requested_addr - base_addr);
}
-/**
- * isci_request_change_state() - This function sets the status of the request
- * object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- */
-static inline enum isci_request_status
-isci_request_change_state(struct isci_request *isci_request,
- enum isci_request_status status)
-{
- enum isci_request_status old_state;
- unsigned long flags;
-
- dev_dbg(&isci_request->isci_host->pdev->dev,
- "%s: isci_request = %p, state = 0x%x\n",
- __func__,
- isci_request,
- status);
-
- BUG_ON(isci_request == NULL);
-
- spin_lock_irqsave(&isci_request->state_lock, flags);
- old_state = isci_request->status;
- isci_request->status = status;
- spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
- return old_state;
-}
-
-/**
- * isci_request_change_started_to_newstate() - This function sets the status of
- * the request object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_newstate(struct isci_request *isci_request,
- struct completion *completion_ptr,
- enum isci_request_status newstate)
-{
- enum isci_request_status old_state;
- unsigned long flags;
-
- spin_lock_irqsave(&isci_request->state_lock, flags);
-
- old_state = isci_request->status;
-
- if (old_state == started || old_state == aborting) {
- BUG_ON(isci_request->io_request_completion != NULL);
-
- isci_request->io_request_completion = completion_ptr;
- isci_request->status = newstate;
- }
-
- spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
- dev_dbg(&isci_request->isci_host->pdev->dev,
- "%s: isci_request = %p, old_state = 0x%x\n",
- __func__,
- isci_request,
- old_state);
-
- return old_state;
-}
-
-/**
- * isci_request_change_started_to_aborted() - This function sets the status of
- * the request object.
- * @request: This parameter points to the isci_request object
- * @completion_ptr: This parameter is saved as the kernel completion structure
- * signalled when the old request completes.
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_aborted(struct isci_request *isci_request,
- struct completion *completion_ptr)
-{
- return isci_request_change_started_to_newstate(isci_request,
- completion_ptr,
- aborted);
-}
-
#define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr)
#define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr)
@@ -404,8 +292,6 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost,
u16 tag);
int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
struct sas_task *task, u16 tag);
-void isci_terminate_pending_requests(struct isci_host *ihost,
- struct isci_remote_device *idev);
enum sci_status
sci_task_request_construct(struct isci_host *ihost,
struct isci_remote_device *idev,
@@ -421,5 +307,4 @@ static inline int isci_task_is_ncq_recovery(struct sas_task *task)
task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ);
}
-
#endif /* !defined(_ISCI_REQUEST_H_) */
diff --git a/drivers/scsi/isci/scu_completion_codes.h b/drivers/scsi/isci/scu_completion_codes.h
index c8b329c..071cb74 100644
--- a/drivers/scsi/isci/scu_completion_codes.h
+++ b/drivers/scsi/isci/scu_completion_codes.h
@@ -224,6 +224,7 @@
* 32-bit value like we want, each immediate value must be cast to a u32.
*/
#define SCU_TASK_DONE_GOOD ((u32)0x00)
+#define SCU_TASK_DONE_TX_RAW_CMD_ERR ((u32)0x08)
#define SCU_TASK_DONE_CRC_ERR ((u32)0x14)
#define SCU_TASK_DONE_CHECK_RESPONSE ((u32)0x14)
#define SCU_TASK_DONE_GEN_RESPONSE ((u32)0x15)
@@ -237,6 +238,7 @@
#define SCU_TASK_DONE_LL_LF_TERM ((u32)0x1A)
#define SCU_TASK_DONE_DATA_LEN_ERR ((u32)0x1A)
#define SCU_TASK_DONE_LL_CL_TERM ((u32)0x1B)
+#define SCU_TASK_DONE_BREAK_RCVD ((u32)0x1B)
#define SCU_TASK_DONE_LL_ABORT_ERR ((u32)0x1B)
#define SCU_TASK_DONE_SEQ_INV_TYPE ((u32)0x1C)
#define SCU_TASK_DONE_UNEXP_XR ((u32)0x1C)
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 374254e..6bc74eb 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -78,54 +78,25 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
enum exec_status status)
{
- enum isci_completion_selection disposition;
+ unsigned long flags;
- disposition = isci_perform_normal_io_completion;
- disposition = isci_task_set_completion_status(task, response, status,
- disposition);
+ /* Normal notification (task_done) */
+ dev_dbg(&ihost->pdev->dev, "%s: task = %p, response=%d, status=%d\n",
+ __func__, task, response, status);
- /* Tasks aborted specifically by a call to the lldd_abort_task
- * function should not be completed to the host in the regular path.
- */
- switch (disposition) {
- case isci_perform_normal_io_completion:
- /* Normal notification (task_done) */
- dev_dbg(&ihost->pdev->dev,
- "%s: Normal - task = %p, response=%d, "
- "status=%d\n",
- __func__, task, response, status);
-
- task->lldd_task = NULL;
- task->task_done(task);
- break;
-
- case isci_perform_aborted_io_completion:
- /*
- * No notification because this request is already in the
- * abort path.
- */
- dev_dbg(&ihost->pdev->dev,
- "%s: Aborted - task = %p, response=%d, "
- "status=%d\n",
- __func__, task, response, status);
- break;
+ spin_lock_irqsave(&task->task_state_lock, flags);
- case isci_perform_error_io_completion:
- /* Use sas_task_abort */
- dev_dbg(&ihost->pdev->dev,
- "%s: Error - task = %p, response=%d, "
- "status=%d\n",
- __func__, task, response, status);
- sas_task_abort(task);
- break;
+ task->task_status.resp = response;
+ task->task_status.stat = status;
- default:
- dev_dbg(&ihost->pdev->dev,
- "%s: isci task notification default case!",
- __func__);
- sas_task_abort(task);
- break;
- }
+ /* Normal notification (task_done) */
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+ SAS_TASK_STATE_PENDING);
+ task->lldd_task = NULL;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ task->task_done(task);
}
#define for_each_sas_task(num, task) \
@@ -289,60 +260,6 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
return ireq;
}
-/**
-* isci_request_mark_zombie() - This function must be called with scic_lock held.
-*/
-static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq)
-{
- struct completion *tmf_completion = NULL;
- struct completion *req_completion;
-
- /* Set the request state to "dead". */
- ireq->status = dead;
-
- req_completion = ireq->io_request_completion;
- ireq->io_request_completion = NULL;
-
- if (test_bit(IREQ_TMF, &ireq->flags)) {
- /* Break links with the TMF request. */
- struct isci_tmf *tmf = isci_request_access_tmf(ireq);
-
- /* In the case where a task request is dying,
- * the thread waiting on the complete will sit and
- * timeout unless we wake it now. Since the TMF
- * has a default error status, complete it here
- * to wake the waiting thread.
- */
- if (tmf) {
- tmf_completion = tmf->complete;
- tmf->complete = NULL;
- }
- ireq->ttype_ptr.tmf_task_ptr = NULL;
- dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n",
- __func__, tmf->tmf_code, tmf->io_tag);
- } else {
- /* Break links with the sas_task - the callback is done
- * elsewhere.
- */
- struct sas_task *task = isci_request_access_task(ireq);
-
- if (task)
- task->lldd_task = NULL;
-
- ireq->ttype_ptr.io_task_ptr = NULL;
- }
-
- dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n",
- ireq->io_tag);
-
- /* Don't force waiting threads to timeout. */
- if (req_completion)
- complete(req_completion);
-
- if (tmf_completion != NULL)
- complete(tmf_completion);
-}
-
static int isci_task_execute_tmf(struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_tmf *tmf, unsigned long timeout_ms)
@@ -400,17 +317,11 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
spin_unlock_irqrestore(&ihost->scic_lock, flags);
goto err_tci;
}
-
- if (tmf->cb_state_func != NULL)
- tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data);
-
- isci_request_change_state(ireq, started);
-
- /* add the request to the remote device request list. */
- list_add(&ireq->dev_node, &idev->reqs_in_process);
-
spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ /* The RNC must be unsuspended before the TMF can get a response. */
+ isci_remote_device_resume_from_abort(ihost, idev);
+
/* Wait for the TMF to complete, or a timeout. */
timeleft = wait_for_completion_timeout(&completion,
msecs_to_jiffies(timeout_ms));
@@ -419,32 +330,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
/* The TMF did not complete - this could be because
* of an unplug. Terminate the TMF request now.
*/
- spin_lock_irqsave(&ihost->scic_lock, flags);
-
- if (tmf->cb_state_func != NULL)
- tmf->cb_state_func(isci_tmf_timed_out, tmf,
- tmf->cb_data);
-
- sci_controller_terminate_request(ihost, idev, ireq);
-
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- timeleft = wait_for_completion_timeout(
- &completion,
- msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
- if (!timeleft) {
- /* Strange condition - the termination of the TMF
- * request timed-out.
- */
- spin_lock_irqsave(&ihost->scic_lock, flags);
-
- /* If the TMF status has not changed, kill it. */
- if (tmf->status == SCI_FAILURE_TIMEOUT)
- isci_request_mark_zombie(ihost, ireq);
-
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
- }
+ isci_remote_device_suspend_terminate(ihost, idev, ireq);
}
isci_print_tmf(ihost, tmf);
@@ -476,315 +362,21 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
}
static void isci_task_build_tmf(struct isci_tmf *tmf,
- enum isci_tmf_function_codes code,
- void (*tmf_sent_cb)(enum isci_tmf_cb_state,
- struct isci_tmf *,
- void *),
- void *cb_data)
+ enum isci_tmf_function_codes code)
{
memset(tmf, 0, sizeof(*tmf));
-
- tmf->tmf_code = code;
- tmf->cb_state_func = tmf_sent_cb;
- tmf->cb_data = cb_data;
+ tmf->tmf_code = code;
}
static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf,
enum isci_tmf_function_codes code,
- void (*tmf_sent_cb)(enum isci_tmf_cb_state,
- struct isci_tmf *,
- void *),
struct isci_request *old_request)
{
- isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request);
+ isci_task_build_tmf(tmf, code);
tmf->io_tag = old_request->io_tag;
}
/**
- * isci_task_validate_request_to_abort() - This function checks the given I/O
- * against the "started" state. If the request is still "started", it's
- * state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD
- * BEFORE CALLING THIS FUNCTION.
- * @isci_request: This parameter specifies the request object to control.
- * @isci_host: This parameter specifies the ISCI host object
- * @isci_device: This is the device to which the request is pending.
- * @aborted_io_completion: This is a completion structure that will be added to
- * the request in case it is changed to aborting; this completion is
- * triggered when the request is fully completed.
- *
- * Either "started" on successful change of the task status to "aborted", or
- * "unallocated" if the task cannot be controlled.
- */
-static enum isci_request_status isci_task_validate_request_to_abort(
- struct isci_request *isci_request,
- struct isci_host *isci_host,
- struct isci_remote_device *isci_device,
- struct completion *aborted_io_completion)
-{
- enum isci_request_status old_state = unallocated;
-
- /* Only abort the task if it's in the
- * device's request_in_process list
- */
- if (isci_request && !list_empty(&isci_request->dev_node)) {
- old_state = isci_request_change_started_to_aborted(
- isci_request, aborted_io_completion);
-
- }
-
- return old_state;
-}
-
-static int isci_request_is_dealloc_managed(enum isci_request_status stat)
-{
- switch (stat) {
- case aborted:
- case aborting:
- case terminating:
- case completed:
- case dead:
- return true;
- default:
- return false;
- }
-}
-
-/**
- * isci_terminate_request_core() - This function will terminate the given
- * request, and wait for it to complete. This function must only be called
- * from a thread that can wait. Note that the request is terminated and
- * completed (back to the host, if started there).
- * @ihost: This SCU.
- * @idev: The target.
- * @isci_request: The I/O request to be terminated.
- *
- */
-static void isci_terminate_request_core(struct isci_host *ihost,
- struct isci_remote_device *idev,
- struct isci_request *isci_request)
-{
- enum sci_status status = SCI_SUCCESS;
- bool was_terminated = false;
- bool needs_cleanup_handling = false;
- unsigned long flags;
- unsigned long termination_completed = 1;
- struct completion *io_request_completion;
-
- dev_dbg(&ihost->pdev->dev,
- "%s: device = %p; request = %p\n",
- __func__, idev, isci_request);
-
- spin_lock_irqsave(&ihost->scic_lock, flags);
-
- io_request_completion = isci_request->io_request_completion;
-
- /* Note that we are not going to control
- * the target to abort the request.
- */
- set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags);
-
- /* Make sure the request wasn't just sitting around signalling
- * device condition (if the request handle is NULL, then the
- * request completed but needed additional handling here).
- */
- if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
- was_terminated = true;
- needs_cleanup_handling = true;
- status = sci_controller_terminate_request(ihost,
- idev,
- isci_request);
- }
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- /*
- * The only time the request to terminate will
- * fail is when the io request is completed and
- * being aborted.
- */
- if (status != SCI_SUCCESS) {
- dev_dbg(&ihost->pdev->dev,
- "%s: sci_controller_terminate_request"
- " returned = 0x%x\n",
- __func__, status);
-
- isci_request->io_request_completion = NULL;
-
- } else {
- if (was_terminated) {
- dev_dbg(&ihost->pdev->dev,
- "%s: before completion wait (%p/%p)\n",
- __func__, isci_request, io_request_completion);
-
- /* Wait here for the request to complete. */
- termination_completed
- = wait_for_completion_timeout(
- io_request_completion,
- msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
- if (!termination_completed) {
-
- /* The request to terminate has timed out. */
- spin_lock_irqsave(&ihost->scic_lock, flags);
-
- /* Check for state changes. */
- if (!test_bit(IREQ_TERMINATED,
- &isci_request->flags)) {
-
- /* The best we can do is to have the
- * request die a silent death if it
- * ever really completes.
- */
- isci_request_mark_zombie(ihost,
- isci_request);
- needs_cleanup_handling = true;
- } else
- termination_completed = 1;
-
- spin_unlock_irqrestore(&ihost->scic_lock,
- flags);
-
- if (!termination_completed) {
-
- dev_dbg(&ihost->pdev->dev,
- "%s: *** Timeout waiting for "
- "termination(%p/%p)\n",
- __func__, io_request_completion,
- isci_request);
-
- /* The request can no longer be referenced
- * safely since it may go away if the
- * termination every really does complete.
- */
- isci_request = NULL;
- }
- }
- if (termination_completed)
- dev_dbg(&ihost->pdev->dev,
- "%s: after completion wait (%p/%p)\n",
- __func__, isci_request, io_request_completion);
- }
-
- if (termination_completed) {
-
- isci_request->io_request_completion = NULL;
-
- /* Peek at the status of the request. This will tell
- * us if there was special handling on the request such that it
- * needs to be detached and freed here.
- */
- spin_lock_irqsave(&isci_request->state_lock, flags);
-
- needs_cleanup_handling
- = isci_request_is_dealloc_managed(
- isci_request->status);
-
- spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
- }
- if (needs_cleanup_handling) {
-
- dev_dbg(&ihost->pdev->dev,
- "%s: cleanup isci_device=%p, request=%p\n",
- __func__, idev, isci_request);
-
- if (isci_request != NULL) {
- spin_lock_irqsave(&ihost->scic_lock, flags);
- isci_free_tag(ihost, isci_request->io_tag);
- isci_request_change_state(isci_request, unallocated);
- list_del_init(&isci_request->dev_node);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
- }
- }
- }
-}
-
-/**
- * isci_terminate_pending_requests() - This function will change the all of the
- * requests on the given device's state to "aborting", will terminate the
- * requests, and wait for them to complete. This function must only be
- * called from a thread that can wait. Note that the requests are all
- * terminated and completed (back to the host, if started there).
- * @isci_host: This parameter specifies SCU.
- * @idev: This parameter specifies the target.
- *
- */
-void isci_terminate_pending_requests(struct isci_host *ihost,
- struct isci_remote_device *idev)
-{
- struct completion request_completion;
- enum isci_request_status old_state;
- unsigned long flags;
- LIST_HEAD(list);
-
- spin_lock_irqsave(&ihost->scic_lock, flags);
- list_splice_init(&idev->reqs_in_process, &list);
-
- /* assumes that isci_terminate_request_core deletes from the list */
- while (!list_empty(&list)) {
- struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node);
-
- /* Change state to "terminating" if it is currently
- * "started".
- */
- old_state = isci_request_change_started_to_newstate(ireq,
- &request_completion,
- terminating);
- switch (old_state) {
- case started:
- case completed:
- case aborting:
- break;
- default:
- /* termination in progress, or otherwise dispositioned.
- * We know the request was on 'list' so should be safe
- * to move it back to reqs_in_process
- */
- list_move(&ireq->dev_node, &idev->reqs_in_process);
- ireq = NULL;
- break;
- }
-
- if (!ireq)
- continue;
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- init_completion(&request_completion);
-
- dev_dbg(&ihost->pdev->dev,
- "%s: idev=%p request=%p; task=%p old_state=%d\n",
- __func__, idev, ireq,
- (!test_bit(IREQ_TMF, &ireq->flags)
- ? isci_request_access_task(ireq)
- : NULL),
- old_state);
-
- /* If the old_state is started:
- * This request was not already being aborted. If it had been,
- * then the aborting I/O (ie. the TMF request) would not be in
- * the aborting state, and thus would be terminated here. Note
- * that since the TMF completion's call to the kernel function
- * "complete()" does not happen until the pending I/O request
- * terminate fully completes, we do not have to implement a
- * special wait here for already aborting requests - the
- * termination of the TMF request will force the request
- * to finish it's already started terminate.
- *
- * If old_state == completed:
- * This request completed from the SCU hardware perspective
- * and now just needs cleaning up in terms of freeing the
- * request and potentially calling up to libsas.
- *
- * If old_state == aborting:
- * This request has already gone through a TMF timeout, but may
- * not have been terminated; needs cleaning up at least.
- */
- isci_terminate_request_core(ihost, idev, ireq);
- spin_lock_irqsave(&ihost->scic_lock, flags);
- }
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-}
-
-/**
* isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain
* Template functions.
* @lun: This parameter specifies the lun to be reset.
@@ -807,7 +399,7 @@ static int isci_task_send_lu_reset_sas(
* value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or
* was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED").
*/
- isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL);
+ isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset);
#define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS);
@@ -826,42 +418,44 @@ static int isci_task_send_lu_reset_sas(
int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
{
- struct isci_host *isci_host = dev_to_ihost(dev);
- struct isci_remote_device *isci_device;
+ struct isci_host *ihost = dev_to_ihost(dev);
+ struct isci_remote_device *idev;
unsigned long flags;
- int ret;
+ int ret = TMF_RESP_FUNC_COMPLETE;
- spin_lock_irqsave(&isci_host->scic_lock, flags);
- isci_device = isci_lookup_device(dev);
- spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ idev = isci_get_device(dev->lldd_dev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
- dev_dbg(&isci_host->pdev->dev,
+ dev_dbg(&ihost->pdev->dev,
"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
- __func__, dev, isci_host, isci_device);
+ __func__, dev, ihost, idev);
- if (!isci_device) {
- /* If the device is gone, stop the escalations. */
- dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);
+ if (!idev) {
+ /* If the device is gone, escalate to I_T_Nexus_Reset. */
+ dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
- ret = TMF_RESP_FUNC_COMPLETE;
+ ret = TMF_RESP_FUNC_FAILED;
goto out;
}
- /* Send the task management part of the reset. */
- if (dev_is_sata(dev)) {
- sas_ata_schedule_reset(dev);
- ret = TMF_RESP_FUNC_COMPLETE;
- } else
- ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
-
- /* If the LUN reset worked, all the I/O can now be terminated. */
- if (ret == TMF_RESP_FUNC_COMPLETE)
- /* Terminate all I/O now. */
- isci_terminate_pending_requests(isci_host,
- isci_device);
-
+ /* Suspend the RNC, kill all TCs */
+ if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+ != SCI_SUCCESS) {
+ /* The suspend/terminate only fails if isci_get_device fails */
+ ret = TMF_RESP_FUNC_FAILED;
+ goto out;
+ }
+ /* All pending I/Os have been terminated and cleaned up. */
+ if (!test_bit(IDEV_GONE, &idev->flags)) {
+ if (dev_is_sata(dev))
+ sas_ata_schedule_reset(dev);
+ else
+ /* Send the task management part of the reset. */
+ ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
+ }
out:
- isci_put_device(isci_device);
+ isci_put_device(idev);
return ret;
}
@@ -882,63 +476,6 @@ int isci_task_clear_nexus_ha(struct sas_ha_struct *ha)
/* Task Management Functions. Must be called from process context. */
/**
- * isci_abort_task_process_cb() - This is a helper function for the abort task
- * TMF command. It manages the request state with respect to the successful
- * transmission / completion of the abort task request.
- * @cb_state: This parameter specifies when this function was called - after
- * the TMF request has been started and after it has timed-out.
- * @tmf: This parameter specifies the TMF in progress.
- *
- *
- */
-static void isci_abort_task_process_cb(
- enum isci_tmf_cb_state cb_state,
- struct isci_tmf *tmf,
- void *cb_data)
-{
- struct isci_request *old_request;
-
- old_request = (struct isci_request *)cb_data;
-
- dev_dbg(&old_request->isci_host->pdev->dev,
- "%s: tmf=%p, old_request=%p\n",
- __func__, tmf, old_request);
-
- switch (cb_state) {
-
- case isci_tmf_started:
- /* The TMF has been started. Nothing to do here, since the
- * request state was already set to "aborted" by the abort
- * task function.
- */
- if ((old_request->status != aborted)
- && (old_request->status != completed))
- dev_dbg(&old_request->isci_host->pdev->dev,
- "%s: Bad request status (%d): tmf=%p, old_request=%p\n",
- __func__, old_request->status, tmf, old_request);
- break;
-
- case isci_tmf_timed_out:
-
- /* Set the task's state to "aborting", since the abort task
- * function thread set it to "aborted" (above) in anticipation
- * of the task management request working correctly. Since the
- * timeout has now fired, the TMF request failed. We set the
- * state such that the request completion will indicate the
- * device is no longer present.
- */
- isci_request_change_state(old_request, aborting);
- break;
-
- default:
- dev_dbg(&old_request->isci_host->pdev->dev,
- "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n",
- __func__, cb_state, tmf, old_request);
- break;
- }
-}
-
-/**
* isci_task_abort_task() - This function is one of the SAS Domain Template
* functions. This function is called by libsas to abort a specified task.
* @task: This parameter specifies the SAS task to abort.
@@ -947,22 +484,20 @@ static void isci_abort_task_process_cb(
*/
int isci_task_abort_task(struct sas_task *task)
{
- struct isci_host *isci_host = dev_to_ihost(task->dev);
+ struct isci_host *ihost = dev_to_ihost(task->dev);
DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
struct isci_request *old_request = NULL;
- enum isci_request_status old_state;
- struct isci_remote_device *isci_device = NULL;
+ struct isci_remote_device *idev = NULL;
struct isci_tmf tmf;
int ret = TMF_RESP_FUNC_FAILED;
unsigned long flags;
- int perform_termination = 0;
/* Get the isci_request reference from the task. Note that
* this check does not depend on the pending request list
* in the device, because tasks driving resets may land here
* after completion in the core.
*/
- spin_lock_irqsave(&isci_host->scic_lock, flags);
+ spin_lock_irqsave(&ihost->scic_lock, flags);
spin_lock(&task->task_state_lock);
old_request = task->lldd_task;
@@ -971,20 +506,29 @@ int isci_task_abort_task(struct sas_task *task)
if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
(task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
old_request)
- isci_device = isci_lookup_device(task->dev);
+ idev = isci_get_device(task->dev->lldd_dev);
spin_unlock(&task->task_state_lock);
- spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
- dev_dbg(&isci_host->pdev->dev,
- "%s: dev = %p, task = %p, old_request == %p\n",
- __func__, isci_device, task, old_request);
+ dev_warn(&ihost->pdev->dev,
+ "%s: dev = %p (%s%s), task = %p, old_request == %p\n",
+ __func__, idev,
+ (dev_is_sata(task->dev) ? "STP/SATA"
+ : ((dev_is_expander(task->dev))
+ ? "SMP"
+ : "SSP")),
+ ((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
+ ? " IDEV_GONE"
+ : "")
+ : " <NULL>"),
+ task, old_request);
/* Device reset conditions signalled in task_state_flags are the
* responsbility of libsas to observe at the start of the error
* handler thread.
*/
- if (!isci_device || !old_request) {
+ if (!idev || !old_request) {
/* The request has already completed and there
* is nothing to do here other than to set the task
* done bit, and indicate that the task abort function
@@ -998,108 +542,72 @@ int isci_task_abort_task(struct sas_task *task)
ret = TMF_RESP_FUNC_COMPLETE;
- dev_dbg(&isci_host->pdev->dev,
- "%s: abort task not needed for %p\n",
- __func__, task);
+ dev_warn(&ihost->pdev->dev,
+ "%s: abort task not needed for %p\n",
+ __func__, task);
goto out;
}
-
- spin_lock_irqsave(&isci_host->scic_lock, flags);
-
- /* Check the request status and change to "aborted" if currently
- * "starting"; if true then set the I/O kernel completion
- * struct that will be triggered when the request completes.
- */
- old_state = isci_task_validate_request_to_abort(
- old_request, isci_host, isci_device,
- &aborted_io_completion);
- if ((old_state != started) &&
- (old_state != completed) &&
- (old_state != aborting)) {
-
- spin_unlock_irqrestore(&isci_host->scic_lock, flags);
-
- /* The request was already being handled by someone else (because
- * they got to set the state away from started).
- */
- dev_dbg(&isci_host->pdev->dev,
- "%s: device = %p; old_request %p already being aborted\n",
- __func__,
- isci_device, old_request);
- ret = TMF_RESP_FUNC_COMPLETE;
+ /* Suspend the RNC, kill the TC */
+ if (isci_remote_device_suspend_terminate(ihost, idev, old_request)
+ != SCI_SUCCESS) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: isci_remote_device_reset_terminate(dev=%p, "
+ "req=%p, task=%p) failed\n",
+ __func__, idev, old_request, task);
+ ret = TMF_RESP_FUNC_FAILED;
goto out;
}
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
if (task->task_proto == SAS_PROTOCOL_SMP ||
sas_protocol_ata(task->task_proto) ||
- test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
+ test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags) ||
+ test_bit(IDEV_GONE, &idev->flags)) {
- spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
- dev_dbg(&isci_host->pdev->dev,
- "%s: %s request"
- " or complete_in_target (%d), thus no TMF\n",
- __func__,
- ((task->task_proto == SAS_PROTOCOL_SMP)
- ? "SMP"
- : (sas_protocol_ata(task->task_proto)
- ? "SATA/STP"
- : "<other>")
- ),
- test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));
-
- if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
- spin_lock_irqsave(&task->task_state_lock, flags);
- task->task_state_flags |= SAS_TASK_STATE_DONE;
- task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
- SAS_TASK_STATE_PENDING);
- spin_unlock_irqrestore(&task->task_state_lock, flags);
- ret = TMF_RESP_FUNC_COMPLETE;
- } else {
- spin_lock_irqsave(&task->task_state_lock, flags);
- task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
- SAS_TASK_STATE_PENDING);
- spin_unlock_irqrestore(&task->task_state_lock, flags);
- }
+ /* No task to send, so explicitly resume the device here */
+ isci_remote_device_resume_from_abort(ihost, idev);
- /* STP and SMP devices are not sent a TMF, but the
- * outstanding I/O request is terminated below. This is
- * because SATA/STP and SMP discovery path timeouts directly
- * call the abort task interface for cleanup.
- */
- perform_termination = 1;
+ dev_warn(&ihost->pdev->dev,
+ "%s: %s request"
+ " or complete_in_target (%d), "
+ "or IDEV_GONE (%d), thus no TMF\n",
+ __func__,
+ ((task->task_proto == SAS_PROTOCOL_SMP)
+ ? "SMP"
+ : (sas_protocol_ata(task->task_proto)
+ ? "SATA/STP"
+ : "<other>")
+ ),
+ test_bit(IREQ_COMPLETE_IN_TARGET,
+ &old_request->flags),
+ test_bit(IDEV_GONE, &idev->flags));
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+ SAS_TASK_STATE_PENDING);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ ret = TMF_RESP_FUNC_COMPLETE;
} else {
/* Fill in the tmf stucture */
isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
- isci_abort_task_process_cb,
old_request);
- spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ /* Send the task management request. */
#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
- ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
+ ret = isci_task_execute_tmf(ihost, idev, &tmf,
ISCI_ABORT_TASK_TIMEOUT_MS);
-
- if (ret == TMF_RESP_FUNC_COMPLETE)
- perform_termination = 1;
- else
- dev_dbg(&isci_host->pdev->dev,
- "%s: isci_task_send_tmf failed\n", __func__);
}
- if (perform_termination) {
- set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);
-
- /* Clean up the request on our side, and wait for the aborted
- * I/O to complete.
- */
- isci_terminate_request_core(isci_host, isci_device,
- old_request);
- }
-
- /* Make sure we do not leave a reference to aborted_io_completion */
- old_request->io_request_completion = NULL;
- out:
- isci_put_device(isci_device);
+out:
+ dev_warn(&ihost->pdev->dev,
+ "%s: Done; dev = %p, task = %p , old_request == %p\n",
+ __func__, idev, task, old_request);
+ isci_put_device(idev);
return ret;
}
@@ -1195,14 +703,11 @@ isci_task_request_complete(struct isci_host *ihost,
{
struct isci_tmf *tmf = isci_request_access_tmf(ireq);
struct completion *tmf_complete = NULL;
- struct completion *request_complete = ireq->io_request_completion;
dev_dbg(&ihost->pdev->dev,
"%s: request = %p, status=%d\n",
__func__, ireq, completion_status);
- isci_request_change_state(ireq, completed);
-
set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags);
if (tmf) {
@@ -1226,20 +731,11 @@ isci_task_request_complete(struct isci_host *ihost,
*/
set_bit(IREQ_TERMINATED, &ireq->flags);
- /* As soon as something is in the terminate path, deallocation is
- * managed there. Note that the final non-managed state of a task
- * request is "completed".
- */
- if ((ireq->status == completed) ||
- !isci_request_is_dealloc_managed(ireq->status)) {
- isci_request_change_state(ireq, unallocated);
- isci_free_tag(ihost, ireq->io_tag);
- list_del_init(&ireq->dev_node);
- }
+ if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+ wake_up_all(&ihost->eventq);
- /* "request_complete" is set if the task was being terminated. */
- if (request_complete)
- complete(request_complete);
+ if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags))
+ isci_free_tag(ihost, ireq->io_tag);
/* The task management part completes last. */
if (tmf_complete)
@@ -1250,48 +746,38 @@ static int isci_reset_device(struct isci_host *ihost,
struct domain_device *dev,
struct isci_remote_device *idev)
{
- int rc;
- unsigned long flags;
- enum sci_status status;
+ int rc = TMF_RESP_FUNC_COMPLETE, reset_stat = -1;
struct sas_phy *phy = sas_get_local_phy(dev);
struct isci_port *iport = dev->port->lldd_port;
dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
- spin_lock_irqsave(&ihost->scic_lock, flags);
- status = sci_remote_device_reset(idev);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- if (status != SCI_SUCCESS) {
- dev_dbg(&ihost->pdev->dev,
- "%s: sci_remote_device_reset(%p) returned %d!\n",
- __func__, idev, status);
+ /* Suspend the RNC, terminate all outstanding TCs. */
+ if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+ != SCI_SUCCESS) {
rc = TMF_RESP_FUNC_FAILED;
goto out;
}
-
- if (scsi_is_sas_phy_local(phy)) {
- struct isci_phy *iphy = &ihost->phys[phy->number];
-
- rc = isci_port_perform_hard_reset(ihost, iport, iphy);
- } else
- rc = sas_phy_reset(phy, !dev_is_sata(dev));
-
- /* Terminate in-progress I/O now. */
- isci_remote_device_nuke_requests(ihost, idev);
-
- /* Since all pending TCs have been cleaned, resume the RNC. */
- spin_lock_irqsave(&ihost->scic_lock, flags);
- status = sci_remote_device_reset_complete(idev);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
- if (status != SCI_SUCCESS) {
- dev_dbg(&ihost->pdev->dev,
- "%s: sci_remote_device_reset_complete(%p) "
- "returned %d!\n", __func__, idev, status);
+ /* Note that since the termination for outstanding requests succeeded,
+ * this function will return success. This is because the resets will
+ * only fail if the device has been removed (ie. hotplug), and the
+ * primary duty of this function is to cleanup tasks, so that is the
+ * relevant status.
+ */
+ if (!test_bit(IDEV_GONE, &idev->flags)) {
+ if (scsi_is_sas_phy_local(phy)) {
+ struct isci_phy *iphy = &ihost->phys[phy->number];
+
+ reset_stat = isci_port_perform_hard_reset(ihost, iport,
+ iphy);
+ } else
+ reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
}
+ /* Explicitly resume the RNC here, since there was no task sent. */
+ isci_remote_device_resume_from_abort(ihost, idev);
- dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
+ dev_dbg(&ihost->pdev->dev, "%s: idev %p complete, reset_stat=%d.\n",
+ __func__, idev, reset_stat);
out:
sas_put_local_phy(phy);
return rc;
@@ -1305,7 +791,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
int ret;
spin_lock_irqsave(&ihost->scic_lock, flags);
- idev = isci_lookup_device(dev);
+ idev = isci_get_device(dev->lldd_dev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (!idev) {
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
index 7b6d0e3..9c06cba 100644
--- a/drivers/scsi/isci/task.h
+++ b/drivers/scsi/isci/task.h
@@ -63,19 +63,6 @@
struct isci_request;
/**
- * enum isci_tmf_cb_state - This enum defines the possible states in which the
- * TMF callback function is invoked during the TMF execution process.
- *
- *
- */
-enum isci_tmf_cb_state {
-
- isci_tmf_init_state = 0,
- isci_tmf_started,
- isci_tmf_timed_out
-};
-
-/**
* enum isci_tmf_function_codes - This enum defines the possible preparations
* of task management requests.
*
@@ -87,6 +74,7 @@ enum isci_tmf_function_codes {
isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
isci_tmf_ssp_lun_reset = TMF_LU_RESET,
};
+
/**
* struct isci_tmf - This class represents the task management object which
* acts as an interface to libsas for processing task management requests
@@ -106,15 +94,6 @@ struct isci_tmf {
u16 io_tag;
enum isci_tmf_function_codes tmf_code;
int status;
-
- /* The optional callback function allows the user process to
- * track the TMF transmit / timeout conditions.
- */
- void (*cb_state_func)(
- enum isci_tmf_cb_state,
- struct isci_tmf *, void *);
- void *cb_data;
-
};
static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
@@ -208,113 +187,4 @@ int isci_queuecommand(
struct scsi_cmnd *scsi_cmd,
void (*donefunc)(struct scsi_cmnd *));
-/**
- * enum isci_completion_selection - This enum defines the possible actions to
- * take with respect to a given request's notification back to libsas.
- *
- *
- */
-enum isci_completion_selection {
-
- isci_perform_normal_io_completion, /* Normal notify (task_done) */
- isci_perform_aborted_io_completion, /* No notification. */
- isci_perform_error_io_completion /* Use sas_task_abort */
-};
-
-/**
- * isci_task_set_completion_status() - This function sets the completion status
- * for the request.
- * @task: This parameter is the completed request.
- * @response: This parameter is the response code for the completed task.
- * @status: This parameter is the status code for the completed task.
- *
-* @return The new notification mode for the request.
-*/
-static inline enum isci_completion_selection
-isci_task_set_completion_status(
- struct sas_task *task,
- enum service_response response,
- enum exec_status status,
- enum isci_completion_selection task_notification_selection)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&task->task_state_lock, flags);
-
- /* If a device reset is being indicated, make sure the I/O
- * is in the error path.
- */
- if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
- /* Fail the I/O to make sure it goes into the error path. */
- response = SAS_TASK_UNDELIVERED;
- status = SAM_STAT_TASK_ABORTED;
-
- task_notification_selection = isci_perform_error_io_completion;
- }
- task->task_status.resp = response;
- task->task_status.stat = status;
-
- switch (task->task_proto) {
-
- case SAS_PROTOCOL_SATA:
- case SAS_PROTOCOL_STP:
- case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-
- if (task_notification_selection
- == isci_perform_error_io_completion) {
- /* SATA/STP I/O has it's own means of scheduling device
- * error handling on the normal path.
- */
- task_notification_selection
- = isci_perform_normal_io_completion;
- }
- break;
- default:
- break;
- }
-
- switch (task_notification_selection) {
-
- case isci_perform_error_io_completion:
-
- if (task->task_proto == SAS_PROTOCOL_SMP) {
- /* There is no error escalation in the SMP case.
- * Convert to a normal completion to avoid the
- * timeout in the discovery path and to let the
- * next action take place quickly.
- */
- task_notification_selection
- = isci_perform_normal_io_completion;
-
- /* Fall through to the normal case... */
- } else {
- /* Use sas_task_abort */
- /* Leave SAS_TASK_STATE_DONE clear
- * Leave SAS_TASK_AT_INITIATOR set.
- */
- break;
- }
-
- case isci_perform_aborted_io_completion:
- /* This path can occur with task-managed requests as well as
- * requests terminated because of LUN or device resets.
- */
- /* Fall through to the normal case... */
- case isci_perform_normal_io_completion:
- /* Normal notification (task_done) */
- task->task_state_flags |= SAS_TASK_STATE_DONE;
- task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
- SAS_TASK_STATE_PENDING);
- break;
- default:
- WARN_ONCE(1, "unknown task_notification_selection: %d\n",
- task_notification_selection);
- break;
- }
-
- spin_unlock_irqrestore(&task->task_state_lock, flags);
-
- return task_notification_selection;
-
-}
#endif /* !defined(_SCI_TASK_H_) */
diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c
index 16f88ab..04a6d0d 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.c
+++ b/drivers/scsi/isci/unsolicited_frame_control.c
@@ -57,31 +57,19 @@
#include "unsolicited_frame_control.h"
#include "registers.h"
-int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
+void sci_unsolicited_frame_control_construct(struct isci_host *ihost)
{
struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control;
struct sci_unsolicited_frame *uf;
- u32 buf_len, header_len, i;
- dma_addr_t dma;
- size_t size;
- void *virt;
-
- /*
- * Prepare all of the memory sizes for the UF headers, UF address
- * table, and UF buffers themselves.
- */
- buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
- header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
- size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
+ dma_addr_t dma = ihost->ufi_dma;
+ void *virt = ihost->ufi_buf;
+ int i;
/*
* The Unsolicited Frame buffers are set at the start of the UF
* memory descriptor entry. The headers and address table will be
* placed after the buffers.
*/
- virt = dmam_alloc_coherent(&ihost->pdev->dev, size, &dma, GFP_KERNEL);
- if (!virt)
- return -ENOMEM;
/*
* Program the location of the UF header table into the SCU.
@@ -93,8 +81,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
* headers, since we program the UF address table pointers to
* NULL.
*/
- uf_control->headers.physical_address = dma + buf_len;
- uf_control->headers.array = virt + buf_len;
+ uf_control->headers.physical_address = dma + SCI_UFI_BUF_SIZE;
+ uf_control->headers.array = virt + SCI_UFI_BUF_SIZE;
/*
* Program the location of the UF address table into the SCU.
@@ -103,8 +91,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
* byte boundary already due to above programming headers being on a
* 64-bit boundary and headers are on a 64-bytes in size.
*/
- uf_control->address_table.physical_address = dma + buf_len + header_len;
- uf_control->address_table.array = virt + buf_len + header_len;
+ uf_control->address_table.physical_address = dma + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE;
+ uf_control->address_table.array = virt + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE;
uf_control->get = 0;
/*
@@ -135,8 +123,6 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
}
-
- return 0;
}
enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control,
diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h
index 75d8966..1bc551e 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.h
+++ b/drivers/scsi/isci/unsolicited_frame_control.h
@@ -257,9 +257,13 @@ struct sci_unsolicited_frame_control {
};
+#define SCI_UFI_BUF_SIZE (SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE)
+#define SCI_UFI_HDR_SIZE (SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header))
+#define SCI_UFI_TOTAL_SIZE (SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE + SCU_MAX_UNSOLICITED_FRAMES * sizeof(u64))
+
struct isci_host;
-int sci_unsolicited_frame_control_construct(struct isci_host *ihost);
+void sci_unsolicited_frame_control_construct(struct isci_host *ihost);
enum sci_status sci_unsolicited_frame_control_get_header(
struct sci_unsolicited_frame_control *uf_control,
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index cc83b66..c1402fb 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -648,6 +648,7 @@ int fc_lport_destroy(struct fc_lport *lport)
lport->tt.fcp_abort_io(lport);
lport->tt.disc_stop_final(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
+ cancel_delayed_work_sync(&lport->retry_work);
fc_fc4_del_lport(lport);
return 0;
}
@@ -1564,7 +1565,6 @@ static void fc_lport_timeout(struct work_struct *work)
switch (lport->state) {
case LPORT_ST_DISABLED:
- WARN_ON(1);
break;
case LPORT_ST_READY:
break;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3a1ffdd..e5da6da 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -93,6 +93,9 @@ struct lpfc_sli2_slim;
/* lpfc wait event data ready flag */
#define LPFC_DATA_READY (1<<0)
+/* queue dump line buffer size */
+#define LPFC_LBUF_SZ 128
+
enum lpfc_polling_flags {
ENABLE_FCP_RING_POLLING = 0x1,
DISABLE_FCP_RING_INT = 0x2
@@ -620,6 +623,7 @@ struct lpfc_hba {
#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
+#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 141e4b4..253d9a8 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2009-2011 Emulex. All rights reserved. *
+ * Copyright (C) 2009-2012 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -599,6 +599,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
cmdiocbq->context1 = dd_data;
+ cmdiocbq->context_un.ndlp = ndlp;
cmdiocbq->context2 = rspiocbq;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
@@ -3978,6 +3979,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
} else if (subsys == SLI_CONFIG_SUBSYS_COMN) {
switch (opcode) {
case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
+ case COMN_OPCODE_GET_CNTL_ATTRIBUTES:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3106 Handled SLI_CONFIG "
"subsys_comn, opcode:x%x\n",
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index edfe61fc..67f7d0a 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2010 Emulex. All rights reserved. *
+ * Copyright (C) 2010-2012 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -249,6 +249,7 @@ struct lpfc_sli_config_emb1_subsys {
#define COMN_OPCODE_READ_OBJECT_LIST 0xAD
#define COMN_OPCODE_DELETE_OBJECT 0xAE
#define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79
+#define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20
uint32_t timeout;
uint32_t request_length;
uint32_t word9;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 330dd71..9b2a16f 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -254,6 +254,7 @@ int
lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
+struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -460,6 +461,7 @@ int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t);
int lpfc_issue_reg_vfi(struct lpfc_vport *);
int lpfc_issue_unreg_vfi(struct lpfc_vport *);
int lpfc_selective_reset(struct lpfc_hba *);
-int lpfc_sli4_read_config(struct lpfc_hba *phba);
-int lpfc_scsi_buf_update(struct lpfc_hba *phba);
-void lpfc_sli4_node_prep(struct lpfc_hba *phba);
+int lpfc_sli4_read_config(struct lpfc_hba *);
+void lpfc_sli4_node_prep(struct lpfc_hba *);
+int lpfc_sli4_xri_sgl_update(struct lpfc_hba *);
+void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index af04b0d..3217d63 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -4466,3 +4466,49 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
#endif
return;
}
+
+/*
+ * Driver debug utility routines outside of debugfs. The debug utility
+ * routines implemented here is intended to be used in the instrumented
+ * debug driver for debugging host or port issues.
+ */
+
+/**
+ * lpfc_debug_dump_all_queues - dump all the queues with a hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps entries of all the queues asociated with the @phba.
+ **/
+void
+lpfc_debug_dump_all_queues(struct lpfc_hba *phba)
+{
+ int fcp_wqidx;
+
+ /*
+ * Dump Work Queues (WQs)
+ */
+ lpfc_debug_dump_mbx_wq(phba);
+ lpfc_debug_dump_els_wq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_wq(phba, fcp_wqidx);
+
+ lpfc_debug_dump_hdr_rq(phba);
+ lpfc_debug_dump_dat_rq(phba);
+ /*
+ * Dump Complete Queues (CQs)
+ */
+ lpfc_debug_dump_mbx_cq(phba);
+ lpfc_debug_dump_els_cq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_cq(phba, fcp_wqidx);
+
+ /*
+ * Dump Event Queues (EQs)
+ */
+ lpfc_debug_dump_sp_eq(phba);
+
+ for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++)
+ lpfc_debug_dump_fcp_eq(phba, fcp_wqidx);
+}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index f83bd94..616c400 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -267,3 +267,421 @@ struct lpfc_idiag {
#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general
* discovery */
#endif /* H_LPFC_DEBUG_FS */
+
+
+/*
+ * Driver debug utility routines outside of debugfs. The debug utility
+ * routines implemented here is intended to be used in the instrumented
+ * debug driver for debugging host or port issues.
+ */
+
+/**
+ * lpfc_debug_dump_qe - dump an specific entry from a queue
+ * @q: Pointer to the queue descriptor.
+ * @idx: Index to the entry on the queue.
+ *
+ * This function dumps an entry indexed by @idx from a queue specified by the
+ * queue descriptor @q.
+ **/
+static inline void
+lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx)
+{
+ char line_buf[LPFC_LBUF_SZ];
+ int i, esize, qe_word_cnt, len;
+ uint32_t *pword;
+
+ /* sanity checks */
+ if (!q)
+ return;
+ if (idx >= q->entry_count)
+ return;
+
+ esize = q->entry_size;
+ qe_word_cnt = esize / sizeof(uint32_t);
+ pword = q->qe[idx].address;
+
+ len = 0;
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx);
+ if (qe_word_cnt > 8)
+ printk(KERN_ERR "%s\n", line_buf);
+
+ for (i = 0; i < qe_word_cnt; i++) {
+ if (!(i % 8)) {
+ if (i != 0)
+ printk(KERN_ERR "%s\n", line_buf);
+ if (qe_word_cnt > 8) {
+ len = 0;
+ memset(line_buf, 0, LPFC_LBUF_SZ);
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len,
+ "%03d: ", i);
+ }
+ }
+ len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ",
+ ((uint32_t)*pword) & 0xffffffff);
+ pword++;
+ }
+ if (qe_word_cnt <= 8 || (i - 1) % 8)
+ printk(KERN_ERR "%s\n", line_buf);
+}
+
+/**
+ * lpfc_debug_dump_q - dump all entries from an specific queue
+ * @q: Pointer to the queue descriptor.
+ *
+ * This function dumps all entries from a queue specified by the queue
+ * descriptor @q.
+ **/
+static inline void
+lpfc_debug_dump_q(struct lpfc_queue *q)
+{
+ int idx, entry_count;
+
+ /* sanity check */
+ if (!q)
+ return;
+
+ dev_printk(KERN_ERR, &(((q->phba))->pcidev)->dev,
+ "%d: [qid:%d, type:%d, subtype:%d, "
+ "qe_size:%d, qe_count:%d, "
+ "host_index:%d, port_index:%d]\n",
+ (q->phba)->brd_no,
+ q->queue_id, q->type, q->subtype,
+ q->entry_size, q->entry_count,
+ q->host_index, q->hba_index);
+ entry_count = q->entry_count;
+ for (idx = 0; idx < entry_count; idx++)
+ lpfc_debug_dump_qe(q, idx);
+ printk(KERN_ERR "\n");
+}
+
+/**
+ * lpfc_debug_dump_fcp_wq - dump all entries from a fcp work queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP work queue specified by the
+ * @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_wq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+
+ printk(KERN_ERR "FCP WQ: WQ[Idx:%d|Qid:%d]\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[fcp_wqidx]);
+}
+
+/**
+ * lpfc_debug_dump_fcp_cq - dump all entries from a fcp work queue's cmpl queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP complete queue which is
+ * associated to the FCP work queue specified by the @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ int fcp_cqidx, fcp_cqid;
+
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+
+ fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid;
+ for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
+ if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
+ break;
+ if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+ return;
+
+ printk(KERN_ERR "FCP CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]:\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+ fcp_cqidx, fcp_cqid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[fcp_cqidx]);
+}
+
+/**
+ * lpfc_debug_dump_fcp_eq - dump all entries from a fcp work queue's evt queue
+ * @phba: Pointer to HBA context object.
+ * @fcp_wqidx: Index to a FCP work queue.
+ *
+ * This function dumps all entries from a FCP event queue which is
+ * associated to the FCP work queue specified by the @fcp_wqidx.
+ **/
+static inline void
+lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx)
+{
+ struct lpfc_queue *qdesc;
+ int fcp_eqidx, fcp_eqid;
+ int fcp_cqidx, fcp_cqid;
+
+ /* sanity check */
+ if (fcp_wqidx >= phba->cfg_fcp_wq_count)
+ return;
+ fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid;
+ for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++)
+ if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid)
+ break;
+ if (fcp_cqidx >= phba->cfg_fcp_eq_count)
+ return;
+
+ if (phba->cfg_fcp_eq_count == 0) {
+ fcp_eqidx = -1;
+ fcp_eqid = phba->sli4_hba.sp_eq->queue_id;
+ qdesc = phba->sli4_hba.sp_eq;
+ } else {
+ fcp_eqidx = fcp_cqidx;
+ fcp_eqid = phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id;
+ qdesc = phba->sli4_hba.fp_eq[fcp_eqidx];
+ }
+
+ printk(KERN_ERR "FCP EQ: WQ[Idx:%d|Qid:%d]->CQ[Idx:%d|Qid:%d]->"
+ "EQ[Idx:%d|Qid:%d]\n",
+ fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+ fcp_cqidx, fcp_cqid, fcp_eqidx, fcp_eqid);
+ lpfc_debug_dump_q(qdesc);
+}
+
+/**
+ * lpfc_debug_dump_els_wq - dump all entries from the els work queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the ELS work queue.
+ **/
+static inline void
+lpfc_debug_dump_els_wq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "ELS WQ: WQ[Qid:%d]:\n",
+ phba->sli4_hba.els_wq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.els_wq);
+}
+
+/**
+ * lpfc_debug_dump_mbx_wq - dump all entries from the mbox work queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the MBOX work queue.
+ **/
+static inline void
+lpfc_debug_dump_mbx_wq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "MBX WQ: WQ[Qid:%d]\n",
+ phba->sli4_hba.mbx_wq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_wq);
+}
+
+/**
+ * lpfc_debug_dump_dat_rq - dump all entries from the receive data queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the receive data queue.
+ **/
+static inline void
+lpfc_debug_dump_dat_rq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "DAT RQ: RQ[Qid:%d]\n",
+ phba->sli4_hba.dat_rq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.dat_rq);
+}
+
+/**
+ * lpfc_debug_dump_hdr_rq - dump all entries from the receive header queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the receive header queue.
+ **/
+static inline void
+lpfc_debug_dump_hdr_rq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "HDR RQ: RQ[Qid:%d]\n",
+ phba->sli4_hba.hdr_rq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.hdr_rq);
+}
+
+/**
+ * lpfc_debug_dump_els_cq - dump all entries from the els complete queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the els complete queue.
+ **/
+static inline void
+lpfc_debug_dump_els_cq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "ELS CQ: WQ[Qid:%d]->CQ[Qid:%d]\n",
+ phba->sli4_hba.els_wq->queue_id,
+ phba->sli4_hba.els_cq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.els_cq);
+}
+
+/**
+ * lpfc_debug_dump_mbx_cq - dump all entries from the mbox complete queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the mbox complete queue.
+ **/
+static inline void
+lpfc_debug_dump_mbx_cq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "MBX CQ: WQ[Qid:%d]->CQ[Qid:%d]\n",
+ phba->sli4_hba.mbx_wq->queue_id,
+ phba->sli4_hba.mbx_cq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_cq);
+}
+
+/**
+ * lpfc_debug_dump_sp_eq - dump all entries from slow-path event queue
+ * @phba: Pointer to HBA context object.
+ *
+ * This function dumps all entries from the slow-path event queue.
+ **/
+static inline void
+lpfc_debug_dump_sp_eq(struct lpfc_hba *phba)
+{
+ printk(KERN_ERR "SP EQ: WQ[Qid:%d/Qid:%d]->CQ[Qid:%d/Qid:%d]->"
+ "EQ[Qid:%d]:\n",
+ phba->sli4_hba.mbx_wq->queue_id,
+ phba->sli4_hba.els_wq->queue_id,
+ phba->sli4_hba.mbx_cq->queue_id,
+ phba->sli4_hba.els_cq->queue_id,
+ phba->sli4_hba.sp_eq->queue_id);
+ lpfc_debug_dump_q(phba->sli4_hba.sp_eq);
+}
+
+/**
+ * lpfc_debug_dump_wq_by_id - dump all entries from a work queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Work queue identifier.
+ *
+ * This function dumps all entries from a work queue identified by the queue
+ * identifier.
+ **/
+static inline void
+lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int wq_idx;
+
+ for (wq_idx = 0; wq_idx < phba->cfg_fcp_wq_count; wq_idx++)
+ if (phba->sli4_hba.fcp_wq[wq_idx]->queue_id == qid)
+ break;
+ if (wq_idx < phba->cfg_fcp_wq_count) {
+ printk(KERN_ERR "FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[wq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.els_wq->queue_id == qid) {
+ printk(KERN_ERR "ELS WQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.els_wq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_mq_by_id - dump all entries from a mbox queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Mbox work queue identifier.
+ *
+ * This function dumps all entries from a mbox work queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_mq_by_id(struct lpfc_hba *phba, int qid)
+{
+ if (phba->sli4_hba.mbx_wq->queue_id == qid) {
+ printk(KERN_ERR "MBX WQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_wq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_rq_by_id - dump all entries from a receive queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Receive queue identifier.
+ *
+ * This function dumps all entries from a receive queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_rq_by_id(struct lpfc_hba *phba, int qid)
+{
+ if (phba->sli4_hba.hdr_rq->queue_id == qid) {
+ printk(KERN_ERR "HDR RQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.hdr_rq);
+ return;
+ }
+ if (phba->sli4_hba.dat_rq->queue_id == qid) {
+ printk(KERN_ERR "DAT RQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.dat_rq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_cq_by_id - dump all entries from a cmpl queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Complete queue identifier.
+ *
+ * This function dumps all entries from a complete queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int cq_idx = 0;
+
+ do {
+ if (phba->sli4_hba.fcp_cq[cq_idx]->queue_id == qid)
+ break;
+ } while (++cq_idx < phba->cfg_fcp_eq_count);
+
+ if (cq_idx < phba->cfg_fcp_eq_count) {
+ printk(KERN_ERR "FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[cq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.els_cq->queue_id == qid) {
+ printk(KERN_ERR "ELS CQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.els_cq);
+ return;
+ }
+
+ if (phba->sli4_hba.mbx_cq->queue_id == qid) {
+ printk(KERN_ERR "MBX CQ[Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.mbx_cq);
+ }
+}
+
+/**
+ * lpfc_debug_dump_eq_by_id - dump all entries from an event queue by queue id
+ * @phba: Pointer to HBA context object.
+ * @qid: Complete queue identifier.
+ *
+ * This function dumps all entries from an event queue identified by the
+ * queue identifier.
+ **/
+static inline void
+lpfc_debug_dump_eq_by_id(struct lpfc_hba *phba, int qid)
+{
+ int eq_idx;
+
+ for (eq_idx = 0; eq_idx < phba->cfg_fcp_eq_count; eq_idx++) {
+ if (phba->sli4_hba.fp_eq[eq_idx]->queue_id == qid)
+ break;
+ }
+
+ if (eq_idx < phba->cfg_fcp_eq_count) {
+ printk(KERN_ERR "FCP EQ[Idx:%d|Qid:%d]\n", eq_idx, qid);
+ lpfc_debug_dump_q(phba->sli4_hba.fp_eq[eq_idx]);
+ return;
+ }
+
+ if (phba->sli4_hba.sp_eq->queue_id == qid) {
+ printk(KERN_ERR "SP EQ[|Qid:%d]\n", qid);
+ lpfc_debug_dump_q(phba->sli4_hba.sp_eq);
+ }
+}
+
+void lpfc_debug_dump_all_queues(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 3407b39..d54ae19 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -230,27 +230,43 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
INIT_LIST_HEAD(&pbuflist->list);
- icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
- icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
- icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
- icmd->un.elsreq64.remoteID = did; /* DID */
if (expectRsp) {
+ icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
+ icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
+ icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
+
+ icmd->un.elsreq64.remoteID = did; /* DID */
icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
icmd->ulpTimeout = phba->fc_ratov * 2;
} else {
- icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
+ icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
+ icmd->un.xseq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
+ icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ icmd->un.xseq64.bdl.bdeSize = sizeof(struct ulp_bde64);
+ icmd->un.xseq64.xmit_els_remoteID = did; /* DID */
icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
}
icmd->ulpBdeCount = 1;
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
- if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
- icmd->un.elsreq64.myID = vport->fc_myDID;
+ /*
+ * If we have NPIV enabled, we want to send ELS traffic by VPI.
+ * For SLI4, since the driver controls VPIs we also want to include
+ * all ELS pt2pt protocol traffic as well.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) ||
+ ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (vport->fc_flag & FC_PT2PT))) {
+
+ if (expectRsp) {
+ icmd->un.elsreq64.myID = vport->fc_myDID;
+
+ /* For ELS_REQUEST64_CR, use the VPI by default */
+ icmd->ulpContext = phba->vpi_ids[vport->vpi];
+ }
- /* For ELS_REQUEST64_CR, use the VPI by default */
- icmd->ulpContext = phba->vpi_ids[vport->vpi];
icmd->ulpCt_h = 0;
/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
if (elscmd == ELS_CMD_ECHO)
@@ -438,9 +454,10 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
int rc = 0;
sp = &phba->fc_fabparam;
- /* move forward in case of SLI4 FC port loopback test */
+ /* move forward in case of SLI4 FC port loopback test and pt2pt mode */
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- !(phba->link_flag & LS_LOOPBACK_MODE)) {
+ !(phba->link_flag & LS_LOOPBACK_MODE) &&
+ !(vport->fc_flag & FC_PT2PT)) {
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
rc = -ENODEV;
@@ -707,14 +724,17 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- /*
- * If VPI is unreged, driver need to do INIT_VPI
- * before re-registering
- */
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
+
+ /*
+ * For SLI3 and SLI4, the VPI needs to be reregistered in
+ * response to this fabric parameter change event.
+ */
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
} else if ((phba->sli_rev == LPFC_SLI_REV4) &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/*
@@ -817,6 +837,17 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
+
+ /*
+ * For SLI4, the VFI/VPI are registered AFTER the
+ * Nport with the higher WWPN sends the PLOGI with
+ * an assigned NPortId.
+ */
+
+ /* not equal */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
+ lpfc_issue_reg_vfi(vport);
+
/* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done.
*/
@@ -2972,7 +3003,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* ABTS we cannot generate and RRQ.
*/
lpfc_set_rrq_active(phba, ndlp,
- cmdiocb->sli4_xritag, 0, 0);
+ cmdiocb->sli4_lxritag, 0, 0);
}
break;
case IOSTAT_LOCAL_REJECT:
@@ -3803,10 +3834,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
- "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+ "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x "
+ "fc_flag x%x\n",
elsiocb->iotag, elsiocb->iocb.ulpContext,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- ndlp->nlp_rpi);
+ ndlp->nlp_rpi, vport->fc_flag);
if (ndlp->nlp_flag & NLP_LOGO_ACC) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
@@ -4936,8 +4968,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
- did = Fabric_DID;
-
if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
@@ -4976,26 +5006,82 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
+
+ /* If we have the high WWPN we can assign our own
+ * myDID; otherwise, we have to WAIT for a PLOGI
+ * from the remote NPort to find out what it
+ * will be.
+ */
+ vport->fc_myDID = PT2PT_LocalID;
}
+
+ /*
+ * The vport state should go to LPFC_FLOGI only
+ * AFTER we issue a FLOGI, not receive one.
+ */
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PT2PT;
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(shost->host_lock);
+
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI ACC rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
+
} else {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
+
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI LS_RJT rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
+
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
+
+ /* Now lets put fc_myDID back to what its supposed to be */
+ vport->fc_myDID = did;
+
return 1;
}
/* Send back ACC */
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+ /* Now lets put fc_myDID back to what its supposed to be */
+ vport->fc_myDID = did;
+
+ if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto fail;
+ }
+ }
+
return 0;
+fail:
+ return 1;
}
/**
@@ -5176,7 +5262,6 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t);
- mempool_free(pmb, phba->mbox_mem_pool);
elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
lpfc_max_els_tries, ndlp,
ndlp->nlp_DID, ELS_CMD_ACC);
@@ -5184,8 +5269,10 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Decrement the ndlp reference count from previous mbox command */
lpfc_nlp_put(ndlp);
- if (!elsiocb)
+ if (!elsiocb) {
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
+ }
icmd = &elsiocb->iocb;
icmd->ulpContext = rxid;
@@ -5202,7 +5289,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
-
+ mempool_free(pmb, phba->mbox_mem_pool);
/* Xmit ELS RLS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
"2874 Xmit ELS RLS ACC response tag x%x xri x%x, "
@@ -5586,7 +5673,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
pcmd += sizeof(uint32_t);
els_rrq = (struct RRQ *) pcmd;
- bf_set(rrq_oxid, els_rrq, rrq->xritag);
+ bf_set(rrq_oxid, els_rrq, phba->sli4_hba.xri_ids[rrq->xritag]);
bf_set(rrq_rxid, els_rrq, rrq->rxid);
bf_set(rrq_did, els_rrq, vport->fc_myDID);
els_rrq->rrq = cpu_to_be32(els_rrq->rrq);
@@ -7873,7 +7960,9 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
- lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
+ lpfc_set_rrq_active(phba, ndlp,
+ sglq_entry->sli4_lxritag,
+ rxid, 1);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index b507536..5bb269e 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -713,6 +713,7 @@ lpfc_do_work(void *p)
int rc;
set_user_nice(current, -20);
+ current->flags |= PF_NOFREEZE;
phba->data_flags = 0;
while (!kthread_should_stop()) {
@@ -1094,7 +1095,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI)
+ if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
lpfc_initial_flogi(vport);
return;
@@ -2881,9 +2882,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
}
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
- /* For private loop just start discovery and we are done. */
- if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
- !(vport->fc_flag & FC_PUBLIC_LOOP)) {
+ /*
+ * For private loop or for NPort pt2pt,
+ * just start discovery and we are done.
+ */
+ if ((vport->fc_flag & FC_PT2PT) ||
+ ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP))) {
+
/* Use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
/* Start discovery */
@@ -5490,9 +5496,9 @@ lpfc_nlp_release(struct kref *kref)
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
- "0279 lpfc_nlp_release: ndlp:x%p "
+ "0279 lpfc_nlp_release: ndlp:x%p did %x "
"usgmap:x%x refcnt:%d\n",
- (void *)ndlp, ndlp->nlp_usg_map,
+ (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map,
atomic_read(&ndlp->kref.refcount));
/* remove ndlp from action. */
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 5f280b5..41bb1d2 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -3374,6 +3374,9 @@ typedef struct {
WORD5 w5; /* Header control/status word */
} XMT_SEQ_FIELDS64;
+/* This word is remote ports D_ID for XMIT_ELS_RSP64 */
+#define xmit_els_remoteID xrsqRo
+
/* IOCB Command template for 64 bit RCV_SEQUENCE64 */
typedef struct {
struct ulp_bde64 rcvBde;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 91f0976..f1946df 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -228,19 +228,15 @@ struct lpfc_sli4_flags {
#define lpfc_idx_rsrc_rdy_MASK 0x00000001
#define lpfc_idx_rsrc_rdy_WORD word0
#define LPFC_IDX_RSRC_RDY 1
-#define lpfc_xri_rsrc_rdy_SHIFT 1
-#define lpfc_xri_rsrc_rdy_MASK 0x00000001
-#define lpfc_xri_rsrc_rdy_WORD word0
-#define LPFC_XRI_RSRC_RDY 1
-#define lpfc_rpi_rsrc_rdy_SHIFT 2
+#define lpfc_rpi_rsrc_rdy_SHIFT 1
#define lpfc_rpi_rsrc_rdy_MASK 0x00000001
#define lpfc_rpi_rsrc_rdy_WORD word0
#define LPFC_RPI_RSRC_RDY 1
-#define lpfc_vpi_rsrc_rdy_SHIFT 3
+#define lpfc_vpi_rsrc_rdy_SHIFT 2
#define lpfc_vpi_rsrc_rdy_MASK 0x00000001
#define lpfc_vpi_rsrc_rdy_WORD word0
#define LPFC_VPI_RSRC_RDY 1
-#define lpfc_vfi_rsrc_rdy_SHIFT 4
+#define lpfc_vfi_rsrc_rdy_SHIFT 3
#define lpfc_vfi_rsrc_rdy_MASK 0x00000001
#define lpfc_vfi_rsrc_rdy_WORD word0
#define LPFC_VFI_RSRC_RDY 1
@@ -3299,7 +3295,13 @@ struct els_request64_wqe {
struct xmit_els_rsp64_wqe {
struct ulp_bde64 bde;
uint32_t response_payload_len;
- uint32_t rsvd4;
+ uint32_t word4;
+#define els_rsp64_sid_SHIFT 0
+#define els_rsp64_sid_MASK 0x00FFFFFF
+#define els_rsp64_sid_WORD word4
+#define els_rsp64_sp_SHIFT 24
+#define els_rsp64_sp_MASK 0x00000001
+#define els_rsp64_sp_WORD word4
struct wqe_did wqe_dest;
struct wqe_common wqe_com; /* words 6-11 */
uint32_t word12;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 9598fdc..411ed48 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *);
static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);
static int lpfc_setup_endian_order(struct lpfc_hba *);
static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *);
-static void lpfc_free_sgl_list(struct lpfc_hba *);
-static int lpfc_init_sgl_list(struct lpfc_hba *);
+static void lpfc_free_els_sgl_list(struct lpfc_hba *);
+static void lpfc_init_sgl_list(struct lpfc_hba *);
static int lpfc_init_active_sgl_array(struct lpfc_hba *);
static void lpfc_free_active_sgl(struct lpfc_hba *);
static int lpfc_hba_down_post_s3(struct lpfc_hba *phba);
@@ -2767,47 +2767,14 @@ lpfc_offline(struct lpfc_hba *phba)
}
/**
- * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated.
- * @phba: pointer to lpfc hba data structure.
- *
- * This routine goes through all the scsi buffers in the system and updates the
- * Physical XRIs assigned to the SCSI buffer because these may change after any
- * firmware reset
- *
- * Return codes
- * 0 - successful (for now, it always returns 0)
- **/
-int
-lpfc_scsi_buf_update(struct lpfc_hba *phba)
-{
- struct lpfc_scsi_buf *sb, *sb_next;
-
- spin_lock_irq(&phba->hbalock);
- spin_lock(&phba->scsi_buf_list_lock);
- list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
- sb->cur_iocbq.sli4_xritag =
- phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag];
- set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask);
- phba->sli4_hba.max_cfg_param.xri_used++;
- phba->sli4_hba.xri_count++;
- }
- spin_unlock(&phba->scsi_buf_list_lock);
- spin_unlock_irq(&phba->hbalock);
- return 0;
-}
-
-/**
* lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists
* @phba: pointer to lpfc hba data structure.
*
* This routine is to free all the SCSI buffers and IOCBs from the driver
* list back to kernel. It is called from lpfc_pci_remove_one to free
* the internal resources before the device is removed from the system.
- *
- * Return codes
- * 0 - successful (for now, it always returns 0)
**/
-static int
+static void
lpfc_scsi_free(struct lpfc_hba *phba)
{
struct lpfc_scsi_buf *sb, *sb_next;
@@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba)
}
spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine first calculates the sizes of the current els and allocated
+ * scsi sgl lists, and then goes through all sgls to updates the physical
+ * XRIs assigned due to port function reset. During port initialization, the
+ * current els and allocated scsi sgl lists are 0s.
+ *
+ * Return codes
+ * 0 - successful (for now, it always returns 0)
+ **/
+int
+lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
+{
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL;
+ struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL;
+ uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt;
+ LIST_HEAD(els_sgl_list);
+ LIST_HEAD(scsi_sgl_list);
+ int rc;
+
+ /*
+ * update on pci function's els xri-sgl list
+ */
+ els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+ if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) {
+ /* els xri-sgl expanded */
+ xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt;
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3157 ELS xri-sgl count increased from "
+ "%d to %d\n", phba->sli4_hba.els_xri_cnt,
+ els_xri_cnt);
+ /* allocate the additional els sgls */
+ for (i = 0; i < xri_cnt; i++) {
+ sglq_entry = kzalloc(sizeof(struct lpfc_sglq),
+ GFP_KERNEL);
+ if (sglq_entry == NULL) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2562 Failure to allocate an "
+ "ELS sgl entry:%d\n", i);
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->buff_type = GEN_BUFF_TYPE;
+ sglq_entry->virt = lpfc_mbuf_alloc(phba, 0,
+ &sglq_entry->phys);
+ if (sglq_entry->virt == NULL) {
+ kfree(sglq_entry);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2563 Failure to allocate an "
+ "ELS mbuf:%d\n", i);
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->sgl = sglq_entry->virt;
+ memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
+ sglq_entry->state = SGL_FREED;
+ list_add_tail(&sglq_entry->list, &els_sgl_list);
+ }
+ spin_lock(&phba->hbalock);
+ list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock(&phba->hbalock);
+ } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) {
+ /* els xri-sgl shrinked */
+ xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt;
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3158 ELS xri-sgl count decreased from "
+ "%d to %d\n", phba->sli4_hba.els_xri_cnt,
+ els_xri_cnt);
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list);
+ spin_unlock_irq(&phba->hbalock);
+ /* release extra els sgls from list */
+ for (i = 0; i < xri_cnt; i++) {
+ list_remove_head(&els_sgl_list,
+ sglq_entry, struct lpfc_sglq, list);
+ if (sglq_entry) {
+ lpfc_mbuf_free(phba, sglq_entry->virt,
+ sglq_entry->phys);
+ kfree(sglq_entry);
+ }
+ }
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock_irq(&phba->hbalock);
+ } else
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3163 ELS xri-sgl count unchanged: %d\n",
+ els_xri_cnt);
+ phba->sli4_hba.els_xri_cnt = els_xri_cnt;
+
+ /* update xris to els sgls on the list */
+ sglq_entry = NULL;
+ sglq_entry_next = NULL;
+ list_for_each_entry_safe(sglq_entry, sglq_entry_next,
+ &phba->sli4_hba.lpfc_sgl_list, list) {
+ lxri = lpfc_sli4_next_xritag(phba);
+ if (lxri == NO_XRI) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2400 Failed to allocate xri for "
+ "ELS sgl\n");
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ sglq_entry->sli4_lxritag = lxri;
+ sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
+ }
+
+ /*
+ * update on pci function's allocated scsi xri-sgl list
+ */
+ phba->total_scsi_bufs = 0;
+
+ /* maximum number of xris available for scsi buffers */
+ phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri -
+ els_xri_cnt;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2401 Current allocated SCSI xri-sgl count:%d, "
+ "maximum SCSI xri count:%d\n",
+ phba->sli4_hba.scsi_xri_cnt,
+ phba->sli4_hba.scsi_xri_max);
+
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
+
+ if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) {
+ /* max scsi xri shrinked below the allocated scsi buffers */
+ scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt -
+ phba->sli4_hba.scsi_xri_max;
+ /* release the extra allocated scsi buffers */
+ for (i = 0; i < scsi_xri_cnt; i++) {
+ list_remove_head(&scsi_sgl_list, psb,
+ struct lpfc_scsi_buf, list);
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data,
+ psb->dma_handle);
+ kfree(psb);
+ }
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt;
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
+ }
+
+ /* update xris associated to remaining allocated scsi buffers */
+ psb = NULL;
+ psb_next = NULL;
+ list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) {
+ lxri = lpfc_sli4_next_xritag(phba);
+ if (lxri == NO_XRI) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2560 Failed to allocate xri for "
+ "scsi buffer\n");
+ rc = -ENOMEM;
+ goto out_free_mem;
+ }
+ psb->cur_iocbq.sli4_lxritag = lxri;
+ psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
+ }
+ spin_lock(&phba->scsi_buf_list_lock);
+ list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list);
+ spin_unlock(&phba->scsi_buf_list_lock);
+
return 0;
+
+out_free_mem:
+ lpfc_free_els_sgl_list(phba);
+ lpfc_scsi_free(phba);
+ return rc;
}
/**
@@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (rc)
goto out_free_bsmbx;
- /* Initialize and populate the iocb list per host */
- rc = lpfc_init_sgl_list(phba);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1400 Failed to initialize sgl list.\n");
- goto out_destroy_cq_event_pool;
- }
+ /* Initialize sgl lists per host */
+ lpfc_init_sgl_list(phba);
+
+ /* Allocate and initialize active sgl array */
rc = lpfc_init_active_sgl_array(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1430 Failed to initialize sgl list.\n");
- goto out_free_sgl_list;
+ goto out_destroy_cq_event_pool;
}
rc = lpfc_sli4_init_rpi_hdrs(phba);
if (rc) {
@@ -4722,8 +4857,6 @@ out_remove_rpi_hdrs:
lpfc_sli4_remove_rpi_hdrs(phba);
out_free_active_sgl:
lpfc_free_active_sgl(phba);
-out_free_sgl_list:
- lpfc_free_sgl_list(phba);
out_destroy_cq_event_pool:
lpfc_sli4_cq_event_pool_destroy(phba);
out_free_bsmbx:
@@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
/* Free the ELS sgl list */
lpfc_free_active_sgl(phba);
- lpfc_free_sgl_list(phba);
-
- /* Free the SCSI sgl management array */
- kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+ lpfc_free_els_sgl_list(phba);
/* Free the completion queue EQ event pool */
lpfc_sli4_cq_event_release_all(phba);
@@ -4990,29 +5120,42 @@ out_free_iocbq:
}
/**
- * lpfc_free_sgl_list - Free sgl list.
+ * lpfc_free_sgl_list - Free a given sgl list.
* @phba: pointer to lpfc hba data structure.
+ * @sglq_list: pointer to the head of sgl list.
*
- * This routine is invoked to free the driver's sgl list and memory.
+ * This routine is invoked to free a give sgl list and memory.
**/
-static void
-lpfc_free_sgl_list(struct lpfc_hba *phba)
+void
+lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list)
{
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+
+ list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) {
+ list_del(&sglq_entry->list);
+ lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
+ kfree(sglq_entry);
+ }
+}
+
+/**
+ * lpfc_free_els_sgl_list - Free els sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's els sgl list and memory.
+ **/
+static void
+lpfc_free_els_sgl_list(struct lpfc_hba *phba)
+{
LIST_HEAD(sglq_list);
+ /* Retrieve all els sgls from driver list */
spin_lock_irq(&phba->hbalock);
list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list);
spin_unlock_irq(&phba->hbalock);
- list_for_each_entry_safe(sglq_entry, sglq_next,
- &sglq_list, list) {
- list_del(&sglq_entry->list);
- lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
- kfree(sglq_entry);
- phba->sli4_hba.total_sglq_bufs--;
- }
- kfree(phba->sli4_hba.lpfc_els_sgl_array);
+ /* Now free the sgl list */
+ lpfc_free_sgl_list(phba, &sglq_list);
}
/**
@@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba)
* This routine is invoked to allocate and initizlize the driver's sgl
* list and set up the sgl xritag tag array accordingly.
*
- * Return codes
- * 0 - successful
- * other values - error
**/
-static int
+static void
lpfc_init_sgl_list(struct lpfc_hba *phba)
{
- struct lpfc_sglq *sglq_entry = NULL;
- int i;
- int els_xri_cnt;
-
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2400 ELS XRI count %d.\n",
- els_xri_cnt);
/* Initialize and populate the sglq list per host/VF. */
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list);
- /* Sanity check on XRI management */
- if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2562 No room left for SCSI XRI allocation: "
- "max_xri=%d, els_xri=%d\n",
- phba->sli4_hba.max_cfg_param.max_xri,
- els_xri_cnt);
- return -ENOMEM;
- }
-
- /* Allocate memory for the ELS XRI management array */
- phba->sli4_hba.lpfc_els_sgl_array =
- kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt),
- GFP_KERNEL);
-
- if (!phba->sli4_hba.lpfc_els_sgl_array) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2401 Failed to allocate memory for ELS "
- "XRI management array of size %d.\n",
- els_xri_cnt);
- return -ENOMEM;
- }
+ /* els xri-sgl book keeping */
+ phba->sli4_hba.els_xri_cnt = 0;
- /* Keep the SCSI XRI into the XRI management array */
- phba->sli4_hba.scsi_xri_max =
- phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
+ /* scsi xri-buffer book keeping */
phba->sli4_hba.scsi_xri_cnt = 0;
- phba->sli4_hba.lpfc_scsi_psb_array =
- kzalloc((sizeof(struct lpfc_scsi_buf *) *
- phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
-
- if (!phba->sli4_hba.lpfc_scsi_psb_array) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2563 Failed to allocate memory for SCSI "
- "XRI management array of size %d.\n",
- phba->sli4_hba.scsi_xri_max);
- kfree(phba->sli4_hba.lpfc_els_sgl_array);
- return -ENOMEM;
- }
-
- for (i = 0; i < els_xri_cnt; i++) {
- sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL);
- if (sglq_entry == NULL) {
- printk(KERN_ERR "%s: only allocated %d sgls of "
- "expected %d count. Unloading driver.\n",
- __func__, i, els_xri_cnt);
- goto out_free_mem;
- }
-
- sglq_entry->buff_type = GEN_BUFF_TYPE;
- sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
- if (sglq_entry->virt == NULL) {
- kfree(sglq_entry);
- printk(KERN_ERR "%s: failed to allocate mbuf.\n"
- "Unloading driver.\n", __func__);
- goto out_free_mem;
- }
- sglq_entry->sgl = sglq_entry->virt;
- memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
-
- /* The list order is used by later block SGL registraton */
- spin_lock_irq(&phba->hbalock);
- sglq_entry->state = SGL_FREED;
- list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list);
- phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry;
- phba->sli4_hba.total_sglq_bufs++;
- spin_unlock_irq(&phba->hbalock);
- }
- return 0;
-
-out_free_mem:
- kfree(phba->sli4_hba.lpfc_scsi_psb_array);
- lpfc_free_sgl_list(phba);
- return -ENOMEM;
}
/**
@@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
phba->sli4_hba.u.if_type2.ERR2regaddr);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2890 Port error detected during port "
- "reset(%d): port status reg 0x%x, "
+ "reset(%d): wait_tmo:%d ms, "
+ "port status reg 0x%x, "
"error 1=0x%x, error 2=0x%x\n",
- num_resets, reg_data.word0,
+ num_resets, rdy_chk*10,
+ reg_data.word0,
phba->work_status[0],
phba->work_status[1]);
rc = -ENODEV;
@@ -8694,8 +8759,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
/* Release all the vports against this physical port */
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ continue;
fc_vport_terminate(vports[i]->fc_vport);
+ }
lpfc_destroy_vport_work_array(phba, vports);
/* Remove FC host and then SCSI host with the physical port */
@@ -9115,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
return 50;
else if (max_xri <= 1024)
return 100;
- else
+ else if (max_xri <= 1536)
return 150;
+ else if (max_xri <= 2048)
+ return 200;
+ else
+ return 250;
} else
return 0;
}
@@ -9455,8 +9527,11 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
/* Release all the vports against this physical port */
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ continue;
fc_vport_terminate(vports[i]->fc_vport);
+ }
lpfc_destroy_vport_work_array(phba, vports);
/* Remove FC host and then SCSI host with the physical port */
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 15ca2a9a..9133a97 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -367,8 +367,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 1;
}
+ /* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) {
+
/* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -382,6 +384,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
+ /*
+ * For SLI4, the VFI/VPI are registered AFTER the
+ * Nport with the higher WWPN sends us a PLOGI with
+ * our assigned NPortId.
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_issue_reg_vfi(vport);
lpfc_can_disctmo(vport);
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 88f3a83..66e0906 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -399,6 +399,14 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
num_rsrc_err = atomic_read(&phba->num_rsrc_err);
num_cmd_success = atomic_read(&phba->num_cmd_success);
+ /*
+ * The error and success command counters are global per
+ * driver instance. If another handler has already
+ * operated on this error event, just exit.
+ */
+ if (num_rsrc_err == 0)
+ return;
+
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
@@ -688,7 +696,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (ndlp) {
- lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
+ lpfc_set_rrq_active(phba, ndlp,
+ psb->cur_iocbq.sli4_lxritag, rxid, 1);
lpfc_sli4_abts_err_handler(phba, ndlp, axri);
}
lpfc_release_scsi_buf_s4(phba, psb);
@@ -718,72 +727,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block
+ * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list
* @phba: pointer to lpfc hba data structure.
+ * @post_sblist: pointer to the scsi buffer list.
*
- * This routine walks the list of scsi buffers that have been allocated and
- * repost them to the HBA by using SGL block post. This is needed after a
- * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
- * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
- * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ * This routine walks a list of scsi buffers that was passed in. It attempts
+ * to construct blocks of scsi buffer sgls which contains contiguous xris and
+ * uses the non-embedded SGL block post mailbox commands to post to the port.
+ * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use
+ * embedded SGL post mailbox command for posting. The @post_sblist passed in
+ * must be local list, thus no lock is needed when manipulate the list.
*
- * Returns: 0 = success, non-zero failure.
+ * Returns: 0 = failure, non-zero number of successfully posted buffers.
**/
int
-lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba,
+ struct list_head *post_sblist, int sb_count)
{
- struct lpfc_scsi_buf *psb;
- int index, status, bcnt = 0, rcnt = 0, rc = 0;
- LIST_HEAD(sblist);
-
- for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) {
- psb = phba->sli4_hba.lpfc_scsi_psb_array[index];
- if (psb) {
- /* Remove from SCSI buffer list */
- list_del(&psb->list);
- /* Add it to a local SCSI buffer list */
- list_add_tail(&psb->list, &sblist);
- if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) {
- bcnt = rcnt;
- rcnt = 0;
+ struct lpfc_scsi_buf *psb, *psb_next;
+ int status;
+ int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0;
+ dma_addr_t pdma_phys_bpl1;
+ int last_xritag = NO_XRI;
+ LIST_HEAD(prep_sblist);
+ LIST_HEAD(blck_sblist);
+ LIST_HEAD(scsi_sblist);
+
+ /* sanity check */
+ if (sb_count <= 0)
+ return -EINVAL;
+
+ list_for_each_entry_safe(psb, psb_next, post_sblist, list) {
+ list_del_init(&psb->list);
+ block_cnt++;
+ if ((last_xritag != NO_XRI) &&
+ (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) {
+ /* a hole in xri block, form a sgl posting block */
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt - 1;
+ /* prepare list for next posting block */
+ list_add_tail(&psb->list, &prep_sblist);
+ block_cnt = 1;
+ } else {
+ /* prepare list for next posting block */
+ list_add_tail(&psb->list, &prep_sblist);
+ /* enough sgls for non-embed sgl mbox command */
+ if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt;
+ block_cnt = 0;
}
- } else
- /* A hole present in the XRI array, need to skip */
- bcnt = rcnt;
+ }
+ num_posting++;
+ last_xritag = psb->cur_iocbq.sli4_xritag;
- if (index == phba->sli4_hba.scsi_xri_cnt - 1)
- /* End of XRI array for SCSI buffer, complete */
- bcnt = rcnt;
+ /* end of repost sgl list condition for SCSI buffers */
+ if (num_posting == sb_count) {
+ if (post_cnt == 0) {
+ /* last sgl posting block */
+ list_splice_init(&prep_sblist, &blck_sblist);
+ post_cnt = block_cnt;
+ } else if (block_cnt == 1) {
+ /* last single sgl with non-contiguous xri */
+ if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+ pdma_phys_bpl1 = psb->dma_phys_bpl +
+ SGL_PAGE_SIZE;
+ else
+ pdma_phys_bpl1 = 0;
+ status = lpfc_sli4_post_sgl(phba,
+ psb->dma_phys_bpl,
+ pdma_phys_bpl1,
+ psb->cur_iocbq.sli4_xritag);
+ if (status) {
+ /* failure, put on abort scsi list */
+ psb->exch_busy = 1;
+ } else {
+ /* success, put on SCSI buffer list */
+ psb->exch_busy = 0;
+ psb->status = IOSTAT_SUCCESS;
+ num_posted++;
+ }
+ /* success, put on SCSI buffer sgl list */
+ list_add_tail(&psb->list, &scsi_sblist);
+ }
+ }
- /* Continue until collect up to a nembed page worth of sgls */
- if (bcnt == 0)
+ /* continue until a nembed page worth of sgls */
+ if (post_cnt == 0)
continue;
- /* Now, post the SCSI buffer list sgls as a block */
- if (!phba->sli4_hba.extents_in_use)
- status = lpfc_sli4_post_scsi_sgl_block(phba,
- &sblist,
- bcnt);
- else
- status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
- &sblist,
- bcnt);
- /* Reset SCSI buffer count for next round of posting */
- bcnt = 0;
- while (!list_empty(&sblist)) {
- list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
- list);
+
+ /* post block of SCSI buffer list sgls */
+ status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist,
+ post_cnt);
+
+ /* don't reset xirtag due to hole in xri block */
+ if (block_cnt == 0)
+ last_xritag = NO_XRI;
+
+ /* reset SCSI buffer post count for next round of posting */
+ post_cnt = 0;
+
+ /* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */
+ while (!list_empty(&blck_sblist)) {
+ list_remove_head(&blck_sblist, psb,
+ struct lpfc_scsi_buf, list);
if (status) {
- /* Put this back on the abort scsi list */
+ /* failure, put on abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
+ /* success, put on SCSI buffer list */
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
+ num_posted++;
}
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
+ list_add_tail(&psb->list, &scsi_sblist);
}
}
+ /* Push SCSI buffers with sgl posted to the availble list */
+ while (!list_empty(&scsi_sblist)) {
+ list_remove_head(&scsi_sblist, psb,
+ struct lpfc_scsi_buf, list);
+ lpfc_release_scsi_buf_s4(phba, psb);
+ }
+ return num_posted;
+}
+
+/**
+ * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of scsi buffers that have been allocated and
+ * repost them to the port by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
+ * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
+ * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+int
+lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+{
+ LIST_HEAD(post_sblist);
+ int num_posted, rc = 0;
+
+ /* get all SCSI buffers need to repost to a local list */
+ spin_lock(&phba->scsi_buf_list_lock);
+ list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist);
+ spin_unlock(&phba->scsi_buf_list_lock);
+
+ /* post the list of scsi buffer sgls to port if available */
+ if (!list_empty(&post_sblist)) {
+ num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist,
+ phba->sli4_hba.scsi_xri_cnt);
+ /* failed to post any scsi buffer, return error */
+ if (num_posted == 0)
+ rc = -EIO;
+ }
return rc;
}
@@ -792,12 +891,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
* @vport: The virtual port for which this call being executed.
* @num_to_allocate: The requested number of buffers to allocate.
*
- * This routine allocates a scsi buffer for device with SLI-4 interface spec,
+ * This routine allocates scsi buffers for device with SLI-4 interface spec,
* the scsi buffer contains all the necessary information needed to initiate
- * a SCSI I/O.
+ * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put
+ * them on a list, it post them to the port by using SGL block post.
*
* Return codes:
- * int - number of scsi buffers that were allocated.
+ * int - number of scsi buffers that were allocated and posted.
* 0 = failure, less than num_to_alloc is a partial failure.
**/
static int
@@ -810,22 +910,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
dma_addr_t pdma_phys_fcp_cmd;
dma_addr_t pdma_phys_fcp_rsp;
dma_addr_t pdma_phys_bpl, pdma_phys_bpl1;
- uint16_t iotag, last_xritag = NO_XRI, lxri = 0;
- int status = 0, index;
- int bcnt;
- int non_sequential_xri = 0;
- LIST_HEAD(sblist);
+ uint16_t iotag, lxri = 0;
+ int bcnt, num_posted;
+ LIST_HEAD(prep_sblist);
+ LIST_HEAD(post_sblist);
+ LIST_HEAD(scsi_sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
if (!psb)
break;
-
/*
- * Get memory from the pci pool to map the virt space to pci bus
- * space for an I/O. The DMA buffer includes space for the
- * struct fcp_cmnd, struct fcp_rsp and the number of bde's
- * necessary to support the sg_tablesize.
+ * Get memory from the pci pool to map the virt space to
+ * pci bus space for an I/O. The DMA buffer includes space
+ * for the struct fcp_cmnd, struct fcp_rsp and the number
+ * of bde's necessary to support the sg_tablesize.
*/
psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
GFP_KERNEL, &psb->dma_handle);
@@ -833,8 +932,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
kfree(psb);
break;
}
-
- /* Initialize virtual ptrs to dma_buf region. */
memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
/* Allocate iotag for psb->cur_iocbq. */
@@ -855,16 +952,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
psb->cur_iocbq.sli4_lxritag = lxri;
psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
- if (last_xritag != NO_XRI
- && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) {
- non_sequential_xri = 1;
- } else
- list_add_tail(&psb->list, &sblist);
- last_xritag = psb->cur_iocbq.sli4_xritag;
-
- index = phba->sli4_hba.scsi_xri_cnt++;
psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
-
psb->fcp_bpl = psb->data;
psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size)
- (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
@@ -880,9 +968,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
/*
- * The first two bdes are the FCP_CMD and FCP_RSP. The balance
- * are sg list bdes. Initialize the first two and leave the
- * rest for queuecommand.
+ * The first two bdes are the FCP_CMD and FCP_RSP.
+ * The balance are sg list bdes. Initialize the
+ * first two and leave the rest for queuecommand.
*/
sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
@@ -917,62 +1005,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
iocb->ulpBdeCount = 1;
iocb->ulpLe = 1;
iocb->ulpClass = CLASS3;
- psb->cur_iocbq.context1 = psb;
+ psb->cur_iocbq.context1 = psb;
if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE;
else
pdma_phys_bpl1 = 0;
psb->dma_phys_bpl = pdma_phys_bpl;
- phba->sli4_hba.lpfc_scsi_psb_array[index] = psb;
- if (non_sequential_xri) {
- status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl,
- pdma_phys_bpl1,
- psb->cur_iocbq.sli4_xritag);
- if (status) {
- /* Put this back on the abort scsi list */
- psb->exch_busy = 1;
- } else {
- psb->exch_busy = 0;
- psb->status = IOSTAT_SUCCESS;
- }
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
- break;
- }
- }
- if (bcnt) {
- if (!phba->sli4_hba.extents_in_use)
- status = lpfc_sli4_post_scsi_sgl_block(phba,
- &sblist,
- bcnt);
- else
- status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
- &sblist,
- bcnt);
-
- if (status) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "3021 SCSI SGL post error %d\n",
- status);
- bcnt = 0;
- }
- /* Reset SCSI buffer count for next round of posting */
- while (!list_empty(&sblist)) {
- list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
- list);
- if (status) {
- /* Put this back on the abort scsi list */
- psb->exch_busy = 1;
- } else {
- psb->exch_busy = 0;
- psb->status = IOSTAT_SUCCESS;
- }
- /* Put it back into the SCSI buffer list */
- lpfc_release_scsi_buf_s4(phba, psb);
- }
+
+ /* add the scsi buffer to a post list */
+ list_add_tail(&psb->list, &post_sblist);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
+ phba->sli4_hba.scsi_xri_cnt++;
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
}
+ lpfc_printf_log(phba, KERN_INFO, LOG_BG,
+ "3021 Allocate %d out of %d requested new SCSI "
+ "buffers\n", bcnt, num_to_alloc);
+
+ /* post the list of scsi buffer sgls to port if available */
+ if (!list_empty(&post_sblist))
+ num_posted = lpfc_sli4_post_scsi_sgl_list(phba,
+ &post_sblist, bcnt);
+ else
+ num_posted = 0;
- return bcnt + non_sequential_xri;
+ return num_posted;
}
/**
@@ -1043,7 +1100,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list,
list) {
if (lpfc_test_rrq_active(phba, ndlp,
- lpfc_cmd->cur_iocbq.sli4_xritag))
+ lpfc_cmd->cur_iocbq.sli4_lxritag))
continue;
list_del(&lpfc_cmd->list);
found = 1;
@@ -1897,7 +1954,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
dma_addr_t physaddr;
int i = 0, num_bde = 0, status;
int datadir = sc->sc_data_direction;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t reftag;
unsigned blksize;
@@ -2034,7 +2093,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
int datadir = sc->sc_data_direction;
unsigned char pgdone = 0, alldone = 0;
unsigned blksize;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t reftag;
uint8_t txop, rxop;
@@ -2253,7 +2314,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t reftag;
unsigned blksize;
uint8_t txop, rxop;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t dma_len;
uint32_t dma_offset = 0;
@@ -2383,7 +2446,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t reftag;
uint8_t txop, rxop;
uint32_t dma_len;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint32_t rc;
+#endif
uint32_t checking = 1;
uint32_t dma_offset = 0;
int num_sge = 0;
@@ -3604,11 +3669,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
logit = LOG_FCP | LOG_FCP_UNDER;
lpfc_printf_vlog(vport, KERN_WARNING, logit,
"9030 FCP cmd x%x failed <%d/%d> "
- "status: x%x result: x%x Data: x%x x%x\n",
+ "status: x%x result: x%x "
+ "sid: x%x did: x%x oxid: x%x "
+ "Data: x%x x%x\n",
cmd->cmnd[0],
cmd->device ? cmd->device->id : 0xffff,
cmd->device ? cmd->device->lun : 0xffff,
lpfc_cmd->status, lpfc_cmd->result,
+ vport->fc_myDID, pnode->nlp_DID,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
pIocbOut->iocb.ulpContext,
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
@@ -3689,8 +3759,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
* ABTS we cannot generate and RRQ.
*/
lpfc_set_rrq_active(phba, pnode,
- lpfc_cmd->cur_iocbq.sli4_xritag,
- 0, 0);
+ lpfc_cmd->cur_iocbq.sli4_lxritag,
+ 0, 0);
}
/* else: fall through */
default:
@@ -4348,8 +4418,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
ret = fc_block_scsi_eh(cmnd);
if (ret)
return ret;
+
+ spin_lock_irq(&phba->hbalock);
+ /* driver queued commands are in process of being flushed */
+ if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3168 SCSI Layer abort requested I/O has been "
+ "flushed by LLD.\n");
+ return FAILED;
+ }
+
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
if (!lpfc_cmd) {
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"2873 SCSI Layer I/O Abort Request IO CMPL Status "
"x%x ID %d LUN %d\n",
@@ -4357,23 +4439,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
return SUCCESS;
}
+ iocb = &lpfc_cmd->cur_iocbq;
+ /* the command is in process of being cancelled */
+ if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3169 SCSI Layer abort requested I/O has been "
+ "cancelled by LLD.\n");
+ return FAILED;
+ }
/*
* If pCmd field of the corresponding lpfc_scsi_buf structure
* points to a different SCSI command, then the driver has
* already completed this command, but the midlayer did not
- * see the completion before the eh fired. Just return
- * SUCCESS.
+ * see the completion before the eh fired. Just return SUCCESS.
*/
- iocb = &lpfc_cmd->cur_iocbq;
- if (lpfc_cmd->pCmd != cmnd)
- goto out;
+ if (lpfc_cmd->pCmd != cmnd) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "3170 SCSI Layer abort requested I/O has been "
+ "completed by LLD.\n");
+ goto out_unlock;
+ }
BUG_ON(iocb->context1 != lpfc_cmd);
- abtsiocb = lpfc_sli_get_iocbq(phba);
+ abtsiocb = __lpfc_sli_get_iocbq(phba);
if (abtsiocb == NULL) {
ret = FAILED;
- goto out;
+ goto out_unlock;
}
/*
@@ -4405,6 +4498,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
abtsiocb->vport = vport;
+ /* no longer need the lock after this point */
+ spin_unlock_irq(&phba->hbalock);
+
if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==
IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, abtsiocb);
@@ -4421,10 +4517,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
wait_event_timeout(waitq,
(lpfc_cmd->pCmd != cmnd),
(2*vport->cfg_devloss_tmo*HZ));
-
- spin_lock_irq(shost->host_lock);
lpfc_cmd->waitq = NULL;
- spin_unlock_irq(shost->host_lock);
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
@@ -4434,8 +4527,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
"LUN %d\n",
ret, cmnd->device->id, cmnd->device->lun);
}
+ goto out;
- out:
+out_unlock:
+ spin_unlock_irq(&phba->hbalock);
+out:
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"0749 SCSI Layer I/O Abort Request Status x%x ID %d "
"LUN %d\n", ret, cmnd->device->id,
@@ -4863,6 +4959,43 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
}
/**
+ * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt
+ * @cmnd: Pointer to scsi_cmnd data structure.
+ *
+ * This routine does host reset to the adaptor port. It brings the HBA
+ * offline, performs a board restart, and then brings the board back online.
+ * The lpfc_offline calls lpfc_sli_hba_down which will abort and local
+ * reject all outstanding SCSI commands to the host and error returned
+ * back to SCSI mid-level. As this will be SCSI mid-level's last resort
+ * of error handling, it will only return error if resetting of the adapter
+ * is not successful; in all other cases, will return success.
+ *
+ * Return code :
+ * 0x2003 - Error
+ * 0x2002 - Success
+ **/
+static int
+lpfc_host_reset_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int rc, ret = SUCCESS;
+
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ rc = lpfc_sli_brdrestart(phba);
+ if (rc)
+ ret = FAILED;
+ lpfc_online(phba);
+ lpfc_unblock_mgmt_io(phba);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "3172 SCSI layer issued Host Reset Data: x%x\n", ret);
+ return ret;
+}
+
+/**
* lpfc_slave_alloc - scsi_host_template slave_alloc entry point
* @sdev: Pointer to scsi_device.
*
@@ -4994,6 +5127,7 @@ struct scsi_host_template lpfc_template = {
.eh_device_reset_handler = lpfc_device_reset_handler,
.eh_target_reset_handler = lpfc_target_reset_handler,
.eh_bus_reset_handler = lpfc_bus_reset_handler,
+ .eh_host_reset_handler = lpfc_host_reset_handler,
.slave_alloc = lpfc_slave_alloc,
.slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index dbaf5b9..b4720a1 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -67,6 +67,8 @@ static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
struct hbq_dmabuf *);
static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *,
struct lpfc_cqe *);
+static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *,
+ int);
static IOCB_t *
lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
@@ -500,7 +502,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* allocation is successful, it returns pointer to the newly
* allocated iocb object else it returns NULL.
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
@@ -875,6 +877,9 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
} else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) &&
!(piocbq->iocb_flag & LPFC_IO_LIBDFC))
ndlp = piocbq->context_un.ndlp;
+ else if ((piocbq->iocb.ulpCommand == CMD_ELS_REQUEST64_CR) &&
+ (piocbq->iocb_flag & LPFC_IO_LIBDFC))
+ ndlp = piocbq->context_un.ndlp;
else
ndlp = piocbq->context1;
@@ -883,7 +888,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
while (!found) {
if (!sglq)
return NULL;
- if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
+ if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_lxritag)) {
/* This xri has an rrq outstanding for this DID.
* put it back in the list and get another xri.
*/
@@ -1257,7 +1262,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
- piocb->iocb_flag |= LPFC_IO_ON_Q;
+ piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt++;
if (pring->txcmplq_cnt > pring->txcmplq_max)
pring->txcmplq_max = pring->txcmplq_cnt;
@@ -2556,9 +2561,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
pring->txcmplq_cnt--;
- cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
}
return cmd_iocb;
}
@@ -2591,14 +2596,14 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
- list_del_init(&cmd_iocb->list);
- if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
- cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
+ /* remove from txcmpl queue list */
+ list_del_init(&cmd_iocb->list);
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt--;
+ return cmd_iocb;
}
- return cmd_iocb;
}
-
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0372 iotag x%x is out off range: max iotag (x%x)\n",
iotag, phba->sli.last_iotag);
@@ -3466,6 +3471,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
pring->txcmplq_cnt = 0;
+
+ /* Indicate the I/O queues are flushed */
+ phba->hba_flag |= HBA_FCP_IOQ_FLUSH;
spin_unlock_irq(&phba->hbalock);
/* Flush the txq */
@@ -3877,6 +3885,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
uint16_t cfg_value;
+ int rc;
/* Reset HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3905,12 +3914,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
/* Perform FCoE PCI function reset */
lpfc_sli4_queue_destroy(phba);
- lpfc_pci_function_reset(phba);
+ rc = lpfc_pci_function_reset(phba);
/* Restore PCI cmd register */
pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
- return 0;
+ return rc;
}
/**
@@ -4002,6 +4011,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
uint32_t hba_aer_enabled;
+ int rc;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -4011,7 +4021,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
/* Take PCIe device Advanced Error Reporting (AER) state */
hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
- lpfc_sli4_brdreset(phba);
+ rc = lpfc_sli4_brdreset(phba);
spin_lock_irq(&phba->hbalock);
phba->pport->stopped = 0;
@@ -4028,7 +4038,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
lpfc_hba_down_post(phba);
- return 0;
+ return rc;
}
/**
@@ -4967,7 +4977,12 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
&rsrc_info->u.rsp);
*extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size,
&rsrc_info->u.rsp);
- err_exit:
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "3162 Retrieved extents type-%d from port: count:%d, "
+ "size:%d\n", type, *extnt_count, *extnt_size);
+
+err_exit:
mempool_free(mbox, phba->mbox_mem_pool);
return rc;
}
@@ -5051,7 +5066,7 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type)
* 0: if successful
**/
static int
-lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
+lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt,
uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox)
{
int rc = 0;
@@ -5060,7 +5075,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
uint32_t alloc_len, mbox_tmo;
/* Calculate the total requested length of the dma memory */
- req_len = *extnt_cnt * sizeof(uint16_t);
+ req_len = extnt_cnt * sizeof(uint16_t);
/*
* Calculate the size of an embedded mailbox. The uint32_t
@@ -5075,7 +5090,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
*/
*emb = LPFC_SLI4_MBX_EMBED;
if (req_len > emb_len) {
- req_len = *extnt_cnt * sizeof(uint16_t) +
+ req_len = extnt_cnt * sizeof(uint16_t) +
sizeof(union lpfc_sli4_cfg_shdr) +
sizeof(uint32_t);
*emb = LPFC_SLI4_MBX_NEMBED;
@@ -5091,7 +5106,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
"size (x%x)\n", alloc_len, req_len);
return -ENOMEM;
}
- rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb);
+ rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb);
if (unlikely(rc))
return -EIO;
@@ -5149,17 +5164,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
return -ENOMEM;
}
- lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT,
- "2903 Available Resource Extents "
- "for resource type 0x%x: Count: 0x%x, "
- "Size 0x%x\n", type, rsrc_cnt,
- rsrc_size);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI,
+ "2903 Post resource extents type-0x%x: "
+ "count:%d, size %d\n", type, rsrc_cnt, rsrc_size);
mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return -ENOMEM;
- rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox);
+ rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox);
if (unlikely(rc)) {
rc = -EIO;
goto err_exit;
@@ -5250,6 +5263,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
rc = -ENOMEM;
goto err_exit;
}
+ phba->sli4_hba.max_cfg_param.xri_used = 0;
phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt *
sizeof(uint16_t),
GFP_KERNEL);
@@ -5420,7 +5434,6 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
case LPFC_RSC_TYPE_FCOE_XRI:
kfree(phba->sli4_hba.xri_bmask);
kfree(phba->sli4_hba.xri_ids);
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
&phba->sli4_hba.lpfc_xri_blk_list, list) {
list_del_init(&rsrc_blk->list);
@@ -5612,7 +5625,6 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba)
goto free_vpi_ids;
}
phba->sli4_hba.max_cfg_param.xri_used = 0;
- phba->sli4_hba.xri_count = 0;
phba->sli4_hba.xri_ids = kzalloc(count *
sizeof(uint16_t),
GFP_KERNEL);
@@ -5694,7 +5706,6 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
kfree(phba->sli4_hba.xri_bmask);
kfree(phba->sli4_hba.xri_ids);
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
kfree(phba->sli4_hba.vfi_bmask);
kfree(phba->sli4_hba.vfi_ids);
bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
@@ -5853,6 +5864,149 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
}
/**
+ * lpfc_sli4_repost_els_sgl_list - Repsot the els buffers sgl pages as block
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of els buffers that have been allocated and
+ * repost them to the port by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. It attempts to construct blocks
+ * of els buffer sgls which contains contiguous xris and uses the non-embedded
+ * SGL block post mailbox commands to post them to the port. For single els
+ * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post
+ * mailbox command for posting.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+static int
+lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
+{
+ struct lpfc_sglq *sglq_entry = NULL;
+ struct lpfc_sglq *sglq_entry_next = NULL;
+ struct lpfc_sglq *sglq_entry_first = NULL;
+ int status, post_cnt = 0, num_posted = 0, block_cnt = 0;
+ int last_xritag = NO_XRI;
+ LIST_HEAD(prep_sgl_list);
+ LIST_HEAD(blck_sgl_list);
+ LIST_HEAD(allc_sgl_list);
+ LIST_HEAD(post_sgl_list);
+ LIST_HEAD(free_sgl_list);
+
+ spin_lock(&phba->hbalock);
+ list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list);
+ spin_unlock(&phba->hbalock);
+
+ list_for_each_entry_safe(sglq_entry, sglq_entry_next,
+ &allc_sgl_list, list) {
+ list_del_init(&sglq_entry->list);
+ block_cnt++;
+ if ((last_xritag != NO_XRI) &&
+ (sglq_entry->sli4_xritag != last_xritag + 1)) {
+ /* a hole in xri block, form a sgl posting block */
+ list_splice_init(&prep_sgl_list, &blck_sgl_list);
+ post_cnt = block_cnt - 1;
+ /* prepare list for next posting block */
+ list_add_tail(&sglq_entry->list, &prep_sgl_list);
+ block_cnt = 1;
+ } else {
+ /* prepare list for next posting block */
+ list_add_tail(&sglq_entry->list, &prep_sgl_list);
+ /* enough sgls for non-embed sgl mbox command */
+ if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+ list_splice_init(&prep_sgl_list,
+ &blck_sgl_list);
+ post_cnt = block_cnt;
+ block_cnt = 0;
+ }
+ }
+ num_posted++;
+
+ /* keep track of last sgl's xritag */
+ last_xritag = sglq_entry->sli4_xritag;
+
+ /* end of repost sgl list condition for els buffers */
+ if (num_posted == phba->sli4_hba.els_xri_cnt) {
+ if (post_cnt == 0) {
+ list_splice_init(&prep_sgl_list,
+ &blck_sgl_list);
+ post_cnt = block_cnt;
+ } else if (block_cnt == 1) {
+ status = lpfc_sli4_post_sgl(phba,
+ sglq_entry->phys, 0,
+ sglq_entry->sli4_xritag);
+ if (!status) {
+ /* successful, put sgl to posted list */
+ list_add_tail(&sglq_entry->list,
+ &post_sgl_list);
+ } else {
+ /* Failure, put sgl to free list */
+ lpfc_printf_log(phba, KERN_WARNING,
+ LOG_SLI,
+ "3159 Failed to post els "
+ "sgl, xritag:x%x\n",
+ sglq_entry->sli4_xritag);
+ list_add_tail(&sglq_entry->list,
+ &free_sgl_list);
+ spin_lock_irq(&phba->hbalock);
+ phba->sli4_hba.els_xri_cnt--;
+ spin_unlock_irq(&phba->hbalock);
+ }
+ }
+ }
+
+ /* continue until a nembed page worth of sgls */
+ if (post_cnt == 0)
+ continue;
+
+ /* post the els buffer list sgls as a block */
+ status = lpfc_sli4_post_els_sgl_list(phba, &blck_sgl_list,
+ post_cnt);
+
+ if (!status) {
+ /* success, put sgl list to posted sgl list */
+ list_splice_init(&blck_sgl_list, &post_sgl_list);
+ } else {
+ /* Failure, put sgl list to free sgl list */
+ sglq_entry_first = list_first_entry(&blck_sgl_list,
+ struct lpfc_sglq,
+ list);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "3160 Failed to post els sgl-list, "
+ "xritag:x%x-x%x\n",
+ sglq_entry_first->sli4_xritag,
+ (sglq_entry_first->sli4_xritag +
+ post_cnt - 1));
+ list_splice_init(&blck_sgl_list, &free_sgl_list);
+ spin_lock_irq(&phba->hbalock);
+ phba->sli4_hba.els_xri_cnt -= post_cnt;
+ spin_unlock_irq(&phba->hbalock);
+ }
+
+ /* don't reset xirtag due to hole in xri block */
+ if (block_cnt == 0)
+ last_xritag = NO_XRI;
+
+ /* reset els sgl post count for next round of posting */
+ post_cnt = 0;
+ }
+
+ /* free the els sgls failed to post */
+ lpfc_free_sgl_list(phba, &free_sgl_list);
+
+ /* push els sgls posted to the availble list */
+ if (!list_empty(&post_sgl_list)) {
+ spin_lock(&phba->hbalock);
+ list_splice_init(&post_sgl_list,
+ &phba->sli4_hba.lpfc_sgl_list);
+ spin_unlock(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "3161 Failure to post els sgl to port.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
* lpfc_sli4_hba_setup - SLI4 device intialization PCI function
* @phba: Pointer to HBA context object.
*
@@ -5923,6 +6077,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
else
phba->hba_flag &= ~HBA_FIP_SUPPORT;
+ phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH;
+
if (phba->sli_rev != LPFC_SLI_REV4) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"0376 READ_REV Error. SLI Level %d "
@@ -6063,8 +6219,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"rc = x%x\n", rc);
goto out_free_mbox;
}
- /* update physical xri mappings in the scsi buffers */
- lpfc_scsi_buf_update(phba);
/* Read the port's service parameters. */
rc = lpfc_read_sparam(phba, mboxq, vport->vpi);
@@ -6105,28 +6259,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
- /* Register SGL pool to the device using non-embedded mailbox command */
- if (!phba->sli4_hba.extents_in_use) {
- rc = lpfc_sli4_post_els_sgl_list(phba);
- if (unlikely(rc)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "0582 Error %d during els sgl post "
- "operation\n", rc);
- rc = -ENODEV;
- goto out_free_mbox;
- }
- } else {
- rc = lpfc_sli4_post_els_sgl_list_ext(phba);
- if (unlikely(rc)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "2560 Error %d during els sgl post "
- "operation\n", rc);
- rc = -ENODEV;
- goto out_free_mbox;
- }
+ /* update host els and scsi xri-sgl sizes and mappings */
+ rc = lpfc_sli4_xri_sgl_update(phba);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "1400 Failed to update xri-sgl size and "
+ "mapping: %d\n", rc);
+ goto out_free_mbox;
}
- /* Register SCSI SGL pool to the device */
+ /* register the els sgl pool to the port */
+ rc = lpfc_sli4_repost_els_sgl_list(phba);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "0582 Error %d during els sgl post "
+ "operation\n", rc);
+ rc = -ENODEV;
+ goto out_free_mbox;
+ }
+
+ /* register the allocated scsi sgl pool to the port */
rc = lpfc_sli4_repost_scsi_sgl_list(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
@@ -7060,14 +7212,19 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
if (rc != MBX_SUCCESS)
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
"(%d):2541 Mailbox command x%x "
- "(x%x/x%x) cannot issue Data: "
- "x%x x%x\n",
+ "(x%x/x%x) failure: "
+ "mqe_sta: x%x mcqe_sta: x%x/x%x "
+ "Data: x%x x%x\n,",
mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli_config_mbox_subsys_get(phba,
mboxq),
lpfc_sli_config_mbox_opcode_get(phba,
mboxq),
+ bf_get(lpfc_mqe_status, &mboxq->u.mqe),
+ bf_get(lpfc_mcqe_status, &mboxq->mcqe),
+ bf_get(lpfc_mcqe_ext_status,
+ &mboxq->mcqe),
psli->sli_flag, flag);
return rc;
} else if (flag == MBX_POLL) {
@@ -7086,18 +7243,22 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
/* Successfully blocked, now issue sync mbox cmd */
rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
if (rc != MBX_SUCCESS)
- lpfc_printf_log(phba, KERN_ERR,
+ lpfc_printf_log(phba, KERN_WARNING,
LOG_MBOX | LOG_SLI,
- "(%d):2597 Mailbox command "
- "x%x (x%x/x%x) cannot issue "
- "Data: x%x x%x\n",
- mboxq->vport ?
- mboxq->vport->vpi : 0,
+ "(%d):2597 Sync Mailbox command "
+ "x%x (x%x/x%x) failure: "
+ "mqe_sta: x%x mcqe_sta: x%x/x%x "
+ "Data: x%x x%x\n,",
+ mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli_config_mbox_subsys_get(phba,
mboxq),
lpfc_sli_config_mbox_opcode_get(phba,
mboxq),
+ bf_get(lpfc_mqe_status, &mboxq->u.mqe),
+ bf_get(lpfc_mcqe_status, &mboxq->mcqe),
+ bf_get(lpfc_mcqe_ext_status,
+ &mboxq->mcqe),
psli->sli_flag, flag);
/* Unblock the async mailbox posting afterward */
lpfc_sli4_async_mbox_unblock(phba);
@@ -7712,7 +7873,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
switch (iocbq->iocb.ulpCommand) {
case CMD_ELS_REQUEST64_CR:
- ndlp = (struct lpfc_nodelist *)iocbq->context1;
+ if (iocbq->iocb_flag & LPFC_IO_LIBDFC)
+ ndlp = iocbq->context_un.ndlp;
+ else
+ ndlp = (struct lpfc_nodelist *)iocbq->context1;
if (!iocbq->iocb.ulpLe) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2007 Only Limited Edition cmd Format"
@@ -7751,9 +7915,13 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(els_req64_sp, &wqe->els_req, 1);
bf_set(els_req64_sid, &wqe->els_req,
iocbq->vport->fc_myDID);
+ if ((*pcmd == ELS_CMD_FLOGI) &&
+ !(phba->fc_topology ==
+ LPFC_TOPOLOGY_LOOP))
+ bf_set(els_req64_sid, &wqe->els_req, 0);
bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
- phba->vpi_ids[phba->pport->vpi]);
+ phba->vpi_ids[iocbq->vport->vpi]);
} else if (pcmd && iocbq->context1) {
bf_set(wqe_ct, &wqe->els_req.wqe_com, 0);
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
@@ -7908,11 +8076,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
/* words0-2 BDE memcpy */
/* word3 iocb=iotag32 wqe=response_payload_len */
wqe->xmit_els_rsp.response_payload_len = xmit_len;
- /* word4 iocb=did wge=rsvd. */
- wqe->xmit_els_rsp.rsvd4 = 0;
+ /* word4 */
+ wqe->xmit_els_rsp.word4 = 0;
/* word5 iocb=rsvd wge=did */
bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
- iocbq->iocb.un.elsreq64.remoteID);
+ iocbq->iocb.un.xseq64.xmit_els_remoteID);
+
+ if_type = bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf);
+ if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (iocbq->vport->fc_flag & FC_PT2PT) {
+ bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
+ bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
+ iocbq->vport->fc_myDID);
+ if (iocbq->vport->fc_myDID == Fabric_DID) {
+ bf_set(wqe_els_did,
+ &wqe->xmit_els_rsp.wqe_dest, 0);
+ }
+ }
+ }
bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
@@ -7932,11 +8114,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
iocbq->context2)->virt);
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
- bf_set(els_req64_sp, &wqe->els_req, 1);
- bf_set(els_req64_sid, &wqe->els_req,
+ bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
+ bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
iocbq->vport->fc_myDID);
- bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
- bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
+ bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1);
+ bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
phba->vpi_ids[phba->pport->vpi]);
}
command_type = OTHER_COMMAND;
@@ -13080,9 +13262,7 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
} else {
set_bit(xri, phba->sli4_hba.xri_bmask);
phba->sli4_hba.max_cfg_param.xri_used++;
- phba->sli4_hba.xri_count++;
}
-
spin_unlock_irq(&phba->hbalock);
return xri;
}
@@ -13098,7 +13278,6 @@ void
__lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
{
if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) {
- phba->sli4_hba.xri_count--;
phba->sli4_hba.max_cfg_param.xri_used--;
}
}
@@ -13134,46 +13313,45 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba)
uint16_t xri_index;
xri_index = lpfc_sli4_alloc_xri(phba);
- if (xri_index != NO_XRI)
- return xri_index;
-
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2004 Failed to allocate XRI.last XRITAG is %d"
- " Max XRI is %d, Used XRI is %d\n",
- xri_index,
- phba->sli4_hba.max_cfg_param.max_xri,
- phba->sli4_hba.max_cfg_param.xri_used);
- return NO_XRI;
+ if (xri_index == NO_XRI)
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "2004 Failed to allocate XRI.last XRITAG is %d"
+ " Max XRI is %d, Used XRI is %d\n",
+ xri_index,
+ phba->sli4_hba.max_cfg_param.max_xri,
+ phba->sli4_hba.max_cfg_param.xri_used);
+ return xri_index;
}
/**
* lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port.
* @phba: pointer to lpfc hba data structure.
+ * @post_sgl_list: pointer to els sgl entry list.
+ * @count: number of els sgl entries on the list.
*
* This routine is invoked to post a block of driver's sgl pages to the
* HBA using non-embedded mailbox command. No Lock is held. This routine
* is only called when the driver is loading and after all IO has been
* stopped.
**/
-int
-lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
+static int
+lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba,
+ struct list_head *post_sgl_list,
+ int post_cnt)
{
- struct lpfc_sglq *sglq_entry;
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
struct sgl_page_pairs *sgl_pg_pairs;
void *viraddr;
LPFC_MBOXQ_t *mbox;
uint32_t reqlen, alloclen, pg_pairs;
uint32_t mbox_tmo;
- uint16_t xritag_start = 0, lxri = 0;
- int els_xri_cnt, rc = 0;
+ uint16_t xritag_start = 0;
+ int rc = 0;
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
- /* The number of sgls to be posted */
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
-
- reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
+ reqlen = phba->sli4_hba.els_xri_cnt * sizeof(struct sgl_page_pairs) +
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
if (reqlen > SLI4_PAGE_SIZE) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -13203,25 +13381,8 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
sgl_pg_pairs = &sgl->sgl_pg_pairs;
- for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) {
- sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs];
-
- /*
- * Assign the sglq a physical xri only if the driver has not
- * initialized those resources. A port reset only needs
- * the sglq's posted.
- */
- if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) !=
- LPFC_XRI_RSRC_RDY) {
- lxri = lpfc_sli4_next_xritag(phba);
- if (lxri == NO_XRI) {
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
- sglq_entry->sli4_lxritag = lxri;
- sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
- }
-
+ pg_pairs = 0;
+ list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) {
/* Set up the sge entry */
sgl_pg_pairs->sgl_pg0_addr_lo =
cpu_to_le32(putPaddrLow(sglq_entry->phys));
@@ -13236,11 +13397,12 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
if (pg_pairs == 0)
xritag_start = sglq_entry->sli4_xritag;
sgl_pg_pairs++;
+ pg_pairs++;
}
/* Complete initialization and perform endian conversion. */
bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt);
+ bf_set(lpfc_post_sgl_pages_xricnt, sgl, phba->sli4_hba.els_xri_cnt);
sgl->word0 = cpu_to_le32(sgl->word0);
if (!phba->sli4_hba.intr_enable)
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
@@ -13260,183 +13422,6 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
shdr_status, shdr_add_status, rc);
rc = -ENXIO;
}
-
- if (rc == 0)
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
- LPFC_XRI_RSRC_RDY);
- return rc;
-}
-
-/**
- * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port.
- * @phba: pointer to lpfc hba data structure.
- *
- * This routine is invoked to post a block of driver's sgl pages to the
- * HBA using non-embedded mailbox command. No Lock is held. This routine
- * is only called when the driver is loading and after all IO has been
- * stopped.
- **/
-int
-lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba)
-{
- struct lpfc_sglq *sglq_entry;
- struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
- struct sgl_page_pairs *sgl_pg_pairs;
- void *viraddr;
- LPFC_MBOXQ_t *mbox;
- uint32_t reqlen, alloclen, index;
- uint32_t mbox_tmo;
- uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt;
- uint16_t xritag_start = 0, lxri = 0;
- struct lpfc_rsrc_blks *rsrc_blk;
- int cnt, ttl_cnt, rc = 0;
- int loop_cnt;
- uint32_t shdr_status, shdr_add_status;
- union lpfc_sli4_cfg_shdr *shdr;
-
- /* The number of sgls to be posted */
- els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
-
- reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- if (reqlen > SLI4_PAGE_SIZE) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "2989 Block sgl registration required DMA "
- "size (%d) great than a page\n", reqlen);
- return -ENOMEM;
- }
-
- cnt = 0;
- ttl_cnt = 0;
- post_els_xri_cnt = els_xri_cnt;
- list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
- list) {
- rsrc_start = rsrc_blk->rsrc_start;
- rsrc_size = rsrc_blk->rsrc_size;
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3014 Working ELS Extent start %d, cnt %d\n",
- rsrc_start, rsrc_size);
-
- loop_cnt = min(post_els_xri_cnt, rsrc_size);
- if (loop_cnt < post_els_xri_cnt) {
- post_els_xri_cnt -= loop_cnt;
- ttl_cnt += loop_cnt;
- } else
- ttl_cnt += post_els_xri_cnt;
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- return -ENOMEM;
- /*
- * Allocate DMA memory and set up the non-embedded mailbox
- * command.
- */
- alloclen = lpfc_sli4_config(phba, mbox,
- LPFC_MBOX_SUBSYSTEM_FCOE,
- LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
- reqlen, LPFC_SLI4_MBX_NEMBED);
- if (alloclen < reqlen) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2987 Allocated DMA memory size (%d) "
- "is less than the requested DMA memory "
- "size (%d)\n", alloclen, reqlen);
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
-
- /* Set up the SGL pages in the non-embedded DMA pages */
- viraddr = mbox->sge_array->addr[0];
- sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
- sgl_pg_pairs = &sgl->sgl_pg_pairs;
-
- /*
- * The starting resource may not begin at zero. Control
- * the loop variants via the block resource parameters,
- * but handle the sge pointers with a zero-based index
- * that doesn't get reset per loop pass.
- */
- for (index = rsrc_start;
- index < rsrc_start + loop_cnt;
- index++) {
- sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt];
-
- /*
- * Assign the sglq a physical xri only if the driver
- * has not initialized those resources. A port reset
- * only needs the sglq's posted.
- */
- if (bf_get(lpfc_xri_rsrc_rdy,
- &phba->sli4_hba.sli4_flags) !=
- LPFC_XRI_RSRC_RDY) {
- lxri = lpfc_sli4_next_xritag(phba);
- if (lxri == NO_XRI) {
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- rc = -ENOMEM;
- goto err_exit;
- }
- sglq_entry->sli4_lxritag = lxri;
- sglq_entry->sli4_xritag =
- phba->sli4_hba.xri_ids[lxri];
- }
-
- /* Set up the sge entry */
- sgl_pg_pairs->sgl_pg0_addr_lo =
- cpu_to_le32(putPaddrLow(sglq_entry->phys));
- sgl_pg_pairs->sgl_pg0_addr_hi =
- cpu_to_le32(putPaddrHigh(sglq_entry->phys));
- sgl_pg_pairs->sgl_pg1_addr_lo =
- cpu_to_le32(putPaddrLow(0));
- sgl_pg_pairs->sgl_pg1_addr_hi =
- cpu_to_le32(putPaddrHigh(0));
-
- /* Track the starting physical XRI for the mailbox. */
- if (index == rsrc_start)
- xritag_start = sglq_entry->sli4_xritag;
- sgl_pg_pairs++;
- cnt++;
- }
-
- /* Complete initialization and perform endian conversion. */
- rsrc_blk->rsrc_used += loop_cnt;
- bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt);
- sgl->word0 = cpu_to_le32(sgl->word0);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3015 Post ELS Extent SGL, start %d, "
- "cnt %d, used %d\n",
- xritag_start, loop_cnt, rsrc_blk->rsrc_used);
- if (!phba->sli4_hba.intr_enable)
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
- else {
- mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
- rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
- }
- shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status,
- &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &shdr->response);
- if (rc != MBX_TIMEOUT)
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2988 POST_SGL_BLOCK mailbox "
- "command failed status x%x "
- "add_status x%x mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- rc = -ENXIO;
- goto err_exit;
- }
- if (ttl_cnt >= els_xri_cnt)
- break;
- }
-
- err_exit:
- if (rc == 0)
- bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
- LPFC_XRI_RSRC_RDY);
return rc;
}
@@ -13452,8 +13437,9 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba)
*
**/
int
-lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
- int cnt)
+lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba,
+ struct list_head *sblist,
+ int count)
{
struct lpfc_scsi_buf *psb;
struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
@@ -13469,7 +13455,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
union lpfc_sli4_cfg_shdr *shdr;
/* Calculate the requested length of the dma memory */
- reqlen = cnt * sizeof(struct sgl_page_pairs) +
+ reqlen = count * sizeof(struct sgl_page_pairs) +
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
if (reqlen > SLI4_PAGE_SIZE) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -13553,169 +13539,6 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
}
/**
- * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port.
- * @phba: pointer to lpfc hba data structure.
- * @sblist: pointer to scsi buffer list.
- * @count: number of scsi buffers on the list.
- *
- * This routine is invoked to post a block of @count scsi sgl pages from a
- * SCSI buffer list @sblist to the HBA using non-embedded mailbox command.
- * No Lock is held.
- *
- **/
-int
-lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist,
- int cnt)
-{
- struct lpfc_scsi_buf *psb = NULL;
- struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
- struct sgl_page_pairs *sgl_pg_pairs;
- void *viraddr;
- LPFC_MBOXQ_t *mbox;
- uint32_t reqlen, alloclen, pg_pairs;
- uint32_t mbox_tmo;
- uint16_t xri_start = 0, scsi_xri_start;
- uint16_t rsrc_range;
- int rc = 0, avail_cnt;
- uint32_t shdr_status, shdr_add_status;
- dma_addr_t pdma_phys_bpl1;
- union lpfc_sli4_cfg_shdr *shdr;
- struct lpfc_rsrc_blks *rsrc_blk;
- uint32_t xri_cnt = 0;
-
- /* Calculate the total requested length of the dma memory */
- reqlen = cnt * sizeof(struct sgl_page_pairs) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- if (reqlen > SLI4_PAGE_SIZE) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "2932 Block sgl registration required DMA "
- "size (%d) great than a page\n", reqlen);
- return -ENOMEM;
- }
-
- /*
- * The use of extents requires the driver to post the sgl headers
- * in multiple postings to meet the contiguous resource assignment.
- */
- psb = list_prepare_entry(psb, sblist, list);
- scsi_xri_start = phba->sli4_hba.scsi_xri_start;
- list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
- list) {
- rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size;
- if (rsrc_range < scsi_xri_start)
- continue;
- else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size)
- continue;
- else
- avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used;
-
- reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) +
- sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
- /*
- * Allocate DMA memory and set up the non-embedded mailbox
- * command. The mbox is used to post an SGL page per loop
- * but the DMA memory has a use-once semantic so the mailbox
- * is used and freed per loop pass.
- */
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2933 Failed to allocate mbox cmd "
- "memory\n");
- return -ENOMEM;
- }
- alloclen = lpfc_sli4_config(phba, mbox,
- LPFC_MBOX_SUBSYSTEM_FCOE,
- LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
- reqlen,
- LPFC_SLI4_MBX_NEMBED);
- if (alloclen < reqlen) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2934 Allocated DMA memory size (%d) "
- "is less than the requested DMA memory "
- "size (%d)\n", alloclen, reqlen);
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- return -ENOMEM;
- }
-
- /* Get the first SGE entry from the non-embedded DMA memory */
- viraddr = mbox->sge_array->addr[0];
-
- /* Set up the SGL pages in the non-embedded DMA pages */
- sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
- sgl_pg_pairs = &sgl->sgl_pg_pairs;
-
- /* pg_pairs tracks posted SGEs per loop iteration. */
- pg_pairs = 0;
- list_for_each_entry_continue(psb, sblist, list) {
- /* Set up the sge entry */
- sgl_pg_pairs->sgl_pg0_addr_lo =
- cpu_to_le32(putPaddrLow(psb->dma_phys_bpl));
- sgl_pg_pairs->sgl_pg0_addr_hi =
- cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl));
- if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
- pdma_phys_bpl1 = psb->dma_phys_bpl +
- SGL_PAGE_SIZE;
- else
- pdma_phys_bpl1 = 0;
- sgl_pg_pairs->sgl_pg1_addr_lo =
- cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
- sgl_pg_pairs->sgl_pg1_addr_hi =
- cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
- /* Keep the first xri for this extent. */
- if (pg_pairs == 0)
- xri_start = psb->cur_iocbq.sli4_xritag;
- sgl_pg_pairs++;
- pg_pairs++;
- xri_cnt++;
-
- /*
- * Track two exit conditions - the loop has constructed
- * all of the caller's SGE pairs or all available
- * resource IDs in this extent are consumed.
- */
- if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt))
- break;
- }
- rsrc_blk->rsrc_used += pg_pairs;
- bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start);
- bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3016 Post SCSI Extent SGL, start %d, cnt %d "
- "blk use %d\n",
- xri_start, pg_pairs, rsrc_blk->rsrc_used);
- /* Perform endian conversion if necessary */
- sgl->word0 = cpu_to_le32(sgl->word0);
- if (!phba->sli4_hba.intr_enable)
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
- else {
- mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
- rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
- }
- shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &shdr->response);
- if (rc != MBX_TIMEOUT)
- lpfc_sli4_mbox_cmd_free(phba, mbox);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2935 POST_SGL_BLOCK mailbox command "
- "failed status x%x add_status x%x "
- "mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- return -ENXIO;
- }
-
- /* Post only what is requested. */
- if (xri_cnt >= cnt)
- break;
- }
- return rc;
-}
-
-/**
* lpfc_fc_frame_check - Check that this frame is a valid frame to handle
* @phba: pointer to lpfc_hba struct that the frame was received on
* @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
@@ -13839,8 +13662,13 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
uint32_t did = (fc_hdr->fh_d_id[0] << 16 |
fc_hdr->fh_d_id[1] << 8 |
fc_hdr->fh_d_id[2]);
+
if (did == Fabric_DID)
return phba->pport;
+ if ((phba->pport->fc_flag & FC_PT2PT) &&
+ !(phba->link_state == LPFC_HBA_READY))
+ return phba->pport;
+
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
@@ -14133,7 +13961,6 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
return NO_XRI;
}
-
/**
* lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort
* @phba: Pointer to HBA context object.
@@ -14148,7 +13975,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
{
struct lpfc_iocbq *ctiocb = NULL;
struct lpfc_nodelist *ndlp;
- uint16_t oxid, rxid;
+ uint16_t oxid, rxid, xri, lxri;
uint32_t sid, fctl;
IOCB_t *icmd;
int rc;
@@ -14167,8 +13994,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
"SID:x%x\n", oxid, sid);
return;
}
- if (lpfc_sli4_xri_inrange(phba, rxid))
- lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0);
/* Allocate buffer for rsp iocb */
ctiocb = lpfc_sli_get_iocbq(phba);
@@ -14199,13 +14024,24 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
ctiocb->sli4_lxritag = NO_XRI;
ctiocb->sli4_xritag = NO_XRI;
+ if (fctl & FC_FC_EX_CTX)
+ /* Exchange responder sent the abort so we
+ * own the oxid.
+ */
+ xri = oxid;
+ else
+ xri = rxid;
+ lxri = lpfc_sli4_xri_inrange(phba, xri);
+ if (lxri != NO_XRI)
+ lpfc_set_rrq_active(phba, ndlp, lxri,
+ (xri == oxid) ? rxid : oxid, 0);
/* If the oxid maps to the FCP XRI range or if it is out of range,
* send a BLS_RJT. The driver no longer has that exchange.
* Override the IOCB for a BA_RJT.
*/
- if (oxid > (phba->sli4_hba.max_cfg_param.max_xri +
+ if (xri > (phba->sli4_hba.max_cfg_param.max_xri +
phba->sli4_hba.max_cfg_param.xri_base) ||
- oxid > (lpfc_sli4_get_els_iocb_cnt(phba) +
+ xri > (lpfc_sli4_get_els_iocb_cnt(phba) +
phba->sli4_hba.max_cfg_param.xri_base)) {
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT;
bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0);
@@ -14377,7 +14213,15 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
/* Initialize the first IOCB. */
first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
- first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
+
+ /* Check FC Header to see what TYPE of frame we are rcv'ing */
+ if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) {
+ first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX;
+ first_iocbq->iocb.un.rcvels.parmRo =
+ sli4_did_from_fc_hdr(fc_hdr);
+ first_iocbq->iocb.ulpPU = PARM_NPIV_DID;
+ } else
+ first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
first_iocbq->iocb.ulpContext = NO_XRI;
first_iocbq->iocb.unsli3.rcvsli3.ox_id =
be16_to_cpu(fc_hdr->fh_ox_id);
@@ -14507,6 +14351,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
struct fc_frame_header *fc_hdr;
struct lpfc_vport *vport;
uint32_t fcfi;
+ uint32_t did;
/* Process each received buffer */
fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
@@ -14522,12 +14367,32 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
else
fcfi = bf_get(lpfc_rcqe_fcf_id,
&dmabuf->cq_event.cqe.rcqe_cmpl);
+
vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
- if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {
+ if (!vport) {
/* throw out the frame */
lpfc_in_buf_free(phba, &dmabuf->dbuf);
return;
}
+
+ /* d_id this frame is directed to */
+ did = sli4_did_from_fc_hdr(fc_hdr);
+
+ /* vport is registered unless we rcv a FLOGI directed to Fabric_DID */
+ if (!(vport->vpi_state & LPFC_VPI_REGISTERED) &&
+ (did != Fabric_DID)) {
+ /*
+ * Throw out the frame if we are not pt2pt.
+ * The pt2pt protocol allows for discovery frames
+ * to be received without a registered VPI.
+ */
+ if (!(vport->fc_flag & FC_PT2PT) ||
+ (phba->link_state == LPFC_HBA_READY)) {
+ lpfc_in_buf_free(phba, &dmabuf->dbuf);
+ return;
+ }
+ }
+
/* Handle the basic abort sequence (BA_ABTS) event */
if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) {
lpfc_sli4_handle_unsol_abort(vport, dmabuf);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 3290b8e..2626f58c 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -68,7 +68,7 @@ struct lpfc_iocbq {
#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */
-#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
+#define LPFC_IO_ON_TXCMPLQ 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_IO_DIF 0x400 /* T10 DIF IO */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index c19d139..a4a7708 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -75,11 +75,19 @@
(fc_hdr)->fh_s_id[1] << 8 | \
(fc_hdr)->fh_s_id[2])
+#define sli4_did_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_d_id[0] << 16 | \
+ (fc_hdr)->fh_d_id[1] << 8 | \
+ (fc_hdr)->fh_d_id[2])
+
#define sli4_fctl_from_fc_hdr(fc_hdr) \
((fc_hdr)->fh_f_ctl[0] << 16 | \
(fc_hdr)->fh_f_ctl[1] << 8 | \
(fc_hdr)->fh_f_ctl[2])
+#define sli4_type_from_fc_hdr(fc_hdr) \
+ ((fc_hdr)->fh_type)
+
#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000
enum lpfc_sli4_queue_type {
@@ -493,14 +501,12 @@ struct lpfc_sli4_hba {
uint16_t next_rpi;
uint16_t scsi_xri_max;
uint16_t scsi_xri_cnt;
+ uint16_t els_xri_cnt;
uint16_t scsi_xri_start;
struct list_head lpfc_free_sgl_list;
struct list_head lpfc_sgl_list;
- struct lpfc_sglq **lpfc_els_sgl_array;
struct list_head lpfc_abts_els_sgl_list;
- struct lpfc_scsi_buf **lpfc_scsi_psb_array;
struct list_head lpfc_abts_scsi_buf_list;
- uint32_t total_sglq_bufs;
struct lpfc_sglq **lpfc_sglq_active_list;
struct list_head lpfc_rpi_hdr_list;
unsigned long *rpi_bmask;
@@ -509,7 +515,6 @@ struct lpfc_sli4_hba {
struct list_head lpfc_rpi_blk_list;
unsigned long *xri_bmask;
uint16_t *xri_ids;
- uint16_t xri_count;
struct list_head lpfc_xri_blk_list;
unsigned long *vfi_bmask;
uint16_t *vfi_ids;
@@ -614,11 +619,7 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
-int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba);
-int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba);
int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
-int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *,
- int);
struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 25cefc2..59c57a4 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.30"
+#define LPFC_DRIVER_VERSION "8.3.31"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index e5f416f..e8f8926 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -33,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.06.14-rc1"
-#define MEGASAS_RELDATE "Jan. 6, 2012"
-#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012"
+#define MEGASAS_VERSION "00.00.06.15-rc1"
+#define MEGASAS_RELDATE "Mar. 19, 2012"
+#define MEGASAS_EXT_VERSION "Mon. Mar. 19 17:00:00 PDT 2012"
/*
* Device IDs
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 8b300be..dc27598 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FILE: megaraid_sas_base.c
- * Version : v00.00.06.14-rc1
+ * Version : v00.00.06.15-rc1
*
* Authors: LSI Corporation
* Sreenivas Bagalkote
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 294abb0..e3d251a 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -362,15 +362,20 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* assume this IO needs the full row - we'll adjust if not true */
regSize = stripSize;
- /* If IO spans more than 1 strip, fp is not possible
- FP is not possible for writes on non-0 raid levels
- FP is not possible if LD is not capable */
- if (num_strips > 1 || (!isRead && raid->level != 0) ||
- !raid->capability.fpCapable) {
+ /* Check if we can send this I/O via FastPath */
+ if (raid->capability.fpCapable) {
+ if (isRead)
+ io_info->fpOkForIo = (raid->capability.fpReadCapable &&
+ ((num_strips == 1) ||
+ raid->capability.
+ fpReadAcrossStripe));
+ else
+ io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
+ ((num_strips == 1) ||
+ raid->capability.
+ fpWriteAcrossStripe));
+ } else
io_info->fpOkForIo = FALSE;
- } else {
- io_info->fpOkForIo = TRUE;
- }
if (numRows == 1) {
/* single-strip IOs can always lock only the data needed */
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index bfd87fa..a610cf1 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -634,9 +634,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
fusion->reply_frames_desc_phys;
IOCInitMessage->SystemRequestFrameBaseAddress =
fusion->io_request_frames_phys;
- /* Set to 0 for none or 1 MSI-X vectors */
- IOCInitMessage->HostMSIxVectors = (instance->msix_vectors > 0 ?
- instance->msix_vectors : 0);
+ IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
init_frame = (struct megasas_init_frame *)cmd->frame;
memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index a01f0aa..a80f322 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.22
+ * mpi2.h Version: 02.00.23
*
* Version History
* ---------------
@@ -71,6 +71,7 @@
* 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
* 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
* 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -96,7 +97,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x16)
+#define MPI2_HEADER_VERSION_UNIT (0x17)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -480,7 +481,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
- Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
+Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 3a023da..737fa8c 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.21
+ * mpi2_cnfg.h Version: 02.00.22
*
* Version History
* ---------------
@@ -146,7 +146,9 @@
* Added SpinupFlags field containing a Disable Spin-up
* bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of
* SAS IO Unit Page 4.
-
+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
+ * Added UEFIVersion field to BIOS Page 1 and defined new
+ * BiosOptions bits.
* --------------------------------------------------------------------------
*/
@@ -1131,9 +1133,10 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_6
} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
-#define MPI2_IOCPAGE6_PAGEVERSION (0x04)
+#define MPI2_IOCPAGE6_PAGEVERSION (0x05)
/* defines for IOC Page 6 CapabilitiesFlags */
+#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008)
#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004)
@@ -1204,24 +1207,29 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_8
typedef struct _MPI2_CONFIG_PAGE_BIOS_1
{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 BiosOptions; /* 0x04 */
- U32 IOCSettings; /* 0x08 */
- U32 Reserved1; /* 0x0C */
- U32 DeviceSettings; /* 0x10 */
- U16 NumberOfDevices; /* 0x14 */
- U16 Reserved2; /* 0x16 */
- U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
- U16 IOTimeoutSequential; /* 0x1A */
- U16 IOTimeoutOther; /* 0x1C */
- U16 IOTimeoutBlockDevicesRM; /* 0x1E */
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U32 BiosOptions; /* 0x04 */
+ U32 IOCSettings; /* 0x08 */
+ U32 Reserved1; /* 0x0C */
+ U32 DeviceSettings; /* 0x10 */
+ U16 NumberOfDevices; /* 0x14 */
+ U16 UEFIVersion; /* 0x16 */
+ U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
+ U16 IOTimeoutSequential; /* 0x1A */
+ U16 IOTimeoutOther; /* 0x1C */
+ U16 IOTimeoutBlockDevicesRM; /* 0x1E */
} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
-#define MPI2_BIOSPAGE1_PAGEVERSION (0x04)
+#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
/* values for BIOS Page 1 BiosOptions field */
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
+#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
+#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004)
+
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
/* values for BIOS Page 1 IOCSettings field */
#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000)
@@ -1248,6 +1256,13 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1
#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001)
+/* defines for BIOS Page 1 UEFIVersion field */
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00)
+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF)
+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0)
+
+
/* BIOS Page 2 */
@@ -2216,6 +2231,27 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
+/* SAS IO Unit Page 16 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U64 TimeStamp; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 FastPathPendedRequests; /* 0x18 */
+ U32 FastPathUnPendedRequests; /* 0x1C */
+ U32 FastPathHostRequestStarts; /* 0x20 */
+ U32 FastPathFirmwareRequestStarts; /* 0x24 */
+ U32 FastPathHostCompletions; /* 0x28 */
+ U32 FastPathFirmwareCompletions; /* 0x2C */
+ U32 NonFastPathRequestStarts; /* 0x30 */
+ U32 NonFastPathHostCompletions; /* 0x30 */
+} MPI2_CONFIG_PAGE_SASIOUNIT16,
+MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16,
+Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t;
+
+#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00)
+
/****************************************************************************
* SAS Expander Config Pages
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 8a59a77..6102ef2 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -699,6 +699,11 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u16 ioc_status;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return;
+ }
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
@@ -930,16 +935,18 @@ _base_interrupt(int irq, void *bus_id)
else if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
goto next;
- if (smid)
+ if (smid) {
cb_idx = _base_get_cb_idx(ioc, smid);
- if (smid && cb_idx != 0xFF) {
- rc = mpt_callbacks[cb_idx](ioc, smid, msix_index,
- reply);
+ if ((likely(cb_idx < MPT_MAX_CALLBACKS))
+ && (likely(mpt_callbacks[cb_idx] != NULL))) {
+ rc = mpt_callbacks[cb_idx](ioc, smid,
+ msix_index, reply);
if (reply)
- _base_display_reply_info(ioc, smid, msix_index,
- reply);
+ _base_display_reply_info(ioc, smid,
+ msix_index, reply);
if (rc)
mpt2sas_base_free_smid(ioc, smid);
+ }
}
if (!smid)
_base_async_event(ioc, msix_index, reply);
@@ -3343,7 +3350,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
}
pfacts = &ioc->pfacts[port];
- memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t));
+ memset(pfacts, 0, sizeof(struct mpt2sas_port_facts));
pfacts->PortNumber = mpi_reply.PortNumber;
pfacts->VP_ID = mpi_reply.VP_ID;
pfacts->VF_ID = mpi_reply.VF_ID;
@@ -3385,7 +3392,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
facts = &ioc->facts;
- memset(facts, 0, sizeof(Mpi2IOCFactsReply_t));
+ memset(facts, 0, sizeof(struct mpt2sas_facts));
facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
facts->VP_ID = mpi_reply.VP_ID;
@@ -4153,7 +4160,8 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (ioc->is_driver_loading) {
if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
== 0x80) {
- hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 &
+ hide_flag = (u8) (
+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
MFG_PAGE10_HIDE_SSDS_MASK);
if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
ioc->mfg_pg10_hide_flag = hide_flag;
@@ -4262,7 +4270,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
+ sizeof(struct mpt2sas_port_facts), GFP_KERNEL);
if (!ioc->pfacts) {
r = -ENOMEM;
goto out_free_resources;
@@ -4279,7 +4287,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
init_waitqueue_head(&ioc->reset_wq);
-
/* allocate memory pd handle bitmask list */
ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
if (ioc->facts.MaxDevHandle % 8)
@@ -4290,7 +4297,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
r = -ENOMEM;
goto out_free_resources;
}
-
+ ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
+ GFP_KERNEL);
+ if (!ioc->blocking_handles) {
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
ioc->fwfault_debug = mpt2sas_fwfault_debug;
/* base internal command bits */
@@ -4377,6 +4389,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
if (ioc->is_warpdrive)
kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
+ kfree(ioc->blocking_handles);
kfree(ioc->tm_cmds.reply);
kfree(ioc->transport_cmds.reply);
kfree(ioc->scsih_cmds.reply);
@@ -4418,6 +4431,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
if (ioc->is_warpdrive)
kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
+ kfree(ioc->blocking_handles);
kfree(ioc->pfacts);
kfree(ioc->ctl_cmds.reply);
kfree(ioc->ctl_cmds.sense);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index c7459fd..b6dd3a5 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "12.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 12
+#define MPT2SAS_DRIVER_VERSION "13.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 13
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -720,6 +720,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
* @io_missing_delay: time for IO completed by fw when PDR enabled
* @device_missing_delay: time for device missing by fw when PDR enabled
* @sas_id : used for setting volume target IDs
+ * @blocking_handles: bitmask used to identify which devices need blocking
* @pd_handles : bitmask for PD handles
* @pd_handles_sz : size of pd_handle bitmask
* @config_page_sz: config page size
@@ -889,7 +890,7 @@ struct MPT2SAS_ADAPTER {
u8 io_missing_delay;
u16 device_missing_delay;
int sas_id;
-
+ void *blocking_handles;
void *pd_handles;
u16 pd_handles_sz;
@@ -1058,7 +1059,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address);
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 3b9a28e..49bdd2d 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -620,11 +620,10 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
* @ioc: per adapter object
* @karg - (struct mpt2_ioctl_command)
* @mf - pointer to mf in user space
- * @state - NON_BLOCKING or BLOCKING
*/
static long
-_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
+_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg,
+ void __user *mf)
{
MPI2RequestHeader_t *mpi_request = NULL, *request;
MPI2DefaultReply_t *mpi_reply;
@@ -647,11 +646,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
issue_reset = 0;
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
@@ -871,8 +865,16 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
if (smp_request->PassthroughFlags &
MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
data = (u8 *)&smp_request->SGL;
- else
+ else {
+ if (unlikely(data_out == NULL)) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ mpt2sas_base_free_smid(ioc, smid);
+ ret = -EINVAL;
+ goto out;
+ }
data = data_out;
+ }
if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
ioc->ioc_link_reset_in_progress = 1;
@@ -985,7 +987,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ret = -ENODATA;
if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+ mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
"= (0x%04x)\n", ioc->name,
le16_to_cpu(mpi_request->FunctionDependent1));
@@ -1013,27 +1016,24 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
kfree(mpi_request);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
}
/**
* _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_getiocinfo(void __user *arg)
+_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_iocinfo karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1069,21 +1069,19 @@ _ctl_getiocinfo(void __user *arg)
/**
* _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventquery(void __user *arg)
+_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventquery karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1102,21 +1100,19 @@ _ctl_eventquery(void __user *arg)
/**
* _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventenable(void __user *arg)
+_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventenable karg;
- struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1142,13 +1138,13 @@ _ctl_eventenable(void __user *arg)
/**
* _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_eventreport(void __user *arg)
+_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_eventreport karg;
- struct MPT2SAS_ADAPTER *ioc;
u32 number_bytes, max_events, max;
struct mpt2_ioctl_eventreport __user *uarg = arg;
@@ -1157,8 +1153,6 @@ _ctl_eventreport(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
@@ -1188,13 +1182,13 @@ _ctl_eventreport(void __user *arg)
/**
* _ctl_do_reset - main handler for MPT2HARDRESET opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_do_reset(void __user *arg)
+_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_diag_reset karg;
- struct MPT2SAS_ADAPTER *ioc;
int retval;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1202,8 +1196,6 @@ _ctl_do_reset(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
if (ioc->shost_recovery || ioc->pci_error_recovery ||
ioc->is_driver_loading)
@@ -1292,13 +1284,13 @@ _ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,
/**
* _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*/
static long
-_ctl_btdh_mapping(void __user *arg)
+_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_ioctl_btdh_mapping karg;
- struct MPT2SAS_ADAPTER *ioc;
int rc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1306,8 +1298,6 @@ _ctl_btdh_mapping(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1576,17 +1566,16 @@ mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
/**
* _ctl_diag_register - application register with driver
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*
* This will allow the driver to setup any required buffers that will be
* needed by firmware to communicate with the driver.
*/
static long
-_ctl_diag_register(void __user *arg, enum block_state state)
+_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_register karg;
- struct MPT2SAS_ADAPTER *ioc;
long rc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
@@ -1594,30 +1583,23 @@ _ctl_diag_register(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
rc = _ctl_diag_register_2(ioc, &karg);
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_unregister - application unregister with driver
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*
* This will allow the driver to cleanup any memory allocated for diag
* messages and to free up any resources.
*/
static long
-_ctl_diag_unregister(void __user *arg)
+_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_unregister karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
dma_addr_t request_data_dma;
u32 request_data_sz;
@@ -1628,8 +1610,6 @@ _ctl_diag_unregister(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1678,6 +1658,7 @@ _ctl_diag_unregister(void __user *arg)
/**
* _ctl_diag_query - query relevant info associated with diag buffers
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
*
* The application will send only buffer_type and unique_id. Driver will
@@ -1685,10 +1666,9 @@ _ctl_diag_unregister(void __user *arg)
* 0x00, the driver will return info specified by Buffer Type.
*/
static long
-_ctl_diag_query(void __user *arg)
+_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_query karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int i;
u8 buffer_type;
@@ -1698,8 +1678,6 @@ _ctl_diag_query(void __user *arg)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1866,17 +1844,15 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
/**
* _ctl_diag_release - request to send Diag Release Message to firmware
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*
* This allows ownership of the specified buffer to returned to the driver,
* allowing an application to read the buffer without fear that firmware is
* overwritting information in the buffer.
*/
static long
-_ctl_diag_release(void __user *arg, enum block_state state)
+_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_release karg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int rc;
u8 buffer_type;
@@ -1887,8 +1863,6 @@ _ctl_diag_release(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1942,32 +1916,25 @@ _ctl_diag_release(void __user *arg, enum block_state state)
return 0;
}
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
rc = _ctl_send_release(ioc, buffer_type, &issue_reset);
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_read_buffer - request for copy of the diag buffer
+ * @ioc: per adapter object
* @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
*/
static long
-_ctl_diag_read_buffer(void __user *arg, enum block_state state)
+_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt2_diag_read_buffer karg;
struct mpt2_diag_read_buffer __user *uarg = arg;
- struct MPT2SAS_ADAPTER *ioc;
void *request_data, *diag_data;
Mpi2DiagBufferPostRequest_t *mpi_request;
Mpi2DiagBufferPostReply_t *mpi_reply;
@@ -1983,8 +1950,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
__FILE__, __LINE__, __func__);
return -EFAULT;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -2055,10 +2020,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
}
/* Get a free request frame and save the message context.
*/
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
@@ -2139,115 +2100,170 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
out:
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
+
+#ifdef CONFIG_COMPAT
+/**
+ * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
+ * @ioc: per adapter object
+ * @cmd - ioctl opcode
+ * @arg - (struct mpt2_ioctl_command32)
+ *
+ * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
+ */
+static long
+_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd,
+ void __user *arg)
+{
+ struct mpt2_ioctl_command32 karg32;
+ struct mpt2_ioctl_command32 __user *uarg;
+ struct mpt2_ioctl_command karg;
+
+ if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
+ return -EINVAL;
+
+ uarg = (struct mpt2_ioctl_command32 __user *) arg;
+
+ if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+
+ memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
+ karg.hdr.ioc_number = karg32.hdr.ioc_number;
+ karg.hdr.port_number = karg32.hdr.port_number;
+ karg.hdr.max_data_size = karg32.hdr.max_data_size;
+ karg.timeout = karg32.timeout;
+ karg.max_reply_bytes = karg32.max_reply_bytes;
+ karg.data_in_size = karg32.data_in_size;
+ karg.data_out_size = karg32.data_out_size;
+ karg.max_sense_bytes = karg32.max_sense_bytes;
+ karg.data_sge_offset = karg32.data_sge_offset;
+ karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
+ karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
+ karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
+ karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
+ return _ctl_do_mpt_command(ioc, karg, &uarg->mf);
+}
+#endif
+
/**
* _ctl_ioctl_main - main ioctl entry point
* @file - (struct file)
* @cmd - ioctl opcode
* @arg -
+ * compat - handles 32 bit applications in 64bit os
*/
static long
-_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
+_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
+ u8 compat)
{
+ struct MPT2SAS_ADAPTER *ioc;
+ struct mpt2_ioctl_header ioctl_header;
enum block_state state;
long ret = -EINVAL;
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
- BLOCKING;
+ /* get IOCTL header */
+ if (copy_from_user(&ioctl_header, (char __user *)arg,
+ sizeof(struct mpt2_ioctl_header))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+
+ if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
+ return -ENODEV;
+ if (ioc->shost_recovery || ioc->pci_error_recovery ||
+ ioc->is_driver_loading)
+ return -EAGAIN;
+
+ state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
+ if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+ return -EAGAIN;
+ else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+ return -ERESTARTSYS;
switch (cmd) {
case MPT2IOCINFO:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
- ret = _ctl_getiocinfo(arg);
+ ret = _ctl_getiocinfo(ioc, arg);
break;
+#ifdef CONFIG_COMPAT
+ case MPT2COMMAND32:
+#endif
case MPT2COMMAND:
{
- struct mpt2_ioctl_command karg;
struct mpt2_ioctl_command __user *uarg;
- struct MPT2SAS_ADAPTER *ioc;
-
+ struct mpt2_ioctl_command karg;
+#ifdef CONFIG_COMPAT
+ if (compat) {
+ ret = _ctl_compat_mpt_command(ioc, cmd, arg);
+ break;
+ }
+#endif
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
- return -EFAULT;
+ ret = -EFAULT;
+ break;
}
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
- !ioc)
- return -ENODEV;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
-
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
uarg = arg;
- ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
+ ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
}
break;
}
case MPT2EVENTQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
- ret = _ctl_eventquery(arg);
+ ret = _ctl_eventquery(ioc, arg);
break;
case MPT2EVENTENABLE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
- ret = _ctl_eventenable(arg);
+ ret = _ctl_eventenable(ioc, arg);
break;
case MPT2EVENTREPORT:
- ret = _ctl_eventreport(arg);
+ ret = _ctl_eventreport(ioc, arg);
break;
case MPT2HARDRESET:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
- ret = _ctl_do_reset(arg);
+ ret = _ctl_do_reset(ioc, arg);
break;
case MPT2BTDHMAPPING:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
- ret = _ctl_btdh_mapping(arg);
+ ret = _ctl_btdh_mapping(ioc, arg);
break;
case MPT2DIAGREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
- ret = _ctl_diag_register(arg, state);
+ ret = _ctl_diag_register(ioc, arg);
break;
case MPT2DIAGUNREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
- ret = _ctl_diag_unregister(arg);
+ ret = _ctl_diag_unregister(ioc, arg);
break;
case MPT2DIAGQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
- ret = _ctl_diag_query(arg);
+ ret = _ctl_diag_query(ioc, arg);
break;
case MPT2DIAGRELEASE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
- ret = _ctl_diag_release(arg, state);
+ ret = _ctl_diag_release(ioc, arg);
break;
case MPT2DIAGREADBUFFER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
- ret = _ctl_diag_read_buffer(arg, state);
+ ret = _ctl_diag_read_buffer(ioc, arg);
break;
default:
- {
- struct mpt2_ioctl_command karg;
- struct MPT2SAS_ADAPTER *ioc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
- !ioc)
- return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
"unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
break;
}
- }
+
+ mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
}
@@ -2262,66 +2278,11 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- mutex_lock(&_ctl_mutex);
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
- mutex_unlock(&_ctl_mutex);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
return ret;
}
-
#ifdef CONFIG_COMPAT
/**
- * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg - (struct mpt2_ioctl_command32)
- *
- * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
- */
-static long
-_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
-{
- struct mpt2_ioctl_command32 karg32;
- struct mpt2_ioctl_command32 __user *uarg;
- struct mpt2_ioctl_command karg;
- struct MPT2SAS_ADAPTER *ioc;
- enum block_state state;
-
- if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
- return -EINVAL;
-
- uarg = (struct mpt2_ioctl_command32 __user *) arg;
-
- if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
-
- memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
- karg.hdr.ioc_number = karg32.hdr.ioc_number;
- karg.hdr.port_number = karg32.hdr.port_number;
- karg.hdr.max_data_size = karg32.hdr.max_data_size;
- karg.timeout = karg32.timeout;
- karg.max_reply_bytes = karg32.max_reply_bytes;
- karg.data_in_size = karg32.data_in_size;
- karg.data_out_size = karg32.data_out_size;
- karg.max_sense_bytes = karg32.max_sense_bytes;
- karg.data_sge_offset = karg32.data_sge_offset;
- karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
- karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
- karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
- karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
- return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
-}
-
-/**
* _ctl_ioctl_compat - main ioctl entry point (compat)
* @file -
* @cmd -
@@ -2334,12 +2295,7 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
- mutex_lock(&_ctl_mutex);
- if (cmd == MPT2COMMAND32)
- ret = _ctl_compat_mpt_command(file, cmd, arg);
- else
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
- mutex_unlock(&_ctl_mutex);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
return ret;
}
#endif
@@ -2884,7 +2840,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
struct mpt2_diag_register diag_register;
u8 issue_reset = 0;
- if (sscanf(buf, "%s", str) != 1)
+ if (sscanf(buf, "%9s", str) != 1)
return -EINVAL;
if (!strcmp(str, "post")) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index d953a57..76973e8 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -579,14 +579,12 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device->sas_address)) {
- list_del(&sas_device->list);
- kfree(sas_device);
- }
+ list_del(&sas_device->list);
+ kfree(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
+
/**
* _scsih_sas_device_add - insert sas_device to the list.
* @ioc: per adapter object
@@ -645,8 +643,8 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
_scsih_determine_boot_device(ioc, sas_device, 0);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
/**
@@ -755,7 +753,6 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
* @ioc: per adapter object
* @raid_device: raid_device object
*
- * This is removed from the raid_device_list link list.
*/
static void
_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
@@ -765,7 +762,6 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->raid_device_lock, flags);
list_del(&raid_device->list);
- memset(raid_device, 0, sizeof(struct _raid_device));
kfree(raid_device);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
@@ -1199,10 +1195,10 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_device_priv_data->sas_target->sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device && sas_device->device_info &
MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata:
@@ -1299,7 +1295,8 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->handle = raid_device->handle;
sas_target_priv_data->sas_address = raid_device->wwid;
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- sas_target_priv_data->raid_device = raid_device;
+ if (ioc->is_warpdrive)
+ sas_target_priv_data->raid_device = raid_device;
raid_device->starget = starget;
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
@@ -1465,12 +1462,12 @@ _scsih_slave_destroy(struct scsi_device *sdev)
/**
* _scsih_display_sata_capabilities - sata capabilities
* @ioc: per adapter object
- * @sas_device: the sas_device object
+ * @handle: device handle
* @sdev: scsi device struct
*/
static void
_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device, struct scsi_device *sdev)
+ u16 handle, struct scsi_device *sdev)
{
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
@@ -1479,7 +1476,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
u32 device_info;
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return;
@@ -1537,27 +1534,40 @@ _scsih_get_resync(struct device *dev)
Mpi2RaidVolPage0_t vol_pg0;
Mpi2ConfigReply_t mpi_reply;
u32 volume_status_flags;
- u8 percent_complete = 0;
+ u8 percent_complete;
+ u16 handle;
+
+ percent_complete = 0;
+ handle = 0;
+ if (ioc->is_warpdrive)
+ goto out;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
+ if (raid_device) {
+ handle = raid_device->handle;
+ percent_complete = raid_device->percent_complete;
+ }
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device || ioc->is_warpdrive)
+ if (!handle)
goto out;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
+ percent_complete = 0;
goto out;
}
volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
- percent_complete = raid_device->percent_complete;
+ if (!(volume_status_flags &
+ MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
+ percent_complete = 0;
+
out:
raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
}
@@ -1577,17 +1587,20 @@ _scsih_get_state(struct device *dev)
Mpi2ConfigReply_t mpi_reply;
u32 volstate;
enum raid_state state = RAID_STATE_UNKNOWN;
+ u16 handle = 0;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
+ if (raid_device)
+ handle = raid_device->handle;
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device)
goto out;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -1620,14 +1633,14 @@ _scsih_get_state(struct device *dev)
/**
* _scsih_set_level - set raid level
* @sdev: scsi device struct
- * @raid_device: raid_device object
+ * @volume_type: volume type
*/
static void
-_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
+_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
{
enum raid_level level = RAID_LEVEL_UNKNOWN;
- switch (raid_device->volume_type) {
+ switch (volume_type) {
case MPI2_RAID_VOL_TYPE_RAID0:
level = RAID_LEVEL_0;
break;
@@ -1722,6 +1735,7 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
struct _raid_device *raid_device;
u16 handle;
u16 ioc_status;
+ unsigned long flags;
handle = 0xFFFF;
while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
@@ -1731,9 +1745,11 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(vol_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
if (raid_device)
raid_device->direct_io_enabled = 0;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
return;
}
@@ -1838,7 +1854,8 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
&pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
vol_pg0->PhysDisk[count].PhysDiskNum) ||
- pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) {
+ le16_to_cpu(pd_pg0.DevHandle) ==
+ MPT2SAS_INVALID_DEVICE_HANDLE) {
printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
"disabled for the drive with handle(0x%04x) member"
"handle retrieval failed for member number=%d\n",
@@ -1968,19 +1985,21 @@ _scsih_slave_configure(struct scsi_device *sdev)
u8 ssp_target = 0;
char *ds = "";
char *r_level = "";
+ u16 handle, volume_handle = 0;
+ u64 volume_wwid = 0;
qdepth = 1;
sas_device_priv_data = sdev->hostdata;
sas_device_priv_data->configured_lun = 1;
sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
sas_target_priv_data = sas_device_priv_data->sas_target;
+ handle = sas_target_priv_data->handle;
/* raid volume handling */
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc,
- sas_target_priv_data->handle);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device) {
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
@@ -1989,8 +2008,6 @@ _scsih_slave_configure(struct scsi_device *sdev)
return 1;
}
- _scsih_get_volume_capabilities(ioc, raid_device);
-
if (_scsih_get_volume_capabilities(ioc, raid_device)) {
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
"failure at %s:%d/%s()!\n", ioc->name, __FILE__,
@@ -2058,68 +2075,67 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
/* raid transport support */
if (!ioc->is_warpdrive)
- _scsih_set_level(sdev, raid_device);
+ _scsih_set_level(sdev, raid_device->volume_type);
return 0;
}
/* non-raid handling */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device_priv_data->sas_target->sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device) {
- if (sas_target_priv_data->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- if (mpt2sas_config_get_volume_handle(ioc,
- sas_device->handle, &sas_device->volume_handle)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- if (sas_device->volume_handle &&
- mpt2sas_config_get_volume_wwid(ioc,
- sas_device->volume_handle,
- &sas_device->volume_wwid)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ if (mpt2sas_config_get_volume_handle(ioc, handle,
+ &volume_handle)) {
+ dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+ "failure at %s:%d/%s()!\n", ioc->name,
+ __FILE__, __LINE__, __func__));
+ return 1;
}
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ssp_target = 1;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_STP_TARGET)
- ds = "STP";
- else if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
+ if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
+ volume_handle, &volume_wwid)) {
+ dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+ "failure at %s:%d/%s()!\n", ioc->name,
+ __FILE__, __LINE__, __func__));
+ return 1;
}
+ }
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
- ds, sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy,
- (unsigned long long)sas_device->device_name);
- sdev_printk(KERN_INFO, sdev, "%s: "
- "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
- (unsigned long long) sas_device->enclosure_logical_id,
- sas_device->slot);
-
- if (!ssp_target)
- _scsih_display_sata_capabilities(ioc, sas_device, sdev);
- } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device_priv_data->sas_target->sas_address);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
+ __LINE__, __func__));
return 1;
}
+ sas_device->volume_handle = volume_handle;
+ sas_device->volume_wwid = volume_wwid;
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+ qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
+ ssp_target = 1;
+ ds = "SSP";
+ } else {
+ qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
+ ds = "STP";
+ else if (sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ ds = "SATA";
+ }
+ sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
+ "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
+ ds, sas_device->handle,
+ (unsigned long long)sas_device->sas_address,
+ sas_device->phy,
+ (unsigned long long)sas_device->device_name);
+ sdev_printk(KERN_INFO, sdev, "%s: "
+ "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
+ (unsigned long long) sas_device->enclosure_logical_id,
+ sas_device->slot);
+
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!ssp_target)
+ _scsih_display_sata_capabilities(ioc, handle, sdev);
+
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
@@ -2899,7 +2915,7 @@ _scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
* During device pull we need to appropiately set the sdev state.
*/
static void
-_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct scsi_device *sdev;
@@ -2910,10 +2926,12 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
continue;
if (!sas_device_priv_data->block)
continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
+ if (sas_device_priv_data->sas_target->sas_address ==
+ sas_address) {
dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
MPT2SAS_INFO_FMT "SDEV_RUNNING: "
- "handle(0x%04x)\n", ioc->name, handle));
+ "sas address(0x%016llx)\n", ioc->name,
+ (unsigned long long)sas_address));
sas_device_priv_data->block = 0;
scsi_internal_device_unblock(sdev);
}
@@ -3006,10 +3024,10 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
sas_device =
mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
+ if (sas_device)
+ set_bit(sas_device->handle,
+ ioc->blocking_handles);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- continue;
- _scsih_block_io_device(ioc, sas_device->handle);
}
}
@@ -3020,12 +3038,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
SAS_FANOUT_EXPANDER_DEVICE) {
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_sibling =
mpt2sas_scsih_expander_find_by_sas_address(
ioc, mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_block_io_to_children_attached_to_ex(ioc,
expander_sibling);
}
@@ -3124,7 +3139,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle,
(unsigned long long)sas_address));
- _scsih_ublock_io_device(ioc, handle);
+ _scsih_ublock_io_device(ioc, sas_address);
sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
}
@@ -3174,16 +3189,19 @@ static u8
_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u8 msix_index, u32 reply)
{
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2SasIoUnitControlReply_t *mpi_reply =
mpt2sas_base_get_reply_virt_addr(ioc, reply);
-#endif
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "sc_complete:handle(0x%04x), (open) "
- "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
- le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo)));
+ if (likely(mpi_reply)) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "sc_complete:handle(0x%04x), (open) "
+ "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ } else {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ }
return 1;
}
@@ -3262,7 +3280,11 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
"progress!\n", __func__, ioc->name));
return 1;
}
-
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
@@ -3325,7 +3347,11 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
"operational\n", __func__, ioc->name));
return 1;
}
-
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
@@ -3441,14 +3467,20 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
_scsih_block_io_to_children_attached_directly(ioc, event_data);
return;
}
-
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
- || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
+ if (event_data->ExpStatus ==
+ MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
+ /* put expander attached devices into blocking state */
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
expander_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ do {
+ handle = find_first_bit(ioc->blocking_handles,
+ ioc->facts.MaxDevHandle);
+ if (handle < ioc->facts.MaxDevHandle)
+ _scsih_block_io_device(ioc, handle);
+ } while (test_and_clear_bit(handle, ioc->blocking_handles));
} else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
_scsih_block_io_to_children_attached_directly(ioc, event_data);
@@ -4446,8 +4478,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
!= MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
ioc->scsi_lookup[smid - 1].scmd = scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
_scsih_scsi_direct_io_set(ioc, smid, 0);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
mpi_request->DevHandle =
cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -5020,13 +5052,11 @@ mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
- if (!sas_expander) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- list_del(&sas_expander->list);
+ if (sas_expander)
+ list_del(&sas_expander->list);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- _scsih_expander_node_remove(ioc, sas_expander);
+ if (sas_expander)
+ _scsih_expander_node_remove(ioc, sas_expander);
}
/**
@@ -5106,6 +5136,7 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
struct MPT2SAS_TARGET *sas_target_priv_data;
u32 device_info;
+
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
return;
@@ -5139,21 +5170,24 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
sas_target_priv_data->handle = handle;
sas_device->handle = handle;
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
/* check if device is present */
if (!(le16_to_cpu(sas_device_pg0.Flags) &
MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
printk(MPT2SAS_ERR_FMT "device is not present "
"handle(0x%04x), flags!!!\n", ioc->name, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
}
/* check if there were any issues with discovery */
if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
+ sas_device_pg0.AccessStatus)) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
- _scsih_ublock_io_device(ioc, handle);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_ublock_io_device(ioc, sas_address);
}
@@ -5280,54 +5314,71 @@ static void
_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
struct _sas_device *sas_device)
{
- struct _sas_device sas_device_backup;
struct MPT2SAS_TARGET *sas_target_priv_data;
- if (!sas_device)
- return;
-
- memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
- _scsih_sas_device_remove(ioc, sas_device);
-
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device_backup.handle, (unsigned long long)
- sas_device_backup.sas_address));
+ sas_device->handle, (unsigned long long)
+ sas_device->sas_address));
- if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
- sas_target_priv_data = sas_device_backup.starget->hostdata;
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
sas_target_priv_data->deleted = 1;
- _scsih_ublock_io_device(ioc, sas_device_backup.handle);
+ _scsih_ublock_io_device(ioc, sas_device->sas_address);
sas_target_priv_data->handle =
MPT2SAS_INVALID_DEVICE_HANDLE;
}
- _scsih_ublock_io_device(ioc, sas_device_backup.handle);
-
if (!ioc->hide_drives)
mpt2sas_transport_port_remove(ioc,
- sas_device_backup.sas_address,
- sas_device_backup.sas_address_parent);
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
- (unsigned long long) sas_device_backup.sas_address);
+ "(0x%016llx)\n", ioc->name, sas_device->handle,
+ (unsigned long long) sas_device->sas_address);
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device_backup.handle, (unsigned long long)
- sas_device_backup.sas_address));
+ sas_device->handle, (unsigned long long)
+ sas_device->sas_address));
+ kfree(sas_device);
+}
+/**
+ * _scsih_device_remove_by_handle - removing device object by handle
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_device *sas_device;
+ unsigned long flags;
+
+ if (ioc->shost_recovery)
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device)
+ list_del(&sas_device->list);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device)
+ _scsih_remove_device(ioc, sas_device);
}
/**
- * mpt2sas_device_remove - removing device object
+ * mpt2sas_device_remove_by_sas_address - removing device object by sas address
* @ioc: per adapter object
- * @sas_address: expander sas_address
+ * @sas_address: device sas_address
*
* Return nothing.
*/
void
-mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address)
{
struct _sas_device *sas_device;
unsigned long flags;
@@ -5338,14 +5389,12 @@ mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (sas_device)
+ list_del(&sas_device->list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_remove_device(ioc, sas_device);
+ if (sas_device)
+ _scsih_remove_device(ioc, sas_device);
}
-
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
@@ -5442,7 +5491,6 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number, max_phys;
struct _sas_node *sas_expander;
- struct _sas_device *sas_device;
u64 sas_address;
unsigned long flags;
u8 link_rate, prev_link_rate;
@@ -5477,15 +5525,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
parent_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (sas_expander) {
sas_address = sas_expander->sas_address;
max_phys = sas_expander->num_phys;
} else if (parent_handle < ioc->sas_hba.num_phys) {
sas_address = ioc->sas_hba.sas_address;
max_phys = ioc->sas_hba.num_phys;
- } else
+ } else {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
@@ -5540,16 +5590,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock,
- flags);
- break;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_remove_device(ioc, sas_device);
+ _scsih_device_remove_by_handle(ioc, handle);
break;
}
}
@@ -5672,20 +5713,24 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
sas_address = le64_to_cpu(event_data->SASAddress);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device || !sas_device->starget)
+ if (!sas_device || !sas_device->starget) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
+ }
target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data)
+ if (!target_priv_data) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return;
+ }
if (event_data->ReasonCode ==
MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
target_priv_data->tm_busy = 1;
else
target_priv_data->tm_busy = 0;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -5950,30 +5995,6 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
}
/**
- * _scsih_reprobe_target - reprobing target
- * @starget: scsi target struct
- * @no_uld_attach: sdev->no_uld_attach flag setting
- *
- * Note: no_uld_attach flag determines whether the disk device is attached
- * to block layer. A value of `1` means to not attach.
- **/
-static void
-_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
-
- if (starget == NULL)
- return;
- sas_target_priv_data = starget->hostdata;
- if (no_uld_attach)
- sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
- else
- sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-
- starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
- _scsih_reprobe_lun);
-}
-/**
* _scsih_sas_volume_add - add new volume
* @ioc: per adapter object
* @element: IR config element data
@@ -6024,8 +6045,11 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
raid_device->id, 0);
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
- } else
+ } else {
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
_scsih_determine_boot_device(ioc, raid_device, 1);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ }
}
/**
@@ -6042,21 +6066,25 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
struct _raid_device *raid_device;
unsigned long flags;
struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct scsi_target *starget = NULL;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device)
- return;
- if (raid_device->starget) {
- sas_target_priv_data = raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- scsi_remove_target(&raid_device->starget->dev);
+ if (raid_device) {
+ if (raid_device->starget) {
+ starget = raid_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ }
+ printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+ "(0x%016llx)\n", ioc->name, raid_device->handle,
+ (unsigned long long) raid_device->wwid);
+ list_del(&raid_device->list);
+ kfree(raid_device);
}
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- _scsih_raid_device_remove(ioc, raid_device);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ if (starget)
+ scsi_remove_target(&starget->dev);
}
/**
@@ -6072,20 +6100,31 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
+ struct scsi_target *starget = NULL;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device->volume_handle = 0;
+ sas_device->volume_wwid = 0;
+ clear_bit(handle, ioc->pd_handles);
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->flags &=
+ ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+ }
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
/* exposing raid component */
- sas_device->volume_handle = 0;
- sas_device->volume_wwid = 0;
- clear_bit(handle, ioc->pd_handles);
- _scsih_reprobe_target(sas_device->starget, 0);
+ if (starget)
+ starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
}
/**
@@ -6101,23 +6140,38 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
+ struct scsi_target *starget = NULL;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+ u16 volume_handle = 0;
+ u64 volume_wwid = 0;
+
+ mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
+ if (volume_handle)
+ mpt2sas_config_get_volume_wwid(ioc, volume_handle,
+ &volume_wwid);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (sas_device) {
+ set_bit(handle, ioc->pd_handles);
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->flags |=
+ MPT_TARGET_FLAGS_RAID_COMPONENT;
+ sas_device->volume_handle = volume_handle;
+ sas_device->volume_wwid = volume_wwid;
+ }
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
/* hiding raid component */
- mpt2sas_config_get_volume_handle(ioc, handle,
- &sas_device->volume_handle);
- mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
- &sas_device->volume_wwid);
- set_bit(handle, ioc->pd_handles);
- _scsih_reprobe_target(sas_device->starget, 1);
-
+ if (starget)
+ starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
}
/**
@@ -6132,16 +6186,9 @@ static void
_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
- struct _sas_device *sas_device;
- unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
- _scsih_remove_device(ioc, sas_device);
+ _scsih_device_remove_by_handle(ioc, handle);
}
/**
@@ -6583,18 +6630,13 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
/* code added for raid transport support */
if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
- handle = le16_to_cpu(event_data->VolDevHandle);
-
spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ handle = le16_to_cpu(event_data->VolDevHandle);
raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!raid_device)
- return;
-
- if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
+ if (raid_device)
raid_device->percent_complete =
event_data->PercentComplete;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
}
@@ -6761,13 +6803,18 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
* required data for Direct IO
*/
_scsih_init_warpdrive_properties(ioc, raid_device);
- if (raid_device->handle == handle)
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ if (raid_device->handle == handle) {
+ spin_unlock_irqrestore(&ioc->raid_device_lock,
+ flags);
return;
+ }
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
raid_device->handle);
raid_device->handle = handle;
if (sas_target_priv_data)
sas_target_priv_data->handle = handle;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
return;
}
}
@@ -6939,58 +6986,56 @@ static void
_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
{
struct _sas_device *sas_device, *sas_device_next;
- struct _sas_node *sas_expander;
+ struct _sas_node *sas_expander, *sas_expander_next;
struct _raid_device *raid_device, *raid_device_next;
+ struct list_head tmp_list;
+ unsigned long flags;
printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
ioc->name);
+ /* removing unresponding end devices */
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
+ ioc->name);
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
- if (sas_device->responding) {
+ if (!sas_device->responding)
+ mpt2sas_device_remove_by_sas_address(ioc,
+ sas_device->sas_address);
+ else
sas_device->responding = 0;
- continue;
- }
- if (sas_device->starget)
- starget_printk(KERN_INFO, sas_device->starget,
- "removing: handle(0x%04x), sas_addr(0x%016llx), "
- "enclosure logical id(0x%016llx), slot(%d)\n",
- sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
- _scsih_remove_device(ioc, sas_device);
}
- if (!ioc->ir_firmware)
- goto retry_expander_search;
-
- list_for_each_entry_safe(raid_device, raid_device_next,
- &ioc->raid_device_list, list) {
- if (raid_device->responding) {
- raid_device->responding = 0;
- continue;
- }
- if (raid_device->starget) {
- starget_printk(KERN_INFO, raid_device->starget,
- "removing: handle(0x%04x), wwid(0x%016llx)\n",
- raid_device->handle,
- (unsigned long long)raid_device->wwid);
- scsi_remove_target(&raid_device->starget->dev);
+ /* removing unresponding volumes */
+ if (ioc->ir_firmware) {
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
+ "volumes\n", ioc->name);
+ list_for_each_entry_safe(raid_device, raid_device_next,
+ &ioc->raid_device_list, list) {
+ if (!raid_device->responding)
+ _scsih_sas_volume_delete(ioc,
+ raid_device->handle);
+ else
+ raid_device->responding = 0;
}
- _scsih_raid_device_remove(ioc, raid_device);
}
-
- retry_expander_search:
- sas_expander = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->responding) {
+ /* removing unresponding expanders */
+ printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
+ ioc->name);
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ INIT_LIST_HEAD(&tmp_list);
+ list_for_each_entry_safe(sas_expander, sas_expander_next,
+ &ioc->sas_expander_list, list) {
+ if (!sas_expander->responding)
+ list_move_tail(&sas_expander->list, &tmp_list);
+ else
sas_expander->responding = 0;
- continue;
- }
- mpt2sas_expander_remove(ioc, sas_expander->sas_address);
- goto retry_expander_search;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
+ list) {
+ list_del(&sas_expander->list);
+ _scsih_expander_node_remove(ioc, sas_expander);
}
printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
ioc->name);
@@ -7043,6 +7088,7 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
struct _sas_device *sas_device;
struct _sas_node *expander_device;
static struct _raid_device *raid_device;
+ unsigned long flags;
printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
@@ -7057,8 +7103,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(expander_pg0.DevHandle);
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_device = mpt2sas_scsih_expander_find_by_sas_address(
ioc, le64_to_cpu(expander_pg0.SASAddress));
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (expander_device)
_scsih_refresh_expander_links(ioc, expander_device,
handle);
@@ -7080,7 +7128,9 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
break;
phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle);
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device)
continue;
if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
@@ -7107,8 +7157,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(volume_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_wwid(ioc,
le64_to_cpu(volume_pg1.WWID));
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (raid_device)
continue;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
@@ -7140,8 +7192,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
if (!(_scsih_is_end_device(
le32_to_cpu(sas_device_pg0.DeviceInfo))))
continue;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
le64_to_cpu(sas_device_pg0.SASAddress));
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device)
continue;
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
@@ -7235,7 +7289,7 @@ _firmware_event_work(struct work_struct *work)
switch (fw_event->event) {
case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost))
+ while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
ssleep(1);
_scsih_remove_unresponding_sas_devices(ioc);
_scsih_scan_for_devices_after_reset(ioc);
@@ -7313,6 +7367,13 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
return 1;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return 1;
+ }
+
event = le16_to_cpu(mpi_reply->Event);
switch (event) {
@@ -7353,14 +7414,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_LOG_ENTRY_ADDED:
{
Mpi2EventDataLogEntryAdded_t *log_entry;
- u32 *log_code;
+ __le32 *log_code;
if (!ioc->is_warpdrive)
break;
log_entry = (Mpi2EventDataLogEntryAdded_t *)
mpi_reply->EventData;
- log_code = (u32 *)log_entry->LogData;
+ log_code = (__le32 *)log_entry->LogData;
if (le16_to_cpu(log_entry->LogEntryQualifier)
!= MPT2_WARPDRIVE_LOGENTRY)
@@ -7487,7 +7548,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
return;
if (mpt2sas_port->remote_identify.device_type ==
SAS_END_DEVICE)
- mpt2sas_device_remove(ioc,
+ mpt2sas_device_remove_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
else if (mpt2sas_port->remote_identify.device_type ==
SAS_EDGE_EXPANDER_DEVICE ||
@@ -7661,7 +7722,7 @@ _scsih_remove(struct pci_dev *pdev)
&ioc->sas_hba.sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
SAS_END_DEVICE)
- mpt2sas_device_remove(ioc,
+ mpt2sas_device_remove_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
else if (mpt2sas_port->remote_identify.device_type ==
SAS_EDGE_EXPANDER_DEVICE ||
@@ -7733,11 +7794,11 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
} else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = device;
handle = sas_device->handle;
sas_address_parent = sas_device->sas_address_parent;
sas_address = sas_device->sas_address;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -8061,8 +8122,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_thread_fail:
list_del(&ioc->list);
scsi_remove_host(shost);
- scsi_host_put(shost);
out_add_shost_fail:
+ scsi_host_put(shost);
return -ENODEV;
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 8310474..c6cf20f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -163,12 +163,15 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
return -EIO;
}
- memset(identify, 0, sizeof(*identify));
+ memset(identify, 0, sizeof(struct sas_identify));
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
/* sas_address */
identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+ /* phy number of the parent device this device is linked to */
+ identify->phy_identifier = sas_device_pg0.PhyNum;
+
/* device_type */
switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
@@ -484,7 +487,7 @@ _transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
ioc->logging_level |= MPT_DEBUG_TRANSPORT;
if (device_type == SAS_END_DEVICE)
- mpt2sas_device_remove(ioc, sas_address);
+ mpt2sas_device_remove_by_sas_address(ioc, sas_address);
else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
device_type == SAS_FANOUT_EXPANDER_DEVICE)
mpt2sas_expander_remove(ioc, sas_address);
@@ -792,9 +795,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_sas_address(ioc,
sas_address_parent);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_node)
+ if (!sas_node) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
port_list) {
if (mpt2sas_port->remote_identify.sas_address != sas_address)
@@ -804,8 +808,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
goto out;
}
out:
- if (!found)
+ if (!found) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
for (i = 0; i < sas_node->num_phys; i++) {
if (sas_node->phy[i].remote_identify.sas_address == sas_address)
@@ -813,6 +819,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
sizeof(struct sas_identify));
}
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
list_for_each_entry_safe(mpt2sas_phy, next_phy,
&mpt2sas_port->phy_list, port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
@@ -986,12 +993,14 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_node)
+ if (!sas_node) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return;
+ }
mpt2sas_phy = &sas_node->phy[phy_number];
mpt2sas_phy->attached_handle = handle;
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
_transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
@@ -1310,17 +1319,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_device *sas_device;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
+ if (sas_device) {
+ *identifier = sas_device->enclosure_logical_id;
+ rc = 0;
+ } else {
+ *identifier = 0;
+ rc = -ENXIO;
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!sas_device)
- return -ENXIO;
-
- *identifier = sas_device->enclosure_logical_id;
- return 0;
+ return rc;
}
/**
@@ -1335,16 +1347,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_device *sas_device;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
+ if (sas_device)
+ rc = sas_device->slot;
+ else
+ rc = -ENXIO;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!sas_device)
- return -ENXIO;
-
- return sas_device->slot;
+ return rc;
}
/* phy control request structure */
@@ -1629,11 +1642,13 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
u16 sz;
int rc = 0;
unsigned long flags;
+ int i, discovery_active;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
if (_transport_sas_node_find_by_sas_address(ioc,
@@ -1651,7 +1666,50 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
/* handle hba phys */
- /* sas_iounit page 1 */
+ /* read sas_iounit page 0 */
+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
+ sizeof(Mpi2SasIOUnit0PhyData_t));
+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg0) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+ sas_iounit_pg0, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENXIO;
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -EIO;
+ goto out;
+ }
+
+ /* unable to enable/disable phys when when discovery is active */
+ for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {
+ if (sas_iounit_pg0->PhyData[i].PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
+ printk(MPT2SAS_ERR_FMT "discovery is active on "
+ "port = %d, phy = %d: unable to enable/disable "
+ "phys, try again later!\n", ioc->name,
+ sas_iounit_pg0->PhyData[i].Port, i);
+ discovery_active = 1;
+ }
+ }
+
+ if (discovery_active) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ /* read sas_iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
@@ -1676,7 +1734,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
rc = -EIO;
goto out;
}
-
+ /* copy Port/PortFlags/PhyFlags from page 0 */
+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ sas_iounit_pg1->PhyData[i].Port =
+ sas_iounit_pg0->PhyData[i].Port;
+ sas_iounit_pg1->PhyData[i].PortFlags =
+ (sas_iounit_pg0->PhyData[i].PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);
+ sas_iounit_pg1->PhyData[i].PhyFlags =
+ (sas_iounit_pg0->PhyData[i].PhyFlags &
+ (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +
+ MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));
+ }
if (enable)
sas_iounit_pg1->PhyData[phy->number].PhyFlags
&= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
@@ -1692,6 +1761,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
out:
kfree(sas_iounit_pg1);
+ kfree(sas_iounit_pg0);
return rc;
}
@@ -1828,7 +1898,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Mpi2SmpPassthroughRequest_t *mpi_request;
Mpi2SmpPassthroughReply_t *mpi_reply;
- int rc;
+ int rc, i;
u16 smid;
u32 ioc_state;
unsigned long timeleft;
@@ -1837,24 +1907,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u8 issue_reset = 0;
dma_addr_t dma_addr_in = 0;
dma_addr_t dma_addr_out = 0;
+ dma_addr_t pci_dma_in = 0;
+ dma_addr_t pci_dma_out = 0;
+ void *pci_addr_in = NULL;
+ void *pci_addr_out = NULL;
u16 wait_state_count;
struct request *rsp = req->next_rq;
+ struct bio_vec *bvec = NULL;
if (!rsp) {
printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
"missing\n", ioc->name, __func__);
return -EINVAL;
}
-
- /* do we need to support multiple segments? */
- if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
- printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
- "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
- blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
- return -EINVAL;
- }
-
- if (ioc->shost_recovery) {
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
@@ -1872,6 +1938,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
}
ioc->transport_cmds.status = MPT2_CMD_PENDING;
+ /* Check if the request is split across multiple segments */
+ if (req->bio->bi_vcnt > 1) {
+ u32 offset = 0;
+
+ /* Allocate memory and copy the request */
+ pci_addr_out = pci_alloc_consistent(ioc->pdev,
+ blk_rq_bytes(req), &pci_dma_out);
+ if (!pci_addr_out) {
+ printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ bio_for_each_segment(bvec, req->bio, i) {
+ memcpy(pci_addr_out + offset,
+ page_address(bvec->bv_page) + bvec->bv_offset,
+ bvec->bv_len);
+ offset += bvec->bv_len;
+ }
+ } else {
+ dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
+ blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_out) {
+ printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto free_pci;
+ }
+ }
+
+ /* Check if the response needs to be populated across
+ * multiple segments */
+ if (rsp->bio->bi_vcnt > 1) {
+ pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
+ &pci_dma_in);
+ if (!pci_addr_in) {
+ printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto unmap;
+ }
+ } else {
+ dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
+ blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_in) {
+ printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
+ ioc->name, __func__);
+ rc = -ENOMEM;
+ goto unmap;
+ }
+ }
+
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
@@ -1880,7 +1999,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
rc = -EFAULT;
- goto out;
+ goto unmap;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
@@ -1897,7 +2016,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
- goto out;
+ goto unmap;
}
rc = 0;
@@ -1919,16 +2038,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
- blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_out) {
- mpt2sas_base_free_smid(ioc, smid);
- goto unmap;
+ if (req->bio->bi_vcnt > 1) {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(req) - 4), pci_dma_out);
+ } else {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(req) - 4), dma_addr_out);
}
- ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
- dma_addr_out);
-
/* incr sgel */
psge += ioc->sge_size;
@@ -1937,16 +2054,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
MPI2_SGE_FLAGS_END_OF_LIST);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
- blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_in) {
- mpt2sas_base_free_smid(ioc, smid);
- goto unmap;
+ if (rsp->bio->bi_vcnt > 1) {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(rsp) + 4), pci_dma_in);
+ } else {
+ ioc->base_add_sg_single(psge, sgl_flags |
+ (blk_rq_bytes(rsp) + 4), dma_addr_in);
}
- ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
- dma_addr_in);
-
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
@@ -1982,6 +2097,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
req->resid_len = 0;
rsp->resid_len -=
le16_to_cpu(mpi_reply->ResponseDataLength);
+ /* check if the resp needs to be copied from the allocated
+ * pci mem */
+ if (rsp->bio->bi_vcnt > 1) {
+ u32 offset = 0;
+ u32 bytes_to_copy =
+ le16_to_cpu(mpi_reply->ResponseDataLength);
+ bio_for_each_segment(bvec, rsp->bio, i) {
+ if (bytes_to_copy <= bvec->bv_len) {
+ memcpy(page_address(bvec->bv_page) +
+ bvec->bv_offset, pci_addr_in +
+ offset, bytes_to_copy);
+ break;
+ } else {
+ memcpy(page_address(bvec->bv_page) +
+ bvec->bv_offset, pci_addr_in +
+ offset, bvec->bv_len);
+ bytes_to_copy -= bvec->bv_len;
+ }
+ offset += bvec->bv_len;
+ }
+ }
} else {
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - no reply\n", ioc->name, __func__));
@@ -2003,6 +2139,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
PCI_DMA_BIDIRECTIONAL);
+ free_pci:
+ if (pci_addr_out)
+ pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
+ pci_dma_out);
+
+ if (pci_addr_in)
+ pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
+ pci_dma_in);
+
out:
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->transport_cmds.mutex);
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index 944afad..c3d20c8 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -66,9 +66,10 @@ enum port_type {
/* driver compile-time configuration */
#define PM8001_MAX_CCB 512 /* max ccbs supported */
+#define PM8001_MPI_QUEUE 1024 /* maximum mpi queue entries */
#define PM8001_MAX_INB_NUM 1
#define PM8001_MAX_OUTB_NUM 1
-#define PM8001_CAN_QUEUE 128 /* SCSI Queue depth */
+#define PM8001_CAN_QUEUE 508 /* SCSI Queue depth */
/* unchangeable hardware details */
#define PM8001_MAX_PHYS 8 /* max. possible phys */
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 9d82ee5..bf54aaf 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -192,7 +192,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl.fatal_err_interrupt = 0x01;
for (i = 0; i < qn; i++) {
pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
- 0x00000100 | (0x00000040 << 16) | (0x00<<30);
+ PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[IB].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
@@ -218,7 +218,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha)
}
for (i = 0; i < qn; i++) {
pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
- 256 | (64 << 16) | (1<<30);
+ PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[OB].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
@@ -1245,7 +1245,7 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
/* Stores the new consumer index */
consumer_index = pm8001_read_32(circularQ->ci_virt);
circularQ->consumer_index = cpu_to_le32(consumer_index);
- if (((circularQ->producer_idx + bcCount) % 256) ==
+ if (((circularQ->producer_idx + bcCount) % PM8001_MPI_QUEUE) ==
le32_to_cpu(circularQ->consumer_index)) {
*messagePtr = NULL;
return -1;
@@ -1253,7 +1253,8 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
/* get memory IOMB buffer address */
offset = circularQ->producer_idx * 64;
/* increment to next bcCount element */
- circularQ->producer_idx = (circularQ->producer_idx + bcCount) % 256;
+ circularQ->producer_idx = (circularQ->producer_idx + bcCount)
+ % PM8001_MPI_QUEUE;
/* Adds that distance to the base of the region virtual address plus
the message header size*/
msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + offset);
@@ -1326,7 +1327,8 @@ static u32 mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
return 0;
}
/* free the circular queue buffer elements associated with the message*/
- circularQ->consumer_idx = (circularQ->consumer_idx + bc) % 256;
+ circularQ->consumer_idx = (circularQ->consumer_idx + bc)
+ % PM8001_MPI_QUEUE;
/* update the CI of outbound queue */
pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset,
circularQ->consumer_idx);
@@ -1383,7 +1385,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
circularQ->consumer_idx =
(circularQ->consumer_idx +
((le32_to_cpu(msgHeader_tmp)
- >> 24) & 0x1f)) % 256;
+ >> 24) & 0x1f))
+ % PM8001_MPI_QUEUE;
msgHeader_tmp = 0;
pm8001_write_32(msgHeader, 0, 0);
/* update the CI of outbound queue */
@@ -1396,7 +1399,7 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
circularQ->consumer_idx =
(circularQ->consumer_idx +
((le32_to_cpu(msgHeader_tmp) >> 24) &
- 0x1f)) % 256;
+ 0x1f)) % PM8001_MPI_QUEUE;
msgHeader_tmp = 0;
pm8001_write_32(msgHeader, 0, 0);
/* update the CI of outbound queue */
@@ -3357,7 +3360,7 @@ mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
struct fw_control_ex fw_control_context;
struct fw_flash_Update_resp *ppayload =
(struct fw_flash_Update_resp *)(piomb + 4);
- u32 tag = ppayload->tag;
+ u32 tag = le32_to_cpu(ppayload->tag);
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
status = le32_to_cpu(ppayload->status);
memcpy(&fw_control_context,
@@ -3703,8 +3706,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
*/
static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
- u32 pHeader = (u32)*(u32 *)piomb;
- u8 opc = (u8)(pHeader & 0xFFF);
+ __le32 pHeader = *(__le32 *)piomb;
+ u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 1a4611e..d437309 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -599,7 +599,7 @@ struct fw_flash_Update_req {
*
*/
struct fw_flash_Update_resp {
- dma_addr_t tag;
+ __le32 tag;
__le32 status;
u32 reserved[13];
} __attribute__((packed, aligned(4)));
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 36efaa7..0267c22 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -235,15 +235,15 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->memoryMap.region[PI].alignment = 4;
/* MPI Memory region 5 inbound queues */
- pm8001_ha->memoryMap.region[IB].num_elements = 256;
+ pm8001_ha->memoryMap.region[IB].num_elements = PM8001_MPI_QUEUE;
pm8001_ha->memoryMap.region[IB].element_size = 64;
- pm8001_ha->memoryMap.region[IB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[IB].total_len = PM8001_MPI_QUEUE * 64;
pm8001_ha->memoryMap.region[IB].alignment = 64;
- /* MPI Memory region 6 inbound queues */
- pm8001_ha->memoryMap.region[OB].num_elements = 256;
+ /* MPI Memory region 6 outbound queues */
+ pm8001_ha->memoryMap.region[OB].num_elements = PM8001_MPI_QUEUE;
pm8001_ha->memoryMap.region[OB].element_size = 64;
- pm8001_ha->memoryMap.region[OB].total_len = 256 * 64;
+ pm8001_ha->memoryMap.region[OB].total_len = PM8001_MPI_QUEUE * 64;
pm8001_ha->memoryMap.region[OB].alignment = 64;
/* Memory region write DMA*/
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6c6486f..538230b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4473,17 +4473,14 @@ qla1280_exit(void)
pci_unregister_driver(&qla1280_pci_driver);
/* release any allocated firmware images */
for (i = 0; i < QL_NUM_FW_IMAGES; i++) {
- if (qla1280_fw_tbl[i].fw) {
- release_firmware(qla1280_fw_tbl[i].fw);
- qla1280_fw_tbl[i].fw = NULL;
- }
+ release_firmware(qla1280_fw_tbl[i].fw);
+ qla1280_fw_tbl[i].fw = NULL;
}
}
module_init(qla1280_init);
module_exit(qla1280_exit);
-
MODULE_AUTHOR("Qlogic & Jes Sorensen");
MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 7db8033..c9c56a8 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4122,8 +4122,7 @@ qla2x00_release_firmware(void)
mutex_lock(&qla_fw_lock);
for (idx = 0; idx < FW_BLOBS; idx++)
- if (qla_fw_blobs[idx].fw)
- release_firmware(qla_fw_blobs[idx].fw);
+ release_firmware(qla_fw_blobs[idx].fw);
mutex_unlock(&qla_fw_lock);
}
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 07322ec..61c82a3 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -90,6 +90,12 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_BLK_DEV_SD)
+/* sd and scsi_pm need to coordinate flushing async actions */
+LIST_HEAD(scsi_sd_probe_domain);
+EXPORT_SYMBOL(scsi_sd_probe_domain);
+#endif
+
/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
* You may not alter any existing entry (although adding new ones is
* encouraged once assigned by ANSI/INCITS T10
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 386f0c5..d0f71e5 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -664,7 +664,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
}
/**
- * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory
+ * scsi_eh_prep_cmnd - Save a scsi command info as part of error recovery
* @scmd: SCSI command structure to hijack
* @ses: structure to save restore information
* @cmnd: CDB to send. Can be NULL if no new cmnd is needed
@@ -739,7 +739,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
EXPORT_SYMBOL(scsi_eh_prep_cmnd);
/**
- * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
+ * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recovery
* @scmd: SCSI command structure to restore
* @ses: saved information from a coresponding call to scsi_eh_prep_cmnd
*
@@ -762,7 +762,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
EXPORT_SYMBOL(scsi_eh_restore_cmnd);
/**
- * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * scsi_send_eh_cmnd - submit a scsi command as part of error recovery
* @scmd: SCSI command structure to hijack
* @cmnd: CDB to send
* @cmnd_size: size in bytes of @cmnd
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5dfd749..62ddfd3 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2348,10 +2348,14 @@ EXPORT_SYMBOL(scsi_device_quiesce);
*
* Must be called with user context, may sleep.
*/
-void
-scsi_device_resume(struct scsi_device *sdev)
+void scsi_device_resume(struct scsi_device *sdev)
{
- if(scsi_device_set_state(sdev, SDEV_RUNNING))
+ /* check if the device state was mutated prior to resume, and if
+ * so assume the state is being managed elsewhere (for example
+ * device deleted during suspend)
+ */
+ if (sdev->sdev_state != SDEV_QUIESCE ||
+ scsi_device_set_state(sdev, SDEV_RUNNING))
return;
scsi_run_queue(sdev->request_queue);
}
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index c467064..f661a41 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -97,7 +97,7 @@ static int scsi_bus_prepare(struct device *dev)
{
if (scsi_is_sdev_device(dev)) {
/* sd probing uses async_schedule. Wait until it finishes. */
- async_synchronize_full();
+ async_synchronize_full_domain(&scsi_sd_probe_domain);
} else if (scsi_is_host_device(dev)) {
/* Wait until async scanning is finished */
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index be4fa6d..07ce3f5 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -163,6 +163,8 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM_RUNTIME */
+extern struct list_head scsi_sd_probe_domain;
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 80fbe2a..5797604 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2808,17 +2808,20 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
FC_RPORT_DEVLOSS_PENDING |
FC_RPORT_DEVLOSS_CALLBK_DONE);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
/* if target, initiate a scan */
if (rport->scsi_target_id != -1) {
+ scsi_target_unblock(&rport->dev);
+
+ spin_lock_irqsave(shost->host_lock,
+ flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost,
&rport->scan_work);
spin_unlock_irqrestore(shost->host_lock,
flags);
- scsi_target_unblock(&rport->dev);
- } else
- spin_unlock_irqrestore(shost->host_lock,
- flags);
+ }
fc_bsg_goose_queue(rport);
@@ -2876,16 +2879,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
if (fci->f->dd_fcrport_size)
memset(rport->dd_data, 0,
fci->f->dd_fcrport_size);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (ids->roles & FC_PORT_ROLE_FCP_TARGET) {
+ scsi_target_unblock(&rport->dev);
- if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
+ spin_lock_irqsave(shost->host_lock, flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_target_unblock(&rport->dev);
- } else
- spin_unlock_irqrestore(shost->host_lock, flags);
-
+ }
return rport;
}
}
@@ -3083,12 +3087,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
/* ensure any stgt delete functions are done */
fc_flush_work(shost);
+ scsi_target_unblock(&rport->dev);
/* initiate a scan of the target */
spin_lock_irqsave(shost->host_lock, flags);
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_target_unblock(&rport->dev);
}
}
EXPORT_SYMBOL(fc_remote_port_rolechg);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index a2715c3..cf08071 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -1010,10 +1010,10 @@ spi_dv_device(struct scsi_device *sdev)
u8 *buffer;
const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
- if (unlikely(scsi_device_get(sdev)))
+ if (unlikely(spi_dv_in_progress(starget)))
return;
- if (unlikely(spi_dv_in_progress(starget)))
+ if (unlikely(scsi_device_get(sdev)))
return;
spi_dv_in_progress(starget) = 1;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5ba5c2a..6f0a4c6 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -65,6 +65,7 @@
#include <scsi/scsicam.h>
#include "sd.h"
+#include "scsi_priv.h"
#include "scsi_logging.h"
MODULE_AUTHOR("Eric Youngdale");
@@ -2722,7 +2723,7 @@ static int sd_probe(struct device *dev)
dev_set_drvdata(dev, sdkp);
get_device(&sdkp->dev); /* prevent release before async_schedule */
- async_schedule(sd_probe_async, sdkp);
+ async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
return 0;
@@ -2756,7 +2757,7 @@ static int sd_remove(struct device *dev)
sdkp = dev_get_drvdata(dev);
scsi_autopm_get_device(sdkp->device);
- async_synchronize_full();
+ async_synchronize_full_domain(&scsi_sd_probe_domain);
blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
blk_queue_unprep_rq(sdkp->device->request_queue, NULL);
device_del(&sdkp->dev);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index eacd46b..9c5c5f2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -104,7 +104,7 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
static int sg_add(struct device *, struct class_interface *);
static void sg_remove(struct device *, struct class_interface *);
-static DEFINE_MUTEX(sg_mutex);
+static DEFINE_SPINLOCK(sg_open_exclusive_lock);
static DEFINE_IDR(sg_index_idr);
static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
@@ -137,13 +137,15 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
char orphan; /* 1 -> drop on sight, 0 -> normal */
char sg_io_owned; /* 1 -> packet belongs to SG_IO */
- volatile char done; /* 0->before bh, 1->before read, 2->read */
+ /* done protected by rq_list_lock */
+ char done; /* 0->before bh, 1->before read, 2->read */
struct request *rq;
struct bio *bio;
struct execute_work ew;
} Sg_request;
typedef struct sg_fd { /* holds the state of a file descriptor */
+ /* sfd_siblings is protected by sg_index_lock */
struct list_head sfd_siblings;
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
@@ -157,7 +159,6 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
char low_dma; /* as in parent but possibly overridden to 1 */
char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
- volatile char closed; /* 1 -> fd closed but request(s) outstanding */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
@@ -171,9 +172,11 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
u32 index; /* device index number */
+ /* sfds is protected by sg_index_lock */
struct list_head sfds;
volatile char detached; /* 0->attached, 1->detached pending removal */
- volatile char exclude; /* opened for exclusive access */
+ /* exclude protected by sg_open_exclusive_lock */
+ char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
struct gendisk *disk;
struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */
@@ -221,6 +224,38 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd)
return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
}
+static int get_exclude(Sg_device *sdp)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+ ret = sdp->exclude;
+ spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+ return ret;
+}
+
+static int set_exclude(Sg_device *sdp, char val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+ sdp->exclude = val;
+ spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+ return val;
+}
+
+static int sfds_list_empty(Sg_device *sdp)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&sg_index_lock, flags);
+ ret = list_empty(&sdp->sfds);
+ read_unlock_irqrestore(&sg_index_lock, flags);
+ return ret;
+}
+
static int
sg_open(struct inode *inode, struct file *filp)
{
@@ -232,7 +267,6 @@ sg_open(struct inode *inode, struct file *filp)
int res;
int retval;
- mutex_lock(&sg_mutex);
nonseekable_open(inode, filp);
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
sdp = sg_get_dev(dev);
@@ -264,25 +298,22 @@ sg_open(struct inode *inode, struct file *filp)
retval = -EPERM; /* Can't lock it with read only access */
goto error_out;
}
- if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) {
+ if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
retval = -EBUSY;
goto error_out;
}
- res = 0;
- __wait_event_interruptible(sdp->o_excl_wait,
- ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
+ res = wait_event_interruptible(sdp->o_excl_wait,
+ ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
if (res) {
retval = res; /* -ERESTARTSYS because signal hit process */
goto error_out;
}
- } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
+ } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
if (flags & O_NONBLOCK) {
retval = -EBUSY;
goto error_out;
}
- res = 0;
- __wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude),
- res);
+ res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
if (res) {
retval = res; /* -ERESTARTSYS because signal hit process */
goto error_out;
@@ -292,7 +323,7 @@ sg_open(struct inode *inode, struct file *filp)
retval = -ENODEV;
goto error_out;
}
- if (list_empty(&sdp->sfds)) { /* no existing opens on this device */
+ if (sfds_list_empty(sdp)) { /* no existing opens on this device */
sdp->sgdebug = 0;
q = sdp->device->request_queue;
sdp->sg_tablesize = queue_max_segments(q);
@@ -301,7 +332,7 @@ sg_open(struct inode *inode, struct file *filp)
filp->private_data = sfp;
else {
if (flags & O_EXCL) {
- sdp->exclude = 0; /* undo if error */
+ set_exclude(sdp, 0); /* undo if error */
wake_up_interruptible(&sdp->o_excl_wait);
}
retval = -ENOMEM;
@@ -317,7 +348,6 @@ sdp_put:
sg_put:
if (sdp)
sg_put_dev(sdp);
- mutex_unlock(&sg_mutex);
return retval;
}
@@ -332,9 +362,7 @@ sg_release(struct inode *inode, struct file *filp)
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
- sfp->closed = 1;
-
- sdp->exclude = 0;
+ set_exclude(sdp, 0);
wake_up_interruptible(&sdp->o_excl_wait);
scsi_autopm_put_device(sdp->device);
@@ -398,19 +426,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
retval = -EAGAIN;
goto free_old_hdr;
}
- while (1) {
- retval = 0; /* following macro beats race condition */
- __wait_event_interruptible(sfp->read_wait,
- (sdp->detached ||
- (srp = sg_get_rq_mark(sfp, req_pack_id))),
- retval);
- if (sdp->detached) {
- retval = -ENODEV;
- goto free_old_hdr;
- }
- if (0 == retval)
- break;
-
+ retval = wait_event_interruptible(sfp->read_wait,
+ (sdp->detached ||
+ (srp = sg_get_rq_mark(sfp, req_pack_id))));
+ if (sdp->detached) {
+ retval = -ENODEV;
+ goto free_old_hdr;
+ }
+ if (retval) {
/* -ERESTARTSYS as signal hit process */
goto free_old_hdr;
}
@@ -771,7 +794,18 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return 0;
}
-static int
+static int srp_done(Sg_fd *sfp, Sg_request *srp)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&sfp->rq_list_lock, flags);
+ ret = srp->done;
+ read_unlock_irqrestore(&sfp->rq_list_lock, flags);
+ return ret;
+}
+
+static long
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
void __user *p = (void __user *)arg;
@@ -791,40 +825,30 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
switch (cmd_in) {
case SG_IO:
- {
- int blocking = 1; /* ignore O_NONBLOCK flag */
-
- if (sdp->detached)
- return -ENODEV;
- if (!scsi_block_when_processing_errors(sdp->device))
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
- return -EFAULT;
- result =
- sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
- blocking, read_only, 1, &srp);
- if (result < 0)
- return result;
- while (1) {
- result = 0; /* following macro to beat race condition */
- __wait_event_interruptible(sfp->read_wait,
- (srp->done || sdp->detached),
- result);
- if (sdp->detached)
- return -ENODEV;
- write_lock_irq(&sfp->rq_list_lock);
- if (srp->done) {
- srp->done = 2;
- write_unlock_irq(&sfp->rq_list_lock);
- break;
- }
- srp->orphan = 1;
- write_unlock_irq(&sfp->rq_list_lock);
- return result; /* -ERESTARTSYS because signal hit process */
- }
+ if (sdp->detached)
+ return -ENODEV;
+ if (!scsi_block_when_processing_errors(sdp->device))
+ return -ENXIO;
+ if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
+ return -EFAULT;
+ result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
+ 1, read_only, 1, &srp);
+ if (result < 0)
+ return result;
+ result = wait_event_interruptible(sfp->read_wait,
+ (srp_done(sfp, srp) || sdp->detached));
+ if (sdp->detached)
+ return -ENODEV;
+ write_lock_irq(&sfp->rq_list_lock);
+ if (srp->done) {
+ srp->done = 2;
+ write_unlock_irq(&sfp->rq_list_lock);
result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
return (result < 0) ? result : 0;
}
+ srp->orphan = 1;
+ write_unlock_irq(&sfp->rq_list_lock);
+ return result; /* -ERESTARTSYS because signal hit process */
case SG_SET_TIMEOUT:
result = get_user(val, ip);
if (result)
@@ -1091,18 +1115,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
}
}
-static long
-sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&sg_mutex);
- ret = sg_ioctl(filp, cmd_in, arg);
- mutex_unlock(&sg_mutex);
-
- return ret;
-}
-
#ifdef CONFIG_COMPAT
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{
@@ -1136,8 +1148,11 @@ sg_poll(struct file *filp, poll_table * wait)
int count = 0;
unsigned long iflags;
- if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))
- || sfp->closed)
+ sfp = filp->private_data;
+ if (!sfp)
+ return POLLERR;
+ sdp = sfp->parentdp;
+ if (!sdp)
return POLLERR;
poll_wait(filp, &sfp->read_wait, wait);
read_lock_irqsave(&sfp->rq_list_lock, iflags);
@@ -1347,7 +1362,7 @@ static const struct file_operations sg_fops = {
.read = sg_read,
.write = sg_write,
.poll = sg_poll,
- .unlocked_ioctl = sg_unlocked_ioctl,
+ .unlocked_ioctl = sg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = sg_compat_ioctl,
#endif
@@ -2312,7 +2327,7 @@ struct sg_proc_leaf {
const struct file_operations * fops;
};
-static struct sg_proc_leaf sg_proc_leaf_arr[] = {
+static const struct sg_proc_leaf sg_proc_leaf_arr[] = {
{"allow_dio", &adio_fops},
{"debug", &debug_fops},
{"def_reserved_size", &dressz_fops},
@@ -2332,7 +2347,7 @@ sg_proc_init(void)
if (!sg_proc_sgp)
return 1;
for (k = 0; k < num_leaves; ++k) {
- struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k];
+ const struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k];
umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops);
}
@@ -2533,9 +2548,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
fp->reserve.bufflen,
(int) fp->reserve.k_use_sg,
(int) fp->low_dma);
- seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
+ seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
(int) fp->cmd_q, (int) fp->force_packid,
- (int) fp->keep_orphan, (int) fp->closed);
+ (int) fp->keep_orphan);
for (m = 0, srp = fp->headrp;
srp != NULL;
++m, srp = srp->nextrp) {
@@ -2612,7 +2627,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
scsidp->lun,
scsidp->host->hostt->emulated);
seq_printf(s, " sg_tablesize=%d excl=%d\n",
- sdp->sg_tablesize, sdp->exclude);
+ sdp->sg_tablesize, get_exclude(sdp));
sg_proc_debug_helper(s, sdp);
}
read_unlock_irqrestore(&sg_index_lock, iflags);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index ea35632..b548923 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -35,8 +35,8 @@ struct st_request {
/* The tape buffer descriptor. */
struct st_buffer {
unsigned char dma; /* DMA-able buffer */
- unsigned char do_dio; /* direct i/o set up? */
unsigned char cleared; /* internal buffer cleared after open? */
+ unsigned short do_dio; /* direct i/o set up? */
int buffer_size;
int buffer_blocks;
int buffer_bytes;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 83a1972..528d52b 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -785,12 +785,22 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
/*
* If there is an error; offline the device since all
* error recovery strategies would have already been
- * deployed on the host side.
+ * deployed on the host side. However, if the command
+ * were a pass-through command deal with it appropriately.
*/
- if (vm_srb->srb_status == SRB_STATUS_ERROR)
- scmnd->result = DID_TARGET_FAILURE << 16;
- else
- scmnd->result = vm_srb->scsi_status;
+ scmnd->result = vm_srb->scsi_status;
+
+ if (vm_srb->srb_status == SRB_STATUS_ERROR) {
+ switch (scmnd->cmnd[0]) {
+ case ATA_16:
+ case ATA_12:
+ set_host_byte(scmnd, DID_PASSTHROUGH);
+ break;
+ default:
+ set_host_byte(scmnd, DID_TARGET_FAILURE);
+ }
+ }
+
/*
* If the LUN is invalid; remove the device.
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 52b96e8..4e010b7 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1032,11 +1032,11 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
return -EIO;
/* Configure UTRL and UTMRL base address registers */
- writel(hba->utrdl_dma_addr,
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
writel(lower_32_bits(hba->utrdl_dma_addr),
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
+ writel(upper_32_bits(hba->utrdl_dma_addr),
(hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
- writel(hba->utmrdl_dma_addr,
+ writel(lower_32_bits(hba->utmrdl_dma_addr),
(hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
writel(upper_32_bits(hba->utmrdl_dma_addr),
(hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
@@ -1160,7 +1160,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
task_result = be32_to_cpu(task_rsp_upiup->header.dword_1);
task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
- if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL ||
+ if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL &&
task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
task_result = FAILED;
} else {
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 91b6d52..f0d015d 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -2,6 +2,7 @@
* Helper routines for SuperH Clock Pulse Generator blocks (CPG).
*
* Copyright (C) 2010 Magnus Damm
+ * Copyright (C) 2010 - 2012 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
@@ -13,26 +14,44 @@
#include <linux/io.h>
#include <linux/sh_clk.h>
-static int sh_clk_mstp32_enable(struct clk *clk)
+static unsigned int sh_clk_read(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
- clk->mapped_reg);
+ if (clk->flags & CLK_ENABLE_REG_8BIT)
+ return ioread8(clk->mapped_reg);
+ else if (clk->flags & CLK_ENABLE_REG_16BIT)
+ return ioread16(clk->mapped_reg);
+
+ return ioread32(clk->mapped_reg);
+}
+
+static void sh_clk_write(int value, struct clk *clk)
+{
+ if (clk->flags & CLK_ENABLE_REG_8BIT)
+ iowrite8(value, clk->mapped_reg);
+ else if (clk->flags & CLK_ENABLE_REG_16BIT)
+ iowrite16(value, clk->mapped_reg);
+ else
+ iowrite32(value, clk->mapped_reg);
+}
+
+static int sh_clk_mstp_enable(struct clk *clk)
+{
+ sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
return 0;
}
-static void sh_clk_mstp32_disable(struct clk *clk)
+static void sh_clk_mstp_disable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
- clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
}
-static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
- .enable = sh_clk_mstp32_enable,
- .disable = sh_clk_mstp32_disable,
+static struct sh_clk_ops sh_clk_mstp_clk_ops = {
+ .enable = sh_clk_mstp_enable,
+ .disable = sh_clk_mstp_disable,
.recalc = followparent_recalc,
};
-int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+int __init sh_clk_mstp_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
@@ -40,7 +59,7 @@ int __init sh_clk_mstp32_register(struct clk *clks, int nr)
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
- clkp->ops = &sh_clk_mstp32_clk_ops;
+ clkp->ops = &sh_clk_mstp_clk_ops;
ret |= clk_register(clkp);
}
@@ -72,7 +91,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, NULL);
- idx = ioread32(clk->mapped_reg) & 0x003f;
+ idx = sh_clk_read(clk) & 0x003f;
return clk->freq_table[idx].frequency;
}
@@ -98,10 +117,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
if (ret < 0)
return ret;
- value = ioread32(clk->mapped_reg) &
+ value = sh_clk_read(clk) &
~(((1 << clk->src_width) - 1) << clk->src_shift);
- iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
+ sh_clk_write(value | (i << clk->src_shift), clk);
/* Rebuild the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +138,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~0x3f;
value |= idx;
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
return 0;
}
@@ -133,9 +152,9 @@ static int sh_clk_div6_enable(struct clk *clk)
ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~0x100; /* clear stop bit to enable clock */
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
}
return ret;
}
@@ -144,10 +163,10 @@ static void sh_clk_div6_disable(struct clk *clk)
{
unsigned long value;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value |= 0x100; /* stop clock */
value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
}
static struct sh_clk_ops sh_clk_div6_clk_ops = {
@@ -182,7 +201,7 @@ static int __init sh_clk_init_parent(struct clk *clk)
return -EINVAL;
}
- val = (ioread32(clk->mapped_reg) >> clk->src_shift);
+ val = (sh_clk_read(clk) >> clk->src_shift);
val &= (1 << clk->src_width) - 1;
if (val >= clk->parent_num) {
@@ -252,7 +271,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, &clk->arch_flags);
- idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
+ idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
return clk->freq_table[idx].frequency;
}
@@ -270,15 +289,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
*/
if (parent->flags & CLK_ENABLE_ON_INIT)
- value = ioread32(clk->mapped_reg) & ~(1 << 7);
+ value = sh_clk_read(clk) & ~(1 << 7);
else
- value = ioread32(clk->mapped_reg) | (1 << 7);
+ value = sh_clk_read(clk) | (1 << 7);
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
/* Rebiuld the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -295,10 +314,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~(0xf << clk->enable_bit);
value |= (idx << clk->enable_bit);
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
if (d4t->kick)
d4t->kick(clk);
@@ -308,13 +327,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
static int sh_clk_div4_enable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
return 0;
}
static void sh_clk_div4_disable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
}
static struct sh_clk_ops sh_clk_div4_clk_ops = {
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 5fea1ee..14eb01e 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -55,11 +55,3 @@ void destroy_irq(unsigned int irq)
{
irq_free_desc(irq);
}
-
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
-{
- int i;
-
- for (i = 0; i < nr_vecs; i++)
- irq_reserve_irq(evt2irq(vectors[i].vect));
-}
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 570f220..69c9a66 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -37,6 +37,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/spi.h>
@@ -758,6 +759,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
+ struct pinctrl *pinctrl;
int i, ret, num_cs;
if (!np && !mxc_platform_info) {
@@ -845,6 +847,12 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
goto out_iounmap;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_free_irq;
+ }
+
spi_imx->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(spi_imx->clk)) {
dev_err(&pdev->dev, "unable to get clock\n");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 97d412d..05e33c7 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,8 +24,6 @@ menuconfig STAGING
if STAGING
-source "drivers/staging/serial/Kconfig"
-
source "drivers/staging/et131x/Kconfig"
source "drivers/staging/slicoss/Kconfig"
@@ -68,14 +66,10 @@ source "drivers/staging/octeon/Kconfig"
source "drivers/staging/serqt_usb2/Kconfig"
-source "drivers/staging/quatech_usb2/Kconfig"
-
source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
-source "drivers/staging/vme/Kconfig"
-
source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
@@ -116,12 +110,12 @@ source "drivers/staging/cptm1217/Kconfig"
source "drivers/staging/ste_rmi4/Kconfig"
-source "drivers/staging/mei/Kconfig"
-
source "drivers/staging/nvec/Kconfig"
source "drivers/staging/media/Kconfig"
+source "drivers/staging/net/Kconfig"
+
source "drivers/staging/omapdrm/Kconfig"
source "drivers/staging/android/Kconfig"
@@ -132,4 +126,10 @@ source "drivers/staging/ramster/Kconfig"
source "drivers/staging/ozwpan/Kconfig"
+source "drivers/staging/ccg/Kconfig"
+
+source "drivers/staging/ipack/Kconfig"
+
+source "drivers/staging/gdm72xx/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ffe7d44..a987b3a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -3,8 +3,8 @@
# fix for build system bug...
obj-$(CONFIG_STAGING) += staging.o
-obj-y += serial/
obj-y += media/
+obj-y += net/
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_USBIP_CORE) += usbip/
@@ -25,11 +25,11 @@ obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
+obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_ZRAM) += zram/
@@ -50,10 +50,11 @@ obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
-obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_RAMSTER) += ramster/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
+obj-$(CONFIG_USB_G_CCG) += ccg/
+obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index eb1dee2..0e16b59 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,17 +25,9 @@ config ANDROID_LOGGER
tristate "Android log driver"
default n
-config ANDROID_PERSISTENT_RAM
- bool
- depends on HAVE_MEMBLOCK
- select REED_SOLOMON
- select REED_SOLOMON_ENC8
- select REED_SOLOMON_DEC8
-
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
- depends on !S390 && !UML && HAVE_MEMBLOCK
- select ANDROID_PERSISTENT_RAM
+ depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y
default n
config ANDROID_TIMED_OUTPUT
@@ -53,33 +45,14 @@ config ANDROID_LOW_MEMORY_KILLER
---help---
Register processes to be killed when memory is low
-source "drivers/staging/android/switch/Kconfig"
-
-config ANDROID_INTF_ALARM
+config ANDROID_INTF_ALARM_DEV
bool "Android alarm driver"
depends on RTC_CLASS
default n
help
Provides non-wakeup and rtc backed wakeup alarms based on rtc or
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
- Also provides an interface to set the wall time which must be used
- for elapsed realtime to work.
-
-config ANDROID_INTF_ALARM_DEV
- bool "Android alarm device"
- depends on ANDROID_INTF_ALARM
- default y
- help
- Exports the alarm interface to user-space.
-
-config ANDROID_ALARM_OLDDRV_COMPAT
- bool "Android Alarm compatability with old drivers"
- depends on ANDROID_INTF_ALARM
- default n
- help
- Provides preprocessor alias to aid compatability with
- older out-of-tree drivers that use the Android Alarm
- in-kernel API. This will be removed eventually.
+ Also exports the alarm interface to user-space.
endif # if ANDROID
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 9b6c9ed..98711e2 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,11 +1,8 @@
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
-obj-$(CONFIG_ANDROID_PERSISTENT_RAM) += persistent_ram.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
-obj-$(CONFIG_ANDROID_SWITCH) += switch/
-obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index 03efb34..53ce6ec 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -22,19 +22,9 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
+#include <linux/alarmtimer.h>
#include "android_alarm.h"
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
- int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
#define ANDROID_ALARM_PRINT_IO (1U << 1)
#define ANDROID_ALARM_PRINT_INT (1U << 2)
@@ -54,19 +44,65 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
ANDROID_ALARM_RTC_WAKEUP_MASK | \
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-/* support old usespace code */
+/* support old userspace code */
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
static int alarm_opened;
static DEFINE_SPINLOCK(alarm_slock);
-static struct wake_lock alarm_wake_lock;
+static struct wakeup_source alarm_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
static uint32_t alarm_pending;
static uint32_t alarm_enabled;
static uint32_t wait_pending;
-static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
+struct devalarm {
+ union {
+ struct hrtimer hrt;
+ struct alarm alrm;
+ } u;
+ enum android_alarm_type type;
+};
+
+static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
+
+
+static int is_wakeup(enum android_alarm_type type)
+{
+ if (type == ANDROID_ALARM_RTC_WAKEUP ||
+ type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
+ return 1;
+ return 0;
+}
+
+
+static void devalarm_start(struct devalarm *alrm, ktime_t exp)
+{
+ if (is_wakeup(alrm->type))
+ alarm_start(&alrm->u.alrm, exp);
+ else
+ hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
+}
+
+
+static int devalarm_try_to_cancel(struct devalarm *alrm)
+{
+ int ret;
+ if (is_wakeup(alrm->type))
+ ret = alarm_try_to_cancel(&alrm->u.alrm);
+ else
+ ret = hrtimer_try_to_cancel(&alrm->u.hrt);
+ return ret;
+}
+
+static void devalarm_cancel(struct devalarm *alrm)
+{
+ if (is_wakeup(alrm->type))
+ alarm_cancel(&alrm->u.alrm);
+ else
+ hrtimer_cancel(&alrm->u.hrt);
+}
+
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -75,6 +111,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct timespec new_alarm_time;
struct timespec new_rtc_time;
struct timespec tmp_time;
+ struct rtc_time new_rtc_tm;
+ struct rtc_device *rtc_dev;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
uint32_t alarm_type_mask = 1U << alarm_type;
@@ -101,11 +139,11 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case ANDROID_ALARM_CLEAR(0):
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d clear\n", alarm_type);
- android_alarm_try_to_cancel(&alarms[alarm_type]);
+ devalarm_try_to_cancel(&alarms[alarm_type]);
if (alarm_pending) {
alarm_pending &= ~alarm_type_mask;
if (!alarm_pending && !wait_pending)
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
spin_unlock_irqrestore(&alarm_slock, flags);
@@ -132,8 +170,7 @@ from_old_alarm_set:
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_enabled |= alarm_type_mask;
- android_alarm_start_range(&alarms[alarm_type],
- timespec_to_ktime(new_alarm_time),
+ devalarm_start(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
@@ -144,7 +181,7 @@ from_old_alarm_set:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm wait\n");
if (!alarm_pending && wait_pending) {
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
wait_pending = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
@@ -163,7 +200,13 @@ from_old_alarm_set:
rv = -EFAULT;
goto err1;
}
- rv = android_alarm_set_rtc(new_rtc_time);
+ rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm);
+ rtc_dev = alarmtimer_get_rtcdev();
+ rv = do_settimeofday(&new_rtc_time);
+ if (rv < 0)
+ goto err1;
+ if (rtc_dev)
+ rv = rtc_set_time(rtc_dev, &new_rtc_tm);
spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
@@ -179,8 +222,7 @@ from_old_alarm_set:
break;
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
case ANDROID_ALARM_ELAPSED_REALTIME:
- tmp_time =
- ktime_to_timespec(alarm_get_elapsed_realtime());
+ get_monotonic_boottime(&tmp_time);
break;
case ANDROID_ALARM_TYPE_COUNT:
case ANDROID_ALARM_SYSTEMTIME:
@@ -224,14 +266,14 @@ static int alarm_release(struct inode *inode, struct file *file)
alarm_enabled &= ~alarm_type_mask;
}
spin_unlock_irqrestore(&alarm_slock, flags);
- android_alarm_cancel(&alarms[i]);
+ devalarm_cancel(&alarms[i]);
spin_lock_irqsave(&alarm_slock, flags);
}
if (alarm_pending | wait_pending) {
if (alarm_pending)
pr_alarm(INFO, "alarm_release: clear "
"pending alarms %x\n", alarm_pending);
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
wait_pending = 0;
alarm_pending = 0;
}
@@ -241,15 +283,15 @@ static int alarm_release(struct inode *inode, struct file *file)
return 0;
}
-static void alarm_triggered(struct android_alarm *alarm)
+static void devalarm_triggered(struct devalarm *alarm)
{
unsigned long flags;
uint32_t alarm_type_mask = 1U << alarm->type;
- pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
+ pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_enabled & alarm_type_mask) {
- wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
+ __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
alarm_enabled &= ~alarm_type_mask;
alarm_pending |= alarm_type_mask;
wake_up(&alarm_wait_queue);
@@ -257,6 +299,25 @@ static void alarm_triggered(struct android_alarm *alarm)
spin_unlock_irqrestore(&alarm_slock, flags);
}
+
+static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
+{
+ struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
+
+ devalarm_triggered(devalrm);
+ return HRTIMER_NORESTART;
+}
+
+static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
+ ktime_t now)
+{
+ struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
+
+ devalarm_triggered(devalrm);
+ return ALARMTIMER_NORESTART;
+}
+
+
static const struct file_operations alarm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = alarm_ioctl,
@@ -279,17 +340,31 @@ static int __init alarm_dev_init(void)
if (err)
return err;
- for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
- android_alarm_init(&alarms[i], i, alarm_triggered);
- wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
+ alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
+ ALARM_REALTIME, devalarm_alarmhandler);
+ hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
+ CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
+ ALARM_BOOTTIME, devalarm_alarmhandler);
+ hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
+ CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+ hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+
+ for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+ alarms[i].type = i;
+ if (!is_wakeup(i))
+ alarms[i].u.hrt.function = devalarm_hrthandler;
+ }
+ wakeup_source_init(&alarm_wake_lock, "alarm");
return 0;
}
static void __exit alarm_dev_exit(void)
{
misc_deregister(&alarm_device);
- wake_lock_destroy(&alarm_wake_lock);
+ wakeup_source_trash(&alarm_wake_lock);
}
module_init(alarm_dev_init);
diff --git a/drivers/staging/android/alarm.c b/drivers/staging/android/alarm.c
deleted file mode 100644
index c68950b..0000000
--- a/drivers/staging/android/alarm.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/* drivers/rtc/alarm.c
- *
- * Copyright (C) 2007-2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include "android_alarm.h"
-
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
- int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
-#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
-#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
-#define ANDROID_ALARM_PRINT_TSET (1U << 2)
-#define ANDROID_ALARM_PRINT_CALL (1U << 3)
-#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
-#define ANDROID_ALARM_PRINT_INT (1U << 5)
-#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
-
-static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
- ANDROID_ALARM_PRINT_INIT_STATUS;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define pr_alarm(debug_level_mask, args...) \
- do { \
- if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
- pr_info(args); \
- } \
- } while (0)
-
-#define ANDROID_ALARM_WAKEUP_MASK ( \
- ANDROID_ALARM_RTC_WAKEUP_MASK | \
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-
-/* support old usespace code */
-#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
-#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
-
-struct alarm_queue {
- struct rb_root alarms;
- struct rb_node *first;
- struct hrtimer timer;
- ktime_t delta;
- bool stopped;
- ktime_t stopped_time;
-};
-
-static struct rtc_device *alarm_rtc_dev;
-static DEFINE_SPINLOCK(alarm_slock);
-static DEFINE_MUTEX(alarm_setrtc_mutex);
-static struct wake_lock alarm_rtc_wake_lock;
-static struct platform_device *alarm_platform_dev;
-struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
-static bool suspended;
-
-static void update_timer_locked(struct alarm_queue *base, bool head_removed)
-{
- struct android_alarm *alarm;
- bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
- base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
-
- if (base->stopped) {
- pr_alarm(FLOW, "changed alarm while setting the wall time\n");
- return;
- }
-
- if (is_wakeup && !suspended && head_removed)
- wake_unlock(&alarm_rtc_wake_lock);
-
- if (!base->first)
- return;
-
- alarm = container_of(base->first, struct android_alarm, node);
-
- pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
- if (is_wakeup && suspended) {
- pr_alarm(FLOW, "changed alarm while suspened\n");
- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
- return;
- }
-
- hrtimer_try_to_cancel(&base->timer);
- base->timer.node.expires = ktime_add(base->delta, alarm->expires);
- base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
- hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
-}
-
-static void alarm_enqueue_locked(struct android_alarm *alarm)
-{
- struct alarm_queue *base = &alarms[alarm->type];
- struct rb_node **link = &base->alarms.rb_node;
- struct rb_node *parent = NULL;
- struct android_alarm *entry;
- int leftmost = 1;
- bool was_first = false;
-
- pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
- if (base->first == &alarm->node) {
- base->first = rb_next(&alarm->node);
- was_first = true;
- }
- if (!RB_EMPTY_NODE(&alarm->node)) {
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- }
-
- while (*link) {
- parent = *link;
- entry = rb_entry(parent, struct android_alarm, node);
- /*
- * We dont care about collisions. Nodes with
- * the same expiry time stay together.
- */
- if (alarm->expires.tv64 < entry->expires.tv64) {
- link = &(*link)->rb_left;
- } else {
- link = &(*link)->rb_right;
- leftmost = 0;
- }
- }
- if (leftmost)
- base->first = &alarm->node;
- if (leftmost || was_first)
- update_timer_locked(base, was_first);
-
- rb_link_node(&alarm->node, parent, link);
- rb_insert_color(&alarm->node, &base->alarms);
-}
-
-/**
- * android_alarm_init - initialize an alarm
- * @alarm: the alarm to be initialized
- * @type: the alarm type to be used
- * @function: alarm callback function
- */
-void android_alarm_init(struct android_alarm *alarm,
- enum android_alarm_type type, void (*function)(struct android_alarm *))
-{
- RB_CLEAR_NODE(&alarm->node);
- alarm->type = type;
- alarm->function = function;
-
- pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
-}
-
-
-/**
- * android_alarm_start_range - (re)start an alarm
- * @alarm: the alarm to be added
- * @start: earliest expiry time
- * @end: expiry time
- */
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
- ktime_t end)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm->softexpires = start;
- alarm->expires = end;
- alarm_enqueue_locked(alarm);
- spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-/**
- * android_alarm_try_to_cancel - try to deactivate an alarm
- * @alarm: alarm to stop
- *
- * Returns:
- * 0 when the alarm was not active
- * 1 when the alarm was active
- * -1 when the alarm may currently be excuting the callback function and
- * cannot be stopped (it may also be inactive)
- */
-int android_alarm_try_to_cancel(struct android_alarm *alarm)
-{
- struct alarm_queue *base = &alarms[alarm->type];
- unsigned long flags;
- bool first = false;
- int ret = 0;
-
- spin_lock_irqsave(&alarm_slock, flags);
- if (!RB_EMPTY_NODE(&alarm->node)) {
- pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function,
- ktime_to_ns(alarm->expires));
- ret = 1;
- if (base->first == &alarm->node) {
- base->first = rb_next(&alarm->node);
- first = true;
- }
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- if (first)
- update_timer_locked(base, true);
- } else
- pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
- alarm->type, alarm->function);
- spin_unlock_irqrestore(&alarm_slock, flags);
- if (!ret && hrtimer_callback_running(&base->timer))
- ret = -1;
- return ret;
-}
-
-/**
- * android_alarm_cancel - cancel an alarm and wait for the handler to finish.
- * @alarm: the alarm to be cancelled
- *
- * Returns:
- * 0 when the alarm was not active
- * 1 when the alarm was active
- */
-int android_alarm_cancel(struct android_alarm *alarm)
-{
- for (;;) {
- int ret = android_alarm_try_to_cancel(alarm);
- if (ret >= 0)
- return ret;
- cpu_relax();
- }
-}
-
-/**
- * alarm_set_rtc - set the kernel and rtc walltime
- * @new_time: timespec value containing the new time
- */
-int android_alarm_set_rtc(struct timespec new_time)
-{
- int i;
- int ret;
- unsigned long flags;
- struct rtc_time rtc_new_rtc_time;
- struct timespec tmp_time;
-
- rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
-
- pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
- new_time.tv_sec, new_time.tv_nsec,
- rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
- rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
- rtc_new_rtc_time.tm_mday,
- rtc_new_rtc_time.tm_year + 1900);
-
- mutex_lock(&alarm_setrtc_mutex);
- spin_lock_irqsave(&alarm_slock, flags);
- wake_lock(&alarm_rtc_wake_lock);
- getnstimeofday(&tmp_time);
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- hrtimer_try_to_cancel(&alarms[i].timer);
- alarms[i].stopped = true;
- alarms[i].stopped_time = timespec_to_ktime(tmp_time);
- }
- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
- ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
- timespec_to_ktime(timespec_sub(tmp_time, new_time)));
- spin_unlock_irqrestore(&alarm_slock, flags);
- ret = do_settimeofday(&new_time);
- spin_lock_irqsave(&alarm_slock, flags);
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- alarms[i].stopped = false;
- update_timer_locked(&alarms[i], false);
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
- if (ret < 0) {
- pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
- goto err;
- }
- if (!alarm_rtc_dev) {
- pr_alarm(ERROR,
- "alarm_set_rtc: no RTC, time will be lost on reboot\n");
- goto err;
- }
- ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
- if (ret < 0)
- pr_alarm(ERROR, "alarm_set_rtc: "
- "Failed to set RTC, time will be lost on reboot\n");
-err:
- wake_unlock(&alarm_rtc_wake_lock);
- mutex_unlock(&alarm_setrtc_mutex);
- return ret;
-}
-
-/**
- * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
- *
- * returns the time in ktime_t format
- */
-ktime_t alarm_get_elapsed_realtime(void)
-{
- ktime_t now;
- unsigned long flags;
- struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
-
- spin_lock_irqsave(&alarm_slock, flags);
- now = base->stopped ? base->stopped_time : ktime_get_real();
- now = ktime_sub(now, base->delta);
- spin_unlock_irqrestore(&alarm_slock, flags);
- return now;
-}
-
-static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
-{
- struct alarm_queue *base;
- struct android_alarm *alarm;
- unsigned long flags;
- ktime_t now;
-
- spin_lock_irqsave(&alarm_slock, flags);
-
- base = container_of(timer, struct alarm_queue, timer);
- now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
- now = ktime_sub(now, base->delta);
-
- pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
- base - alarms, ktime_to_ns(now));
-
- while (base->first) {
- alarm = container_of(base->first, struct android_alarm, node);
- if (alarm->softexpires.tv64 > now.tv64) {
- pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
- alarm->function, ktime_to_ns(alarm->expires),
- ktime_to_ns(alarm->softexpires));
- break;
- }
- base->first = rb_next(&alarm->node);
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
- alarm->type, alarm->function,
- ktime_to_ns(alarm->expires),
- ktime_to_ns(alarm->softexpires));
- spin_unlock_irqrestore(&alarm_slock, flags);
- alarm->function(alarm);
- spin_lock_irqsave(&alarm_slock, flags);
- }
- if (!base->first)
- pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
- update_timer_locked(base, true);
- spin_unlock_irqrestore(&alarm_slock, flags);
- return HRTIMER_NORESTART;
-}
-
-static void alarm_triggered_func(void *p)
-{
- struct rtc_device *rtc = alarm_rtc_dev;
- if (!(rtc->irq_data & RTC_AF))
- return;
- pr_alarm(INT, "rtc alarm triggered\n");
- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
-}
-
-static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int err = 0;
- unsigned long flags;
- struct rtc_wkalrm rtc_alarm;
- struct rtc_time rtc_current_rtc_time;
- unsigned long rtc_current_time;
- unsigned long rtc_alarm_time;
- struct timespec rtc_delta;
- struct timespec wall_time;
- struct alarm_queue *wakeup_queue = NULL;
- struct alarm_queue *tmp_queue = NULL;
-
- pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = true;
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
- hrtimer_cancel(&alarms[
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
-
- tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
- if (tmp_queue->first)
- wakeup_queue = tmp_queue;
- tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
- if (tmp_queue->first && (!wakeup_queue ||
- hrtimer_get_expires(&tmp_queue->timer).tv64 <
- hrtimer_get_expires(&wakeup_queue->timer).tv64))
- wakeup_queue = tmp_queue;
- if (wakeup_queue) {
- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
- getnstimeofday(&wall_time);
- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
- set_normalized_timespec(&rtc_delta,
- wall_time.tv_sec - rtc_current_time,
- wall_time.tv_nsec);
-
- rtc_alarm_time = timespec_sub(ktime_to_timespec(
- hrtimer_get_expires(&wakeup_queue->timer)),
- rtc_delta).tv_sec;
-
- rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
- rtc_alarm.enabled = 1;
- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
- pr_alarm(SUSPEND,
- "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
- rtc_alarm_time, rtc_current_time,
- rtc_delta.tv_sec, rtc_delta.tv_nsec);
- if (rtc_current_time + 1 >= rtc_alarm_time) {
- pr_alarm(SUSPEND, "alarm about to go off\n");
- memset(&rtc_alarm, 0, sizeof(rtc_alarm));
- rtc_alarm.enabled = 0;
- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = false;
- wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
- false);
- update_timer_locked(&alarms[
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
- err = -EBUSY;
- spin_unlock_irqrestore(&alarm_slock, flags);
- }
- }
- return err;
-}
-
-static int alarm_resume(struct platform_device *pdev)
-{
- struct rtc_wkalrm alarm;
- unsigned long flags;
-
- pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
-
- memset(&alarm, 0, sizeof(alarm));
- alarm.enabled = 0;
- rtc_set_alarm(alarm_rtc_dev, &alarm);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = false;
- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
- update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
- false);
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- return 0;
-}
-
-static struct rtc_task alarm_rtc_task = {
- .func = alarm_triggered_func
-};
-
-static int rtc_alarm_add_device(struct device *dev,
- struct class_interface *class_intf)
-{
- int err;
- struct rtc_device *rtc = to_rtc_device(dev);
-
- mutex_lock(&alarm_setrtc_mutex);
-
- if (alarm_rtc_dev) {
- err = -EBUSY;
- goto err1;
- }
-
- alarm_platform_dev =
- platform_device_register_simple("alarm", -1, NULL, 0);
- if (IS_ERR(alarm_platform_dev)) {
- err = PTR_ERR(alarm_platform_dev);
- goto err2;
- }
- err = rtc_irq_register(rtc, &alarm_rtc_task);
- if (err)
- goto err3;
- alarm_rtc_dev = rtc;
- pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
- mutex_unlock(&alarm_setrtc_mutex);
-
- return 0;
-
-err3:
- platform_device_unregister(alarm_platform_dev);
-err2:
-err1:
- mutex_unlock(&alarm_setrtc_mutex);
- return err;
-}
-
-static void rtc_alarm_remove_device(struct device *dev,
- struct class_interface *class_intf)
-{
- if (dev == &alarm_rtc_dev->dev) {
- pr_alarm(INIT_STATUS, "lost rtc device for alarms");
- rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
- platform_device_unregister(alarm_platform_dev);
- alarm_rtc_dev = NULL;
- }
-}
-
-static struct class_interface rtc_alarm_interface = {
- .add_dev = &rtc_alarm_add_device,
- .remove_dev = &rtc_alarm_remove_device,
-};
-
-static struct platform_driver alarm_driver = {
- .suspend = alarm_suspend,
- .resume = alarm_resume,
- .driver = {
- .name = "alarm"
- }
-};
-
-static int __init alarm_late_init(void)
-{
- unsigned long flags;
- struct timespec tmp_time, system_time;
-
- /* this needs to run after the rtc is read at boot */
- spin_lock_irqsave(&alarm_slock, flags);
- /* We read the current rtc and system time so we can later calulate
- * elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
- * (rtc - (boot_rtc - boot_systemtime))
- */
- getnstimeofday(&tmp_time);
- ktime_get_ts(&system_time);
- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
- timespec_to_ktime(timespec_sub(tmp_time, system_time));
-
- spin_unlock_irqrestore(&alarm_slock, flags);
- return 0;
-}
-
-static int __init alarm_driver_init(void)
-{
- int err;
- int i;
-
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- hrtimer_init(&alarms[i].timer,
- CLOCK_REALTIME, HRTIMER_MODE_ABS);
- alarms[i].timer.function = alarm_timer_triggered;
- }
- hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
- CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
- err = platform_driver_register(&alarm_driver);
- if (err < 0)
- goto err1;
- wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
- rtc_alarm_interface.class = rtc_class;
- err = class_interface_register(&rtc_alarm_interface);
- if (err < 0)
- goto err2;
-
- return 0;
-
-err2:
- wake_lock_destroy(&alarm_rtc_wake_lock);
- platform_driver_unregister(&alarm_driver);
-err1:
- return err;
-}
-
-static void __exit alarm_exit(void)
-{
- class_interface_unregister(&rtc_alarm_interface);
- wake_lock_destroy(&alarm_rtc_wake_lock);
- platform_driver_unregister(&alarm_driver);
-}
-
-late_initcall(alarm_late_init);
-module_init(alarm_driver_init);
-module_exit(alarm_exit);
-
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index 6eecbde..d0cafd6 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -33,65 +33,6 @@ enum android_alarm_type {
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
-#ifdef __KERNEL__
-
-#include <linux/ktime.h>
-#include <linux/rbtree.h>
-
-/*
- * The alarm interface is similar to the hrtimer interface but adds support
- * for wakeup from suspend. It also adds an elapsed realtime clock that can
- * be used for periodic timers that need to keep runing while the system is
- * suspended and not be disrupted when the wall time is set.
- */
-
-/**
- * struct alarm - the basic alarm structure
- * @node: red black tree node for time ordered insertion
- * @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
- * @softexpires: the absolute earliest expiry time of the alarm.
- * @expires: the absolute expiry time.
- * @function: alarm expiry callback function
- *
- * The alarm structure must be initialized by alarm_init()
- *
- */
-
-struct android_alarm {
- struct rb_node node;
- enum android_alarm_type type;
- ktime_t softexpires;
- ktime_t expires;
- void (*function)(struct android_alarm *);
-};
-
-void android_alarm_init(struct android_alarm *alarm,
- enum android_alarm_type type, void (*function)(struct android_alarm *));
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
- ktime_t end);
-int android_alarm_try_to_cancel(struct android_alarm *alarm);
-int android_alarm_cancel(struct android_alarm *alarm);
-ktime_t alarm_get_elapsed_realtime(void);
-
-/* set rtc while preserving elapsed realtime */
-int android_alarm_set_rtc(const struct timespec ts);
-
-#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
-/*
- * Some older drivers depend on the old API,
- * so provide compatability macros for now.
- */
-#define alarm android_alarm
-#define alarm_init(x, y, z) android_alarm_init(x, y, z)
-#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
-#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
-#define alarm_cancel(x) android_alarm_cancel(x)
-#define alarm_set_rtc(x) android_alarm_set_rtc(x)
-#endif
-
-
-#endif
-
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index 25ab6f2..2f7d195 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -53,17 +53,17 @@ struct flat_binder_object {
/* 8 bytes of data. */
union {
- void *binder; /* local object */
+ void __user *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
- void *cookie;
+ void __user *cookie;
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
- * translate the buffer (and local binder) addresses apropriately.
+ * translate the buffer (and local binder) addresses appropriately.
*/
struct binder_write_read {
@@ -139,9 +139,9 @@ struct binder_transaction_data {
union {
struct {
/* transaction data */
- const void *buffer;
+ const void __user *buffer;
/* offsets from buffer to flat_binder_object structs */
- const void *offsets;
+ const void __user *offsets;
} ptr;
uint8_t buf[8];
} data;
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index ea69b6a..b2e71c6 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -25,6 +25,7 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/vmalloc.h>
#include "logger.h"
#include <asm/ioctls.h>
@@ -45,8 +46,12 @@ struct logger_log {
size_t w_off; /* current write head offset */
size_t head; /* new readers start here */
size_t size; /* size of the log */
+ struct list_head logs; /* list of log channels (myself)*/
};
+static LIST_HEAD(log_list);
+
+
/*
* struct logger_reader - a logging device open for reading
*
@@ -60,9 +65,9 @@ struct logger_reader {
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
-size_t logger_offset(struct logger_log *log, size_t n)
+static size_t logger_offset(struct logger_log *log, size_t n)
{
- return n & (log->size-1);
+ return n & (log->size - 1);
}
@@ -348,7 +353,7 @@ static ssize_t do_write_log_from_user(struct logger_log *log,
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
* them above all else.
*/
-ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t ppos)
{
struct logger_log *log = file_get_log(iocb->ki_filp);
@@ -408,7 +413,15 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
return ret;
}
-static struct logger_log *get_log_from_minor(int);
+static struct logger_log *get_log_from_minor(int minor)
+{
+ struct logger_log *log;
+
+ list_for_each_entry(log, &log_list, logs)
+ if (log->misc.minor == minor)
+ return log;
+ return NULL;
+}
/*
* logger_open - the log's open() file operation
@@ -565,80 +578,84 @@ static const struct file_operations logger_fops = {
};
/*
- * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
+ * Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN,
+ * and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
*/
-#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
-static unsigned char _buf_ ## VAR[SIZE]; \
-static struct logger_log VAR = { \
- .buffer = _buf_ ## VAR, \
- .misc = { \
- .minor = MISC_DYNAMIC_MINOR, \
- .name = NAME, \
- .fops = &logger_fops, \
- .parent = NULL, \
- }, \
- .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
- .readers = LIST_HEAD_INIT(VAR .readers), \
- .mutex = __MUTEX_INITIALIZER(VAR .mutex), \
- .w_off = 0, \
- .head = 0, \
- .size = SIZE, \
-};
+static int __init create_log(char *log_name, int size)
+{
+ int ret = 0;
+ struct logger_log *log;
+ unsigned char *buffer;
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+ buffer = vmalloc(size);
+ if (buffer == NULL)
+ return -ENOMEM;
-static struct logger_log *get_log_from_minor(int minor)
-{
- if (log_main.misc.minor == minor)
- return &log_main;
- if (log_events.misc.minor == minor)
- return &log_events;
- if (log_radio.misc.minor == minor)
- return &log_radio;
- if (log_system.misc.minor == minor)
- return &log_system;
- return NULL;
-}
+ log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
+ if (log == NULL) {
+ ret = -ENOMEM;
+ goto out_free_buffer;
+ }
+ log->buffer = buffer;
-static int __init init_log(struct logger_log *log)
-{
- int ret;
+ log->misc.minor = MISC_DYNAMIC_MINOR;
+ log->misc.name = kstrdup(log_name, GFP_KERNEL);
+ if (log->misc.name == NULL) {
+ ret = -ENOMEM;
+ goto out_free_log;
+ }
+
+ log->misc.fops = &logger_fops;
+ log->misc.parent = NULL;
+ init_waitqueue_head(&log->wq);
+ INIT_LIST_HEAD(&log->readers);
+ mutex_init(&log->mutex);
+ log->w_off = 0;
+ log->head = 0;
+ log->size = size;
+
+ INIT_LIST_HEAD(&log->logs);
+ list_add_tail(&log->logs, &log_list);
+
+ /* finally, initialize the misc device for this log */
ret = misc_register(&log->misc);
if (unlikely(ret)) {
printk(KERN_ERR "logger: failed to register misc "
"device for log '%s'!\n", log->misc.name);
- return ret;
+ goto out_free_log;
}
printk(KERN_INFO "logger: created %luK log '%s'\n",
(unsigned long) log->size >> 10, log->misc.name);
return 0;
+
+out_free_log:
+ kfree(log);
+
+out_free_buffer:
+ vfree(buffer);
+ return ret;
}
static int __init logger_init(void)
{
int ret;
- ret = init_log(&log_main);
+ ret = create_log(LOGGER_LOG_MAIN, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_events);
+ ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_radio);
+ ret = create_log(LOGGER_LOG_RADIO, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_system);
+ ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
if (unlikely(ret))
goto out;
diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c
deleted file mode 100644
index 8d8c1e3..0000000
--- a/drivers/staging/android/persistent_ram.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Copyright (C) 2012 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/rslib.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "persistent_ram.h"
-
-struct persistent_ram_buffer {
- uint32_t sig;
- atomic_t start;
- atomic_t size;
- uint8_t data[0];
-};
-
-#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
-
-static __initdata LIST_HEAD(persistent_ram_list);
-
-static inline size_t buffer_size(struct persistent_ram_zone *prz)
-{
- return atomic_read(&prz->buffer->size);
-}
-
-static inline size_t buffer_start(struct persistent_ram_zone *prz)
-{
- return atomic_read(&prz->buffer->start);
-}
-
-/* increase and wrap the start pointer, returning the old value */
-static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
-{
- int old;
- int new;
-
- do {
- old = atomic_read(&prz->buffer->start);
- new = old + a;
- while (unlikely(new > prz->buffer_size))
- new -= prz->buffer_size;
- } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
-
- return old;
-}
-
-/* increase the size counter until it hits the max size */
-static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
-{
- size_t old;
- size_t new;
-
- if (atomic_read(&prz->buffer->size) == prz->buffer_size)
- return;
-
- do {
- old = atomic_read(&prz->buffer->size);
- new = old + a;
- if (new > prz->buffer_size)
- new = prz->buffer_size;
- } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-}
-
-/* increase the size counter, retuning an error if it hits the max size */
-static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
- size_t a)
-{
- size_t old;
- size_t new;
-
- do {
- old = atomic_read(&prz->buffer->size);
- new = old + a;
- if (new > prz->buffer_size)
- return -ENOMEM;
- } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-
- return 0;
-}
-
-static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
- uint8_t *data, size_t len, uint8_t *ecc)
-{
- int i;
- uint16_t par[prz->ecc_size];
-
- /* Initialize the parity buffer */
- memset(par, 0, sizeof(par));
- encode_rs8(prz->rs_decoder, data, len, par, 0);
- for (i = 0; i < prz->ecc_size; i++)
- ecc[i] = par[i];
-}
-
-static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
- void *data, size_t len, uint8_t *ecc)
-{
- int i;
- uint16_t par[prz->ecc_size];
-
- for (i = 0; i < prz->ecc_size; i++)
- par[i] = ecc[i];
- return decode_rs8(prz->rs_decoder, data, par, len,
- NULL, 0, NULL, 0, NULL);
-}
-
-static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
- unsigned int start, unsigned int count)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- uint8_t *buffer_end = buffer->data + prz->buffer_size;
- uint8_t *block;
- uint8_t *par;
- int ecc_block_size = prz->ecc_block_size;
- int ecc_size = prz->ecc_size;
- int size = prz->ecc_block_size;
-
- if (!prz->ecc)
- return;
-
- block = buffer->data + (start & ~(ecc_block_size - 1));
- par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
-
- do {
- if (block + ecc_block_size > buffer_end)
- size = buffer_end - block;
- persistent_ram_encode_rs8(prz, block, size, par);
- block += ecc_block_size;
- par += ecc_size;
- } while (block < buffer->data + start + count);
-}
-
-static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
-
- if (!prz->ecc)
- return;
-
- persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
- prz->par_header);
-}
-
-static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- uint8_t *block;
- uint8_t *par;
-
- if (!prz->ecc)
- return;
-
- block = buffer->data;
- par = prz->par_buffer;
- while (block < buffer->data + buffer_size(prz)) {
- int numerr;
- int size = prz->ecc_block_size;
- if (block + size > buffer->data + prz->buffer_size)
- size = buffer->data + prz->buffer_size - block;
- numerr = persistent_ram_decode_rs8(prz, block, size, par);
- if (numerr > 0) {
- pr_devel("persistent_ram: error in block %p, %d\n",
- block, numerr);
- prz->corrected_bytes += numerr;
- } else if (numerr < 0) {
- pr_devel("persistent_ram: uncorrectable error in block %p\n",
- block);
- prz->bad_blocks++;
- }
- block += prz->ecc_block_size;
- par += prz->ecc_size;
- }
-}
-
-static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
- size_t buffer_size)
-{
- int numerr;
- struct persistent_ram_buffer *buffer = prz->buffer;
- int ecc_blocks;
-
- if (!prz->ecc)
- return 0;
-
- prz->ecc_block_size = 128;
- prz->ecc_size = 16;
- prz->ecc_symsize = 8;
- prz->ecc_poly = 0x11d;
-
- ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
- prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
-
- if (prz->buffer_size > buffer_size) {
- pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
- buffer_size, prz->buffer_size);
- return -EINVAL;
- }
-
- prz->par_buffer = buffer->data + prz->buffer_size;
- prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
-
- /*
- * first consecutive root is 0
- * primitive element to generate roots = 1
- */
- prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
- prz->ecc_size);
- if (prz->rs_decoder == NULL) {
- pr_info("persistent_ram: init_rs failed\n");
- return -EINVAL;
- }
-
- prz->corrected_bytes = 0;
- prz->bad_blocks = 0;
-
- numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
- prz->par_header);
- if (numerr > 0) {
- pr_info("persistent_ram: error in header, %d\n", numerr);
- prz->corrected_bytes += numerr;
- } else if (numerr < 0) {
- pr_info("persistent_ram: uncorrectable error in header\n");
- prz->bad_blocks++;
- }
-
- return 0;
-}
-
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
- char *str, size_t len)
-{
- ssize_t ret;
-
- if (prz->corrected_bytes || prz->bad_blocks)
- ret = snprintf(str, len, ""
- "\n%d Corrected bytes, %d unrecoverable blocks\n",
- prz->corrected_bytes, prz->bad_blocks);
- else
- ret = snprintf(str, len, "\nNo errors detected\n");
-
- return ret;
-}
-
-static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
- const void *s, unsigned int start, unsigned int count)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- memcpy(buffer->data + start, s, count);
- persistent_ram_update_ecc(prz, start, count);
-}
-
-static void __init
-persistent_ram_save_old(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- size_t size = buffer_size(prz);
- size_t start = buffer_start(prz);
- char *dest;
-
- persistent_ram_ecc_old(prz);
-
- dest = kmalloc(size, GFP_KERNEL);
- if (dest == NULL) {
- pr_err("persistent_ram: failed to allocate buffer\n");
- return;
- }
-
- prz->old_log = dest;
- prz->old_log_size = size;
- memcpy(prz->old_log, &buffer->data[start], size - start);
- memcpy(prz->old_log + size - start, &buffer->data[0], start);
-}
-
-int notrace persistent_ram_write(struct persistent_ram_zone *prz,
- const void *s, unsigned int count)
-{
- int rem;
- int c = count;
- size_t start;
-
- if (unlikely(c > prz->buffer_size)) {
- s += c - prz->buffer_size;
- c = prz->buffer_size;
- }
-
- buffer_size_add_clamp(prz, c);
-
- start = buffer_start_add(prz, c);
-
- rem = prz->buffer_size - start;
- if (unlikely(rem < c)) {
- persistent_ram_update(prz, s, start, rem);
- s += rem;
- c -= rem;
- start = 0;
- }
- persistent_ram_update(prz, s, start, c);
-
- persistent_ram_update_header_ecc(prz);
-
- return count;
-}
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
-{
- return prz->old_log_size;
-}
-
-void *persistent_ram_old(struct persistent_ram_zone *prz)
-{
- return prz->old_log;
-}
-
-void persistent_ram_free_old(struct persistent_ram_zone *prz)
-{
- kfree(prz->old_log);
- prz->old_log = NULL;
- prz->old_log_size = 0;
-}
-
-static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
- struct persistent_ram_zone *prz)
-{
- struct page **pages;
- phys_addr_t page_start;
- unsigned int page_count;
- pgprot_t prot;
- unsigned int i;
-
- page_start = start - offset_in_page(start);
- page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
-
- prot = pgprot_noncached(PAGE_KERNEL);
-
- pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
- if (!pages) {
- pr_err("%s: Failed to allocate array for %u pages\n", __func__,
- page_count);
- return -ENOMEM;
- }
-
- for (i = 0; i < page_count; i++) {
- phys_addr_t addr = page_start + i * PAGE_SIZE;
- pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
- }
- prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
- kfree(pages);
- if (!prz->vaddr) {
- pr_err("%s: Failed to map %u pages\n", __func__, page_count);
- return -ENOMEM;
- }
-
- prz->buffer = prz->vaddr + offset_in_page(start);
- prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
-
- return 0;
-}
-
-static int __init persistent_ram_buffer_init(const char *name,
- struct persistent_ram_zone *prz)
-{
- int i;
- struct persistent_ram *ram;
- struct persistent_ram_descriptor *desc;
- phys_addr_t start;
-
- list_for_each_entry(ram, &persistent_ram_list, node) {
- start = ram->start;
- for (i = 0; i < ram->num_descs; i++) {
- desc = &ram->descs[i];
- if (!strcmp(desc->name, name))
- return persistent_ram_buffer_map(start,
- desc->size, prz);
- start += desc->size;
- }
- }
-
- return -EINVAL;
-}
-
-static __init
-struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
-{
- struct persistent_ram_zone *prz;
- int ret = -ENOMEM;
-
- prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
- if (!prz) {
- pr_err("persistent_ram: failed to allocate persistent ram zone\n");
- goto err;
- }
-
- INIT_LIST_HEAD(&prz->node);
-
- ret = persistent_ram_buffer_init(dev_name(dev), prz);
- if (ret) {
- pr_err("persistent_ram: failed to initialize buffer\n");
- goto err;
- }
-
- prz->ecc = ecc;
- ret = persistent_ram_init_ecc(prz, prz->buffer_size);
- if (ret)
- goto err;
-
- if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
- if (buffer_size(prz) > prz->buffer_size ||
- buffer_start(prz) > buffer_size(prz))
- pr_info("persistent_ram: found existing invalid buffer,"
- " size %ld, start %ld\n",
- buffer_size(prz), buffer_start(prz));
- else {
- pr_info("persistent_ram: found existing buffer,"
- " size %ld, start %ld\n",
- buffer_size(prz), buffer_start(prz));
- persistent_ram_save_old(prz);
- }
- } else {
- pr_info("persistent_ram: no valid data in buffer"
- " (sig = 0x%08x)\n", prz->buffer->sig);
- }
-
- prz->buffer->sig = PERSISTENT_RAM_SIG;
- atomic_set(&prz->buffer->start, 0);
- atomic_set(&prz->buffer->size, 0);
-
- return prz;
-err:
- kfree(prz);
- return ERR_PTR(ret);
-}
-
-struct persistent_ram_zone * __init
-persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
-{
- return __persistent_ram_init(dev, ecc);
-}
-
-int __init persistent_ram_early_init(struct persistent_ram *ram)
-{
- int ret;
-
- ret = memblock_reserve(ram->start, ram->size);
- if (ret) {
- pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
- (long)ram->start, (long)(ram->start + ram->size - 1));
- return ret;
- }
-
- list_add_tail(&ram->node, &persistent_ram_list);
-
- pr_info("Initialized persistent memory from %08lx-%08lx\n",
- (long)ram->start, (long)(ram->start + ram->size - 1));
-
- return 0;
-}
diff --git a/drivers/staging/android/persistent_ram.h b/drivers/staging/android/persistent_ram.h
deleted file mode 100644
index f41e208..0000000
--- a/drivers/staging/android/persistent_ram.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __LINUX_PERSISTENT_RAM_H__
-#define __LINUX_PERSISTENT_RAM_H__
-
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/types.h>
-
-struct persistent_ram_buffer;
-
-struct persistent_ram_descriptor {
- const char *name;
- phys_addr_t size;
-};
-
-struct persistent_ram {
- phys_addr_t start;
- phys_addr_t size;
-
- int num_descs;
- struct persistent_ram_descriptor *descs;
-
- struct list_head node;
-};
-
-struct persistent_ram_zone {
- struct list_head node;
- void *vaddr;
- struct persistent_ram_buffer *buffer;
- size_t buffer_size;
-
- /* ECC correction */
- bool ecc;
- char *par_buffer;
- char *par_header;
- struct rs_control *rs_decoder;
- int corrected_bytes;
- int bad_blocks;
- int ecc_block_size;
- int ecc_size;
- int ecc_symsize;
- int ecc_poly;
-
- char *old_log;
- size_t old_log_size;
- size_t old_log_footer_size;
- bool early;
-};
-
-int persistent_ram_early_init(struct persistent_ram *ram);
-
-struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
- bool ecc);
-
-int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
- unsigned int count);
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
-void *persistent_ram_old(struct persistent_ram_zone *prz);
-void persistent_ram_free_old(struct persistent_ram_zone *prz);
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
- char *str, size_t len);
-
-#endif
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index ce140ff..82323bb 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,7 +21,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include "persistent_ram.h"
+#include <linux/pstore_ram.h>
#include "ram_console.h"
static struct persistent_ram_zone *ram_console_zone;
diff --git a/drivers/staging/android/switch/Kconfig b/drivers/staging/android/switch/Kconfig
deleted file mode 100644
index 36846f6..0000000
--- a/drivers/staging/android/switch/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-menuconfig ANDROID_SWITCH
- tristate "Android Switch class support"
- help
- Say Y here to enable Android switch class support. This allows
- monitoring switches by userspace via sysfs and uevent.
-
-config ANDROID_SWITCH_GPIO
- tristate "Android GPIO Switch support"
- depends on GENERIC_GPIO && ANDROID_SWITCH
- help
- Say Y here to enable GPIO based switch support.
diff --git a/drivers/staging/android/switch/Makefile b/drivers/staging/android/switch/Makefile
deleted file mode 100644
index d76bfdc..0000000
--- a/drivers/staging/android/switch/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# Android Switch Class Driver
-obj-$(CONFIG_ANDROID_SWITCH) += switch_class.o
-obj-$(CONFIG_ANDROID_SWITCH_GPIO) += switch_gpio.o
-
diff --git a/drivers/staging/android/switch/switch.h b/drivers/staging/android/switch/switch.h
deleted file mode 100644
index 4fcb310..0000000
--- a/drivers/staging/android/switch/switch.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Switch class driver
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
-*/
-
-#ifndef __LINUX_SWITCH_H__
-#define __LINUX_SWITCH_H__
-
-struct switch_dev {
- const char *name;
- struct device *dev;
- int index;
- int state;
-
- ssize_t (*print_name)(struct switch_dev *sdev, char *buf);
- ssize_t (*print_state)(struct switch_dev *sdev, char *buf);
-};
-
-struct gpio_switch_platform_data {
- const char *name;
- unsigned gpio;
-
- /* if NULL, switch_dev.name will be printed */
- const char *name_on;
- const char *name_off;
- /* if NULL, "0" or "1" will be printed */
- const char *state_on;
- const char *state_off;
-};
-
-extern int switch_dev_register(struct switch_dev *sdev);
-extern void switch_dev_unregister(struct switch_dev *sdev);
-
-static inline int switch_get_state(struct switch_dev *sdev)
-{
- return sdev->state;
-}
-
-extern void switch_set_state(struct switch_dev *sdev, int state);
-
-#endif /* __LINUX_SWITCH_H__ */
diff --git a/drivers/staging/android/switch/switch_class.c b/drivers/staging/android/switch/switch_class.c
deleted file mode 100644
index 7468044..0000000
--- a/drivers/staging/android/switch/switch_class.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * switch_class.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include "switch.h"
-
-struct class *switch_class;
-static atomic_t device_count;
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct switch_dev *sdev = (struct switch_dev *)
- dev_get_drvdata(dev);
-
- if (sdev->print_state) {
- int ret = sdev->print_state(sdev, buf);
- if (ret >= 0)
- return ret;
- }
- return sprintf(buf, "%d\n", sdev->state);
-}
-
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct switch_dev *sdev = (struct switch_dev *)
- dev_get_drvdata(dev);
-
- if (sdev->print_name) {
- int ret = sdev->print_name(sdev, buf);
- if (ret >= 0)
- return ret;
- }
- return sprintf(buf, "%s\n", sdev->name);
-}
-
-static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL);
-static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL);
-
-void switch_set_state(struct switch_dev *sdev, int state)
-{
- char name_buf[120];
- char state_buf[120];
- char *prop_buf;
- char *envp[3];
- int env_offset = 0;
- int length;
-
- if (sdev->state != state) {
- sdev->state = state;
-
- prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
- if (prop_buf) {
- length = name_show(sdev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(name_buf, sizeof(name_buf),
- "SWITCH_NAME=%s", prop_buf);
- envp[env_offset++] = name_buf;
- }
- length = state_show(sdev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(state_buf, sizeof(state_buf),
- "SWITCH_STATE=%s", prop_buf);
- envp[env_offset++] = state_buf;
- }
- envp[env_offset] = NULL;
- kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
- free_page((unsigned long)prop_buf);
- } else {
- printk(KERN_ERR "out of memory in switch_set_state\n");
- kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
- }
- }
-}
-EXPORT_SYMBOL_GPL(switch_set_state);
-
-static int create_switch_class(void)
-{
- if (!switch_class) {
- switch_class = class_create(THIS_MODULE, "switch");
- if (IS_ERR(switch_class))
- return PTR_ERR(switch_class);
- atomic_set(&device_count, 0);
- }
-
- return 0;
-}
-
-int switch_dev_register(struct switch_dev *sdev)
-{
- int ret;
-
- if (!switch_class) {
- ret = create_switch_class();
- if (ret < 0)
- return ret;
- }
-
- sdev->index = atomic_inc_return(&device_count);
- sdev->dev = device_create(switch_class, NULL,
- MKDEV(0, sdev->index), NULL, sdev->name);
- if (IS_ERR(sdev->dev))
- return PTR_ERR(sdev->dev);
-
- ret = device_create_file(sdev->dev, &dev_attr_state);
- if (ret < 0)
- goto err_create_file_1;
- ret = device_create_file(sdev->dev, &dev_attr_name);
- if (ret < 0)
- goto err_create_file_2;
-
- dev_set_drvdata(sdev->dev, sdev);
- sdev->state = 0;
- return 0;
-
-err_create_file_2:
- device_remove_file(sdev->dev, &dev_attr_state);
-err_create_file_1:
- device_destroy(switch_class, MKDEV(0, sdev->index));
- printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(switch_dev_register);
-
-void switch_dev_unregister(struct switch_dev *sdev)
-{
- device_remove_file(sdev->dev, &dev_attr_name);
- device_remove_file(sdev->dev, &dev_attr_state);
- device_destroy(switch_class, MKDEV(0, sdev->index));
- dev_set_drvdata(sdev->dev, NULL);
-}
-EXPORT_SYMBOL_GPL(switch_dev_unregister);
-
-static int __init switch_class_init(void)
-{
- return create_switch_class();
-}
-
-static void __exit switch_class_exit(void)
-{
- class_destroy(switch_class);
-}
-
-module_init(switch_class_init);
-module_exit(switch_class_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("Switch class driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/switch/switch_gpio.c b/drivers/staging/android/switch/switch_gpio.c
deleted file mode 100644
index 38b2c2f..0000000
--- a/drivers/staging/android/switch/switch_gpio.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * switch_gpio.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/gpio.h>
-#include "switch.h"
-
-struct gpio_switch_data {
- struct switch_dev sdev;
- unsigned gpio;
- const char *name_on;
- const char *name_off;
- const char *state_on;
- const char *state_off;
- int irq;
- struct work_struct work;
-};
-
-static void gpio_switch_work(struct work_struct *work)
-{
- int state;
- struct gpio_switch_data *data =
- container_of(work, struct gpio_switch_data, work);
-
- state = gpio_get_value(data->gpio);
- switch_set_state(&data->sdev, state);
-}
-
-static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
-{
- struct gpio_switch_data *switch_data =
- (struct gpio_switch_data *)dev_id;
-
- schedule_work(&switch_data->work);
- return IRQ_HANDLED;
-}
-
-static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
-{
- struct gpio_switch_data *switch_data =
- container_of(sdev, struct gpio_switch_data, sdev);
- const char *state;
- if (switch_get_state(sdev))
- state = switch_data->state_on;
- else
- state = switch_data->state_off;
-
- if (state)
- return sprintf(buf, "%s\n", state);
- return -1;
-}
-
-static int gpio_switch_probe(struct platform_device *pdev)
-{
- struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_switch_data *switch_data;
- int ret = 0;
-
- if (!pdata)
- return -EBUSY;
-
- switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
- if (!switch_data)
- return -ENOMEM;
-
- switch_data->sdev.name = pdata->name;
- switch_data->gpio = pdata->gpio;
- switch_data->name_on = pdata->name_on;
- switch_data->name_off = pdata->name_off;
- switch_data->state_on = pdata->state_on;
- switch_data->state_off = pdata->state_off;
- switch_data->sdev.print_state = switch_gpio_print_state;
-
- ret = switch_dev_register(&switch_data->sdev);
- if (ret < 0)
- goto err_switch_dev_register;
-
- ret = gpio_request(switch_data->gpio, pdev->name);
- if (ret < 0)
- goto err_request_gpio;
-
- ret = gpio_direction_input(switch_data->gpio);
- if (ret < 0)
- goto err_set_gpio_input;
-
- INIT_WORK(&switch_data->work, gpio_switch_work);
-
- switch_data->irq = gpio_to_irq(switch_data->gpio);
- if (switch_data->irq < 0) {
- ret = switch_data->irq;
- goto err_detect_irq_num_failed;
- }
-
- ret = request_irq(switch_data->irq, gpio_irq_handler,
- IRQF_TRIGGER_LOW, pdev->name, switch_data);
- if (ret < 0)
- goto err_request_irq;
-
- /* Perform initial detection */
- gpio_switch_work(&switch_data->work);
-
- return 0;
-
-err_request_irq:
-err_detect_irq_num_failed:
-err_set_gpio_input:
- gpio_free(switch_data->gpio);
-err_request_gpio:
- switch_dev_unregister(&switch_data->sdev);
-err_switch_dev_register:
- kfree(switch_data);
-
- return ret;
-}
-
-static int __devexit gpio_switch_remove(struct platform_device *pdev)
-{
- struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
-
- cancel_work_sync(&switch_data->work);
- gpio_free(switch_data->gpio);
- switch_dev_unregister(&switch_data->sdev);
- kfree(switch_data);
-
- return 0;
-}
-
-static struct platform_driver gpio_switch_driver = {
- .probe = gpio_switch_probe,
- .remove = __devexit_p(gpio_switch_remove),
- .driver = {
- .name = "switch-gpio",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init gpio_switch_init(void)
-{
- return platform_driver_register(&gpio_switch_driver);
-}
-
-static void __exit gpio_switch_exit(void)
-{
- platform_driver_unregister(&gpio_switch_driver);
-}
-
-module_init(gpio_switch_init);
-module_exit(gpio_switch_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("GPIO Switch driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index f373422..38d930c 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -99,6 +99,7 @@ EXPORT_SYMBOL_GPL(timed_output_dev_register);
void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
+ tdev->enable(tdev, 0);
device_remove_file(tdev->dev, &dev_attr_enable);
device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL);
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 83549d9..510d796 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -782,20 +782,20 @@ static int __init asus_oled_init(void)
oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
if (IS_ERR(oled_class)) {
- err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class");
+ printk(KERN_ERR "Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n");
return PTR_ERR(oled_class);
}
retval = class_create_file(oled_class, &class_attr_version.attr);
if (retval) {
- err("Error creating class version file");
+ printk(KERN_ERR "Error creating class version file\n");
goto error;
}
retval = usb_register(&oled_driver);
if (retval) {
- err("usb_register failed. Error number %d", retval);
+ printk(KERN_ERR "usb_register failed. Error number %d\n", retval);
goto error;
}
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index 20cca24..aa51d17 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -7,168 +7,145 @@
#define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
#include "Debug.h"
-struct _LEADER
-{
- USHORT Vcid;
- USHORT PLength;
- UCHAR Status;
+struct _LEADER {
+ USHORT Vcid;
+ USHORT PLength;
+ UCHAR Status;
UCHAR Unused[3];
-}__attribute__((packed));
-typedef struct _LEADER LEADER,*PLEADER;
+} __packed;
+typedef struct _LEADER LEADER, *PLEADER;
-struct _PACKETTOSEND
-{
+struct _PACKETTOSEND {
LEADER Leader;
UCHAR ucPayload;
-}__attribute__((packed));
+} __packed;
typedef struct _PACKETTOSEND PACKETTOSEND, *PPACKETTOSEND;
-
-struct _CONTROL_PACKET
-{
+struct _CONTROL_PACKET {
PVOID ControlBuff;
UINT ControlBuffLen;
- struct _CONTROL_PACKET* next;
-}__attribute__((packed));
-typedef struct _CONTROL_PACKET CONTROL_PACKET,*PCONTROL_PACKET;
-
+ struct _CONTROL_PACKET *next;
+} __packed;
+typedef struct _CONTROL_PACKET CONTROL_PACKET, *PCONTROL_PACKET;
-struct link_request
-{
+struct link_request {
LEADER Leader;
UCHAR szData[4];
-}__attribute__((packed));
+} __packed;
typedef struct link_request LINK_REQUEST, *PLINK_REQUEST;
-
-//classification extension is added
-typedef struct _ADD_CONNECTION
-{
- ULONG SrcIpAddressCount;
- ULONG SrcIpAddress[MAX_CONNECTIONS];
- ULONG SrcIpMask[MAX_CONNECTIONS];
-
- ULONG DestIpAddressCount;
- ULONG DestIpAddress[MAX_CONNECTIONS];
- ULONG DestIpMask[MAX_CONNECTIONS];
-
- USHORT SrcPortBegin;
- USHORT SrcPortEnd;
-
- USHORT DestPortBegin;
- USHORT DestPortEnd;
-
- UCHAR SrcTOS;
- UCHAR SrcProtocol;
-} ADD_CONNECTION,*PADD_CONNECTION;
-
-
-typedef struct _CLASSIFICATION_RULE
-{
- UCHAR ucIPSrcAddrLen;
- UCHAR ucIPSrcAddr[32];
- UCHAR ucIPDestAddrLen;
- UCHAR ucIPDestAddr[32];
- UCHAR ucSrcPortRangeLen;
- UCHAR ucSrcPortRange[4];
- UCHAR ucDestPortRangeLen;
- UCHAR ucDestPortRange[4];
- USHORT usVcid;
-} CLASSIFICATION_RULE,*PCLASSIFICATION_RULE;
-
-typedef struct _CLASSIFICATION_ONLY
-{
- USHORT usVcid;
- ULONG DestIpAddress;
- ULONG DestIpMask;
- USHORT usPortLo;
- USHORT usPortHi;
- BOOLEAN bIpVersion;
- UCHAR ucDestinationAddress[16];
+/* classification extension is added */
+typedef struct _ADD_CONNECTION {
+ ULONG SrcIpAddressCount;
+ ULONG SrcIpAddress[MAX_CONNECTIONS];
+ ULONG SrcIpMask[MAX_CONNECTIONS];
+
+ ULONG DestIpAddressCount;
+ ULONG DestIpAddress[MAX_CONNECTIONS];
+ ULONG DestIpMask[MAX_CONNECTIONS];
+
+ USHORT SrcPortBegin;
+ USHORT SrcPortEnd;
+
+ USHORT DestPortBegin;
+ USHORT DestPortEnd;
+
+ UCHAR SrcTOS;
+ UCHAR SrcProtocol;
+} ADD_CONNECTION, *PADD_CONNECTION;
+
+typedef struct _CLASSIFICATION_RULE {
+ UCHAR ucIPSrcAddrLen;
+ UCHAR ucIPSrcAddr[32];
+ UCHAR ucIPDestAddrLen;
+ UCHAR ucIPDestAddr[32];
+ UCHAR ucSrcPortRangeLen;
+ UCHAR ucSrcPortRange[4];
+ UCHAR ucDestPortRangeLen;
+ UCHAR ucDestPortRange[4];
+ USHORT usVcid;
+} CLASSIFICATION_RULE, *PCLASSIFICATION_RULE;
+
+typedef struct _CLASSIFICATION_ONLY {
+ USHORT usVcid;
+ ULONG DestIpAddress;
+ ULONG DestIpMask;
+ USHORT usPortLo;
+ USHORT usPortHi;
+ BOOLEAN bIpVersion;
+ UCHAR ucDestinationAddress[16];
} CLASSIFICATION_ONLY, *PCLASSIFICATION_ONLY;
-
#define MAX_IP_RANGE_LENGTH 4
#define MAX_PORT_RANGE 4
#define MAX_PROTOCOL_LENGTH 32
#define IPV6_ADDRESS_SIZEINBYTES 0x10
-typedef union _U_IP_ADDRESS
-{
- struct
- {
- ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH];//Source Ip Address Range
- ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH];//Source Ip Mask Address Range
+typedef union _U_IP_ADDRESS {
+ struct {
+ ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */
+ ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */
};
- struct
- {
- ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4];//Source Ip Address Range
- ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4];//Source Ip Mask Address Range
-
+ struct {
+ ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */
+ ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Mask Address Range */
};
- struct
- {
- UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
- UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+ struct {
+ UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+ UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
};
- struct
- {
- UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
- UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+ struct {
+ UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+ UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
};
-}U_IP_ADDRESS;
+} U_IP_ADDRESS;
struct _packet_info;
-typedef struct _S_HDR_SUPRESSION_CONTEXTINFO
-{
+typedef struct _S_HDR_SUPRESSION_CONTEXTINFO {
+ UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */
+ UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */
+} S_HDR_SUPRESSION_CONTEXTINFO;
+
+typedef struct _S_CLASSIFIER_RULE {
+ ULONG ulSFID;
+ UCHAR ucReserved[2];
+ B_UINT16 uiClassifierRuleIndex;
+ BOOLEAN bUsed;
+ USHORT usVCID_Value;
+ B_UINT8 u8ClassifierRulePriority; /* This field detemines the Classifier Priority */
+ U_IP_ADDRESS stSrcIpAddress;
+ UCHAR ucIPSourceAddressLength; /* Ip Source Address Length */
- UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; //Intermediate buffer to accumulate pkt Header for PHS
- UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; //Intermediate buffer containing pkt Header after PHS
+ U_IP_ADDRESS stDestIpAddress;
+ UCHAR ucIPDestinationAddressLength; /* Ip Destination Address Length */
+ UCHAR ucIPTypeOfServiceLength; /* Type of service Length */
+ UCHAR ucTosLow; /* Tos Low */
+ UCHAR ucTosHigh; /* Tos High */
+ UCHAR ucTosMask; /* Tos Mask */
-}S_HDR_SUPRESSION_CONTEXTINFO;
+ UCHAR ucProtocolLength; /* protocol Length */
+ UCHAR ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */
+ USHORT usSrcPortRangeLo[MAX_PORT_RANGE];
+ USHORT usSrcPortRangeHi[MAX_PORT_RANGE];
+ UCHAR ucSrcPortRangeLength;
+ USHORT usDestPortRangeLo[MAX_PORT_RANGE];
+ USHORT usDestPortRangeHi[MAX_PORT_RANGE];
+ UCHAR ucDestPortRangeLength;
-typedef struct _S_CLASSIFIER_RULE
-{
- ULONG ulSFID;
- UCHAR ucReserved[2];
- B_UINT16 uiClassifierRuleIndex;
- BOOLEAN bUsed;
- USHORT usVCID_Value;
- B_UINT8 u8ClassifierRulePriority; //This field detemines the Classifier Priority
- U_IP_ADDRESS stSrcIpAddress;
- UCHAR ucIPSourceAddressLength;//Ip Source Address Length
-
- U_IP_ADDRESS stDestIpAddress;
- UCHAR ucIPDestinationAddressLength;//Ip Destination Address Length
- UCHAR ucIPTypeOfServiceLength;//Type of service Length
- UCHAR ucTosLow;//Tos Low
- UCHAR ucTosHigh;//Tos High
- UCHAR ucTosMask;//Tos Mask
-
- UCHAR ucProtocolLength;//protocol Length
- UCHAR ucProtocol[MAX_PROTOCOL_LENGTH];//protocol Length
- USHORT usSrcPortRangeLo[MAX_PORT_RANGE];
- USHORT usSrcPortRangeHi[MAX_PORT_RANGE];
- UCHAR ucSrcPortRangeLength;
-
- USHORT usDestPortRangeLo[MAX_PORT_RANGE];
- USHORT usDestPortRangeHi[MAX_PORT_RANGE];
- UCHAR ucDestPortRangeLength;
-
- BOOLEAN bProtocolValid;
- BOOLEAN bTOSValid;
- BOOLEAN bDestIpValid;
- BOOLEAN bSrcIpValid;
-
- //For IPv6 Addressing
- UCHAR ucDirection;
- BOOLEAN bIpv6Protocol;
- UINT32 u32PHSRuleID;
- S_PHS_RULE sPhsRule;
- UCHAR u8AssociatedPHSI;
-
- //Classification fields for ETH CS
+ BOOLEAN bProtocolValid;
+ BOOLEAN bTOSValid;
+ BOOLEAN bDestIpValid;
+ BOOLEAN bSrcIpValid;
+
+ /* For IPv6 Addressing */
+ UCHAR ucDirection;
+ BOOLEAN bIpv6Protocol;
+ UINT32 u32PHSRuleID;
+ S_PHS_RULE sPhsRule;
+ UCHAR u8AssociatedPHSI;
+
+ /* Classification fields for ETH CS */
UCHAR ucEthCSSrcMACLen;
UCHAR au8EThCSSrcMAC[MAC_ADDRESS_SIZE];
UCHAR au8EThCSSrcMACMask[MAC_ADDRESS_SIZE];
@@ -180,71 +157,67 @@ typedef struct _S_CLASSIFIER_RULE
UCHAR usUserPriority[2];
USHORT usVLANID;
USHORT usValidityBitMap;
-}S_CLASSIFIER_RULE;
-//typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE;
-
-typedef struct _S_FRAGMENTED_PACKET_INFO
-{
- BOOLEAN bUsed;
- ULONG ulSrcIpAddress;
- USHORT usIpIdentification;
- S_CLASSIFIER_RULE *pstMatchedClassifierEntry;
- BOOLEAN bOutOfOrderFragment;
-}S_FRAGMENTED_PACKET_INFO,*PS_FRAGMENTED_PACKET_INFO;
-
-struct _packet_info
-{
- //classification extension Rule
- ULONG ulSFID;
- USHORT usVCID_Value;
- UINT uiThreshold;
- // This field determines the priority of the SF Queues
- B_UINT8 u8TrafficPriority;
-
- BOOLEAN bValid;
- BOOLEAN bActive;
- BOOLEAN bActivateRequestSent;
-
- B_UINT8 u8QueueType;//BE or rtPS
-
- UINT uiMaxBucketSize;//maximum size of the bucket for the queue
- UINT uiCurrentQueueDepthOnTarget;
- UINT uiCurrentBytesOnHost;
- UINT uiCurrentPacketsOnHost;
- UINT uiDroppedCountBytes;
- UINT uiDroppedCountPackets;
- UINT uiSentBytes;
- UINT uiSentPackets;
- UINT uiCurrentDrainRate;
- UINT uiThisPeriodSentBytes;
+} S_CLASSIFIER_RULE;
+/* typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; */
+
+typedef struct _S_FRAGMENTED_PACKET_INFO {
+ BOOLEAN bUsed;
+ ULONG ulSrcIpAddress;
+ USHORT usIpIdentification;
+ S_CLASSIFIER_RULE *pstMatchedClassifierEntry;
+ BOOLEAN bOutOfOrderFragment;
+} S_FRAGMENTED_PACKET_INFO, *PS_FRAGMENTED_PACKET_INFO;
+
+struct _packet_info {
+ /* classification extension Rule */
+ ULONG ulSFID;
+ USHORT usVCID_Value;
+ UINT uiThreshold;
+ /* This field determines the priority of the SF Queues */
+ B_UINT8 u8TrafficPriority;
+
+ BOOLEAN bValid;
+ BOOLEAN bActive;
+ BOOLEAN bActivateRequestSent;
+
+ B_UINT8 u8QueueType; /* BE or rtPS */
+
+ UINT uiMaxBucketSize; /* maximum size of the bucket for the queue */
+ UINT uiCurrentQueueDepthOnTarget;
+ UINT uiCurrentBytesOnHost;
+ UINT uiCurrentPacketsOnHost;
+ UINT uiDroppedCountBytes;
+ UINT uiDroppedCountPackets;
+ UINT uiSentBytes;
+ UINT uiSentPackets;
+ UINT uiCurrentDrainRate;
+ UINT uiThisPeriodSentBytes;
LARGE_INTEGER liDrainCalculated;
- UINT uiCurrentTokenCount;
- LARGE_INTEGER liLastUpdateTokenAt;
- UINT uiMaxAllowedRate;
- UINT NumOfPacketsSent;
- UCHAR ucDirection;
- USHORT usCID;
+ UINT uiCurrentTokenCount;
+ LARGE_INTEGER liLastUpdateTokenAt;
+ UINT uiMaxAllowedRate;
+ UINT NumOfPacketsSent;
+ UCHAR ucDirection;
+ USHORT usCID;
S_MIBS_EXTSERVICEFLOW_PARAMETERS stMibsExtServiceFlowTable;
- UINT uiCurrentRxRate;
- UINT uiThisPeriodRxBytes;
- UINT uiTotalRxBytes;
- UINT uiTotalTxBytes;
- UINT uiPendedLast;
- UCHAR ucIpVersion;
-
- union
- {
- struct
- {
- struct sk_buff* FirstTxQueue;
- struct sk_buff* LastTxQueue;
+ UINT uiCurrentRxRate;
+ UINT uiThisPeriodRxBytes;
+ UINT uiTotalRxBytes;
+ UINT uiTotalTxBytes;
+ UINT uiPendedLast;
+ UCHAR ucIpVersion;
+
+ union {
+ struct {
+ struct sk_buff *FirstTxQueue;
+ struct sk_buff *LastTxQueue;
};
- struct
- {
- struct sk_buff* ControlHead;
- struct sk_buff* ControlTail;
+ struct {
+ struct sk_buff *ControlHead;
+ struct sk_buff *ControlTail;
};
};
+
BOOLEAN bProtocolValid;
BOOLEAN bTOSValid;
BOOLEAN bDestIpValid;
@@ -255,226 +228,209 @@ struct _packet_info
BOOLEAN bAuthorizedSet;
BOOLEAN bClassifierPriority;
UCHAR ucServiceClassName[MAX_CLASS_NAME_LENGTH];
- BOOLEAN bHeaderSuppressionEnabled;
+ BOOLEAN bHeaderSuppressionEnabled;
spinlock_t SFQueueLock;
- void *pstSFIndication;
+ void *pstSFIndication;
struct timeval stLastUpdateTokenAt;
- atomic_t uiPerSFTxResourceCount;
+ atomic_t uiPerSFTxResourceCount;
UINT uiMaxLatency;
- UCHAR bIPCSSupport;
- UCHAR bEthCSSupport;
+ UCHAR bIPCSSupport;
+ UCHAR bEthCSSupport;
};
typedef struct _packet_info PacketInfo;
-
-typedef struct _PER_TARANG_DATA
-{
- struct _PER_TARANG_DATA * next;
- struct _MINI_ADAPTER * Adapter;
- struct sk_buff* RxAppControlHead;
- struct sk_buff* RxAppControlTail;
- volatile INT AppCtrlQueueLen;
- BOOLEAN MacTracingEnabled;
- BOOLEAN bApplicationToExit;
- S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs;
- ULONG RxCntrlMsgBitMask;
+typedef struct _PER_TARANG_DATA {
+ struct _PER_TARANG_DATA *next;
+ struct _MINI_ADAPTER *Adapter;
+ struct sk_buff *RxAppControlHead;
+ struct sk_buff *RxAppControlTail;
+ int AppCtrlQueueLen;
+ BOOLEAN MacTracingEnabled;
+ BOOLEAN bApplicationToExit;
+ S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs;
+ ULONG RxCntrlMsgBitMask;
} PER_TARANG_DATA, *PPER_TARANG_DATA;
-
#ifdef REL_4_1
-typedef struct _TARGET_PARAMS
-{
- B_UINT32 m_u32CfgVersion;
-
- // Scanning Related Params
- B_UINT32 m_u32CenterFrequency;
- B_UINT32 m_u32BandAScan;
- B_UINT32 m_u32BandBScan;
- B_UINT32 m_u32BandCScan;
-
- // QoS Params
- B_UINT32 m_u32minGrantsize; // size of minimum grant is 0 or 6
- B_UINT32 m_u32PHSEnable;
-
- // HO Params
- B_UINT32 m_u32HoEnable;
- B_UINT32 m_u32HoReserved1;
- B_UINT32 m_u32HoReserved2;
-
- // Power Control Params
- B_UINT32 m_u32MimoEnable;
- B_UINT32 m_u32SecurityEnable;
+typedef struct _TARGET_PARAMS {
+ B_UINT32 m_u32CfgVersion;
+
+ /* Scanning Related Params */
+ B_UINT32 m_u32CenterFrequency;
+ B_UINT32 m_u32BandAScan;
+ B_UINT32 m_u32BandBScan;
+ B_UINT32 m_u32BandCScan;
+
+ /* QoS Params */
+ B_UINT32 m_u32minGrantsize; /* size of minimum grant is 0 or 6 */
+ B_UINT32 m_u32PHSEnable;
+
+ /* HO Params */
+ B_UINT32 m_u32HoEnable;
+ B_UINT32 m_u32HoReserved1;
+ B_UINT32 m_u32HoReserved2;
+
+ /* Power Control Params */
+ B_UINT32 m_u32MimoEnable;
+ B_UINT32 m_u32SecurityEnable;
/*
- * bit 1: 1 Idlemode enable;
- * bit 2: 1 Sleepmode Enable
- */
- B_UINT32 m_u32PowerSavingModesEnable;
- /* PowerSaving Mode Options:
- bit 0 = 1: CPE mode - to keep pcmcia if alive;
- bit 1 = 1: CINR reporing in Idlemode Msg
- bit 2 = 1: Default PSC Enable in sleepmode*/
- B_UINT32 m_u32PowerSavingModeOptions;
-
- B_UINT32 m_u32ArqEnable;
-
- // From Version #3, the HARQ section renamed as general
- B_UINT32 m_u32HarqEnable;
- // EEPROM Param Location
- B_UINT32 m_u32EEPROMFlag;
- /* BINARY TYPE - 4th MSByte:
- * Interface Type - 3rd MSByte:
- * Vendor Type - 2nd MSByte
- */
- // Unused - LSByte
- B_UINT32 m_u32Customize;
- B_UINT32 m_u32ConfigBW; /* In Hz */
- B_UINT32 m_u32ShutDownTimer;
-
-
- B_UINT32 m_u32RadioParameter;
- B_UINT32 m_u32PhyParameter1;
- B_UINT32 m_u32PhyParameter2;
- B_UINT32 m_u32PhyParameter3;
+ * bit 1: 1 Idlemode enable;
+ * bit 2: 1 Sleepmode Enable
+ */
+ B_UINT32 m_u32PowerSavingModesEnable;
+ /* PowerSaving Mode Options:
+ * bit 0 = 1: CPE mode - to keep pcmcia if alive;
+ * bit 1 = 1: CINR reporing in Idlemode Msg
+ * bit 2 = 1: Default PSC Enable in sleepmode
+ */
+ B_UINT32 m_u32PowerSavingModeOptions;
+
+ B_UINT32 m_u32ArqEnable;
+
+ /* From Version #3, the HARQ section renamed as general */
+ B_UINT32 m_u32HarqEnable;
+ /* EEPROM Param Location */
+ B_UINT32 m_u32EEPROMFlag;
+ /* BINARY TYPE - 4th MSByte:
+ * Interface Type - 3rd MSByte:
+ * Vendor Type - 2nd MSByte
+ */
+ /* Unused - LSByte */
+ B_UINT32 m_u32Customize;
+ B_UINT32 m_u32ConfigBW; /* In Hz */
+ B_UINT32 m_u32ShutDownTimer;
+ B_UINT32 m_u32RadioParameter;
+ B_UINT32 m_u32PhyParameter1;
+ B_UINT32 m_u32PhyParameter2;
+ B_UINT32 m_u32PhyParameter3;
/* in eval mode only;
- * lower 16bits = basic cid for testing;
- * then bit 16 is test cqich,
- * bit 17 test init rang;
- * bit 18 test periodic rang
- * bit 19 is test harq ack/nack
- */
- B_UINT32 m_u32TestOptions;
-
+ * lower 16bits = basic cid for testing;
+ * then bit 16 is test cqich,
+ * bit 17 test init rang;
+ * bit 18 test periodic rang
+ * bit 19 is test harq ack/nack
+ */
+ B_UINT32 m_u32TestOptions;
B_UINT32 m_u32MaxMACDataperDLFrame;
B_UINT32 m_u32MaxMACDataperULFrame;
-
B_UINT32 m_u32Corr2MacFlags;
- //adding driver params.
- B_UINT32 HostDrvrConfig1;
- B_UINT32 HostDrvrConfig2;
- B_UINT32 HostDrvrConfig3;
- B_UINT32 HostDrvrConfig4;
- B_UINT32 HostDrvrConfig5;
- B_UINT32 HostDrvrConfig6;
- B_UINT32 m_u32SegmentedPUSCenable;
-
- // BAMC enable - but 4.x does not support this feature
- // This is added just to sync 4.x and 5.x CFGs
+ /* adding driver params. */
+ B_UINT32 HostDrvrConfig1;
+ B_UINT32 HostDrvrConfig2;
+ B_UINT32 HostDrvrConfig3;
+ B_UINT32 HostDrvrConfig4;
+ B_UINT32 HostDrvrConfig5;
+ B_UINT32 HostDrvrConfig6;
+ B_UINT32 m_u32SegmentedPUSCenable;
+
+ /* BAMC enable - but 4.x does not support this feature
+ * This is added just to sync 4.x and 5.x CFGs
+ */
B_UINT32 m_u32BandAMCEnable;
} STARGETPARAMS, *PSTARGETPARAMS;
#endif
-typedef struct _STTARGETDSXBUFFER
-{
- ULONG ulTargetDsxBuffer;
- B_UINT16 tid;
- BOOLEAN valid;
-}STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
+typedef struct _STTARGETDSXBUFFER {
+ ULONG ulTargetDsxBuffer;
+ B_UINT16 tid;
+ BOOLEAN valid;
+} STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
-typedef INT (*FP_FLASH_WRITE)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE)(struct _MINI_ADAPTER *, UINT, PVOID);
-typedef INT (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER *, UINT, PVOID);
-/**
-Driver adapter data structure
-*/
-struct _MINI_ADAPTER
-{
- struct _MINI_ADAPTER *next;
+/*
+ * Driver adapter data structure
+ */
+struct _MINI_ADAPTER {
+ struct _MINI_ADAPTER *next;
struct net_device *dev;
u32 msg_enable;
-
- CHAR *caDsxReqResp;
+ CHAR *caDsxReqResp;
atomic_t ApplicationRunning;
- volatile INT CtrlQueueLen;
- atomic_t AppCtrlQueueLen;
- BOOLEAN AppCtrlQueueOverFlow;
+ BOOLEAN AppCtrlQueueOverFlow;
atomic_t CurrentApplicationCount;
- atomic_t RegisteredApplicationCount;
- BOOLEAN LinkUpStatus;
- BOOLEAN TimerActive;
+ atomic_t RegisteredApplicationCount;
+ BOOLEAN LinkUpStatus;
+ BOOLEAN TimerActive;
u32 StatisticsPointer;
struct sk_buff *RxControlHead;
struct sk_buff *RxControlTail;
-
struct semaphore RxAppControlQueuelock;
struct semaphore fw_download_sema;
-
- PPER_TARANG_DATA pTarangs;
- spinlock_t control_queue_lock;
+ PPER_TARANG_DATA pTarangs;
+ spinlock_t control_queue_lock;
wait_queue_head_t process_read_wait_queue;
- // the pointer to the first packet we have queued in send
- // deserialized miniport support variables
- atomic_t TotalPacketCount;
- atomic_t TxPktAvail;
-
- // this to keep track of the Tx and Rx MailBox Registers.
- atomic_t CurrNumFreeTxDesc;
- // to keep track the no of byte received
- USHORT PrevNumRecvDescs;
- USHORT CurrNumRecvDescs;
- UINT u32TotalDSD;
- PacketInfo PackInfo[NO_OF_QUEUES];
+ /* the pointer to the first packet we have queued in send
+ * deserialized miniport support variables
+ */
+ atomic_t TotalPacketCount;
+ atomic_t TxPktAvail;
+
+ /* this to keep track of the Tx and Rx MailBox Registers. */
+ atomic_t CurrNumFreeTxDesc;
+ /* to keep track the no of byte received */
+ USHORT PrevNumRecvDescs;
+ USHORT CurrNumRecvDescs;
+ UINT u32TotalDSD;
+ PacketInfo PackInfo[NO_OF_QUEUES];
S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS];
- BOOLEAN TransferMode;
+ BOOLEAN TransferMode;
/*************** qos ******************/
- BOOLEAN bETHCSEnabled;
-
- ULONG BEBucketSize;
- ULONG rtPSBucketSize;
- UCHAR LinkStatus;
- BOOLEAN AutoLinkUp;
- BOOLEAN AutoSyncup;
-
- int major;
- int minor;
- wait_queue_head_t tx_packet_wait_queue;
- wait_queue_head_t process_rx_cntrlpkt;
- atomic_t process_waiting;
- BOOLEAN fw_download_done;
-
- char *txctlpacket[MAX_CNTRL_PKTS];
- atomic_t cntrlpktCnt ;
- atomic_t index_app_read_cntrlpkt;
- atomic_t index_wr_txcntrlpkt;
- atomic_t index_rd_txcntrlpkt;
- UINT index_datpkt;
- struct semaphore rdmwrmsync;
+ BOOLEAN bETHCSEnabled;
+ ULONG BEBucketSize;
+ ULONG rtPSBucketSize;
+ UCHAR LinkStatus;
+ BOOLEAN AutoLinkUp;
+ BOOLEAN AutoSyncup;
+
+ int major;
+ int minor;
+ wait_queue_head_t tx_packet_wait_queue;
+ wait_queue_head_t process_rx_cntrlpkt;
+ atomic_t process_waiting;
+ BOOLEAN fw_download_done;
+
+ char *txctlpacket[MAX_CNTRL_PKTS];
+ atomic_t cntrlpktCnt ;
+ atomic_t index_app_read_cntrlpkt;
+ atomic_t index_wr_txcntrlpkt;
+ atomic_t index_rd_txcntrlpkt;
+ UINT index_datpkt;
+ struct semaphore rdmwrmsync;
STTARGETDSXBUFFER astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
ULONG ulFreeTargetBufferCnt;
- ULONG ulCurrentTargetBuffer;
- ULONG ulTotalTargetBuffersAvailable;
-
- unsigned long chip_id;
-
- wait_queue_head_t lowpower_mode_wait_queue;
-
+ ULONG ulCurrentTargetBuffer;
+ ULONG ulTotalTargetBuffersAvailable;
+ unsigned long chip_id;
+ wait_queue_head_t lowpower_mode_wait_queue;
BOOLEAN bFlashBoot;
BOOLEAN bBinDownloaded;
BOOLEAN bCfgDownloaded;
BOOLEAN bSyncUpRequestSent;
USHORT usBestEffortQueueIndex;
-
- wait_queue_head_t ioctl_fw_dnld_wait_queue;
- BOOLEAN waiting_to_fw_download_done;
- pid_t fw_download_process_pid;
+ wait_queue_head_t ioctl_fw_dnld_wait_queue;
+ BOOLEAN waiting_to_fw_download_done;
+ pid_t fw_download_process_pid;
PSTARGETPARAMS pstargetparams;
- BOOLEAN device_removed;
- BOOLEAN DeviceAccess;
- BOOLEAN bIsAutoCorrectEnabled;
- BOOLEAN bDDRInitDone;
- INT DDRSetting;
- ULONG ulPowerSaveMode;
- spinlock_t txtransmitlock;
- B_UINT8 txtransmit_running;
+ BOOLEAN device_removed;
+ BOOLEAN DeviceAccess;
+ BOOLEAN bIsAutoCorrectEnabled;
+ BOOLEAN bDDRInitDone;
+ int DDRSetting;
+ ULONG ulPowerSaveMode;
+ spinlock_t txtransmitlock;
+ B_UINT8 txtransmit_running;
/* Thread for control packet handling */
- struct task_struct *control_packet_handler;
+ struct task_struct *control_packet_handler;
/* thread for transmitting packets. */
- struct task_struct *transmit_packet_thread;
+ struct task_struct *transmit_packet_thread;
/* LED Related Structures */
LED_INFO_STRUCT LEDInfo;
@@ -482,39 +438,38 @@ struct _MINI_ADAPTER
/* Driver State for LED Blinking */
LedEventInfo_t DriverState;
/* Interface Specific */
- PVOID pvInterfaceAdapter;
- int (*bcm_file_download)( PVOID,
- struct file *,
- unsigned int);
- int (*bcm_file_readback_from_chip)( PVOID,
- struct file *,
- unsigned int);
- INT (*interface_rdm)(PVOID,
- UINT ,
- PVOID ,
- INT);
- INT (*interface_wrm)(PVOID,
- UINT ,
- PVOID ,
- INT);
+ PVOID pvInterfaceAdapter;
+ int (*bcm_file_download)(PVOID,
+ struct file *,
+ unsigned int);
+ int (*bcm_file_readback_from_chip)(PVOID,
+ struct file *,
+ unsigned int);
+ int (*interface_rdm)(PVOID,
+ UINT,
+ PVOID,
+ int);
+ int (*interface_wrm)(PVOID,
+ UINT,
+ PVOID,
+ int);
int (*interface_transmit)(PVOID, PVOID , UINT);
BOOLEAN IdleMode;
BOOLEAN bDregRequestSentInIdleMode;
BOOLEAN bTriedToWakeUpFromlowPowerMode;
BOOLEAN bShutStatus;
BOOLEAN bWakeUpDevice;
- unsigned int usIdleModePattern;
- //BOOLEAN bTriedToWakeUpFromShutdown;
+ unsigned int usIdleModePattern;
+ /* BOOLEAN bTriedToWakeUpFromShutdown; */
BOOLEAN bLinkDownRequested;
-
- int downloadDDR;
- PHS_DEVICE_EXTENSION stBCMPhsContext;
- S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
+ int downloadDDR;
+ PHS_DEVICE_EXTENSION stBCMPhsContext;
+ S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
uint8_t ucaPHSPktRestoreBuf[2048];
uint8_t bPHSEnabled;
BOOLEAN AutoFirmDld;
- BOOLEAN bMipsConfig;
- BOOLEAN bDPLLConfig;
+ BOOLEAN bMipsConfig;
+ BOOLEAN bDPLLConfig;
UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
UINT32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
S_FRAGMENTED_PACKET_INFO astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
@@ -527,108 +482,101 @@ struct _MINI_ADAPTER
BOOLEAN bStatusWrite;
UINT uiNVMDSDSize;
UINT uiVendorExtnFlag;
- //it will always represent chosen DSD at any point of time.
- // Generally it is Active DSD but in case of NVM RD/WR it might be different.
+ /* it will always represent chosen DSD at any point of time.
+ * Generally it is Active DSD but in case of NVM RD/WR it might be different.
+ */
UINT ulFlashCalStart;
- ULONG ulFlashControlSectionStart;
- ULONG ulFlashWriteSize;
- ULONG ulFlashID;
- FP_FLASH_WRITE fpFlashWrite;
- FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck;
-
+ ULONG ulFlashControlSectionStart;
+ ULONG ulFlashWriteSize;
+ ULONG ulFlashID;
+ FP_FLASH_WRITE fpFlashWrite;
+ FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck;
struct semaphore NVMRdmWrmLock;
+ struct device *pstCreatedClassDevice;
- struct device *pstCreatedClassDevice;
-
-// BOOLEAN InterfaceUpStatus;
- PFLASH2X_CS_INFO psFlash2xCSInfo;
- PFLASH_CS_INFO psFlashCSInfo ;
+ /* BOOLEAN InterfaceUpStatus; */
+ PFLASH2X_CS_INFO psFlash2xCSInfo;
+ PFLASH_CS_INFO psFlashCSInfo;
PFLASH2X_VENDORSPECIFIC_INFO psFlash2xVendorInfo;
- UINT uiFlashBaseAdd; //Flash start address
- UINT uiActiveISOOffset; //Active ISO offset chosen before f/w download
- FLASH2X_SECTION_VAL eActiveISO; //Active ISO section val
- FLASH2X_SECTION_VAL eActiveDSD; //Active DSD val chosen before f/w download
- UINT uiActiveDSDOffsetAtFwDld; //For accessing Active DSD chosen before f/w download
- UINT uiFlashLayoutMajorVersion ;
- UINT uiFlashLayoutMinorVersion;
- BOOLEAN bAllDSDWriteAllow ;
- BOOLEAN bSigCorrupted ;
- //this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately.
- BOOLEAN bHeaderChangeAllowed ;
- INT SelectedChip ;
- BOOLEAN bEndPointHalted;
- //while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map.
- BOOLEAN bFlashRawRead;
- BOOLEAN bPreparingForLowPowerMode ;
- BOOLEAN bDoSuspend ;
- UINT syscfgBefFwDld ;
- BOOLEAN StopAllXaction ;
- UINT32 liTimeSinceLastNetEntry; //Used to Support extended CAPI requirements from
+ UINT uiFlashBaseAdd; /* Flash start address */
+ UINT uiActiveISOOffset; /* Active ISO offset chosen before f/w download */
+ FLASH2X_SECTION_VAL eActiveISO; /* Active ISO section val */
+ FLASH2X_SECTION_VAL eActiveDSD; /* Active DSD val chosen before f/w download */
+ UINT uiActiveDSDOffsetAtFwDld; /* For accessing Active DSD chosen before f/w download */
+ UINT uiFlashLayoutMajorVersion;
+ UINT uiFlashLayoutMinorVersion;
+ BOOLEAN bAllDSDWriteAllow;
+ BOOLEAN bSigCorrupted;
+ /* this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately. */
+ BOOLEAN bHeaderChangeAllowed;
+ int SelectedChip;
+ BOOLEAN bEndPointHalted;
+ /* while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map. */
+ BOOLEAN bFlashRawRead;
+ BOOLEAN bPreparingForLowPowerMode;
+ BOOLEAN bDoSuspend;
+ UINT syscfgBefFwDld;
+ BOOLEAN StopAllXaction;
+ UINT32 liTimeSinceLastNetEntry; /* Used to Support extended CAPI requirements from */
struct semaphore LowPowerModeSync;
- ULONG liDrainCalculated;
- UINT gpioBitMap;
-
- S_BCM_DEBUG_STATE stDebugState;
-
+ ULONG liDrainCalculated;
+ UINT gpioBitMap;
+ S_BCM_DEBUG_STATE stDebugState;
};
typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
-#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
+#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
struct _ETH_HEADER_STRUC {
- UCHAR au8DestinationAddress[6];
- UCHAR au8SourceAddress[6];
- USHORT u16Etype;
-}__attribute__((packed));
+ UCHAR au8DestinationAddress[6];
+ UCHAR au8SourceAddress[6];
+ USHORT u16Etype;
+} __packed;
typedef struct _ETH_HEADER_STRUC ETH_HEADER_STRUC, *PETH_HEADER_STRUC;
+typedef struct FirmwareInfo {
+ void __user *pvMappedFirmwareAddress;
+ ULONG u32FirmwareLength;
+ ULONG u32StartingAddress;
+} __packed FIRMWARE_INFO, *PFIRMWARE_INFO;
-typedef struct FirmwareInfo
-{
- void __user * pvMappedFirmwareAddress;
- ULONG u32FirmwareLength;
- ULONG u32StartingAddress;
-}__attribute__((packed)) FIRMWARE_INFO, *PFIRMWARE_INFO;
-
-// holds the value of net_device structure..
+/* holds the value of net_device structure.. */
extern struct net_device *gblpnetdev;
-typedef struct _cntl_pkt{
- PMINI_ADAPTER Adapter;
- PLEADER PLeader;
-}cntl_pkt;
+typedef struct _cntl_pkt {
+ PMINI_ADAPTER Adapter;
+ PLEADER PLeader;
+} cntl_pkt;
typedef LINK_REQUEST CONTROL_MESSAGE;
-typedef struct _DDR_SETTING
-{
+typedef struct _DDR_SETTING {
UINT ulRegAddress;
UINT ulRegValue;
-}DDR_SETTING, *PDDR_SETTING;
+} DDR_SETTING, *PDDR_SETTING;
typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE;
-INT
-InitAdapter(PMINI_ADAPTER psAdapter);
-
-// =====================================================================
-// Beceem vendor request codes for EP0
-// =====================================================================
+int InitAdapter(PMINI_ADAPTER psAdapter);
-#define BCM_REQUEST_READ 0x2
-#define BCM_REQUEST_WRITE 0x1
-#define EP2_MPS_REG 0x0F0110A0
-#define EP2_MPS 0x40
+/* =====================================================================
+ * Beceem vendor request codes for EP0
+ * =====================================================================
+ */
-#define EP2_CFG_REG 0x0F0110A8
-#define EP2_CFG_INT 0x27
-#define EP2_CFG_BULK 0x25
+#define BCM_REQUEST_READ 0x2
+#define BCM_REQUEST_WRITE 0x1
+#define EP2_MPS_REG 0x0F0110A0
+#define EP2_MPS 0x40
-#define EP4_MPS_REG 0x0F0110F0
-#define EP4_MPS 0x8C
+#define EP2_CFG_REG 0x0F0110A8
+#define EP2_CFG_INT 0x27
+#define EP2_CFG_BULK 0x25
-#define EP4_CFG_REG 0x0F0110F8
+#define EP4_MPS_REG 0x0F0110F0
+#define EP4_MPS 0x8C
-#define ISO_MPS_REG 0x0F0110C8
-#define ISO_MPS 0x00000000
+#define EP4_CFG_REG 0x0F0110F8
+#define ISO_MPS_REG 0x0F0110C8
+#define ISO_MPS 0x00000000
#define EP1 0
#define EP2 1
@@ -637,12 +585,9 @@ InitAdapter(PMINI_ADAPTER psAdapter);
#define EP5 4
#define EP6 5
-
-typedef enum eInterface_setting
-{
+typedef enum eInterface_setting {
DEFAULT_SETTING_0 = 0,
ALTERNATE_SETTING_1 = 1,
-}INTERFACE_SETTING;
-
-#endif //__ADAPTER_H__
+} INTERFACE_SETTING;
+#endif /* __ADAPTER_H__ */
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 1c7db81..2b46f4d 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -1115,20 +1115,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3LP_DDRSetting80MHz;
- RegCount = (sizeof(asT3LP_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting80MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3LP_DDRSetting100MHz;
- RegCount = (sizeof(asT3LP_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting100MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LP_DDRSetting133MHz;
- RegCount = (sizeof(asT3LP_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting133MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
@@ -1146,20 +1146,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3LPB_DDRSetting80MHz;
- RegCount=(sizeof(asT3LPB_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount=ARRAY_SIZE(asT3LPB_DDRSetting80MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3LPB_DDRSetting100MHz;
- RegCount = (sizeof(asT3LPB_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting100MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LPB_DDRSetting133MHz;
- RegCount = (sizeof(asT3LPB_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting133MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
@@ -1167,7 +1167,7 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
case DDR_160_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LPB_DDRSetting160MHz;
- RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SET_NODE);
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting160MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
@@ -1181,19 +1181,19 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3_DDRSetting80MHz;
- RegCount = (sizeof(asT3_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting80MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3_DDRSetting100MHz;
- RegCount = (sizeof(asT3_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting100MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
psDDRSetting = asT3_DDRSetting133MHz;
- RegCount = (sizeof(asT3_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting133MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
break;
@@ -1207,20 +1207,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3B_DDRSetting80MHz;
- RegCount = (sizeof(asT3B_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting80MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3B_DDRSetting100MHz;
- RegCount = (sizeof(asT3B_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting100MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3B_DDRSetting133MHz;
- RegCount = (sizeof(asT3B_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting133MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
index 5b4fd37..1da2164 100644
--- a/drivers/staging/bcm/IPv6Protocol.c
+++ b/drivers/staging/bcm/IPv6Protocol.c
@@ -1,51 +1,52 @@
#include "headers.h"
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header);
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header);
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
-static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
+static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
+ UCHAR *pucNextHeader, BOOLEAN *bParseDone, USHORT *pusPayloadLength)
{
UCHAR *pucRetHeaderPtr = NULL;
UCHAR *pucPayloadPtr = NULL;
USHORT usNextHeaderOffset = 0 ;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if((NULL == ppucPayload) || (*pusPayloadLength == 0) || (*bParseDone))
- {
+ if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
+ (*bParseDone)) {
*bParseDone = TRUE;
return NULL;
-
}
pucRetHeaderPtr = *ppucPayload;
pucPayloadPtr = *ppucPayload;
- if(!pucRetHeaderPtr || !pucPayloadPtr)
- {
+ if (!pucRetHeaderPtr || !pucPayloadPtr) {
*bParseDone = TRUE;
return NULL;
}
- //Get the Nextt Header Type
+ /* Get the Nextt Header Type */
*bParseDone = FALSE;
-
- switch(*pucNextHeader)
- {
+ switch (*pucNextHeader) {
case IPV6HDR_TYPE_HOPBYHOP:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 HopByHop Header");
- usNextHeaderOffset+=sizeof(IPV6HopByHopOptionsHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 HopByHop Header");
+ usNextHeaderOffset += sizeof(IPV6HopByHopOptionsHeader);
}
break;
case IPV6HDR_TYPE_ROUTING:
{
IPV6RoutingHeader *pstIpv6RoutingHeader;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Routing Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Routing Header");
pstIpv6RoutingHeader = (IPV6RoutingHeader *)pucPayloadPtr;
usNextHeaderOffset += sizeof(IPV6RoutingHeader);
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES;
@@ -54,8 +55,10 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
break;
case IPV6HDR_TYPE_FRAGMENTATION:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Fragmentation Header");
- usNextHeaderOffset+= sizeof(IPV6FragmentHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Fragmentation Header");
+ usNextHeaderOffset += sizeof(IPV6FragmentHeader);
}
break;
@@ -63,9 +66,11 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
{
IPV6DestOptionsHeader *pstIpv6DestOptsHdr = (IPV6DestOptionsHeader *)pucPayloadPtr;
int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 DestOpts Header Header");
- usNextHeaderOffset+= sizeof(IPV6DestOptionsHeader);
- usNextHeaderOffset+= nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 DestOpts Header Header");
+ usNextHeaderOffset += sizeof(IPV6DestOptionsHeader);
+ usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
}
break;
@@ -73,36 +78,43 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
{
IPV6AuthenticationHeader *pstIpv6AuthHdr = (IPV6AuthenticationHeader *)pucPayloadPtr;
int nHdrLen = pstIpv6AuthHdr->ucLength;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Authentication Header");
- usNextHeaderOffset+= nHdrLen * 4;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Authentication Header");
+ usNextHeaderOffset += nHdrLen * 4;
}
break;
case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Encrypted Security Payload Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Encrypted Security Payload Header");
*bParseDone = TRUE;
}
break;
case IPV6_ICMP_HDR_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " ICMP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nICMP Header");
*bParseDone = TRUE;
}
break;
case TCP_HEADER_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nTCP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nTCP Header");
*bParseDone = TRUE;
}
break;
case UDP_HEADER_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nUDP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nUDP Header");
*bParseDone = TRUE;
}
break;
- default :
+ default:
{
*bParseDone = TRUE;
@@ -112,53 +124,49 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
}
- if(*bParseDone == FALSE)
- {
- if(*pusPayloadLength <= usNextHeaderOffset)
- {
+ if (*bParseDone == FALSE) {
+ if (*pusPayloadLength <= usNextHeaderOffset) {
*bParseDone = TRUE;
- }
- else
- {
+ } else {
*pucNextHeader = *pucPayloadPtr;
- pucPayloadPtr+=usNextHeaderOffset;
- (*pusPayloadLength)-=usNextHeaderOffset;
+ pucPayloadPtr += usNextHeaderOffset;
+ (*pusPayloadLength) -= usNextHeaderOffset;
}
}
-
-
*ppucPayload = pucPayloadPtr;
return pucRetHeaderPtr;
}
-static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *pusDestPort,USHORT usPayloadLength,UCHAR ucNextHeader)
+static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
+ USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader)
{
UCHAR *pIpv6HdrScanContext = pucPayload;
BOOLEAN bDone = FALSE;
- UCHAR ucHeaderType =0;
+ UCHAR ucHeaderType = 0;
UCHAR *pucNextHeader = NULL;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if( !pucPayload || (usPayloadLength == 0))
- {
+ if (!pucPayload || (usPayloadLength == 0))
return 0;
- }
*pusSrcPort = *pusDestPort = 0;
ucHeaderType = ucNextHeader;
- while(!bDone)
- {
- pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,&ucHeaderType,&bDone,&usPayloadLength);
- if(bDone)
- {
- if((ucHeaderType==TCP_HEADER_TYPE) || (ucHeaderType == UDP_HEADER_TYPE))
- {
- *pusSrcPort=*((PUSHORT)(pucNextHeader));
- *pusDestPort=*((PUSHORT)(pucNextHeader+2));
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",ntohs(*pusSrcPort),ntohs(*pusDestPort));
+ while (!bDone) {
+ pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,
+ &ucHeaderType, &bDone, &usPayloadLength);
+ if (bDone) {
+ if ((ucHeaderType == TCP_HEADER_TYPE) ||
+ (ucHeaderType == UDP_HEADER_TYPE)) {
+ *pusSrcPort = *((PUSHORT)(pucNextHeader));
+ *pusDestPort = *((PUSHORT)(pucNextHeader+2));
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",
+ ntohs(*pusSrcPort),
+ ntohs(*pusDestPort));
}
break;
@@ -168,92 +176,111 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *p
}
-
-USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
- PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
- S_CLASSIFIER_RULE *pstClassifierRule )
+/*
+ * Arg 1 PMINI_ADAPTER Adapter is a pointer ot the driver contorl structure
+ * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
+ */
+USHORT IpVersion6(PMINI_ADAPTER Adapter, PVOID pcIpHeader,
+ S_CLASSIFIER_RULE *pstClassifierRule)
{
USHORT ushDestPort = 0;
USHORT ushSrcPort = 0;
- UCHAR ucNextProtocolAboveIP =0;
+ UCHAR ucNextProtocolAboveIP = 0;
IPV6Header *pstIpv6Header = NULL;
BOOLEAN bClassificationSucceed = FALSE;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "IpVersion6 ==========>\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "IpVersion6 ==========>\n");
pstIpv6Header = (IPV6Header *)pcIpHeader;
DumpIpv6Header(pstIpv6Header);
- //Try to get the next higher layer protocol and the Ports Nos if TCP or UDP
+ /*
+ * Try to get the next higher layer protocol
+ * and the Ports Nos if TCP or UDP
+ */
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(IPV6Header)),
&ushSrcPort,
&ushDestPort,
pstIpv6Header->usPayloadLength,
pstIpv6Header->ucNextHeader);
- do
- {
- if(0 == pstClassifierRule->ucDirection)
- {
- //cannot be processed for classification.
- // it is a down link connection
+ do {
+ if (pstClassifierRule->ucDirection == 0) {
+ /*
+ * cannot be processed for classification.
+ * it is a down link connection
+ */
break;
}
- if(!pstClassifierRule->bIpv6Protocol)
- {
- //We are looking for Ipv6 Classifiers . Lets ignore this classifier and try the next one.
+ if (!pstClassifierRule->bIpv6Protocol) {
+ /*
+ * We are looking for Ipv6 Classifiers
+ * Lets ignore this classifier and try the next one
+ */
break;
}
- bClassificationSucceed=MatchSrcIpv6Address(pstClassifierRule,pstIpv6Header);
- if(!bClassificationSucceed)
- break;
+ bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule,
+ pstIpv6Header);
+ if (!bClassificationSucceed)
+ break;
- bClassificationSucceed=MatchDestIpv6Address(pstClassifierRule,pstIpv6Header);
- if(!bClassificationSucceed)
- break;
+ bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule,
+ pstIpv6Header);
+ if (!bClassificationSucceed)
+ break;
- //Match the protocol type.For IPv6 the next protocol at end of Chain of IPv6 prot headers
- bClassificationSucceed=MatchProtocol(pstClassifierRule,ucNextProtocolAboveIP);
- if(!bClassificationSucceed)
- break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+ /*
+ * Match the protocol type.
+ * For IPv6 the next protocol at end of
+ * Chain of IPv6 prot headers
+ */
+ bClassificationSucceed = MatchProtocol(pstClassifierRule,
+ ucNextProtocolAboveIP);
+ if (!bClassificationSucceed)
+ break;
- if((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || (ucNextProtocolAboveIP == UDP_HEADER_TYPE))
- {
- //Match Src Port
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",ntohs(ushSrcPort));
- bClassificationSucceed=MatchSrcPort(pstClassifierRule,ntohs(ushSrcPort));
- if(!bClassificationSucceed)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+
+ if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) ||
+ (ucNextProtocolAboveIP == UDP_HEADER_TYPE)) {
+ /* Match Src Port */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",
+ ntohs(ushSrcPort));
+ bClassificationSucceed = MatchSrcPort(pstClassifierRule,
+ ntohs(ushSrcPort));
+ if (!bClassificationSucceed)
break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Src Port Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Src Port Matched");
- //Match Dest Port
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",ntohs(ushDestPort));
- bClassificationSucceed=MatchDestPort(pstClassifierRule,ntohs(ushDestPort));
- if(!bClassificationSucceed)
+ /* Match Dest Port */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",
+ ntohs(ushDestPort));
+ bClassificationSucceed = MatchDestPort(pstClassifierRule,
+ ntohs(ushDestPort));
+ if (!bClassificationSucceed)
break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
}
- }while(0);
+ } while (0);
- if(TRUE==bClassificationSucceed)
- {
+ if (bClassificationSucceed == TRUE) {
INT iMatchedSFQueueIndex = 0;
- iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
- if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
- {
+ iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
+ if (iMatchedSFQueueIndex >= NO_OF_QUEUES) {
bClassificationSucceed = FALSE;
- }
- else
- {
- if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
- {
+ } else {
+ if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == FALSE)
bClassificationSucceed = FALSE;
- }
}
}
@@ -261,52 +288,55 @@ USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
}
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header)
{
- UINT uiLoopIndex=0;
- UINT uiIpv6AddIndex=0;
- UINT uiIpv6AddrNoLongWords = 4;
+ UINT uiLoopIndex = 0;
+ UINT uiIpv6AddIndex = 0;
+ UINT uiIpv6AddrNoLongWords = 4;
ULONG aulSrcIP[4];
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
- //This is the no. of Src Addresses ie Range of IP Addresses contained
- //in the classifier rule for which we need to match
- */
+ * This is the no. of Src Addresses ie Range of IP Addresses contained
+ * in the classifier rule for which we need to match
+ */
UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength;
- if(0 == uiCountIPSrcAddresses)
+ if (uiCountIPSrcAddresses == 0)
return TRUE;
- //First Convert the Ip Address in the packet to Host Endian order
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- aulSrcIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
- }
+ /* First Convert the Ip Address in the packet to Host Endian order */
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+ aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
- for(uiLoopIndex=0;uiLoopIndex<uiCountIPSrcAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Received Packet : \n ");
+ for (uiLoopIndex = 0; uiLoopIndex < uiCountIPSrcAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulSrcIP);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Mask In Classifier Rule: \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Mask In Classifier Rule:\n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Classifier Rule : \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- if((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
- != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
- {
- //Match failed for current Ipv6 Address.Try next Ipv6 Address
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
+ != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+ /*
+ * Match failed for current Ipv6 Address
+ * Try next Ipv6 Address
+ */
break;
}
- if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
- {
- //Match Found
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Src Ip Address Matched\n");
+ if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
+ /* Match Found */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "Ipv6 Src Ip Address Matched\n");
return TRUE;
}
}
@@ -314,52 +344,56 @@ static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Head
return FALSE;
}
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header)
{
- UINT uiLoopIndex=0;
- UINT uiIpv6AddIndex=0;
- UINT uiIpv6AddrNoLongWords = 4;
+ UINT uiLoopIndex = 0;
+ UINT uiIpv6AddIndex = 0;
+ UINT uiIpv6AddrNoLongWords = 4;
ULONG aulDestIP[4];
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
- //This is the no. of Destination Addresses ie Range of IP Addresses contained
- //in the classifier rule for which we need to match
- */
+ * This is the no. of Destination Addresses
+ * ie Range of IP Addresses contained in the classifier rule
+ * for which we need to match
+ */
UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength;
- if(0 == uiCountIPDestinationAddresses)
+ if (uiCountIPDestinationAddresses == 0)
return TRUE;
- //First Convert the Ip Address in the packet to Host Endian order
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- aulDestIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
- }
+ /* First Convert the Ip Address in the packet to Host Endian order */
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+ aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
- for(uiLoopIndex=0;uiLoopIndex<uiCountIPDestinationAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Received Packet : \n ");
+ for (uiLoopIndex = 0; uiLoopIndex < uiCountIPDestinationAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulDestIP);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Mask In Classifier Rule: \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Mask In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Classifier Rule : \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- if((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
- != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
- {
- //Match failed for current Ipv6 Address.Try next Ipv6 Address
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
+ != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+ /*
+ * Match failed for current Ipv6 Address.
+ * Try next Ipv6 Address
+ */
break;
}
- if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
- {
- //Match Found
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Destination Ip Address Matched\n");
+ if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
+ /* Match Found */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "Ipv6 Destination Ip Address Matched\n");
return TRUE;
}
}
@@ -371,11 +405,11 @@ static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Hea
VOID DumpIpv6Address(ULONG *puIpv6Address)
{
UINT uiIpv6AddrNoLongWords = 4;
- UINT uiIpv6AddIndex=0;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, ":%lx",puIpv6Address[uiIpv6AddIndex]);
+ UINT uiIpv6AddIndex = 0;
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ ":%lx", puIpv6Address[uiIpv6AddIndex]);
}
}
@@ -383,22 +417,35 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
{
UCHAR ucVersion;
- UCHAR ucPrio ;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header---");
+ UCHAR ucPrio;
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "----Ipv6 Header---");
ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Version : %x \n",ucVersion);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Version : %x\n", ucVersion);
ucPrio = pstIpv6Header->ucVersionPrio & 0x0f;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Priority : %x \n",ucPrio);
- //BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Flow Label : %x \n",(pstIpv6Header->ucVersionPrio &0xf0);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Payload Length : %x \n",ntohs(pstIpv6Header->usPayloadLength));
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Next Header : %x \n",pstIpv6Header->ucNextHeader);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Hop Limit : %x \n",pstIpv6Header->ucHopLimit);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Src Address :\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Priority : %x\n", ucPrio);
+ /*
+ * BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ * "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0);
+ */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Payload Length : %x\n",
+ ntohs(pstIpv6Header->usPayloadLength));
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Next Header : %x\n", pstIpv6Header->ucNextHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Hop Limit : %x\n", pstIpv6Header->ucHopLimit);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Src Address :\n");
DumpIpv6Address(pstIpv6Header->ulSrcIpAddress);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Dest Address :\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Dest Address :\n");
DumpIpv6Address(pstIpv6Header->ulDestIpAddress);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header End---");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "----Ipv6 Header End---");
}
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index c7725e1..8223a69 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -835,7 +835,7 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter)
Bcm_kill_all_URBs(psIntfAdapter);
/* Reset the UMA-B Device */
if (ps_adapter->chip_id >= T3LPB) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reseting UMA-B\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Resetting UMA-B\n");
retval = usb_reset_device(psIntfAdapter->udev);
psIntfAdapter->psAdapter->StopAllXaction = FALSE;
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
new file mode 100644
index 0000000..ff05e52
--- /dev/null
+++ b/drivers/staging/ccg/Kconfig
@@ -0,0 +1,20 @@
+if USB_GADGET
+
+config USB_G_CCG
+ tristate "Configurable Composite Gadget (STAGING)"
+ depends on STAGING && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
+ help
+ The Configurable Composite Gadget supports multiple USB
+ functions: acm, mass storage, rndis and FunctionFS.
+ Each function can be configured and enabled/disabled
+ dynamically from userspace through a sysfs interface.
+
+ In order to compile this (either as a module or built-in),
+ "USB Gadget Drivers" and anything under it must not be
+ selected compiled-in in
+ Device Drivers->USB Support->USB Gadget Support.
+ However, you can say "M" there, if you do, the
+ Configurable Composite Gadget can be compiled "M" only
+ or not at all.
+
+endif # USB_GADGET
diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile
new file mode 100644
index 0000000..693da63
--- /dev/null
+++ b/drivers/staging/ccg/Makefile
@@ -0,0 +1,4 @@
+g_ccg-y := ccg.o
+ccflags-y += -Idrivers/usb/gadget
+
+obj-$(CONFIG_USB_G_CCG) += g_ccg.o
diff --git a/drivers/staging/ccg/TODO b/drivers/staging/ccg/TODO
new file mode 100644
index 0000000..18612fe
--- /dev/null
+++ b/drivers/staging/ccg/TODO
@@ -0,0 +1,6 @@
+TODO:
+ - change configuration interface from sysfs to configfs
+
+Please send patches to Greg Kroah-Hartmann <gregkh@linuxfoundation.org>,
+Andrzej Pietrasiewicz <andrzej.p@samsung.com>, and
+Cc: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c
new file mode 100644
index 0000000..a5b36a9
--- /dev/null
+++ b/drivers/staging/ccg/ccg.c
@@ -0,0 +1,1299 @@
+/*
+ * Configurable Composite Gadget
+ *
+ * Initially contributed as "Android Composite Gdaget" by:
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ * Benoit Goby <benoit@android.com>
+ *
+ * Tailoring it to become a generic Configurable Composite Gadget is
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+
+#include "gadget_chips.h"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "../../usb/gadget/usbstring.c"
+#include "../../usb/gadget/config.c"
+#include "../../usb/gadget/epautoconf.c"
+#include "../../usb/gadget/composite.c"
+
+#include "../../usb/gadget/f_mass_storage.c"
+#include "../../usb/gadget/u_serial.c"
+#include "../../usb/gadget/f_acm.c"
+#define USB_ETH_RNDIS y
+#include "../../usb/gadget/f_rndis.c"
+#include "../../usb/gadget/rndis.c"
+#include "../../usb/gadget/u_ether.c"
+#include "../../usb/gadget/f_fs.c"
+
+MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
+MODULE_DESCRIPTION("Configurable Composite USB Gadget");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+static const char longname[] = "Configurable Composite Gadget";
+
+/* Default vendor and product IDs, overridden by userspace */
+#define VENDOR_ID 0x1d6b /* Linux Foundation */
+#define PRODUCT_ID 0x0107
+#define GFS_MAX_DEVS 10
+
+struct ccg_usb_function {
+ char *name;
+ void *config;
+
+ struct device *dev;
+ char *dev_name;
+ struct device_attribute **attributes;
+
+ /* for ccg_dev.enabled_functions */
+ struct list_head enabled_list;
+
+ /* Optional: initialization during gadget bind */
+ int (*init)(struct ccg_usb_function *, struct usb_composite_dev *);
+ /* Optional: cleanup during gadget unbind */
+ void (*cleanup)(struct ccg_usb_function *);
+
+ int (*bind_config)(struct ccg_usb_function *,
+ struct usb_configuration *);
+
+ /* Optional: called when the configuration is removed */
+ void (*unbind_config)(struct ccg_usb_function *,
+ struct usb_configuration *);
+ /* Optional: handle ctrl requests before the device is configured */
+ int (*ctrlrequest)(struct ccg_usb_function *,
+ struct usb_composite_dev *,
+ const struct usb_ctrlrequest *);
+};
+
+struct ffs_obj {
+ const char *name;
+ bool mounted;
+ bool desc_ready;
+ bool used;
+ struct ffs_data *ffs_data;
+};
+
+struct ccg_dev {
+ struct ccg_usb_function **functions;
+ struct list_head enabled_functions;
+ struct usb_composite_dev *cdev;
+ struct device *dev;
+
+ bool enabled;
+ struct mutex mutex;
+ bool connected;
+ bool sw_connected;
+ struct work_struct work;
+
+ unsigned int max_func_num;
+ unsigned int func_num;
+ struct ffs_obj ffs_tab[GFS_MAX_DEVS];
+};
+
+static struct class *ccg_class;
+static struct ccg_dev *_ccg_dev;
+static int ccg_bind_config(struct usb_configuration *c);
+static void ccg_unbind_config(struct usb_configuration *c);
+
+static char func_names_buf[256];
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof(device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = __constant_cpu_to_le16(VENDOR_ID),
+ .idProduct = __constant_cpu_to_le16(PRODUCT_ID),
+ .bcdDevice = __constant_cpu_to_le16(0xffff),
+ .bNumConfigurations = 1,
+};
+
+static struct usb_configuration ccg_config_driver = {
+ .label = "ccg",
+ .unbind = ccg_unbind_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 0xFA, /* 500ma */
+};
+
+static void ccg_work(struct work_struct *data)
+{
+ struct ccg_dev *dev = container_of(data, struct ccg_dev, work);
+ struct usb_composite_dev *cdev = dev->cdev;
+ static char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
+ static char *connected[2] = { "USB_STATE=CONNECTED", NULL };
+ static char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
+ char **uevent_envp = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (cdev->config)
+ uevent_envp = configured;
+ else if (dev->connected != dev->sw_connected)
+ uevent_envp = dev->connected ? connected : disconnected;
+ dev->sw_connected = dev->connected;
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ if (uevent_envp) {
+ kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+ pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
+ } else {
+ pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
+ dev->connected, dev->sw_connected, cdev->config);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* Supported functions initialization */
+
+static struct ffs_obj *functionfs_find_dev(struct ccg_dev *dev,
+ const char *dev_name)
+{
+ int i;
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (strcmp(dev->ffs_tab[i].name, dev_name) == 0)
+ return &dev->ffs_tab[i];
+
+ return NULL;
+}
+
+static bool functionfs_all_ready(struct ccg_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].used && !dev->ffs_tab[i].desc_ready)
+ return false;
+
+ return true;
+}
+
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+ struct ffs_obj *ffs_obj;
+ int ret;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (WARN_ON(ffs_obj->desc_ready)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->ffs_data = ffs;
+
+ if (functionfs_all_ready(_ccg_dev)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->desc_ready = true;
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+ return ret;
+}
+
+static void reset_usb(struct ccg_dev *dev)
+{
+ /* Cancel pending control requests */
+ usb_ep_dequeue(dev->cdev->gadget->ep0, dev->cdev->req);
+ usb_remove_config(dev->cdev, &ccg_config_driver);
+ dev->enabled = false;
+ usb_gadget_disconnect(dev->cdev->gadget);
+}
+
+static void functionfs_closed_callback(struct ffs_data *ffs)
+{
+ struct ffs_obj *ffs_obj;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj)
+ goto done;
+
+ ffs_obj->desc_ready = false;
+
+ if (_ccg_dev->enabled)
+ reset_usb(_ccg_dev);
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+}
+
+static void *functionfs_acquire_dev_callback(const char *dev_name)
+{
+ struct ffs_obj *ffs_dev;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_dev = functionfs_find_dev(_ccg_dev, dev_name);
+ if (!ffs_dev) {
+ ffs_dev = ERR_PTR(-ENODEV);
+ goto done;
+ }
+
+ if (ffs_dev->mounted) {
+ ffs_dev = ERR_PTR(-EBUSY);
+ goto done;
+ }
+ ffs_dev->mounted = true;
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+ return ffs_dev;
+}
+
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+ struct ffs_obj *ffs_dev;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_dev = ffs_data->private_data;
+ if (ffs_dev)
+ ffs_dev->mounted = false;
+
+ mutex_unlock(&_ccg_dev->mutex);
+}
+
+static int functionfs_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ return functionfs_init();
+}
+
+static void functionfs_function_cleanup(struct ccg_usb_function *f)
+{
+ functionfs_cleanup();
+}
+
+static int functionfs_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int i, ret;
+
+ for (i = dev->max_func_num; i--; ) {
+ if (!dev->ffs_tab[i].used)
+ continue;
+ ret = functionfs_bind(dev->ffs_tab[i].ffs_data, c->cdev);
+ if (unlikely(ret < 0)) {
+ while (++i < dev->max_func_num)
+ functionfs_unbind(dev->ffs_tab[i].ffs_data);
+ return ret;
+ }
+ }
+
+ for (i = dev->max_func_num; i--; ) {
+ if (!dev->ffs_tab[i].used)
+ continue;
+ ret = functionfs_bind_config(c->cdev, c,
+ dev->ffs_tab[i].ffs_data);
+ if (unlikely(ret < 0))
+ return ret;
+ }
+
+ return 0;
+}
+
+static void functionfs_function_unbind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int i;
+
+ for (i = dev->max_func_num; i--; )
+ if (dev->ffs_tab[i].ffs_data)
+ functionfs_unbind(dev->ffs_tab[i].ffs_data);
+}
+
+static ssize_t functionfs_user_functions_show(struct device *_dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ char *buff = buf;
+ int i;
+
+ mutex_lock(&dev->mutex);
+
+ for (i = 0; i < dev->max_func_num; i++)
+ buff += snprintf(buff, PAGE_SIZE + buf - buff, "%s,",
+ dev->ffs_tab[i].name);
+
+ mutex_unlock(&dev->mutex);
+
+ if (buff != buf)
+ *(buff - 1) = '\n';
+ return buff - buf;
+}
+
+static ssize_t functionfs_user_functions_store(struct device *_dev,
+ struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ char *name, *b;
+ ssize_t ret = size;
+ int i;
+
+ buff = skip_spaces(buff);
+ if (!*buff)
+ return -EINVAL;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->enabled) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].mounted) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ strlcpy(func_names_buf, buff, sizeof(func_names_buf));
+ b = strim(func_names_buf);
+
+ /* replace the list of functions */
+ dev->max_func_num = 0;
+ while (b) {
+ name = strsep(&b, ",");
+ if (dev->max_func_num == GFS_MAX_DEVS) {
+ ret = -ENOSPC;
+ goto end;
+ }
+ if (functionfs_find_dev(dev, name)) {
+ ret = -EEXIST;
+ continue;
+ }
+ dev->ffs_tab[dev->max_func_num++].name = name;
+ }
+
+end:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR(user_functions, S_IRUGO | S_IWUSR,
+ functionfs_user_functions_show,
+ functionfs_user_functions_store);
+
+static ssize_t functionfs_max_user_functions_show(struct device *_dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d", GFS_MAX_DEVS);
+}
+
+static DEVICE_ATTR(max_user_functions, S_IRUGO,
+ functionfs_max_user_functions_show, NULL);
+
+static struct device_attribute *functionfs_function_attributes[] = {
+ &dev_attr_user_functions,
+ &dev_attr_max_user_functions,
+ NULL
+};
+
+static struct ccg_usb_function functionfs_function = {
+ .name = "fs",
+ .init = functionfs_function_init,
+ .cleanup = functionfs_function_cleanup,
+ .bind_config = functionfs_function_bind_config,
+ .unbind_config = functionfs_function_unbind_config,
+ .attributes = functionfs_function_attributes,
+};
+
+#define MAX_ACM_INSTANCES 4
+struct acm_function_config {
+ int instances;
+};
+
+static int
+acm_function_init(struct ccg_usb_function *f, struct usb_composite_dev *cdev)
+{
+ f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+
+ return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
+}
+
+static void acm_function_cleanup(struct ccg_usb_function *f)
+{
+ gserial_cleanup();
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int
+acm_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ int i;
+ int ret = 0;
+ struct acm_function_config *config = f->config;
+
+ for (i = 0; i < config->instances; i++) {
+ ret = acm_bind_config(c, i);
+ if (ret) {
+ pr_err("Could not bind acm%u config\n", i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t acm_instances_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct acm_function_config *config = f->config;
+ return sprintf(buf, "%d\n", config->instances);
+}
+
+static ssize_t acm_instances_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct acm_function_config *config = f->config;
+ int value;
+ int ret = 0;
+
+ ret = kstrtoint(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ if (value > MAX_ACM_INSTANCES)
+ return -EINVAL;
+
+ config->instances = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show,
+ acm_instances_store);
+static struct device_attribute *acm_function_attributes[] = {
+ &dev_attr_instances,
+ NULL
+};
+
+static struct ccg_usb_function acm_function = {
+ .name = "acm",
+ .init = acm_function_init,
+ .cleanup = acm_function_cleanup,
+ .bind_config = acm_function_bind_config,
+ .attributes = acm_function_attributes,
+};
+
+struct rndis_function_config {
+ u8 ethaddr[ETH_ALEN];
+ u32 vendorID;
+ char manufacturer[256];
+ /* "Wireless" RNDIS; auto-detected by Windows */
+ bool wceis;
+};
+
+static int rndis_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+ return 0;
+}
+
+static void rndis_function_cleanup(struct ccg_usb_function *f)
+{
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int rndis_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ int ret;
+ struct rndis_function_config *rndis = f->config;
+
+ if (!rndis) {
+ pr_err("%s: rndis_pdata\n", __func__);
+ return -1;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+ if (ret) {
+ pr_err("%s: gether_setup failed\n", __func__);
+ return ret;
+ }
+
+ if (rndis->wceis) {
+ /* "Wireless" RNDIS; auto-detected by Windows */
+ rndis_iad_descriptor.bFunctionClass =
+ USB_CLASS_WIRELESS_CONTROLLER;
+ rndis_iad_descriptor.bFunctionSubClass = 0x01;
+ rndis_iad_descriptor.bFunctionProtocol = 0x03;
+ rndis_control_intf.bInterfaceClass =
+ USB_CLASS_WIRELESS_CONTROLLER;
+ rndis_control_intf.bInterfaceSubClass = 0x01;
+ rndis_control_intf.bInterfaceProtocol = 0x03;
+ }
+
+ return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
+ rndis->manufacturer);
+}
+
+static void rndis_function_unbind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static ssize_t rndis_manufacturer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%s\n", config->manufacturer);
+}
+
+static ssize_t rndis_manufacturer_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+
+ if (size >= sizeof(config->manufacturer))
+ return -EINVAL;
+ memcpy(config->manufacturer, buf, size);
+ config->manufacturer[size] = 0;
+
+ return size;
+}
+
+static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show,
+ rndis_manufacturer_store);
+
+static ssize_t rndis_wceis_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%d\n", config->wceis);
+}
+
+static ssize_t rndis_wceis_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ int value;
+ int ret;
+
+ ret = kstrtoint(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ config->wceis = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show,
+ rndis_wceis_store);
+
+static ssize_t rndis_ethaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *rndis = f->config;
+ return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+}
+
+static ssize_t rndis_ethaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *rndis = f->config;
+ unsigned char tmp[6];
+
+ if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ tmp + 0, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5) !=
+ ETH_ALEN)
+ return -EINVAL;
+
+ memcpy(rndis->ethaddr, tmp, ETH_ALEN);
+
+ return ETH_ALEN;
+
+}
+
+static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show,
+ rndis_ethaddr_store);
+
+static ssize_t rndis_vendorID_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%04x\n", config->vendorID);
+}
+
+static ssize_t rndis_vendorID_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ int value;
+ int ret;
+
+ ret = kstrtou32(buf, 16, &value);
+ if (ret)
+ return ret;
+
+ config->vendorID = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
+ rndis_vendorID_store);
+
+static struct device_attribute *rndis_function_attributes[] = {
+ &dev_attr_manufacturer,
+ &dev_attr_wceis,
+ &dev_attr_ethaddr,
+ &dev_attr_vendorID,
+ NULL
+};
+
+static struct ccg_usb_function rndis_function = {
+ .name = "rndis",
+ .init = rndis_function_init,
+ .cleanup = rndis_function_cleanup,
+ .bind_config = rndis_function_bind_config,
+ .unbind_config = rndis_function_unbind_config,
+ .attributes = rndis_function_attributes,
+};
+
+static int mass_storage_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ struct fsg_config fsg;
+ struct fsg_common *common;
+ int err;
+
+ memset(&fsg, 0, sizeof fsg);
+ fsg.nluns = 1;
+ fsg.luns[0].removable = 1;
+ fsg.vendor_name = iManufacturer;
+ fsg.product_name = iProduct;
+
+ common = fsg_common_init(NULL, cdev, &fsg);
+ if (IS_ERR(common))
+ return PTR_ERR(common);
+
+ err = sysfs_create_link(&f->dev->kobj,
+ &common->luns[0].dev.kobj,
+ "lun");
+ if (err) {
+ fsg_common_put(common);
+ return err;
+ }
+
+ f->config = common;
+ return 0;
+}
+
+static void mass_storage_function_cleanup(struct ccg_usb_function *f)
+{
+ fsg_common_put(f->config);
+ f->config = NULL;
+}
+
+static int mass_storage_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct fsg_common *common = f->config;
+ return fsg_bind_config(c->cdev, c, common);
+}
+
+static struct ccg_usb_function mass_storage_function = {
+ .name = "mass_storage",
+ .init = mass_storage_function_init,
+ .cleanup = mass_storage_function_cleanup,
+ .bind_config = mass_storage_function_bind_config,
+};
+
+static struct ccg_usb_function *supported_functions[] = {
+ &functionfs_function,
+ &acm_function,
+ &rndis_function,
+ &mass_storage_function,
+ NULL
+};
+
+
+static int ccg_init_functions(struct ccg_usb_function **functions,
+ struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct ccg_usb_function *f;
+ struct device_attribute **attrs;
+ struct device_attribute *attr;
+ int err;
+ int index = 0;
+
+ for (; (f = *functions++); index++) {
+ f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
+ if (!f->dev_name) {
+ pr_err("%s: Failed to alloc name %s", __func__,
+ f->name);
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+ f->dev = device_create(ccg_class, dev->dev,
+ MKDEV(0, index), f, f->dev_name);
+ if (IS_ERR(f->dev)) {
+ pr_err("%s: Failed to create dev %s", __func__,
+ f->dev_name);
+ err = PTR_ERR(f->dev);
+ f->dev = NULL;
+ goto err_create;
+ }
+
+ if (f->init) {
+ err = f->init(f, cdev);
+ if (err) {
+ pr_err("%s: Failed to init %s", __func__,
+ f->name);
+ goto err_out;
+ }
+ }
+
+ attrs = f->attributes;
+ if (attrs) {
+ while ((attr = *attrs++) && !err)
+ err = device_create_file(f->dev, attr);
+ }
+ if (err) {
+ pr_err("%s: Failed to create function %s attributes",
+ __func__, f->name);
+ goto err_uninit;
+ }
+ }
+ return 0;
+
+err_uninit:
+ if (f->cleanup)
+ f->cleanup(f);
+err_out:
+ device_destroy(ccg_class, f->dev->devt);
+ f->dev = NULL;
+err_create:
+ kfree(f->dev_name);
+err_alloc:
+ return err;
+}
+
+static void ccg_cleanup_functions(struct ccg_usb_function **functions)
+{
+ struct ccg_usb_function *f;
+
+ while (*functions) {
+ f = *functions++;
+
+ if (f->dev) {
+ if (f->cleanup)
+ f->cleanup(f);
+ device_destroy(ccg_class, f->dev->devt);
+ kfree(f->dev_name);
+ }
+ }
+}
+
+static int ccg_bind_enabled_functions(struct ccg_dev *dev,
+ struct usb_configuration *c)
+{
+ struct ccg_usb_function *f;
+ int ret;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ ret = f->bind_config(f, c);
+ if (ret) {
+ pr_err("%s: %s failed", __func__, f->name);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void ccg_unbind_enabled_functions(struct ccg_dev *dev,
+ struct usb_configuration *c)
+{
+ struct ccg_usb_function *f;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+ if (f->unbind_config)
+ f->unbind_config(f, c);
+}
+
+static int ccg_enable_function(struct ccg_dev *dev, char *name)
+{
+ struct ccg_usb_function **functions = dev->functions;
+ struct ccg_usb_function *f;
+ while ((f = *functions++)) {
+ if (!strcmp(name, f->name)) {
+ list_add_tail(&f->enabled_list,
+ &dev->enabled_functions);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+/* /sys/class/ccg_usb/ccg%d/ interface */
+
+static ssize_t
+functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct ccg_usb_function *f;
+ char *buff = buf;
+ int i;
+
+ mutex_lock(&dev->mutex);
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+ buff += sprintf(buff, "%s,", f->name);
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].used)
+ buff += sprintf(buff, "%s", dev->ffs_tab[i].name);
+
+ mutex_unlock(&dev->mutex);
+
+ if (buff != buf)
+ *(buff-1) = '\n';
+ return buff - buf;
+}
+
+static ssize_t
+functions_store(struct device *pdev, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ char *name;
+ char buf[256], *b;
+ int err, i;
+ bool functionfs_enabled;
+
+ buff = skip_spaces(buff);
+ if (!*buff)
+ return -EINVAL;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->enabled) {
+ mutex_unlock(&dev->mutex);
+ return -EBUSY;
+ }
+
+ INIT_LIST_HEAD(&dev->enabled_functions);
+ functionfs_enabled = false;
+ for (i = 0; i < dev->max_func_num; i++)
+ dev->ffs_tab[i].used = false;
+
+ strlcpy(buf, buff, sizeof(buf));
+ b = strim(buf);
+
+ while (b) {
+ struct ffs_obj *user_func;
+
+ name = strsep(&b, ",");
+ /* handle FunctionFS implicitly */
+ if (!strcmp(name, functionfs_function.name)) {
+ pr_err("ccg_usb: Cannot explicitly enable '%s'", name);
+ continue;
+ }
+ user_func = functionfs_find_dev(dev, name);
+ if (user_func)
+ name = functionfs_function.name;
+ err = 0;
+ if (!user_func || !functionfs_enabled)
+ err = ccg_enable_function(dev, name);
+ if (err)
+ pr_err("ccg_usb: Cannot enable '%s'", name);
+ else if (user_func) {
+ user_func->used = true;
+ dev->func_num++;
+ functionfs_enabled = true;
+ }
+ }
+
+ mutex_unlock(&dev->mutex);
+
+ return size;
+}
+
+static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ return sprintf(buf, "%d\n", dev->enabled);
+}
+
+static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct usb_composite_dev *cdev = dev->cdev;
+ int enabled = 0;
+
+ mutex_lock(&dev->mutex);
+ sscanf(buff, "%d", &enabled);
+ if (enabled && dev->func_num && !functionfs_all_ready(dev)) {
+ mutex_unlock(&dev->mutex);
+ return -ENODEV;
+ }
+
+ if (enabled && !dev->enabled) {
+ int ret;
+
+ cdev->next_string_id = 0;
+ /*
+ * Update values in composite driver's copy of
+ * device descriptor.
+ */
+ cdev->desc.bDeviceClass = device_desc.bDeviceClass;
+ cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
+ cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
+ cdev->desc.idVendor = idVendor;
+ cdev->desc.idProduct = idProduct;
+ cdev->desc.bcdDevice = bcdDevice;
+
+ usb_add_config(cdev, &ccg_config_driver, ccg_bind_config);
+ dev->enabled = true;
+ ret = usb_gadget_connect(cdev->gadget);
+ if (ret) {
+ dev->enabled = false;
+ usb_remove_config(cdev, &ccg_config_driver);
+ }
+ } else if (!enabled && dev->enabled) {
+ reset_usb(dev);
+ } else {
+ pr_err("ccg_usb: already %s\n",
+ dev->enabled ? "enabled" : "disabled");
+ }
+
+ mutex_unlock(&dev->mutex);
+ return size;
+}
+
+static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct usb_composite_dev *cdev = dev->cdev;
+ char *state = "DISCONNECTED";
+ unsigned long flags;
+
+ if (!cdev)
+ goto out;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (cdev->config)
+ state = "CONFIGURED";
+ else if (dev->connected)
+ state = "CONNECTED";
+ spin_unlock_irqrestore(&cdev->lock, flags);
+out:
+ return sprintf(buf, "%s\n", state);
+}
+
+#define DESCRIPTOR_ATTR(field, format_string) \
+static ssize_t \
+field ## _show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return sprintf(buf, format_string, device_desc.field); \
+} \
+static ssize_t \
+field ## _store(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ int value; \
+ if (sscanf(buf, format_string, &value) == 1) { \
+ device_desc.field = value; \
+ return size; \
+ } \
+ return -1; \
+} \
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
+
+DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
+
+static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,
+ functions_store);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
+
+static struct device_attribute *ccg_usb_attributes[] = {
+ &dev_attr_bDeviceClass,
+ &dev_attr_bDeviceSubClass,
+ &dev_attr_bDeviceProtocol,
+ &dev_attr_functions,
+ &dev_attr_enable,
+ &dev_attr_state,
+ NULL
+};
+
+/*-------------------------------------------------------------------------*/
+/* Composite driver */
+
+static int ccg_bind_config(struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int ret = 0;
+
+ ret = ccg_bind_enabled_functions(dev, c);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ccg_unbind_config(struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+
+ ccg_unbind_enabled_functions(dev, c);
+
+ usb_ep_autoconfig_reset(dev->cdev->gadget);
+}
+
+static int ccg_bind(struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_gadget *gadget = cdev->gadget;
+ int gcnum, ret;
+
+ /*
+ * Start disconnected. Userspace will connect the gadget once
+ * it is done configuring the functions.
+ */
+ usb_gadget_disconnect(gadget);
+
+ ret = ccg_init_functions(dev->functions, cdev);
+ if (ret)
+ return ret;
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+ else {
+ pr_warning("%s: controller '%s' not recognized\n",
+ longname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ }
+
+ usb_gadget_set_selfpowered(gadget);
+ dev->cdev = cdev;
+
+ return 0;
+}
+
+static int ccg_usb_unbind(struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+
+ cancel_work_sync(&dev->work);
+ ccg_cleanup_functions(dev->functions);
+ return 0;
+}
+
+static struct usb_composite_driver ccg_usb_driver = {
+ .name = "configurable_usb",
+ .dev = &device_desc,
+ .unbind = ccg_usb_unbind,
+ .needs_serial = true,
+ .iManufacturer = "Linux Foundation",
+ .iProduct = longname,
+ .iSerialNumber = "1234567890123456",
+};
+
+static int ccg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ struct usb_request *req = cdev->req;
+ struct ccg_usb_function *f;
+ int value = -EOPNOTSUPP;
+ unsigned long flags;
+
+ req->zero = 0;
+ req->complete = composite_setup_complete;
+ req->length = 0;
+ gadget->ep0->driver_data = cdev;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ if (f->ctrlrequest) {
+ value = f->ctrlrequest(f, cdev, c);
+ if (value >= 0)
+ break;
+ }
+ }
+
+ if (value < 0)
+ value = composite_setup(gadget, c);
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (!dev->connected) {
+ dev->connected = 1;
+ schedule_work(&dev->work);
+ } else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
+ cdev->config) {
+ schedule_work(&dev->work);
+ }
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ return value;
+}
+
+static void ccg_disconnect(struct usb_gadget *gadget)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ composite_disconnect(gadget);
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ dev->connected = 0;
+ schedule_work(&dev->work);
+ spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
+static int ccg_create_device(struct ccg_dev *dev)
+{
+ struct device_attribute **attrs = ccg_usb_attributes;
+ struct device_attribute *attr;
+ int err;
+
+ dev->dev = device_create(ccg_class, NULL, MKDEV(0, 0), NULL, "ccg0");
+ if (IS_ERR(dev->dev))
+ return PTR_ERR(dev->dev);
+
+ dev_set_drvdata(dev->dev, dev);
+
+ while ((attr = *attrs++)) {
+ err = device_create_file(dev->dev, attr);
+ if (err) {
+ device_destroy(ccg_class, dev->dev->devt);
+ return err;
+ }
+ }
+ return 0;
+}
+
+
+static int __init init(void)
+{
+ struct ccg_dev *dev;
+ int err;
+
+ ccg_class = class_create(THIS_MODULE, "ccg_usb");
+ if (IS_ERR(ccg_class))
+ return PTR_ERR(ccg_class);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->functions = supported_functions;
+ INIT_LIST_HEAD(&dev->enabled_functions);
+ INIT_WORK(&dev->work, ccg_work);
+ mutex_init(&dev->mutex);
+
+ err = ccg_create_device(dev);
+ if (err) {
+ class_destroy(ccg_class);
+ kfree(dev);
+ return err;
+ }
+
+ _ccg_dev = dev;
+
+ /* Override composite driver functions */
+ composite_driver.setup = ccg_setup;
+ composite_driver.disconnect = ccg_disconnect;
+
+ err = usb_composite_probe(&ccg_usb_driver, ccg_bind);
+ if (err) {
+ class_destroy(ccg_class);
+ kfree(dev);
+ }
+
+ return err;
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+ usb_composite_unregister(&ccg_usb_driver);
+ class_destroy(ccg_class);
+ kfree(_ccg_dev);
+ _ccg_dev = NULL;
+}
+module_exit(cleanup);
diff --git a/drivers/staging/ccg/sysfs-class-ccg_usb b/drivers/staging/ccg/sysfs-class-ccg_usb
new file mode 100644
index 0000000..dd12a33
--- /dev/null
+++ b/drivers/staging/ccg/sysfs-class-ccg_usb
@@ -0,0 +1,158 @@
+What: /sys/class/ccg_usb
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The ccg_usb/ class subdirectory belongs to ccg
+ USB gadget.
+
+What: /sys/class/ccg_usb/ccgX
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccg{0,1,2,3...} class
+ subdirectories correspond to each ccg gadget device;
+ at the time of this writing there is only ccg0 and it
+ represents the ccg gadget.
+
+What: /sys/class/ccg_usb/ccgX/functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A comma-separated list of USB function names to be activated
+ in this ccg gadget. It includes both the functions provided
+ in-kernel by the ccg gadget and the functions provided from
+ userspace through FunctionFS.
+
+What: /sys/class/ccg_usb/ccgX/enable
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A flag activating/deactivating the ccg usb gadget.
+
+What: /sys/class/ccg_usb/ccgX/state
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Configurable usb gadget state:
+
+ DISCONNECTED
+ CONNECTED
+ CONFIGURED
+
+What: /sys/class/ccg_usb/ccgX/f_acm/
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_acm subdirectory
+ corresponds to the gadget's USB CDC serial (ACM) function
+ driver.
+
+What: /sys/class/ccg_usb/ccgX/f_acm/instances
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Maximum number of the /dev/ttyGS<X> interface the driver uses.
+
+What: /sys/class/ccg_usb/ccgX/f_fs
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_fs subdirectory
+ corresponds to the gadget's FunctionFS driver.
+
+What: /sys/class/ccg_usb/ccgX/f_fs/user_functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A comma-separeted list of USB function names to be supported
+ from userspace. No other userspace FunctionFS functions can
+ be supported than listed here. However, the actual activation
+ of these functions is still done through
+ /sys/class/ccg_usb/ccgX/functions, where it is possible
+ to specify any subset (including maximum and empty) of
+ /sys/class/ccg_usb/ccgX/f_fs/user_functions.
+
+What: /sys/class/ccg_usb/ccgX/f_fs/max_user_functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Maximum number of USB functions to be supported from userspace.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_rndis subdirectory
+ corresponds to the gadget's RNDIS driver.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/manufacturer
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port manufacturer string.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/wceis
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port wireless flag.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/ethaddr
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port Ethernet address.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/vendorID
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port vendor ID.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage subdirectory
+ corresponds to the gadget's USB mass storage driver.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+ subdirectory corresponds to the gadget's USB mass storage
+ driver and its underlying storage.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+ subdirectory corresponds to the gadget's USB mass storage
+ driver and its underlying storage.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun/file
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Gadget's USB mass storage underlying file.
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 12c691d..3bbe3fd 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1,6 +1,5 @@
config COMEDI
tristate "Data acquisition support (comedi)"
- default N
depends on m
depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86
---help---
@@ -14,10 +13,29 @@ config COMEDI_DEBUG
This is an option for use by developers; most people should
say N here. This enables comedi core and driver debugging.
+config COMEDI_DEFAULT_BUF_SIZE_KB
+ int "Comedi default initial asynchronous buffer size in KiB"
+ default "2048"
+ depends on COMEDI != n
+ ---help---
+ This is the default asynchronous buffer size which is used for
+ commands running in the background in kernel space. This
+ defaults to 2048 KiB of memory so that a 16 channel card
+ running at 10 kHz has of 2-4 seconds of buffer.
+
+config COMEDI_DEFAULT_BUF_MAXSIZE_KB
+ int "Comedi default maximum asynchronous buffer size in KiB"
+ default "20480"
+ depends on COMEDI != n
+ ---help---
+ This is the default maximum asynchronous buffer size which can
+ be requested by a userspace program without root privileges.
+ This is set to 20480 KiB so that a fast I/O card with 16
+ channels running at 100 kHz has 2-4 seconds of buffer.
+
menuconfig COMEDI_MISC_DRIVERS
tristate "Comedi misc drivers"
depends on COMEDI
- default N
---help---
Enable comedi misc drivers to be built
@@ -35,7 +53,6 @@ config COMEDI_KCOMEDILIB
config COMEDI_BOND
tristate "Device bonding support"
depends on COMEDI_KCOMEDILIB
- default N
---help---
Enable support for a driver to 'bond' (merge) multiple subdevices
from multiple devices together as one.
@@ -46,7 +63,6 @@ config COMEDI_BOND
config COMEDI_TEST
tristate "Fake waveform generator support"
select COMEDI_FC
- default N
---help---
Enable support for the fake waveform generator.
This driver is mainly for testing purposes, but can also be used to
@@ -58,7 +74,6 @@ config COMEDI_TEST
config COMEDI_PARPORT
tristate "Parallel port support"
- default N
---help---
Enable support for the standard parallel port.
A cheap and easy way to get a few more digital I/O lines. Steal
@@ -70,7 +85,6 @@ config COMEDI_PARPORT
config COMEDI_SERIAL2002
tristate "Driver for serial connected hardware"
- default N
---help---
Enable support for serial connected hardware
@@ -79,7 +93,6 @@ config COMEDI_SERIAL2002
config COMEDI_SKEL
tristate "Comedi skeleton driver"
- default N
---help---
Build the Skeleton driver, an example for driver writers
@@ -91,7 +104,6 @@ endif # COMEDI_MISC_DRIVERS
menuconfig COMEDI_ISA_DRIVERS
tristate "Comedi ISA and PC/104 drivers"
depends on COMEDI && ISA
- default N
---help---
Enable comedi ISA and PC/104 drivers to be built
@@ -103,7 +115,6 @@ if COMEDI_ISA_DRIVERS && ISA
config COMEDI_ACL7225B
tristate "ADlink NuDAQ ACL-7225b and compatibles support"
- default N
---help---
Enable support for ADlink NuDAQ ACL-7225b and compatibles,
ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio)
@@ -113,7 +124,6 @@ config COMEDI_ACL7225B
config COMEDI_PCL711
tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support"
- default N
---help---
Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112
@@ -123,7 +133,6 @@ config COMEDI_PCL711
config COMEDI_PCL724
tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCL-724, PCL-722, PCL-731 and
ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards
@@ -133,7 +142,6 @@ config COMEDI_PCL724
config COMEDI_PCL725
tristate "Advantech PCL-725 and compatible ISA card support"
- default N
---help---
Enable support for Advantech PCL-725 and compatible ISA cards.
@@ -142,7 +150,6 @@ config COMEDI_PCL725
config COMEDI_PCL726
tristate "Advantech PCL-726 and compatible ISA card support"
- default N
---help---
Enable support for Advantech PCL-726 and compatible ISA cards.
@@ -151,7 +158,6 @@ config COMEDI_PCL726
config COMEDI_PCL730
tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support"
- default N
---help---
Enable support for Advantech PCL-730, ICP ISO-730 and ADlink
ACL-7130 ISA cards
@@ -162,7 +168,6 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -174,7 +179,6 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
@@ -184,7 +188,6 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -195,7 +198,6 @@ config COMEDI_PCL818
config COMEDI_PCM3724
tristate "Advantech PCM-3724 PC/104 card support"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCM-3724 PC/104 cards.
@@ -204,16 +206,43 @@ config COMEDI_PCM3724
config COMEDI_PCM3730
tristate "Advantech PCM-3730 and clone PC/104 board support"
- default N
---help---
Enable support for Advantech PCM-3730 and clone PC/104 boards
To compile this driver as a module, choose M here: the module will be
called pcm3730.
+config COMEDI_AMPLC_DIO200_ISA
+ tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E"
+ select COMEDI_AMPLC_DIO200
+ depends on COMEDI_ISA_DRIVERS
+ ---help---
+ Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and
+ PC272E ISA DIO boards
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_dio200.
+
+config COMEDI_AMPLC_PC236_ISA
+ tristate "Amplicon PC36AT DIO board support"
+ select COMEDI_AMPLC_PC236
+ ---help---
+ Enable support for Amplicon PC36AT ISA DIO board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_pc236.
+
+config COMEDI_AMPLC_PC263_ISA
+ tristate "Amplicon PC263 relay board support"
+ select COMEDI_AMPLC_PC263
+ ---help---
+ Enable support for Amplicon PC263 ISA relay board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_pc263.
+
config COMEDI_RTI800
tristate "Analog Devices RTI-800/815 ISA card support"
- default N
---help---
Enable support for Analog Devices RTI-800/815 ISA cards
@@ -222,7 +251,6 @@ config COMEDI_RTI800
config COMEDI_RTI802
tristate "Analog Devices RTI-802 ISA card support"
- default N
---help---
Enable support for Analog Devices RTI-802 ISA cards
@@ -233,18 +261,29 @@ config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
To compile this driver as a module, choose M here: the module will be
called das16m1.
+config COMEDI_DAS08_ISA
+ tristate "DAS-08 compatible ISA and PC/104 card support"
+ select COMEDI_DAS08
+ ---help---
+ Enable support for Keithley Metrabyte/ComputerBoards DAS08
+ and compatible ISA and PC/104 cards:
+ Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH,
+ DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO,
+ DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16.
+
+ To compile this driver as a module, choose M here: the module will be
+ called das08.
+
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS16
and compatible ISA and PC/104 cards:
@@ -261,7 +300,6 @@ config COMEDI_DAS16
config COMEDI_DAS800
tristate "DAS800 and compatible ISA card support"
select COMEDI_FC
- default N
---help---
Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
Keithley Metrabyte DAS-800, DAS-801, DAS-802
@@ -275,7 +313,6 @@ config COMEDI_DAS1800
tristate "DAS1800 and compatible ISA card support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for DAS1800 and compatible ISA cards
Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -289,7 +326,6 @@ config COMEDI_DAS1800
config COMEDI_DAS6402
tristate "DAS6402 and compatible ISA card support"
- default N
---help---
Enable support for DAS6402 and compatible ISA cards
Computerboards, Keithley Metrabyte DAS6402 and compatibles
@@ -299,7 +335,6 @@ config COMEDI_DAS6402
config COMEDI_DT2801
tristate "Data Translation DT2801 ISA card support"
- default N
---help---
Enable support for Data Translation DT2801 ISA cards
@@ -308,7 +343,6 @@ config COMEDI_DT2801
config COMEDI_DT2811
tristate "Data Translation DT2811 ISA card support"
- default N
---help---
Enable support for Data Translation DT2811 ISA cards
@@ -317,7 +351,6 @@ config COMEDI_DT2811
config COMEDI_DT2814
tristate "Data Translation DT2814 ISA card support"
- default N
---help---
Enable support for Data Translation DT2814 ISA cards
@@ -326,7 +359,6 @@ config COMEDI_DT2814
config COMEDI_DT2815
tristate "Data Translation DT2815 ISA card support"
- default N
---help---
Enable support for Data Translation DT2815 ISA cards
@@ -335,7 +367,6 @@ config COMEDI_DT2815
config COMEDI_DT2817
tristate "Data Translation DT2817 ISA card support"
- default N
---help---
Enable support for Data Translation DT2817 ISA cards
@@ -346,7 +377,6 @@ config COMEDI_DT282X
tristate "Data Translation DT2821 series and DT-EZ ISA card support"
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Data Translation DT2821 series including DT-EZ
DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI,
@@ -358,7 +388,6 @@ config COMEDI_DT282X
config COMEDI_DMM32AT
tristate "Diamond Systems MM-32-AT PC/104 board support"
- default N
---help---
Enable support for Diamond Systems MM-32-AT PC/104 boards
@@ -367,7 +396,6 @@ config COMEDI_DMM32AT
config COMEDI_FL512
tristate "FL512 ISA card support"
- default N
---help---
Enable support for FL512 ISA card
@@ -377,7 +405,6 @@ config COMEDI_FL512
config COMEDI_AIO_AIO12_8
tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
select COMEDI_8255
- default N
---help---
Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
@@ -386,7 +413,6 @@ config COMEDI_AIO_AIO12_8
config COMEDI_AIO_IIRO_16
tristate "I/O Products PC/104 IIRO16 Board support"
- default N
---help---
Enable support for I/O Products PC/104 IIRO16 Relay And Isolated
Input Board
@@ -396,7 +422,6 @@ config COMEDI_AIO_IIRO_16
config COMEDI_C6XDIGIO
tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support"
- default N
---help---
Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter
card
@@ -406,7 +431,6 @@ config COMEDI_C6XDIGIO
config COMEDI_MPC624
tristate "Micro/sys MPC-624 PC/104 board support"
- default N
---help---
Enable support for Micro/sys MPC-624 PC/104 board
@@ -415,7 +439,6 @@ config COMEDI_MPC624
config COMEDI_ADQ12B
tristate "MicroAxial ADQ12-B data acquisition and control card support"
- default N
---help---
Enable MicroAxial ADQ12-B daq and control card support.
@@ -426,7 +449,6 @@ config COMEDI_NI_AT_A2150
tristate "NI AT-A2150 ISA card support"
depends on COMEDI_NI_COMMON
depends on VIRT_TO_BUS
- default N
---help---
Enable support for National Instruments AT-A2150 cards
@@ -436,7 +458,6 @@ config COMEDI_NI_AT_A2150
config COMEDI_NI_AT_AO
tristate "NI AT-AO-6/10 EISA card support"
depends on COMEDI_NI_COMMON
- default N
---help---
Enable support for National Instruments AT-AO-6/10 cards
@@ -447,7 +468,6 @@ config COMEDI_NI_ATMIO
tristate "NI AT-MIO E series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for National Instruments AT-MIO E series cards
National Instruments AT-MIO-16E-1 (ni_atmio),
@@ -461,7 +481,6 @@ config COMEDI_NI_ATMIO16D
tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
@@ -470,7 +489,6 @@ config COMEDI_NI_ATMIO16D
config COMEDI_PCMAD
tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards.
@@ -479,7 +497,6 @@ config COMEDI_PCMAD
config COMEDI_PCMDA12
tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards.
Note that the board is not ISA-PNP capable and thus needs the I/O
@@ -490,7 +507,6 @@ config COMEDI_PCMDA12
config COMEDI_PCMMIO
tristate "Winsystems PCM-MIO PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-MIO multifunction PC/104 boards.
@@ -499,7 +515,6 @@ config COMEDI_PCMMIO
config COMEDI_PCMUIO
tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support"
- default N
---help---
Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards.
@@ -508,7 +523,6 @@ config COMEDI_PCMUIO
config COMEDI_MULTIQ3
tristate "Quanser Consulting MultiQ-3 ISA card support"
- default N
---help---
Enable support for Quanser Consulting MultiQ-3 ISA cards
@@ -517,7 +531,6 @@ config COMEDI_MULTIQ3
config COMEDI_POC
tristate "Generic driver for very simple devices"
- default N
---help---
Enable generic support for very simple / POC (Piece of Crap) boards,
Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and
@@ -531,7 +544,6 @@ endif # COMEDI_ISA_DRIVERS
menuconfig COMEDI_PCI_DRIVERS
tristate "Comedi PCI drivers"
depends on COMEDI && PCI
- default N
---help---
Enable comedi PCI drivers to be built
@@ -544,7 +556,6 @@ if COMEDI_PCI_DRIVERS && PCI
config COMEDI_ADDI_APCI_035
tristate "ADDI-DATA APCI_035 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_035 cards
@@ -554,7 +565,6 @@ config COMEDI_ADDI_APCI_035
config COMEDI_ADDI_APCI_1032
tristate "ADDI-DATA APCI_1032 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1032 cards
@@ -564,7 +574,6 @@ config COMEDI_ADDI_APCI_1032
config COMEDI_ADDI_APCI_1500
tristate "ADDI-DATA APCI_1500 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1500 cards
@@ -574,7 +583,6 @@ config COMEDI_ADDI_APCI_1500
config COMEDI_ADDI_APCI_1516
tristate "ADDI-DATA APCI_1516 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1516 cards
@@ -584,7 +592,6 @@ config COMEDI_ADDI_APCI_1516
config COMEDI_ADDI_APCI_1564
tristate "ADDI-DATA APCI_1564 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1564 cards
@@ -594,7 +601,6 @@ config COMEDI_ADDI_APCI_1564
config COMEDI_ADDI_APCI_16XX
tristate "ADDI-DATA APCI_16xx support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_16xx cards
@@ -604,7 +610,6 @@ config COMEDI_ADDI_APCI_16XX
config COMEDI_ADDI_APCI_2016
tristate "ADDI-DATA APCI_2016 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2016 cards
@@ -614,7 +619,6 @@ config COMEDI_ADDI_APCI_2016
config COMEDI_ADDI_APCI_2032
tristate "ADDI-DATA APCI_2032 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2032 cards
@@ -624,7 +628,6 @@ config COMEDI_ADDI_APCI_2032
config COMEDI_ADDI_APCI_2200
tristate "ADDI-DATA APCI_2200 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2200 cards
@@ -635,7 +638,6 @@ config COMEDI_ADDI_APCI_3001
tristate "ADDI-DATA APCI_3001 support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for ADDI-DATA APCI_3001 cards
@@ -646,7 +648,6 @@ config COMEDI_ADDI_APCI_3120
tristate "ADDI-DATA APCI_3520 support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for ADDI-DATA APCI_3520 cards
@@ -656,7 +657,6 @@ config COMEDI_ADDI_APCI_3120
config COMEDI_ADDI_APCI_3501
tristate "ADDI-DATA APCI_3501 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_3501 cards
@@ -666,7 +666,6 @@ config COMEDI_ADDI_APCI_3501
config COMEDI_ADDI_APCI_3XXX
tristate "ADDI-DATA APCI_3xxx support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_3xxx cards
@@ -676,7 +675,6 @@ config COMEDI_ADDI_APCI_3XXX
config COMEDI_ADL_PCI6208
tristate "ADLink PCI-6208A support"
select COMEDI_8255
- default N
---help---
Enable support for ADLink PCI-6208A cards
@@ -685,7 +683,6 @@ config COMEDI_ADL_PCI6208
config COMEDI_ADL_PCI7230
tristate "ADLink PCI-7230 digital io board support"
- default N
---help---
Enable support for ADlink PCI-7230 digital io board support
@@ -694,7 +691,6 @@ config COMEDI_ADL_PCI7230
config COMEDI_ADL_PCI7296
tristate "ADLink PCI-7296 96 ch. digital io board support"
- default N
---help---
Enable support for ADlink PCI-7296 96 ch. digital io board support
@@ -703,7 +699,6 @@ config COMEDI_ADL_PCI7296
config COMEDI_ADL_PCI7432
tristate "ADLink PCI-7432 64 ch. isolated digital io board support"
- default N
---help---
Enable support for ADlink PCI-7432 64 ch. isolated digital io board
@@ -712,7 +707,6 @@ config COMEDI_ADL_PCI7432
config COMEDI_ADL_PCI8164
tristate "ADLink PCI-8164 4 Axes Motion Control board support"
- default N
---help---
Enable support for ADlink PCI-8164 4 Axes Motion Control board
@@ -722,7 +716,6 @@ config COMEDI_ADL_PCI8164
config COMEDI_ADL_PCI9111
tristate "ADLink PCI-9111HR support"
select COMEDI_FC
- default N
---help---
Enable support for ADlink PCI9111 cards
@@ -733,7 +726,6 @@ config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
@@ -742,7 +734,6 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
- default N
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
PCI-1713, PCI-1720 and PCI-1731
@@ -752,7 +743,6 @@ config COMEDI_ADV_PCI1710
config COMEDI_ADV_PCI1723
tristate "Advantech PCI-1723 support"
- default N
---help---
Enable support for Advantech PCI-1723 cards
@@ -762,7 +752,6 @@ config COMEDI_ADV_PCI1723
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCI DIO cards
PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
@@ -772,31 +761,29 @@ config COMEDI_ADV_PCI_DIO
To compile this driver as a module, choose M here: the module will be
called adv_pci_dio.
-config COMEDI_AMPLC_DIO200
- tristate "Amplicon PC272E and PCI272 DIO board support"
- select COMEDI_8255
- default N
+config COMEDI_AMPLC_DIO200_PCI
+ tristate "Amplicon PCI215 and PCI272 DIO board support"
+ select COMEDI_AMPLC_DIO200
---help---
- Enable support for Amplicon PC272E and PCI272 DIO boards
+ Enable support for Amplicon PCI215 and PCI272 DIO boards.
To compile this driver as a module, choose M here: the module will be
called amplc_dio200.
-config COMEDI_AMPLC_PC236
- tristate "Amplicon PC36AT and PCI236 DIO board support"
- select COMEDI_8255
- default N
+config COMEDI_AMPLC_PC236_PCI
+ tristate "Amplicon PCI236 DIO board support"
+ select COMEDI_AMPLC_PC236
---help---
- Enable support for Amplicon PC36AT and PCI236 DIO boards
+ Enable support for Amplicon PCI236 DIO board.
To compile this driver as a module, choose M here: the module will be
called amplc_pc236.
-config COMEDI_AMPLC_PC263
- tristate "Amplicon PC263 and PCI263 relay board support"
- default N
+config COMEDI_AMPLC_PC263_PCI
+ tristate "Amplicon PCI263 relay board support"
+ select COMEDI_AMPLC_PC263
---help---
- Enable support for Amplicon PC263 and PCI263 relay boards
+ Enable support for Amplicon PCI263 relay board.
To compile this driver as a module, choose M here: the module will be
called amplc_pc263.
@@ -804,7 +791,6 @@ config COMEDI_AMPLC_PC263
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
select COMEDI_FC
- default N
---help---
Enable support for Amplicon PCI224 and PCI234 AO boards
@@ -814,7 +800,6 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
select COMEDI_8255
- default N
---help---
Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
boards
@@ -824,16 +809,23 @@ config COMEDI_AMPLC_PCI230
config COMEDI_CONTEC_PCI_DIO
tristate "Contec PIO1616L digital I/O board support"
- default N
---help---
Enable support for the Contec PIO1616L digital I/O board
To compile this driver as a module, choose M here: the module will be
called contec_pci_dio.
+config COMEDI_DAS08_PCI
+ tristate "DAS-08 PCI support"
+ select COMEDI_DAS08
+ ---help---
+ Enable support for PCI DAS-08 cards.
+
+ To compile this driver as a module, choose M here: the module will be
+ called das08.
+
config COMEDI_DT3000
tristate "Data Translation DT3000 series support"
- default N
---help---
Enable support for Data Translation DT3000 series
DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -844,7 +836,6 @@ config COMEDI_DT3000
config COMEDI_DYNA_PCI10XX
tristate "Dynalog PCI DAQ series support"
- default N
---help---
Enable support for Dynalog PCI DAQ series
PCI-1050
@@ -854,7 +845,6 @@ config COMEDI_DYNA_PCI10XX
config COMEDI_UNIOXX5
tristate "Fastwel UNIOxx-5 analog and digital io board support"
- default N
---help---
Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards
@@ -864,7 +854,6 @@ config COMEDI_UNIOXX5
config COMEDI_GSC_HPDI
tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support"
select COMEDI_FC
- default N
---help---
Enable support for General Standards Corporation high speed parallel
digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32.
@@ -875,7 +864,6 @@ config COMEDI_GSC_HPDI
config COMEDI_ICP_MULTI
tristate "Inova ICP_MULTI support"
- default N
---help---
Enable support for Inova ICP_MULTI card
@@ -884,7 +872,6 @@ config COMEDI_ICP_MULTI
config COMEDI_II_PCI20KC
tristate "Intelligent Instruments PCI-20001C carrier support"
- default N
---help---
Enable support for Intelligent Instruments PCI-20001C carrier
PCI-20001, PCI-20006 and PCI-20341
@@ -895,7 +882,6 @@ config COMEDI_II_PCI20KC
config COMEDI_DAQBOARD2000
tristate "IOtech DAQboard/2000 support"
select COMEDI_8255
- default N
---help---
Enable support for the IOtech DAQboard/2000
@@ -904,7 +890,6 @@ config COMEDI_DAQBOARD2000
config COMEDI_JR3_PCI
tristate "JR3/PCI force sensor board support"
- default N
---help---
Enable support for JR3/PCI force sensor boards
@@ -913,7 +898,6 @@ config COMEDI_JR3_PCI
config COMEDI_KE_COUNTER
tristate "Kolter-Electronic PCI Counter 1 card support"
- default N
---help---
Enable support for Kolter-Electronic PCI Counter 1 cards
@@ -924,7 +908,6 @@ config COMEDI_CB_PCIDAS64
tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx,
60xx, and 4020 series with the PLX 9080 PCI controller
@@ -936,7 +919,6 @@ config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr,
@@ -949,7 +931,6 @@ config COMEDI_CB_PCIDAS
config COMEDI_CB_PCIDDA
tristate "MeasurementComputing PCI-DDA series support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DDA
series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16,
@@ -961,7 +942,6 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIDIO
tristate "MeasurementComputing PCI-DIO series support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
PCI-DIO24, PCI-DIO24H and PCI-DIO48H
@@ -972,7 +952,6 @@ config COMEDI_CB_PCIDIO
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16 support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI Migration
series PCIM-DAS1602/16
@@ -983,7 +962,6 @@ config COMEDI_CB_PCIMDAS
config COMEDI_CB_PCIMDDA
tristate "MeasurementComputing PCIM-DDA06-16 support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
@@ -992,7 +970,6 @@ config COMEDI_CB_PCIMDDA
config COMEDI_ME4000
tristate "Meilhaus ME-4000 support"
- default N
---help---
Enable support for Meilhaus PCI data acquisition cards
ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is
@@ -1002,7 +979,6 @@ config COMEDI_ME4000
config COMEDI_ME_DAQ
tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support"
- default N
---help---
Enable support for Meilhaus PCI data acquisition cards
ME-2000i, ME-2600i and ME-3000vm1
@@ -1013,7 +989,6 @@ config COMEDI_ME_DAQ
config COMEDI_NI_6527
tristate "NI 6527 support"
depends on COMEDI_MITE
- default N
---help---
Enable support for the National Instruments 6527 PCI card
@@ -1023,7 +998,6 @@ config COMEDI_NI_6527
config COMEDI_NI_65XX
tristate "NI 65xx static dio PCI card support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments 65xx static dio boards.
Supported devices: National Instruments PCI-6509 (ni_65xx),
@@ -1037,7 +1011,6 @@ config COMEDI_NI_65XX
config COMEDI_NI_660X
tristate "NI 660x counter/timer PCI card support"
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
- default N
---help---
Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
PXI-6602 and PXI-6608.
@@ -1048,7 +1021,6 @@ config COMEDI_NI_660X
config COMEDI_NI_670X
tristate "NI 670x PCI card support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments PCI-6703 and PCI-6704
@@ -1059,7 +1031,6 @@ config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
depends on COMEDI_MITE
select COMEDI_8255
- default N
---help---
Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
@@ -1075,7 +1046,6 @@ config COMEDI_NI_PCIMIO
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for National Instruments PCI-MIO-E series and M series
(all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1,
@@ -1094,7 +1064,6 @@ config COMEDI_NI_PCIMIO
config COMEDI_RTD520
tristate "Real Time Devices PCI4520/DM7520 support"
select COMEDI_8255
- default N
---help---
Enable support for Real Time Devices PCI4520/DM7520
@@ -1103,7 +1072,6 @@ config COMEDI_RTD520
config COMEDI_S526
tristate "Sensoray s526 support"
- default N
---help---
Enable support for Sensoray s526
@@ -1113,7 +1081,6 @@ config COMEDI_S526
config COMEDI_S626
tristate "Sensoray 626 support"
select COMEDI_FC
- default N
---help---
Enable support for Sensoray 626
@@ -1122,7 +1089,6 @@ config COMEDI_S626
config COMEDI_SSV_DNP
tristate "SSV Embedded Systems DIL/Net-PC support"
- default N
---help---
Enable support for SSV Embedded Systems DIL/Net-PC
@@ -1134,7 +1100,6 @@ endif # COMEDI_PCI_DRIVERS
menuconfig COMEDI_PCMCIA_DRIVERS
tristate "Comedi PCMCIA drivers"
depends on COMEDI && (PCMCIA || PCCARD)
- default N
---help---
Enable comedi PCMCIA and PCCARD drivers to be built
@@ -1146,7 +1111,6 @@ if COMEDI_PCMCIA_DRIVERS && PCMCIA
config COMEDI_CB_DAS16_CS
tristate "CB DAS16 series PCMCIA support"
- default N
---help---
Enable support for the ComputerBoards/MeasurementComputing PCMCIA
cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16
@@ -1157,7 +1121,6 @@ config COMEDI_CB_DAS16_CS
config COMEDI_DAS08_CS
tristate "CB DAS08 PCMCIA support"
select COMEDI_DAS08
- default N
---help---
Enable support for the ComputerBoards/MeasurementComputing DAS-08
PCMCIA card
@@ -1168,7 +1131,6 @@ config COMEDI_DAS08_CS
config COMEDI_NI_DAQ_700_CS
tristate "NI DAQCard-700 PCMCIA support"
depends on COMEDI_NI_COMMON
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard-700 DIO
@@ -1179,7 +1141,6 @@ config COMEDI_NI_DAQ_DIO24_CS
tristate "NI DAQ-Card DIO-24 PCMCIA support"
depends on COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@@ -1189,7 +1150,6 @@ config COMEDI_NI_DAQ_DIO24_CS
config COMEDI_NI_LABPC_CS
tristate "NI DAQCard-1200 PCMCIA support"
depends on COMEDI_NI_LABPC
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard-1200
@@ -1201,7 +1161,6 @@ config COMEDI_NI_MIO_CS
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard E series
DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@@ -1212,7 +1171,6 @@ config COMEDI_NI_MIO_CS
config COMEDI_QUATECH_DAQP_CS
tristate "Quatech DAQP PCMCIA data capture card support"
- default N
---help---
Enable support for the Quatech DAQP PCMCIA data capture cards
DAQP-208 and DAQP-308
@@ -1225,7 +1183,6 @@ endif # COMEDI_PCMCIA_DRIVERS
menuconfig COMEDI_USB_DRIVERS
tristate "Comedi USB drivers"
depends on COMEDI && USB
- default N
---help---
Enable comedi USB drivers to be built
@@ -1237,7 +1194,6 @@ if COMEDI_USB_DRIVERS && USB
config COMEDI_DT9812
tristate "DataTranslation DT9812 USB module support"
- default N
---help---
Enable support for the Data Translation DT9812 USB module
@@ -1246,7 +1202,6 @@ config COMEDI_DT9812
config COMEDI_USBDUX
tristate "ITL USB-DUX-D support"
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUX-D Board
@@ -1256,7 +1211,6 @@ config COMEDI_USBDUX
config COMEDI_USBDUXFAST
tristate "ITL USB-DUXfast support"
select COMEDI_FC
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUXfast Board
@@ -1266,7 +1220,6 @@ config COMEDI_USBDUXFAST
config COMEDI_USBDUXSIGMA
tristate "ITL USB-DUXsigma support"
select COMEDI_FC
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUXsigma Board
@@ -1275,7 +1228,6 @@ config COMEDI_USBDUXSIGMA
config COMEDI_VMK80XX
tristate "Velleman VM110/VM140 USB Board support"
- default N
---help---
Build the Velleman USB Board Low-Level Driver supporting the
K8055/K8061 aka VM110/VM140 devices
@@ -1288,7 +1240,6 @@ endif # COMEDI_USB_DRIVERS
menuconfig COMEDI_NI_COMMON
tristate "Comedi National Instruments card support"
depends on COMEDI
- default N
---help---
Enable comedi support for National Instruments cards.
Modules in this section are used by many comedi NI drivers.
@@ -1302,7 +1253,6 @@ if COMEDI_NI_COMMON
config COMEDI_MITE
tristate "NI Mite PCI interface chip support"
depends on PCI
- default N
---help---
Enable support for National Instruments Mite PCI interface chip
@@ -1312,7 +1262,6 @@ config COMEDI_MITE
config COMEDI_NI_TIO
tristate "NI general purpose counter support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments general purpose counters.
This module is not used directly by end-users. Rather, it
@@ -1328,7 +1277,6 @@ config COMEDI_NI_LABPC
select COMEDI_8255
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for National Instruments Lab-PC and compatibles
Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
@@ -1343,7 +1291,6 @@ endif # COMEDI_NI_COMMON
config COMEDI_8255
tristate "Generic 8255 support"
depends on COMEDI
- default N
---help---
Enable generic 8255 support.
@@ -1357,24 +1304,9 @@ config COMEDI_8255
To compile this driver as a module, choose M here: the module will be
called 8255.
-config COMEDI_DAS08
- tristate "DAS-08 compatible support"
- depends on COMEDI
- select COMEDI_8255
- default N
- ---help---
- Enable support for DAS08 and compatible ISA, PC/104 and PCI cards.
-
- Note that PCMCIA DAS08 cards are not directly supported by this
- driver, and need a separate driver as a wrapper.
-
- To compile this driver as a module, choose M here: the module will be
- called das08.
-
config COMEDI_FC
tristate "Comedi shared functions for low-level driver support"
depends on COMEDI
- default N
---help---
Enable support for shared functions for low-level drivers.
This module is not used directly by end-users. Rather, it
@@ -1382,3 +1314,22 @@ config COMEDI_FC
To compile this driver as a module, choose M here: the module will be
called comedi_fc.
+
+config COMEDI_AMPLC_DIO200
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
+
+config COMEDI_AMPLC_PC236
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
+
+config COMEDI_AMPLC_PC263
+ tristate
+ depends on COMEDI
+
+config COMEDI_DAS08
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 14ea35a..8ea55ae 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -465,7 +465,7 @@
/* only relevant to kernel modules. */
#define COMEDI_CB_EOS 1 /* end of scan */
-#define COMEDI_CB_EOA 2 /* end of acquisition */
+#define COMEDI_CB_EOA 2 /* end of acquisition/output */
#define COMEDI_CB_BLOCK 4 /* data has arrived:
* wakes up read() / write() */
#define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 9bcf87a..7677657 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -58,14 +58,35 @@ MODULE_LICENSE("GPL");
#ifdef CONFIG_COMEDI_DEBUG
int comedi_debug;
EXPORT_SYMBOL(comedi_debug);
-module_param(comedi_debug, int, 0644);
+module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_debug,
+ "enable comedi core and driver debugging if non-zero (default 0)"
+ );
#endif
bool comedi_autoconfig = 1;
-module_param(comedi_autoconfig, bool, 0444);
+module_param(comedi_autoconfig, bool, S_IRUGO);
+MODULE_PARM_DESC(comedi_autoconfig,
+ "enable drivers to auto-configure comedi devices (default 1)");
static int comedi_num_legacy_minors;
-module_param(comedi_num_legacy_minors, int, 0444);
+module_param(comedi_num_legacy_minors, int, S_IRUGO);
+MODULE_PARM_DESC(comedi_num_legacy_minors,
+ "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
+ );
+
+unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
+module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_size_kb,
+ "default asynchronous buffer size in KiB (default "
+ __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
+
+unsigned int comedi_default_buf_maxsize_kb
+ = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
+module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
+ "default maximum size of asynchronous buffer in KiB (default "
+ __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
static DEFINE_SPINLOCK(comedi_file_info_table_lock);
static struct comedi_device_file_info
@@ -108,15 +129,283 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
static int comedi_fasync(int fd, struct file *file, int on);
static int is_device_busy(struct comedi_device *dev);
+
static int resize_async_buffer(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size);
+ struct comedi_async *async, unsigned new_size)
+{
+ int retval;
+
+ if (new_size > async->max_bufsize)
+ return -EPERM;
+
+ if (s->busy) {
+ DPRINTK("subdevice is busy, cannot resize buffer\n");
+ return -EBUSY;
+ }
+ if (async->mmap_count) {
+ DPRINTK("subdevice is mmapped, cannot resize buffer\n");
+ return -EBUSY;
+ }
+
+ if (!async->prealloc_buf)
+ return -EINVAL;
+
+ /* make sure buffer is an integral number of pages
+ * (we round up) */
+ new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
+
+ retval = comedi_buf_alloc(dev, s, new_size);
+ if (retval < 0)
+ return retval;
+
+ if (s->buf_change) {
+ retval = s->buf_change(dev, s, new_size);
+ if (retval < 0)
+ return retval;
+ }
+
+ DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
+ dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
+ return 0;
+}
+
+/* sysfs attribute files */
+
+static const unsigned bytes_per_kibi = 1024;
+
+static ssize_t show_max_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned max_buffer_size_kb = 0;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice &&
+ (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+ read_subdevice->async) {
+ max_buffer_size_kb = read_subdevice->async->max_bufsize /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_max_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_max_size_kb;
+ unsigned int new_max_size;
+ int ret;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_max_size_kb);
+ if (ret)
+ return ret;
+ if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_max_size = new_max_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice == NULL ||
+ (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+ read_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ read_subdevice->async->max_bufsize = new_max_size;
+ mutex_unlock(&info->device->mutex);
+
+ return count;
+}
+
+static ssize_t show_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned buffer_size_kb = 0;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice &&
+ (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+ read_subdevice->async) {
+ buffer_size_kb = read_subdevice->async->prealloc_bufsz /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_size_kb;
+ unsigned int new_size;
+ int retval;
+ int ret;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_size_kb);
+ if (ret)
+ return ret;
+ if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_size = new_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice == NULL ||
+ (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+ read_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ retval = resize_async_buffer(info->device, read_subdevice,
+ read_subdevice->async, new_size);
+ mutex_unlock(&info->device->mutex);
+
+ if (retval < 0)
+ return retval;
+ return count;
+}
+
+static ssize_t show_max_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned max_buffer_size_kb = 0;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice &&
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+ write_subdevice->async) {
+ max_buffer_size_kb = write_subdevice->async->max_bufsize /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_max_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_max_size_kb;
+ unsigned int new_max_size;
+ int ret;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_max_size_kb);
+ if (ret)
+ return ret;
+ if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_max_size = new_max_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice == NULL ||
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+ write_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ write_subdevice->async->max_bufsize = new_max_size;
+ mutex_unlock(&info->device->mutex);
+
+ return count;
+}
+
+static ssize_t show_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned buffer_size_kb = 0;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice &&
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+ write_subdevice->async) {
+ buffer_size_kb = write_subdevice->async->prealloc_bufsz /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
-/* declarations for sysfs attribute files */
-static struct device_attribute dev_attr_max_read_buffer_kb;
-static struct device_attribute dev_attr_read_buffer_kb;
-static struct device_attribute dev_attr_max_write_buffer_kb;
-static struct device_attribute dev_attr_write_buffer_kb;
+ return retval;
+}
+
+static ssize_t store_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_size_kb;
+ unsigned int new_size;
+ int retval;
+ int ret;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_size_kb);
+ if (ret)
+ return ret;
+ if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice == NULL ||
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+ write_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ retval = resize_async_buffer(info->device, write_subdevice,
+ write_subdevice->async, new_size);
+ mutex_unlock(&info->device->mutex);
+
+ if (retval < 0)
+ return retval;
+ return count;
+}
+
+static struct device_attribute comedi_dev_attrs[] = {
+ __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
+ show_max_read_buffer_kb, store_max_read_buffer_kb),
+ __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_read_buffer_kb, store_read_buffer_kb),
+ __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
+ show_max_write_buffer_kb, store_max_write_buffer_kb),
+ __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_write_buffer_kb, store_write_buffer_kb),
+ __ATTR_NULL
+};
static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -280,7 +569,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
if (ret == 0) {
if (!try_module_get(dev->driver->module)) {
comedi_device_detach(dev);
- return -ENOSYS;
+ ret = -ENOSYS;
}
}
@@ -1545,7 +1834,7 @@ done:
return retval;
}
-static unsigned int comedi_poll(struct file *file, poll_table * wait)
+static unsigned int comedi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
const unsigned minor = iminor(file->f_dentry->d_inode);
@@ -2054,6 +2343,8 @@ static int __init comedi_init(void)
return PTR_ERR(comedi_class);
}
+ comedi_class->dev_attrs = comedi_dev_attrs;
+
/* XXX requires /proc interface */
comedi_proc_init();
@@ -2192,11 +2483,9 @@ static void comedi_device_cleanup(struct comedi_device *dev)
int comedi_alloc_board_minor(struct device *hardware_device)
{
- unsigned long flags;
struct comedi_device_file_info *info;
struct device *csdev;
unsigned i;
- int retval;
info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
if (info == NULL)
@@ -2206,15 +2495,16 @@ int comedi_alloc_board_minor(struct device *hardware_device)
kfree(info);
return -ENOMEM;
}
+ info->hardware_device = hardware_device;
comedi_device_init(info->device);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
}
}
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_BOARD_MINORS) {
comedi_device_cleanup(info->device);
kfree(info->device);
@@ -2230,55 +2520,19 @@ int comedi_alloc_board_minor(struct device *hardware_device)
if (!IS_ERR(csdev))
info->device->class_dev = csdev;
dev_set_drvdata(csdev, info);
- retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_read_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_read_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_write_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_write_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
+
return i;
}
void comedi_free_board_minor(unsigned minor)
{
- unsigned long flags;
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
comedi_file_info_table[minor] = NULL;
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (info) {
struct comedi_device *dev = info->device;
@@ -2294,14 +2548,29 @@ void comedi_free_board_minor(unsigned minor)
}
}
+int comedi_find_board_minor(struct device *hardware_device)
+{
+ int minor;
+ struct comedi_device_file_info *info;
+
+ for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
+ spin_lock(&comedi_file_info_table_lock);
+ info = comedi_file_info_table[minor];
+ if (info && info->hardware_device == hardware_device) {
+ spin_unlock(&comedi_file_info_table_lock);
+ return minor;
+ }
+ spin_unlock(&comedi_file_info_table_lock);
+ }
+ return -ENODEV;
+}
+
int comedi_alloc_subdevice_minor(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- unsigned long flags;
struct comedi_device_file_info *info;
struct device *csdev;
unsigned i;
- int retval;
info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
if (info == NULL)
@@ -2309,14 +2578,14 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
info->device = dev;
info->read_subdevice = s;
info->write_subdevice = s;
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
}
}
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_MINORS) {
kfree(info);
printk(KERN_ERR
@@ -2331,48 +2600,12 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
if (!IS_ERR(csdev))
s->class_dev = csdev;
dev_set_drvdata(csdev, info);
- retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_read_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_read_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_write_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_write_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
+
return i;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
- unsigned long flags;
struct comedi_device_file_info *info;
if (s == NULL)
@@ -2383,10 +2616,10 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
BUG_ON(s->minor >= COMEDI_NUM_MINORS);
BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[s->minor];
comedi_file_info_table[s->minor] = NULL;
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (s->class_dev) {
device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
@@ -2397,310 +2630,12 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
{
- unsigned long flags;
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_MINORS);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
return info;
}
EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
-
-static int resize_async_buffer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size)
-{
- int retval;
-
- if (new_size > async->max_bufsize)
- return -EPERM;
-
- if (s->busy) {
- DPRINTK("subdevice is busy, cannot resize buffer\n");
- return -EBUSY;
- }
- if (async->mmap_count) {
- DPRINTK("subdevice is mmapped, cannot resize buffer\n");
- return -EBUSY;
- }
-
- if (!async->prealloc_buf)
- return -EINVAL;
-
- /* make sure buffer is an integral number of pages
- * (we round up) */
- new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
-
- retval = comedi_buf_alloc(dev, s, new_size);
- if (retval < 0)
- return retval;
-
- if (s->buf_change) {
- retval = s->buf_change(dev, s, new_size);
- if (retval < 0)
- return retval;
- }
-
- DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
- dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
- return 0;
-}
-
-/* sysfs attribute files */
-
-static const unsigned bytes_per_kibi = 1024;
-
-static ssize_t show_max_read_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned max_buffer_size_kb = 0;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice &&
- (read_subdevice->subdev_flags & SDF_CMD_READ) &&
- read_subdevice->async) {
- max_buffer_size_kb = read_subdevice->async->max_bufsize /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_max_read_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_max_size_kb;
- unsigned int new_max_size;
- int ret;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_max_size_kb);
- if (ret)
- return ret;
- if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_max_size = new_max_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice == NULL ||
- (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
- read_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- read_subdevice->async->max_bufsize = new_max_size;
- mutex_unlock(&info->device->mutex);
-
- return count;
-}
-
-static struct device_attribute dev_attr_max_read_buffer_kb = {
- .attr = {
- .name = "max_read_buffer_kb",
- .mode = S_IRUGO | S_IWUSR},
- .show = &show_max_read_buffer_kb,
- .store = &store_max_read_buffer_kb
-};
-
-static ssize_t show_read_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned buffer_size_kb = 0;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice &&
- (read_subdevice->subdev_flags & SDF_CMD_READ) &&
- read_subdevice->async) {
- buffer_size_kb = read_subdevice->async->prealloc_bufsz /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_read_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_size_kb;
- unsigned int new_size;
- int retval;
- int ret;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_size_kb);
- if (ret)
- return ret;
- if (new_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_size = new_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice == NULL ||
- (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
- read_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- retval = resize_async_buffer(info->device, read_subdevice,
- read_subdevice->async, new_size);
- mutex_unlock(&info->device->mutex);
-
- if (retval < 0)
- return retval;
- return count;
-}
-
-static struct device_attribute dev_attr_read_buffer_kb = {
- .attr = {
- .name = "read_buffer_kb",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP},
- .show = &show_read_buffer_kb,
- .store = &store_read_buffer_kb
-};
-
-static ssize_t show_max_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned max_buffer_size_kb = 0;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice &&
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
- write_subdevice->async) {
- max_buffer_size_kb = write_subdevice->async->max_bufsize /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_max_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_max_size_kb;
- unsigned int new_max_size;
- int ret;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_max_size_kb);
- if (ret)
- return ret;
- if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_max_size = new_max_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice == NULL ||
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
- write_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- write_subdevice->async->max_bufsize = new_max_size;
- mutex_unlock(&info->device->mutex);
-
- return count;
-}
-
-static struct device_attribute dev_attr_max_write_buffer_kb = {
- .attr = {
- .name = "max_write_buffer_kb",
- .mode = S_IRUGO | S_IWUSR},
- .show = &show_max_write_buffer_kb,
- .store = &store_max_write_buffer_kb
-};
-
-static ssize_t show_write_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned buffer_size_kb = 0;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice &&
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
- write_subdevice->async) {
- buffer_size_kb = write_subdevice->async->prealloc_bufsz /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_size_kb;
- unsigned int new_size;
- int retval;
- int ret;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_size_kb);
- if (ret)
- return ret;
- if (new_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice == NULL ||
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
- write_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- retval = resize_async_buffer(info->device, write_subdevice,
- write_subdevice->async, new_size);
- mutex_unlock(&info->device->mutex);
-
- if (retval < 0)
- return retval;
- return count;
-}
-
-static struct device_attribute dev_attr_write_buffer_kb = {
- .attr = {
- .name = "write_buffer_kb",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP},
- .show = &show_write_buffer_kb,
- .store = &store_write_buffer_kb
-};
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 7a0d4bc..134be93 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -180,13 +180,18 @@ struct comedi_async {
unsigned int x);
};
+struct pci_dev;
+struct usb_interface;
+
struct comedi_driver {
struct comedi_driver *next;
const char *driver_name;
struct module *module;
int (*attach) (struct comedi_device *, struct comedi_devconfig *);
- int (*detach) (struct comedi_device *);
+ void (*detach) (struct comedi_device *);
+ int (*attach_pci) (struct comedi_device *, struct pci_dev *);
+ int (*attach_usb) (struct comedi_device *, struct usb_interface *);
/* number of elements in board_name and board_id arrays */
unsigned int num_names;
@@ -230,10 +235,16 @@ struct comedi_device {
void (*close) (struct comedi_device *dev);
};
+static inline const void *comedi_board(struct comedi_device *dev)
+{
+ return dev->board_ptr;
+}
+
struct comedi_device_file_info {
struct comedi_device *device;
struct comedi_subdevice *read_subdevice;
struct comedi_subdevice *write_subdevice;
+ struct device *hardware_device;
};
#ifdef CONFIG_COMEDI_DEBUG
@@ -287,6 +298,56 @@ int comedi_device_attach(struct comedi_device *dev,
int comedi_driver_register(struct comedi_driver *);
int comedi_driver_unregister(struct comedi_driver *);
+/**
+ * module_comedi_driver() - Helper macro for registering a comedi driver
+ * @__comedi_driver: comedi_driver struct
+ *
+ * Helper macro for comedi drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only use
+ * this macro once, and calling it replaces module_init() and module_exit().
+ */
+#define module_comedi_driver(__comedi_driver) \
+ module_driver(__comedi_driver, comedi_driver_register, \
+ comedi_driver_unregister)
+
+struct pci_driver;
+
+int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
+void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
+
+/**
+ * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
+ * @__comedi_driver: comedi_driver struct
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for comedi PCI drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \
+ module_driver(__comedi_driver, comedi_pci_driver_register, \
+ comedi_pci_driver_unregister, &(__pci_driver))
+
+struct usb_driver;
+
+int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
+void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+
+/**
+ * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
+ * @__comedi_driver: comedi_driver struct
+ * @__usb_driver: usb_driver struct
+ *
+ * Helper macro for comedi USB drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
+ module_driver(__comedi_driver, comedi_usb_driver_register, \
+ comedi_usb_driver_unregister, &(__usb_driver))
+
void init_polling(void);
void cleanup_polling(void);
void start_polling(struct comedi_device *);
@@ -456,11 +517,12 @@ static inline void *comedi_aux_data(int options[], int n)
int comedi_alloc_subdevice_minor(struct comedi_device *dev,
struct comedi_subdevice *s);
void comedi_free_subdevice_minor(struct comedi_subdevice *s);
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name);
+int comedi_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
-struct usb_device; /* forward declaration */
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
-void comedi_usb_auto_unconfig(struct usb_device *usbdev);
+int comedi_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver);
+void comedi_usb_auto_unconfig(struct usb_interface *intf);
#ifdef CONFIG_COMEDI_PCI_DRIVERS
#define CONFIG_COMEDI_PCI
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index bf185e2..1c3d638 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -106,6 +106,26 @@ void comedi_device_detach(struct comedi_device *dev)
__comedi_device_detach(dev);
}
+/* do a little post-config cleanup */
+/* called with module refcount incremented, decrements it */
+static int comedi_device_postconfig(struct comedi_device *dev)
+{
+ int ret = postconfig(dev);
+ module_put(dev->driver->module);
+ if (ret < 0) {
+ __comedi_device_detach(dev);
+ return ret;
+ }
+ if (!dev->board_name) {
+ printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
+ dev->board_name);
+ dev->board_name = "BUG";
+ }
+ smp_wmb();
+ dev->attached = 1;
+ return 0;
+}
+
int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_driver *driv;
@@ -121,59 +141,36 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
if (driv->num_names) {
dev->board_ptr = comedi_recognize(driv, it->board_name);
- if (dev->board_ptr == NULL) {
- module_put(driv->module);
- continue;
- }
- } else {
- if (strcmp(driv->driver_name, it->board_name)) {
- module_put(driv->module);
+ if (dev->board_ptr)
+ break;
+ } else if (strcmp(driv->driver_name, it->board_name))
+ break;
+ module_put(driv->module);
+ }
+ if (driv == NULL) {
+ /* recognize has failed if we get here */
+ /* report valid board names before returning error */
+ for (driv = comedi_drivers; driv; driv = driv->next) {
+ if (!try_module_get(driv->module)) {
+ printk(KERN_INFO
+ "comedi: failed to increment module count\n");
continue;
}
+ comedi_report_boards(driv);
+ module_put(driv->module);
}
- /* initialize dev->driver here so
- * comedi_error() can be called from attach */
- dev->driver = driv;
- ret = driv->attach(dev, it);
- if (ret < 0) {
- module_put(dev->driver->module);
- __comedi_device_detach(dev);
- return ret;
- }
- goto attached;
+ return -EIO;
}
-
- /* recognize has failed if we get here */
- /* report valid board names before returning error */
- for (driv = comedi_drivers; driv; driv = driv->next) {
- if (!try_module_get(driv->module)) {
- printk(KERN_INFO
- "comedi: failed to increment module count\n");
- continue;
- }
- comedi_report_boards(driv);
- module_put(driv->module);
- }
- return -EIO;
-
-attached:
- /* do a little post-config cleanup */
- ret = postconfig(dev);
- module_put(dev->driver->module);
+ /* initialize dev->driver here so
+ * comedi_error() can be called from attach */
+ dev->driver = driv;
+ ret = driv->attach(dev, it);
if (ret < 0) {
+ module_put(dev->driver->module);
__comedi_device_detach(dev);
return ret;
}
-
- if (!dev->board_name) {
- printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
- dev->board_name);
- dev->board_name = "BUG";
- }
- smp_wmb();
- dev->attached = 1;
-
- return 0;
+ return comedi_device_postconfig(dev);
}
int comedi_driver_register(struct comedi_driver *driver)
@@ -242,6 +239,8 @@ static int postconfig(struct comedi_device *dev)
s->len_chanlist = 1;
if (s->do_cmd) {
+ unsigned int buf_size;
+
BUG_ON((s->subdev_flags & (SDF_CMD_READ |
SDF_CMD_WRITE)) == 0);
BUG_ON(!s->do_cmdtest);
@@ -257,19 +256,20 @@ static int postconfig(struct comedi_device *dev)
async->subdevice = s;
s->async = async;
-#define DEFAULT_BUF_MAXSIZE (64*1024)
-#define DEFAULT_BUF_SIZE (64*1024)
-
- async->max_bufsize = DEFAULT_BUF_MAXSIZE;
+ async->max_bufsize =
+ comedi_default_buf_maxsize_kb * 1024;
+ buf_size = comedi_default_buf_size_kb * 1024;
+ if (buf_size > async->max_bufsize)
+ buf_size = async->max_bufsize;
async->prealloc_buf = NULL;
async->prealloc_bufsz = 0;
- if (comedi_buf_alloc(dev, s, DEFAULT_BUF_SIZE) < 0) {
+ if (comedi_buf_alloc(dev, s, buf_size) < 0) {
printk(KERN_INFO "Buffer allocation failed\n");
return -ENOMEM;
}
if (s->buf_change) {
- ret = s->buf_change(dev, s, DEFAULT_BUF_SIZE);
+ ret = s->buf_change(dev, s, buf_size);
if (ret < 0)
return ret;
}
@@ -814,67 +814,102 @@ void comedi_reset_async_buf(struct comedi_async *async)
async->events = 0;
}
-static int comedi_auto_config(struct device *hardware_device,
- const char *board_name, const int *options,
- unsigned num_options)
+static int
+comedi_auto_config_helper(struct device *hardware_device,
+ struct comedi_driver *driver,
+ int (*attach_wrapper) (struct comedi_device *,
+ void *), void *context)
{
- struct comedi_devconfig it;
int minor;
struct comedi_device_file_info *dev_file_info;
- int retval;
- unsigned *private_data = NULL;
+ struct comedi_device *comedi_dev;
+ int ret;
- if (!comedi_autoconfig) {
- dev_set_drvdata(hardware_device, NULL);
+ if (!comedi_autoconfig)
return 0;
- }
minor = comedi_alloc_board_minor(hardware_device);
if (minor < 0)
return minor;
- private_data = kmalloc(sizeof(unsigned), GFP_KERNEL);
- if (private_data == NULL) {
- retval = -ENOMEM;
- goto cleanup;
+ dev_file_info = comedi_get_device_file_info(minor);
+ comedi_dev = dev_file_info->device;
+
+ mutex_lock(&comedi_dev->mutex);
+ if (comedi_dev->attached)
+ ret = -EBUSY;
+ else if (!try_module_get(driver->module)) {
+ printk(KERN_INFO "comedi: failed to increment module count\n");
+ ret = -EIO;
+ } else {
+ /* set comedi_dev->driver here for attach wrapper */
+ comedi_dev->driver = driver;
+ ret = (*attach_wrapper)(comedi_dev, context);
+ if (ret < 0) {
+ module_put(driver->module);
+ __comedi_device_detach(comedi_dev);
+ } else {
+ ret = comedi_device_postconfig(comedi_dev);
+ }
}
- *private_data = minor;
- dev_set_drvdata(hardware_device, private_data);
+ mutex_unlock(&comedi_dev->mutex);
- dev_file_info = comedi_get_device_file_info(minor);
+ if (ret < 0)
+ comedi_free_board_minor(minor);
+ return ret;
+}
+
+static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context)
+{
+ struct comedi_devconfig *it = context;
+ struct comedi_driver *driv = dev->driver;
+
+ if (driv->num_names) {
+ /* look for generic board entry matching driver name, which
+ * has already been copied to it->board_name */
+ dev->board_ptr = comedi_recognize(driv, it->board_name);
+ if (dev->board_ptr == NULL) {
+ printk(KERN_WARNING
+ "comedi: auto config failed to find board entry"
+ " '%s' for driver '%s'\n", it->board_name,
+ driv->driver_name);
+ comedi_report_boards(driv);
+ return -EINVAL;
+ }
+ }
+ return driv->attach(dev, it);
+}
+
+static int comedi_auto_config(struct device *hardware_device,
+ struct comedi_driver *driver, const int *options,
+ unsigned num_options)
+{
+ struct comedi_devconfig it;
memset(&it, 0, sizeof(it));
- strncpy(it.board_name, board_name, COMEDI_NAMELEN);
+ strncpy(it.board_name, driver->driver_name, COMEDI_NAMELEN);
it.board_name[COMEDI_NAMELEN - 1] = '\0';
BUG_ON(num_options > COMEDI_NDEVCONFOPTS);
memcpy(it.options, options, num_options * sizeof(int));
-
- mutex_lock(&dev_file_info->device->mutex);
- retval = comedi_device_attach(dev_file_info->device, &it);
- mutex_unlock(&dev_file_info->device->mutex);
-
-cleanup:
- if (retval < 0) {
- kfree(private_data);
- comedi_free_board_minor(minor);
- }
- return retval;
+ return comedi_auto_config_helper(hardware_device, driver,
+ comedi_auto_config_wrapper, &it);
}
static void comedi_auto_unconfig(struct device *hardware_device)
{
- unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device);
- if (minor == NULL)
- return;
-
- BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS);
+ int minor;
- comedi_free_board_minor(*minor);
- dev_set_drvdata(hardware_device, NULL);
- kfree(minor);
+ if (hardware_device == NULL)
+ return;
+ minor = comedi_find_board_minor(hardware_device);
+ if (minor < 0)
+ return;
+ BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+ comedi_free_board_minor(minor);
}
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
+static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver)
{
int options[2];
@@ -883,9 +918,30 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
/* pci slot */
options[1] = PCI_SLOT(pcidev->devfn);
- return comedi_auto_config(&pcidev->dev, board_name,
+ return comedi_auto_config(&pcidev->dev, driver,
options, ARRAY_SIZE(options));
}
+
+static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev)
+{
+ return dev->driver->attach_pci(dev, pcidev);
+}
+
+static int comedi_new_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config_helper(&pcidev->dev, driver,
+ comedi_pci_attach_wrapper, pcidev);
+}
+
+int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
+{
+
+ if (driver->attach_pci)
+ return comedi_new_pci_auto_config(pcidev, driver);
+ else
+ return comedi_old_pci_auto_config(pcidev, driver);
+}
EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
@@ -894,16 +950,96 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
}
EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name)
+int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver)
+{
+ int ret;
+
+ ret = comedi_driver_register(comedi_driver);
+ if (ret < 0)
+ return ret;
+
+ /* FIXME: Remove this test after auditing all comedi pci drivers */
+ if (!pci_driver->name)
+ pci_driver->name = comedi_driver->driver_name;
+
+ ret = pci_register_driver(pci_driver);
+ if (ret < 0) {
+ comedi_driver_unregister(comedi_driver);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_register);
+
+void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver)
+{
+ pci_unregister_driver(pci_driver);
+ comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister);
+
+static int comedi_old_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config(&intf->dev, driver, NULL, 0);
+}
+
+static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf)
+{
+ return dev->driver->attach_usb(dev, intf);
+}
+
+static int comedi_new_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config_helper(&intf->dev, driver,
+ comedi_usb_attach_wrapper, intf);
+}
+
+int comedi_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
{
- BUG_ON(usbdev == NULL);
- return comedi_auto_config(&usbdev->dev, board_name, NULL, 0);
+ BUG_ON(intf == NULL);
+ if (driver->attach_usb)
+ return comedi_new_usb_auto_config(intf, driver);
+ else
+ return comedi_old_usb_auto_config(intf, driver);
}
EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
-void comedi_usb_auto_unconfig(struct usb_device *usbdev)
+void comedi_usb_auto_unconfig(struct usb_interface *intf)
{
- BUG_ON(usbdev == NULL);
- comedi_auto_unconfig(&usbdev->dev);
+ BUG_ON(intf == NULL);
+ comedi_auto_unconfig(&intf->dev);
}
EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig);
+
+int comedi_usb_driver_register(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver)
+{
+ int ret;
+
+ ret = comedi_driver_register(comedi_driver);
+ if (ret < 0)
+ return ret;
+
+ ret = usb_register(usb_driver);
+ if (ret < 0) {
+ comedi_driver_unregister(comedi_driver);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_register);
+
+void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver)
+{
+ usb_deregister(usb_driver);
+ comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 6c26ac8..27e39e4 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -107,31 +107,6 @@ struct subdev_8255_struct {
#define CALLBACK_FUNC (((struct subdev_8255_struct *)s->private)->cb_func)
#define subdevpriv ((struct subdev_8255_struct *)s->private)
-static int dev_8255_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dev_8255_detach(struct comedi_device *dev);
-static struct comedi_driver driver_8255 = {
- .driver_name = "8255",
- .module = THIS_MODULE,
- .attach = dev_8255_attach,
- .detach = dev_8255_detach,
-};
-
-static int __init driver_8255_init_module(void)
-{
- return comedi_driver_register(&driver_8255);
-}
-
-static void __exit driver_8255_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_8255);
-}
-
-module_init(driver_8255_init_module);
-module_exit(driver_8255_cleanup_module);
-
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s);
-
void subdev_8255_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -185,6 +160,23 @@ static int subdev_8255_insn(struct comedi_device *dev,
return 2;
}
+static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ int config;
+
+ config = CR_CW;
+ /* 1 in io_bits indicates output, 1 in config indicates input */
+ if (!(s->io_bits & 0x0000ff))
+ config |= CR_A_IO;
+ if (!(s->io_bits & 0x00ff00))
+ config |= CR_B_IO;
+ if (!(s->io_bits & 0x0f0000))
+ config |= CR_C_LO_IO;
+ if (!(s->io_bits & 0xf00000))
+ config |= CR_C_HI_IO;
+ CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
+}
+
static int subdev_8255_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -222,23 +214,6 @@ static int subdev_8255_insn_config(struct comedi_device *dev,
return 1;
}
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- int config;
-
- config = CR_CW;
- /* 1 in io_bits indicates output, 1 in config indicates input */
- if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
- if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
- if (!(s->io_bits & 0x0f0000))
- config |= CR_C_LO_IO;
- if (!(s->io_bits & 0xf00000))
- config |= CR_C_HI_IO;
- CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
-}
-
static int subdev_8255_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -442,14 +417,12 @@ static int dev_8255_attach(struct comedi_device *dev,
return 0;
}
-static int dev_8255_detach(struct comedi_device *dev)
+static void dev_8255_detach(struct comedi_device *dev)
{
int i;
unsigned long iobase;
struct comedi_subdevice *s;
- printk(KERN_INFO "comedi%d: 8255: remove\n", dev->minor);
-
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
if (s->type != COMEDI_SUBD_UNUSED) {
@@ -458,10 +431,16 @@ static int dev_8255_detach(struct comedi_device *dev)
}
subdev_8255_cleanup(dev, s);
}
-
- return 0;
}
+static struct comedi_driver dev_8255_driver = {
+ .driver_name = "8255",
+ .module = THIS_MODULE,
+ .attach = dev_8255_attach,
+ .detach = dev_8255_detach,
+};
+module_comedi_driver(dev_8255_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index 9def225..4e4fc41 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -22,46 +22,13 @@ Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */
#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */
-static int acl7225b_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int acl7225b_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* driver name */
int io_range; /* len of I/O space */
};
-static const struct boardtype boardtypes[] = {
- {"acl7225b", ACL7225_SIZE,},
- {"p16r16dio", P16R16DIO_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
#define this_board ((const struct boardtype *)dev->board_ptr)
-static struct comedi_driver driver_acl7225b = {
- .driver_name = "acl7225b",
- .module = THIS_MODULE,
- .attach = acl7225b_attach,
- .detach = acl7225b_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct boardtype),
-};
-
-static int __init driver_acl7225b_init_module(void)
-{
- return comedi_driver_register(&driver_acl7225b);
-}
-
-static void __exit driver_acl7225b_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_acl7225b);
-}
-
-module_init(driver_acl7225b_init_module);
-module_exit(driver_acl7225b_cleanup_module);
-
static int acl7225b_do_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -152,16 +119,28 @@ static int acl7225b_attach(struct comedi_device *dev,
return 0;
}
-static int acl7225b_detach(struct comedi_device *dev)
+static void acl7225b_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct boardtype boardtypes[] = {
+ { "acl7225b", ACL7225_SIZE, },
+ { "p16r16dio", P16R16DIO_SIZE, },
+};
+
+static struct comedi_driver acl7225b_driver = {
+ .driver_name = "acl7225b",
+ .module = THIS_MODULE,
+ .attach = acl7225b_attach,
+ .detach = acl7225b_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct boardtype),
+};
+module_comedi_driver(acl7225b_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index ca5bd9b8..44aaf83 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -224,2318 +224,1213 @@ MODULE_DEVICE_TABLE(pci, addi_apci_tbl);
static const struct addi_board boardtypes[] = {
#ifdef CONFIG_APCI_3120
- {"apci3120",
- APCI3120_BOARD_VENDOR_ID,
- 0x818D,
- AMCC_OP_REG_SIZE,
- APCI3120_ADDRESS_RANGE,
- 8,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 16,
- 8,
- 16,
- 8,
- 0xffff,
- 0x3fff,
- &range_apci3120_ai,
- &range_apci3120_ao,
- 4,
- 4,
- 0x0f,
- 0,
- NULL,
- 1,
- 1,
- 1,
- 10000,
- 100000,
- v_APCI3120_Interrupt,
- i_APCI3120_Reset,
- i_APCI3120_InsnConfigAnalogInput,
- i_APCI3120_InsnReadAnalogInput,
- NULL,
- NULL,
- i_APCI3120_CommandTestAnalogInput,
- i_APCI3120_CommandAnalogInput,
- i_APCI3120_StopCyclicAcquisition,
- NULL,
- i_APCI3120_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3120_InsnReadDigitalInput,
- NULL,
- i_APCI3120_InsnBitsDigitalInput,
- i_APCI3120_InsnConfigDigitalOutput,
- i_APCI3120_InsnWriteDigitalOutput,
- i_APCI3120_InsnBitsDigitalOutput,
- NULL,
- i_APCI3120_InsnConfigTimer,
- i_APCI3120_InsnWriteTimer,
- i_APCI3120_InsnReadTimer,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3120",
+ .i_VendorId = APCI3120_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x818D,
+ .i_IorangeBase0 = AMCC_OP_REG_SIZE,
+ .i_IorangeBase1 = APCI3120_ADDRESS_RANGE,
+ .i_IorangeBase2 = 8,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 8,
+ .i_AiMaxdata = 0xffff,
+ .i_AoMaxdata = 0x3fff,
+ .pr_AiRangelist = &range_apci3120_ai,
+ .pr_AoRangelist = &range_apci3120_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 0x0f,
+ .i_Dma = 1,
+ .i_Timer = 1,
+ .b_AvailableConvertUnit = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3120_Interrupt,
+ .reset = i_APCI3120_Reset,
+ .ai_config = i_APCI3120_InsnConfigAnalogInput,
+ .ai_read = i_APCI3120_InsnReadAnalogInput,
+ .ai_cmdtest = i_APCI3120_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3120_CommandAnalogInput,
+ .ai_cancel = i_APCI3120_StopCyclicAcquisition,
+ .ao_write = i_APCI3120_InsnWriteAnalogOutput,
+ .di_read = i_APCI3120_InsnReadDigitalInput,
+ .di_bits = i_APCI3120_InsnBitsDigitalInput,
+ .do_config = i_APCI3120_InsnConfigDigitalOutput,
+ .do_write = i_APCI3120_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3120_InsnBitsDigitalOutput,
+ .timer_config = i_APCI3120_InsnConfigTimer,
+ .timer_write = i_APCI3120_InsnWriteTimer,
+ .timer_read = i_APCI3120_InsnReadTimer,
+ },
#endif
#ifdef CONFIG_APCI_1032
- {"apci1032",
- APCI1032_BOARD_VENDOR_ID,
- 0x1003,
- 4,
- APCI1032_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 32,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI1032_Interrupt,
- i_APCI1032_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1032_ConfigDigitalInput,
- i_APCI1032_Read1DigitalInput,
- NULL,
- i_APCI1032_ReadMoreDigitalInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1032",
+ .i_VendorId = APCI1032_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1003,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI1032_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 32,
+ .interrupt = v_APCI1032_Interrupt,
+ .reset = i_APCI1032_Reset,
+ .di_config = i_APCI1032_ConfigDigitalInput,
+ .di_read = i_APCI1032_Read1DigitalInput,
+ .di_bits = i_APCI1032_ReadMoreDigitalInput,
+ },
#endif
#ifdef CONFIG_APCI_1516
- {"apci1516",
- APCI1516_BOARD_VENDOR_ID,
- 0x1001,
- 128,
- APCI1516_ADDRESS_RANGE,
- 32,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 8,
- 8,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI1516_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1516_Read1DigitalInput,
- NULL,
- i_APCI1516_ReadMoreDigitalInput,
- i_APCI1516_ConfigDigitalOutput,
- i_APCI1516_WriteDigitalOutput,
- i_APCI1516_ReadDigitalOutput,
- NULL,
- i_APCI1516_ConfigWatchdog,
- i_APCI1516_StartStopWriteWatchdog,
- i_APCI1516_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1516",
+ .i_VendorId = APCI1516_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1001,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1516_ADDRESS_RANGE,
+ .i_IorangeBase2 = 32,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrDiChannel = 8,
+ .i_NbrDoChannel = 8,
+ .i_Timer = 1,
+ .reset = i_APCI1516_Reset,
+ .di_read = i_APCI1516_Read1DigitalInput,
+ .di_bits = i_APCI1516_ReadMoreDigitalInput,
+ .do_config = i_APCI1516_ConfigDigitalOutput,
+ .do_write = i_APCI1516_WriteDigitalOutput,
+ .do_bits = i_APCI1516_ReadDigitalOutput,
+ .timer_config = i_APCI1516_ConfigWatchdog,
+ .timer_write = i_APCI1516_StartStopWriteWatchdog,
+ .timer_read = i_APCI1516_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2016
- {"apci2016",
- APCI2016_BOARD_VENDOR_ID,
- 0x1002,
- 128,
- APCI2016_ADDRESS_RANGE,
- 32,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 16,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI2016_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2016_ConfigDigitalOutput,
- i_APCI2016_WriteDigitalOutput,
- i_APCI2016_BitsDigitalOutput,
- NULL,
- i_APCI2016_ConfigWatchdog,
- i_APCI2016_StartStopWriteWatchdog,
- i_APCI2016_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2016",
+ .i_VendorId = APCI2016_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1002,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI2016_ADDRESS_RANGE,
+ .i_IorangeBase2 = 32,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrDoChannel = 16,
+ .i_Timer = 1,
+ .reset = i_APCI2016_Reset,
+ .do_config = i_APCI2016_ConfigDigitalOutput,
+ .do_write = i_APCI2016_WriteDigitalOutput,
+ .do_bits = i_APCI2016_BitsDigitalOutput,
+ .timer_config = i_APCI2016_ConfigWatchdog,
+ .timer_write = i_APCI2016_StartStopWriteWatchdog,
+ .timer_read = i_APCI2016_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2032
- {"apci2032",
- APCI2032_BOARD_VENDOR_ID,
- 0x1004,
- 4,
- APCI2032_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 32,
- 0xffffffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI2032_Interrupt,
- i_APCI2032_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2032_ConfigDigitalOutput,
- i_APCI2032_WriteDigitalOutput,
- i_APCI2032_ReadDigitalOutput,
- i_APCI2032_ReadInterruptStatus,
- i_APCI2032_ConfigWatchdog,
- i_APCI2032_StartStopWriteWatchdog,
- i_APCI2032_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2032",
+ .i_VendorId = APCI2032_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1004,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI2032_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDoChannel = 32,
+ .i_DoMaxdata = 0xffffffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI2032_Interrupt,
+ .reset = i_APCI2032_Reset,
+ .do_config = i_APCI2032_ConfigDigitalOutput,
+ .do_write = i_APCI2032_WriteDigitalOutput,
+ .do_bits = i_APCI2032_ReadDigitalOutput,
+ .do_read = i_APCI2032_ReadInterruptStatus,
+ .timer_config = i_APCI2032_ConfigWatchdog,
+ .timer_write = i_APCI2032_StartStopWriteWatchdog,
+ .timer_read = i_APCI2032_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2200
- {"apci2200",
- APCI2200_BOARD_VENDOR_ID,
- 0x1005,
- 4,
- APCI2200_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 8,
- 16,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI2200_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2200_Read1DigitalInput,
- NULL,
- i_APCI2200_ReadMoreDigitalInput,
- i_APCI2200_ConfigDigitalOutput,
- i_APCI2200_WriteDigitalOutput,
- i_APCI2200_ReadDigitalOutput,
- NULL,
- i_APCI2200_ConfigWatchdog,
- i_APCI2200_StartStopWriteWatchdog,
- i_APCI2200_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2200",
+ .i_VendorId = APCI2200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1005,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI2200_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 8,
+ .i_NbrDoChannel = 16,
+ .i_Timer = 1,
+ .reset = i_APCI2200_Reset,
+ .di_read = i_APCI2200_Read1DigitalInput,
+ .di_bits = i_APCI2200_ReadMoreDigitalInput,
+ .do_config = i_APCI2200_ConfigDigitalOutput,
+ .do_write = i_APCI2200_WriteDigitalOutput,
+ .do_bits = i_APCI2200_ReadDigitalOutput,
+ .timer_config = i_APCI2200_ConfigWatchdog,
+ .timer_write = i_APCI2200_StartStopWriteWatchdog,
+ .timer_read = i_APCI2200_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_1564
- {"apci1564",
- APCI1564_BOARD_VENDOR_ID,
- 0x1006,
- 128,
- APCI1564_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 32,
- 32,
- 0xffffffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI1564_Interrupt,
- i_APCI1564_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1564_ConfigDigitalInput,
- i_APCI1564_Read1DigitalInput,
- NULL,
- i_APCI1564_ReadMoreDigitalInput,
- i_APCI1564_ConfigDigitalOutput,
- i_APCI1564_WriteDigitalOutput,
- i_APCI1564_ReadDigitalOutput,
- i_APCI1564_ReadInterruptStatus,
- i_APCI1564_ConfigTimerCounterWatchdog,
- i_APCI1564_StartStopWriteTimerCounterWatchdog,
- i_APCI1564_ReadTimerCounterWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1564",
+ .i_VendorId = APCI1564_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1006,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1564_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 32,
+ .i_NbrDoChannel = 32,
+ .i_DoMaxdata = 0xffffffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI1564_Interrupt,
+ .reset = i_APCI1564_Reset,
+ .di_config = i_APCI1564_ConfigDigitalInput,
+ .di_read = i_APCI1564_Read1DigitalInput,
+ .di_bits = i_APCI1564_ReadMoreDigitalInput,
+ .do_config = i_APCI1564_ConfigDigitalOutput,
+ .do_write = i_APCI1564_WriteDigitalOutput,
+ .do_bits = i_APCI1564_ReadDigitalOutput,
+ .do_read = i_APCI1564_ReadInterruptStatus,
+ .timer_config = i_APCI1564_ConfigTimerCounterWatchdog,
+ .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog,
+ .timer_read = i_APCI1564_ReadTimerCounterWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_1500
- {"apci1500",
- APCI1500_BOARD_VENDOR_ID,
- 0x80fc,
- 128,
- APCI1500_ADDRESS_RANGE,
- 4,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 16,
- 16,
- 0xffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI1500_Interrupt,
- i_APCI1500_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1500_ConfigDigitalInputEvent,
- i_APCI1500_Initialisation,
- i_APCI1500_StartStopInputEvent,
- i_APCI1500_ReadMoreDigitalInput,
- i_APCI1500_ConfigDigitalOutputErrorInterrupt,
- i_APCI1500_WriteDigitalOutput,
- i_APCI1500_ConfigureInterrupt,
- NULL,
- i_APCI1500_ConfigCounterTimerWatchdog,
- i_APCI1500_StartStopTriggerTimerCounterWatchdog,
- i_APCI1500_ReadInterruptMask,
- i_APCI1500_ReadCounterTimerWatchdog,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1500",
+ .i_VendorId = APCI1500_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x80fc,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1500_ADDRESS_RANGE,
+ .i_IorangeBase2 = 4,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrDiChannel = 16,
+ .i_NbrDoChannel = 16,
+ .i_DoMaxdata = 0xffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI1500_Interrupt,
+ .reset = i_APCI1500_Reset,
+ .di_config = i_APCI1500_ConfigDigitalInputEvent,
+ .di_read = i_APCI1500_Initialisation,
+ .di_write = i_APCI1500_StartStopInputEvent,
+ .di_bits = i_APCI1500_ReadMoreDigitalInput,
+ .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt,
+ .do_write = i_APCI1500_WriteDigitalOutput,
+ .do_bits = i_APCI1500_ConfigureInterrupt,
+ .timer_config = i_APCI1500_ConfigCounterTimerWatchdog,
+ .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog,
+ .timer_read = i_APCI1500_ReadInterruptMask,
+ .timer_bits = i_APCI1500_ReadCounterTimerWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_3001
- {"apci3001",
- APCI3120_BOARD_VENDOR_ID,
- 0x828D,
- AMCC_OP_REG_SIZE,
- APCI3120_ADDRESS_RANGE,
- 8,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 16,
- 8,
- 16,
- 0,
- 0xfff,
- 0,
- &range_apci3120_ai,
- NULL,
- 4,
- 4,
- 0x0f,
- 0,
- NULL,
- 1,
- 1,
- 1,
- 10000,
- 100000,
- v_APCI3120_Interrupt,
- i_APCI3120_Reset,
- i_APCI3120_InsnConfigAnalogInput,
- i_APCI3120_InsnReadAnalogInput,
- NULL,
- NULL,
- i_APCI3120_CommandTestAnalogInput,
- i_APCI3120_CommandAnalogInput,
- i_APCI3120_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3120_InsnReadDigitalInput,
- NULL,
- i_APCI3120_InsnBitsDigitalInput,
- i_APCI3120_InsnConfigDigitalOutput,
- i_APCI3120_InsnWriteDigitalOutput,
- i_APCI3120_InsnBitsDigitalOutput,
- NULL,
- i_APCI3120_InsnConfigTimer,
- i_APCI3120_InsnWriteTimer,
- i_APCI3120_InsnReadTimer,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3001",
+ .i_VendorId = APCI3120_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x828D,
+ .i_IorangeBase0 = AMCC_OP_REG_SIZE,
+ .i_IorangeBase1 = APCI3120_ADDRESS_RANGE,
+ .i_IorangeBase2 = 8,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0xfff,
+ .pr_AiRangelist = &range_apci3120_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 0x0f,
+ .i_Dma = 1,
+ .i_Timer = 1,
+ .b_AvailableConvertUnit = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3120_Interrupt,
+ .reset = i_APCI3120_Reset,
+ .ai_config = i_APCI3120_InsnConfigAnalogInput,
+ .ai_read = i_APCI3120_InsnReadAnalogInput,
+ .ai_cmdtest = i_APCI3120_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3120_CommandAnalogInput,
+ .ai_cancel = i_APCI3120_StopCyclicAcquisition,
+ .di_read = i_APCI3120_InsnReadDigitalInput,
+ .di_bits = i_APCI3120_InsnBitsDigitalInput,
+ .do_config = i_APCI3120_InsnConfigDigitalOutput,
+ .do_write = i_APCI3120_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3120_InsnBitsDigitalOutput,
+ .timer_config = i_APCI3120_InsnConfigTimer,
+ .timer_write = i_APCI3120_InsnWriteTimer,
+ .timer_read = i_APCI3120_InsnReadTimer,
+ },
#endif
#ifdef CONFIG_APCI_3501
- {"apci3501",
- APCI3501_BOARD_VENDOR_ID,
- 0x3001,
- 64,
- APCI3501_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5933,
- 0,
- 0,
- 0,
- 8,
- 0,
- 16383,
- NULL,
- &range_apci3501_ao,
- 2,
- 2,
- 0x3,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI3501_Interrupt,
- i_APCI3501_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3501_ConfigAnalogOutput,
- i_APCI3501_WriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3501_ReadDigitalInput,
- i_APCI3501_ConfigDigitalOutput,
- i_APCI3501_WriteDigitalOutput,
- i_APCI3501_ReadDigitalOutput,
- NULL,
- i_APCI3501_ConfigTimerCounterWatchdog,
- i_APCI3501_StartStopWriteTimerCounterWatchdog,
- i_APCI3501_ReadTimerCounterWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3501",
+ .i_VendorId = APCI3501_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3001,
+ .i_IorangeBase0 = 64,
+ .i_IorangeBase1 = APCI3501_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5933,
+ .i_AoMaxdata = 16383,
+ .pr_AoRangelist = &range_apci3501_ao,
+ .i_NbrDiChannel = 2,
+ .i_NbrDoChannel = 2,
+ .i_DoMaxdata = 0x3,
+ .i_Timer = 1,
+ .interrupt = v_APCI3501_Interrupt,
+ .reset = i_APCI3501_Reset,
+ .ao_config = i_APCI3501_ConfigAnalogOutput,
+ .ao_write = i_APCI3501_WriteAnalogOutput,
+ .di_bits = i_APCI3501_ReadDigitalInput,
+ .do_config = i_APCI3501_ConfigDigitalOutput,
+ .do_write = i_APCI3501_WriteDigitalOutput,
+ .do_bits = i_APCI3501_ReadDigitalOutput,
+ .timer_config = i_APCI3501_ConfigTimerCounterWatchdog,
+ .timer_write = i_APCI3501_StartStopWriteTimerCounterWatchdog,
+ .timer_read = i_APCI3501_ReadTimerCounterWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_035
- {"apci035",
- APCI035_BOARD_VENDOR_ID,
- 0x0300,
- 127,
- APCI035_ADDRESS_RANGE,
- 0,
- 0,
- 1,
- ADDIDATA_S5920,
- 16,
- 8,
- 16,
- 0,
- 0xff,
- 0,
- &range_apci035_ai,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 10000,
- 100000,
- v_APCI035_Interrupt,
- i_APCI035_Reset,
- i_APCI035_ConfigAnalogInput,
- i_APCI035_ReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI035_ConfigTimerWatchdog,
- i_APCI035_StartStopWriteTimerWatchdog,
- i_APCI035_ReadTimerWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci035",
+ .i_VendorId = APCI035_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x0300,
+ .i_IorangeBase0 = 127,
+ .i_IorangeBase1 = APCI035_ADDRESS_RANGE,
+ .i_PCIEeprom = 1,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0xff,
+ .pr_AiRangelist = &range_apci035_ai,
+ .i_Timer = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI035_Interrupt,
+ .reset = i_APCI035_Reset,
+ .ai_config = i_APCI035_ConfigAnalogInput,
+ .ai_read = i_APCI035_ReadAnalogInput,
+ .timer_config = i_APCI035_ConfigTimerWatchdog,
+ .timer_write = i_APCI035_StartStopWriteTimerWatchdog,
+ .timer_read = i_APCI035_ReadTimerWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_3200
- {"apci3200",
- APCI3200_BOARD_VENDOR_ID,
- 0x3000,
- 128,
- 256,
- 4,
- 4,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 16,
- 8,
- 16,
- 0,
- 0x3ffff,
- 0,
- &range_apci3200_ai,
- NULL,
- 4,
- 4,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 10000,
- 100000,
- v_APCI3200_Interrupt,
- i_APCI3200_Reset,
- i_APCI3200_ConfigAnalogInput,
- i_APCI3200_ReadAnalogInput,
- i_APCI3200_InsnWriteReleaseAnalogInput,
- i_APCI3200_InsnBits_AnalogInput_Test,
- i_APCI3200_CommandTestAnalogInput,
- i_APCI3200_CommandAnalogInput,
- i_APCI3200_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3200_ReadDigitalInput,
- i_APCI3200_ConfigDigitalOutput,
- i_APCI3200_WriteDigitalOutput,
- i_APCI3200_ReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3200",
+ .i_VendorId = APCI3200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3000,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 4,
+ .i_IorangeBase3 = 4,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0x3ffff,
+ .pr_AiRangelist = &range_apci3200_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3200_Interrupt,
+ .reset = i_APCI3200_Reset,
+ .ai_config = i_APCI3200_ConfigAnalogInput,
+ .ai_read = i_APCI3200_ReadAnalogInput,
+ .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
+ .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
+ .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3200_CommandAnalogInput,
+ .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .di_bits = i_APCI3200_ReadDigitalInput,
+ .do_config = i_APCI3200_ConfigDigitalOutput,
+ .do_write = i_APCI3200_WriteDigitalOutput,
+ .do_bits = i_APCI3200_ReadDigitalOutput,
+ },
#endif
#ifdef CONFIG_APCI_3300
/* Begin JK .20.10.2004 = APCI-3300 integration */
- {"apci3300",
- APCI3200_BOARD_VENDOR_ID,
- 0x3007,
- 128,
- 256,
- 4,
- 4,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 8,
- 8,
- 0,
- 0x3ffff,
- 0,
- &range_apci3300_ai,
- NULL,
- 4,
- 4,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 10000,
- 100000,
- v_APCI3200_Interrupt,
- i_APCI3200_Reset,
- i_APCI3200_ConfigAnalogInput,
- i_APCI3200_ReadAnalogInput,
- i_APCI3200_InsnWriteReleaseAnalogInput,
- i_APCI3200_InsnBits_AnalogInput_Test,
- i_APCI3200_CommandTestAnalogInput,
- i_APCI3200_CommandAnalogInput,
- i_APCI3200_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3200_ReadDigitalInput,
- i_APCI3200_ConfigDigitalOutput,
- i_APCI3200_WriteDigitalOutput,
- i_APCI3200_ReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3300",
+ .i_VendorId = APCI3200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3007,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 4,
+ .i_IorangeBase3 = 4,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 0x3ffff,
+ .pr_AiRangelist = &range_apci3300_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3200_Interrupt,
+ .reset = i_APCI3200_Reset,
+ .ai_config = i_APCI3200_ConfigAnalogInput,
+ .ai_read = i_APCI3200_ReadAnalogInput,
+ .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
+ .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
+ .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3200_CommandAnalogInput,
+ .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .di_bits = i_APCI3200_ReadDigitalInput,
+ .do_config = i_APCI3200_ConfigDigitalOutput,
+ .do_write = i_APCI3200_WriteDigitalOutput,
+ .do_bits = i_APCI3200_ReadDigitalOutput,
+ },
#endif
#ifdef CONFIG_APCI_1710
- {"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID,
- 128,
- 8,
- 256,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI1710_Interrupt,
- i_APCI1710_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1710",
+ .i_VendorId = APCI1710_BOARD_VENDOR_ID,
+ .i_DeviceId = APCI1710_BOARD_DEVICE_ID,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 8,
+ .i_IorangeBase2 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .interrupt = v_APCI1710_Interrupt,
+ .reset = i_APCI1710_Reset,
+ },
#endif
#ifdef CONFIG_APCI_16XX
- {"apci1648",
- PCI_VENDOR_ID_ADDIDATA,
- 0x1009,
- 128,
- 0,
- 0,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 48,
- &range_apci16xx_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- i_APCI16XX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI16XX_InsnConfigInitTTLIO,
- i_APCI16XX_InsnBitsReadTTLIO,
- i_APCI16XX_InsnReadTTLIOAllPortValue,
- i_APCI16XX_InsnBitsWriteTTLIO},
-
- {"apci1696",
- PCI_VENDOR_ID_ADDIDATA,
- 0x100A,
- 128,
- 0,
- 0,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 96,
- &range_apci16xx_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- i_APCI16XX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI16XX_InsnConfigInitTTLIO,
- i_APCI16XX_InsnBitsReadTTLIO,
- i_APCI16XX_InsnReadTTLIOAllPortValue,
- i_APCI16XX_InsnBitsWriteTTLIO},
+ {
+ .pc_DriverName = "apci1648",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x1009,
+ .i_IorangeBase0 = 128,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrTTLChannel = 48,
+ .pr_TTLRangelist = &range_apci16xx_ttl,
+ .reset = i_APCI16XX_Reset,
+ .ttl_config = i_APCI16XX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO,
+ .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue,
+ .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci1696",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x100A,
+ .i_IorangeBase0 = 128,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrTTLChannel = 96,
+ .pr_TTLRangelist = &range_apci16xx_ttl,
+ .reset = i_APCI16XX_Reset,
+ .ttl_config = i_APCI16XX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO,
+ .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue,
+ .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO,
+ },
#endif
#ifdef CONFIG_APCI_3XXX
- {"apci3000-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3010,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3000-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300F,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3000-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300E,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3013,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3014,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3015,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3016,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3017,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3018,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3019,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301A,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301B,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3100-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301C,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3100-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301D,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3106-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301E,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3106-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301F,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3110-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3020,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3110-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3021,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3116-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3022,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3116-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3023,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3003",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300B,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 4,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 7,
- 2500,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3002,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 16,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3003,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 8,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3004,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 4,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3500",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3024,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 0,
- 0,
- 4,
- 0,
- 4095,
- NULL,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
+ {
+ .pc_DriverName = "apci3000-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3010,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3000-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300F,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3000-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300E,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3013,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3014,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3015,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3016,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3017,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3018,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3019,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301A,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301B,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3100-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301C,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3100-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301D,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3106-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301E,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3106-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301F,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3110-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3020,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3110-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3021,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3116-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3022,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3116-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3023,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3003",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300B,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 7,
+ .ui_MinAcquisitiontimeNs = 2500,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3002,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 16,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3003,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3004,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3500",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3024,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAoChannel = 4,
+ .i_AoMaxdata = 4095,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ },
#endif
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board))
-
static struct comedi_driver driver_addi = {
.driver_name = ADDIDATA_DRIVER_NAME,
.module = THIS_MODULE,
.attach = i_ADDI_Attach,
.detach = i_ADDI_Detach,
- .num_names = n_boardtypes,
+ .num_names = ARRAY_SIZE(boardtypes),
.board_name = &boardtypes[0].pc_DriverName,
.offset = sizeof(struct addi_board),
};
@@ -2543,7 +1438,7 @@ static struct comedi_driver driver_addi = {
static int __devinit driver_addi_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_addi.driver_name);
+ return comedi_pci_auto_config(dev, &driver_addi);
}
static void __devexit driver_addi_pci_remove(struct pci_dev *dev)
@@ -2821,16 +1716,13 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Set the initialisation flag */
devpriv->b_AiInitialisation = 1;
- s->insn_config =
- this_board->i_hwdrv_InsnConfigAnalogInput;
- s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteAnalogInput;
- s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput;
- s->do_cmdtest =
- this_board->i_hwdrv_CommandTestAnalogInput;
- s->do_cmd = this_board->i_hwdrv_CommandAnalogInput;
- s->cancel = this_board->i_hwdrv_CancelAnalogInput;
+ s->insn_config = this_board->ai_config;
+ s->insn_read = this_board->ai_read;
+ s->insn_write = this_board->ai_write;
+ s->insn_bits = this_board->ai_bits;
+ s->do_cmdtest = this_board->ai_cmdtest;
+ s->do_cmd = this_board->ai_cmd;
+ s->cancel = this_board->ai_cancel;
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -2846,10 +1738,8 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist =
devpriv->s_EeParameters.i_NbrAoChannel;
s->range_table = this_board->pr_AoRangelist;
- s->insn_config =
- this_board->i_hwdrv_InsnConfigAnalogOutput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteAnalogOutput;
+ s->insn_config = this_board->ao_config;
+ s->insn_write = this_board->ao_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2864,12 +1754,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->s_EeParameters.i_NbrDiChannel;
s->range_table = &range_digital;
s->io_bits = 0; /* all bits input */
- s->insn_config =
- this_board->i_hwdrv_InsnConfigDigitalInput;
- s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteDigitalInput;
- s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput;
+ s->insn_config = this_board->di_config;
+ s->insn_read = this_board->di_read;
+ s->insn_write = this_board->di_write;
+ s->insn_bits = this_board->di_bits;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2886,13 +1774,11 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_digital;
s->io_bits = 0xf; /* all bits output */
- s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; /* for digital output memory.. */
- s->insn_write =
- this_board->i_hwdrv_InsnWriteDigitalOutput;
- s->insn_bits =
- this_board->i_hwdrv_InsnBitsDigitalOutput;
- s->insn_read =
- this_board->i_hwdrv_InsnReadDigitalOutput;
+ /* insn_config - for digital output memory */
+ s->insn_config = this_board->do_config;
+ s->insn_write = this_board->do_write;
+ s->insn_bits = this_board->do_bits;
+ s->insn_read = this_board->do_read;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2907,10 +1793,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = this_board->i_hwdrv_InsnWriteTimer;
- s->insn_read = this_board->i_hwdrv_InsnReadTimer;
- s->insn_config = this_board->i_hwdrv_InsnConfigTimer;
- s->insn_bits = this_board->i_hwdrv_InsnBitsTimer;
+ s->insn_write = this_board->timer_write;
+ s->insn_read = this_board->timer_read;
+ s->insn_config = this_board->timer_config;
+ s->insn_bits = this_board->timer_bits;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2926,10 +1812,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->io_bits = 0; /* all bits input */
s->len_chanlist = this_board->i_NbrTTLChannel;
s->range_table = &range_digital;
- s->insn_config = this_board->i_hwdr_ConfigInitTTLIO;
- s->insn_bits = this_board->i_hwdr_ReadTTLIOBits;
- s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue;
- s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff;
+ s->insn_config = this_board->ttl_config;
+ s->insn_bits = this_board->ttl_bits;
+ s->insn_read = this_board->ttl_read;
+ s->insn_write = this_board->ttl_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2953,50 +1839,22 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
-+----------------------------------------------------------------------------+
-| Function name : static int i_ADDI_Detach(struct comedi_device *dev) |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Task : Deallocates resources of the addi_common driver |
-| Free the DMA buffers, unregister irq. |
-| |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Return Value : 0 |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_ADDI_Detach(struct comedi_device *dev)
+static void i_ADDI_Detach(struct comedi_device *dev)
{
-
if (dev->private) {
- if (devpriv->b_ValidDriver) {
+ if (devpriv->b_ValidDriver)
i_ADDI_Reset(dev);
- }
-
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
-
- if ((this_board->pc_EepromChip == NULL)
- || (strcmp(this_board->pc_EepromChip,
- ADDIDATA_9054) != 0)) {
- if (devpriv->allocated) {
+ if ((this_board->pc_EepromChip == NULL) ||
+ (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) {
+ if (devpriv->allocated)
i_pci_card_free(devpriv->amcc);
- }
-
if (devpriv->ul_DmaBufferVirtual[0]) {
free_pages((unsigned long)devpriv->
ul_DmaBufferVirtual[0],
devpriv->ui_DmaBufferPages[0]);
}
-
if (devpriv->ul_DmaBufferVirtual[1]) {
free_pages((unsigned long)devpriv->
ul_DmaBufferVirtual[1],
@@ -3004,20 +1862,14 @@ static int i_ADDI_Detach(struct comedi_device *dev)
}
} else {
iounmap(devpriv->dw_AiBase);
-
- if (devpriv->allocated) {
+ if (devpriv->allocated)
i_pci_card_free(devpriv->amcc);
- }
}
-
if (pci_list_builded) {
- /* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */
v_pci_card_list_cleanup(this_board->i_VendorId);
pci_list_builded = 0;
}
}
-
- return 0;
}
/*
@@ -3041,7 +1893,7 @@ static int i_ADDI_Detach(struct comedi_device *dev)
static int i_ADDI_Reset(struct comedi_device *dev)
{
- this_board->i_hwdrv_Reset(dev);
+ this_board->reset(dev);
return 0;
}
@@ -3067,7 +1919,7 @@ static int i_ADDI_Reset(struct comedi_device *dev)
static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- this_board->v_hwdrv_Interrupt(irq, d);
+ this_board->interrupt(irq, d);
return IRQ_RETVAL(1);
}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index c6980b7..2c3f347 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -94,111 +94,72 @@ struct addi_board {
unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */
/* interrupt and reset */
- void (*v_hwdrv_Interrupt)(int irq, void *d);
- int (*i_hwdrv_Reset)(struct comedi_device *dev);
+ void (*interrupt)(int irq, void *d);
+ int (*reset)(struct comedi_device *);
/* Subdevice functions */
/* ANALOG INPUT */
- int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
- int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s);
- int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s);
+ int (*ai_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_cmd *);
+ int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *);
+ int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *);
/* Analog Output */
- int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*ao_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ao_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ao_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* Digital Input */
- int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*di_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* Digital Output */
- int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*do_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* TIMER */
- int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ int (*timer_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* TTL IO */
- int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ int (*ttl_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
};
/* MODULE INFO STRUCTURE */
@@ -455,7 +416,7 @@ static unsigned short pci_list_builded; /* set to 1 when list of card is known *
/* Function declarations */
static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int i_ADDI_Detach(struct comedi_device *dev);
+static void i_ADDI_Detach(struct comedi_device *dev);
static int i_ADDI_Reset(struct comedi_device *dev);
static irqreturn_t v_ADDI_Interrupt(int irq, void *d);
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index e886ced..ffe390c 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -156,7 +156,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd
} else
us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
- /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
+ /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
/* Clear software registers */
devpriv->b_TimerSelectMode = 0;
@@ -670,7 +670,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde
/* mode 1 */
devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
- /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
+ /* return this_board->ai_cmd(1,dev,s); */
return i_APCI3120_CyclicAnalogInput(1, dev, s);
}
@@ -680,7 +680,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde
/* mode 2 */
devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
- /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
+ /* return this_board->ai_cmd(2,dev,s); */
return i_APCI3120_CyclicAnalogInput(2, dev, s);
}
return -1;
@@ -1922,7 +1922,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic
ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
- /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
+ /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
/*
@@ -2092,7 +2092,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice
ui_Timervalue2 = 0;
}
- /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
+ /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
switch (data[0]) {
case APCI3120_START:
@@ -2260,7 +2260,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice
comedi_error(dev, "\nread:timer2 not configured ");
}
- /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
+ /* this_board->timer_read(dev,data); */
if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
/* Read the LOW unsigned short of Timer 2 register */
@@ -2331,7 +2331,7 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
- /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
+ /* this_board->di_read(dev,ui_Chan,data); */
if (ui_Chan <= 3) {
ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
@@ -2379,7 +2379,7 @@ int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_sub
*****/
*data = (ui_TmpValue >> 8) & 0xf;
- /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
+ /* this_board->di_bits(dev,data); */
return insn->n;
}
@@ -2595,7 +2595,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
ui_Range = CR_RANGE(insn->chanspec);
ui_Channel = CR_CHAN(insn->chanspec);
- /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
+ /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
if (ui_Range) { /* if 1 then unipolar */
if (data[0] != 0)
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 4fc9e85..de8c68a 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -54,8 +54,6 @@ References:
#include "../comedidev.h"
#include "comedi_pci.h"
-#define PCI6208_DRIVER_NAME "adl_pci6208"
-
/* Board descriptions */
struct pci6208_board {
const char *name;
@@ -85,17 +83,6 @@ static const struct pci6208_board pci6208_boards[] = {
}
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = {
- /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
- /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci6208_pci_table);
-
/* Will be initialized in pci6208_find device(). */
#define thisboard ((const struct pci6208_board *)dev->board_ptr)
@@ -107,157 +94,6 @@ struct pci6208_private {
#define devpriv ((struct pci6208_private *)dev->private)
-static int pci6208_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci6208_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci6208 = {
- .driver_name = PCI6208_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci6208_attach,
- .detach = pci6208_detach,
-};
-
-static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pci6208.driver_name);
-}
-
-static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci6208_pci_driver = {
- .id_table = pci6208_pci_table,
- .probe = &driver_pci6208_pci_probe,
- .remove = __devexit_p(&driver_pci6208_pci_remove)
-};
-
-static int __init driver_pci6208_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci6208);
- if (retval < 0)
- return retval;
-
- driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name;
- return pci_register_driver(&driver_pci6208_pci_driver);
-}
-
-static void __exit driver_pci6208_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci6208_pci_driver);
- comedi_driver_unregister(&driver_pci6208);
-}
-
-module_init(driver_pci6208_init_module);
-module_exit(driver_pci6208_cleanup_module);
-
-static int pci6208_find_device(struct comedi_device *dev, int bus, int slot);
-static int
-pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
- int dev_minor);
-
-/*read/write functions*/
-static int pci6208_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pci6208_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-/* static int pci6208_dio_insn_bits (struct comedi_device *dev,
- * struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-/* static int pci6208_dio_insn_config(struct comedi_device *dev,
- * struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pci6208_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int retval;
- unsigned long io_base;
-
- printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
-
- retval = alloc_private(dev, sizeof(struct pci6208_private));
- if (retval < 0)
- return retval;
-
- retval = pci6208_find_device(dev, it->options[0], it->options[1]);
- if (retval < 0)
- return retval;
-
- retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
- if (retval < 0)
- return retval;
-
- dev->iobase = io_base;
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_subdevices(dev, 2) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */
- s->n_chan = thisboard->ao_chans;
- s->maxdata = 0xffff; /* 16-bit DAC */
- s->range_table = &range_bipolar10; /* this needs to be checked. */
- s->insn_write = pci6208_ao_winsn;
- s->insn_read = pci6208_ao_rinsn;
-
- /* s=dev->subdevices+1; */
- /* digital i/o subdevice */
- /* s->type=COMEDI_SUBD_DIO; */
- /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
- /* s->n_chan=16; */
- /* s->maxdata=1; */
- /* s->range_table=&range_digital; */
- /* s->insn_bits = pci6208_dio_insn_bits; */
- /* s->insn_config = pci6208_dio_insn_config; */
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci6208_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor);
-
- if (devpriv && devpriv->pci_dev) {
- if (dev->iobase)
- comedi_pci_disable(devpriv->pci_dev);
- pci_dev_put(devpriv->pci_dev);
- }
-
- return 0;
-}
-
static int pci6208_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -410,7 +246,7 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
/* Enable PCI device and request regions */
- if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) {
+ if (comedi_pci_enable(pci_dev, "adl_pci6208") < 0) {
printk(KERN_ERR "comedi%d: Failed to enable PCI device "
"and request regions\n",
dev_minor);
@@ -442,6 +278,103 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
return 0;
}
+static int pci6208_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int retval;
+ unsigned long io_base;
+
+ printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
+
+ retval = alloc_private(dev, sizeof(struct pci6208_private));
+ if (retval < 0)
+ return retval;
+
+ retval = pci6208_find_device(dev, it->options[0], it->options[1]);
+ if (retval < 0)
+ return retval;
+
+ retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
+ if (retval < 0)
+ return retval;
+
+ dev->iobase = io_base;
+ dev->board_name = thisboard->name;
+
+ if (alloc_subdevices(dev, 2) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */
+ s->n_chan = thisboard->ao_chans;
+ s->maxdata = 0xffff; /* 16-bit DAC */
+ s->range_table = &range_bipolar10; /* this needs to be checked. */
+ s->insn_write = pci6208_ao_winsn;
+ s->insn_read = pci6208_ao_rinsn;
+
+ /* s=dev->subdevices+1; */
+ /* digital i/o subdevice */
+ /* s->type=COMEDI_SUBD_DIO; */
+ /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
+ /* s->n_chan=16; */
+ /* s->maxdata=1; */
+ /* s->range_table=&range_digital; */
+ /* s->insn_bits = pci6208_dio_insn_bits; */
+ /* s->insn_config = pci6208_dio_insn_config; */
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
+}
+
+static void pci6208_detach(struct comedi_device *dev)
+{
+ if (devpriv && devpriv->pci_dev) {
+ if (dev->iobase)
+ comedi_pci_disable(devpriv->pci_dev);
+ pci_dev_put(devpriv->pci_dev);
+ }
+}
+
+static struct comedi_driver adl_pci6208_driver = {
+ .driver_name = "adl_pci6208",
+ .module = THIS_MODULE,
+ .attach = pci6208_attach,
+ .detach = pci6208_detach,
+};
+
+static int __devinit adl_pci6208_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci6208_driver);
+}
+
+static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+/* This is used by modprobe to translate PCI IDs to drivers. Should
+ * only be used for PCI and ISA-PnP devices */
+static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
+ /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+ /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
+
+static struct pci_driver adl_pci6208_pci_driver = {
+ .name = "adl_pci6208",
+ .id_table = adl_pci6208_pci_table,
+ .probe = adl_pci6208_pci_probe,
+ .remove = __devexit_p(adl_pci6208_pci_remove),
+};
+module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
index 20d5705..e8053bc 100644
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ b/drivers/staging/comedi/drivers/adl_pci7230.c
@@ -43,13 +43,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7230 0x7230
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-
struct adl_pci7230_private {
int data;
struct pci_dev *pci_dev;
@@ -57,27 +50,36 @@ struct adl_pci7230_private {
#define devpriv ((struct adl_pci7230_private *)dev->private)
-static int adl_pci7230_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7230 = {
- .driver_name = "adl_pci7230",
- .module = THIS_MODULE,
- .attach = adl_pci7230_attach,
- .detach = adl_pci7230_detach,
-};
+static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+
+ outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
+ }
-/* Digital IO */
+ return 2;
+}
static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
+
+ return 2;
+}
static int adl_pci7230_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -148,89 +150,46 @@ static int adl_pci7230_attach(struct comedi_device *dev,
return 1;
}
-static int adl_pci7230_detach(struct comedi_device *dev)
+static void adl_pci7230_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
-}
-
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
-
- outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
- }
-
- return 2;
}
-static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
-
- return 2;
-}
+static struct comedi_driver adl_pci7230_driver = {
+ .driver_name = "adl_pci7230",
+ .module = THIS_MODULE,
+ .attach = adl_pci7230_attach,
+ .detach = adl_pci7230_detach,
+};
-static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7230_driver);
}
-static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7230_pci_driver = {
- .id_table = adl_pci7230_pci_table,
- .probe = &driver_adl_pci7230_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7230_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-static int __init driver_adl_pci7230_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7230);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7230_pci_driver.name =
- (char *)driver_adl_pci7230.driver_name;
- return pci_register_driver(&driver_adl_pci7230_pci_driver);
-}
-
-static void __exit driver_adl_pci7230_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7230_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7230);
-}
-
-module_init(driver_adl_pci7230_init_module);
-module_exit(driver_adl_pci7230_cleanup_module);
+static struct pci_driver adl_pci7230_pci_driver = {
+ .name = "adl_pci7230",
+ .id_table = adl_pci7230_pci_table,
+ .probe = adl_pci7230_pci_probe,
+ .remove = __devexit_p(adl_pci7230_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
index 9a232053..b4dae3b 100644
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ b/drivers/staging/comedi/drivers/adl_pci7296.c
@@ -48,13 +48,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7296 0x7296
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-
struct adl_pci7296_private {
int data;
struct pci_dev *pci_dev;
@@ -63,16 +56,6 @@ struct adl_pci7296_private {
#define devpriv ((struct adl_pci7296_private *)dev->private)
static int adl_pci7296_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7296_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7296 = {
- .driver_name = "adl_pci7296",
- .module = THIS_MODULE,
- .attach = adl_pci7296_attach,
- .detach = adl_pci7296_detach,
-};
-
-static int adl_pci7296_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct pci_dev *pcidev = NULL;
@@ -151,66 +134,52 @@ static int adl_pci7296_attach(struct comedi_device *dev,
return -EIO;
}
-static int adl_pci7296_detach(struct comedi_device *dev)
+static void adl_pci7296_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
- /* detach four 8255 digital io subdevices */
if (dev->subdevices) {
subdev_8255_cleanup(dev, dev->subdevices + 0);
subdev_8255_cleanup(dev, dev->subdevices + 1);
subdev_8255_cleanup(dev, dev->subdevices + 2);
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
}
-
- return 0;
}
-static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver adl_pci7296_driver = {
+ .driver_name = "adl_pci7296",
+ .module = THIS_MODULE,
+ .attach = adl_pci7296_attach,
+ .detach = adl_pci7296_detach,
+};
+
+static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7296_driver);
}
-static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7296_pci_driver = {
- .id_table = adl_pci7296_pci_table,
- .probe = &driver_adl_pci7296_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7296_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-static int __init driver_adl_pci7296_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7296);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7296_pci_driver.name =
- (char *)driver_adl_pci7296.driver_name;
- return pci_register_driver(&driver_adl_pci7296_pci_driver);
-}
-
-static void __exit driver_adl_pci7296_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7296_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7296);
-}
-
-module_init(driver_adl_pci7296_init_module);
-module_exit(driver_adl_pci7296_cleanup_module);
+static struct pci_driver adl_pci7296_pci_driver = {
+ .name = "adl_pci7296",
+ .id_table = adl_pci7296_pci_table,
+ .probe = adl_pci7296_pci_probe,
+ .remove = __devexit_p(adl_pci7296_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
index 86ee219..9cbfb61 100644
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ b/drivers/staging/comedi/drivers/adl_pci7432.c
@@ -43,13 +43,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7432 0x7432
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-
struct adl_pci7432_private {
int data;
struct pci_dev *pci_dev;
@@ -57,29 +50,44 @@ struct adl_pci7432_private {
#define devpriv ((struct adl_pci7432_private *)dev->private)
-static int adl_pci7432_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7432_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7432 = {
- .driver_name = "adl_pci7432",
- .module = THIS_MODULE,
- .attach = adl_pci7432_attach,
- .detach = adl_pci7432_detach,
-};
+static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
+ printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
+
+ if (insn->n != 2)
+ return -EINVAL;
-/* Digital IO */
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+
+ printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
+ dev->iobase + PCI7432_DO);
+ outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
+ }
+ return 2;
+}
static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
+ printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ if (insn->n != 2)
+ return -EINVAL;
+
+ data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
+ printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-/* */
+ return 2;
+}
static int adl_pci7432_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -153,97 +161,46 @@ static int adl_pci7432_attach(struct comedi_device *dev,
return -EIO;
}
-static int adl_pci7432_detach(struct comedi_device *dev)
+static void adl_pci7432_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
}
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
- printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
-
- printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
- dev->iobase + PCI7432_DO);
- outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
- }
- return 2;
-}
-
-static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
- printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
- printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-
- return 2;
-}
+static struct comedi_driver adl_pci7432_driver = {
+ .driver_name = "adl_pci7432",
+ .module = THIS_MODULE,
+ .attach = adl_pci7432_attach,
+ .detach = adl_pci7432_detach,
+};
-static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7432_driver);
}
-static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7432_pci_driver = {
- .id_table = adl_pci7432_pci_table,
- .probe = &driver_adl_pci7432_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7432_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-static int __init driver_adl_pci7432_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7432);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7432_pci_driver.name =
- (char *)driver_adl_pci7432.driver_name;
- return pci_register_driver(&driver_adl_pci7432_pci_driver);
-}
-
-static void __exit driver_adl_pci7432_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7432_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7432);
-}
-
-module_init(driver_adl_pci7432_init_module);
-module_exit(driver_adl_pci7432_cleanup_module);
+static struct pci_driver adl_pci7432_pci_driver = {
+ .name = "adl_pci7432",
+ .id_table = adl_pci7432_pci_table,
+ .probe = adl_pci7432_pci_probe,
+ .remove = __devexit_p(adl_pci7432_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 3b83d65..409ef13a 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -56,13 +56,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI8164 0x8164
-static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
-
struct adl_pci8164_private {
int data;
struct pci_dev *pci_dev;
@@ -70,159 +63,6 @@ struct adl_pci8164_private {
#define devpriv ((struct adl_pci8164_private *)dev->private)
-static int adl_pci8164_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci8164_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci8164 = {
- .driver_name = "adl_pci8164",
- .module = THIS_MODULE,
- .attach = adl_pci8164_attach,
- .detach = adl_pci8164_detach,
-};
-
-static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct pci_dev *pcidev = NULL;
- struct comedi_subdevice *s;
- int bus, slot;
-
- printk(KERN_INFO "comedi: attempt to attach...\n");
- printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
-
- dev->board_name = "pci8164";
- bus = it->options[0];
- slot = it->options[1];
-
- if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- for_each_pci_dev(pcidev) {
- if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
- pcidev->device == PCI_DEVICE_ID_PCI8164) {
- if (bus || slot) {
- /* requested particular bus/slot */
- if (pcidev->bus->number != bus
- || PCI_SLOT(pcidev->devfn) != slot)
- continue;
- }
- devpriv->pci_dev = pcidev;
- if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
- printk(KERN_ERR "comedi%d: Failed to enable "
- "PCI device and request regions\n", dev->minor);
- return -EIO;
- }
- dev->iobase = pci_resource_start(pcidev, 2);
- printk(KERN_DEBUG "comedi: base addr %4lx\n",
- dev->iobase);
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_msts;
- s->insn_write = adl_pci8164_insn_write_cmd;
-
- s = dev->subdevices + 1;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_ssts;
- s->insn_write = adl_pci8164_insn_write_otp;
-
- s = dev->subdevices + 2;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf0;
- s->insn_write = adl_pci8164_insn_write_buf0;
-
- s = dev->subdevices + 3;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf1;
- s->insn_write = adl_pci8164_insn_write_buf1;
-
- printk(KERN_INFO "comedi: attached\n");
-
- return 1;
- }
- }
-
- printk(KERN_ERR "comedi%d: no supported board found!"
- "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
- return -EIO;
-}
-
-static int adl_pci8164_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor);
-
- if (devpriv && devpriv->pci_dev) {
- if (dev->iobase)
- comedi_pci_disable(devpriv->pci_dev);
- pci_dev_put(devpriv->pci_dev);
- }
-
- return 0;
-}
-
/*
all the read commands are the same except for the addition a constant
* const to the data for inw()
@@ -384,45 +224,136 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
return 2;
}
-static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int adl_pci8164_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
- return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name);
+ struct pci_dev *pcidev = NULL;
+ struct comedi_subdevice *s;
+ int bus, slot;
+
+ printk(KERN_INFO "comedi: attempt to attach...\n");
+ printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
+
+ dev->board_name = "pci8164";
+ bus = it->options[0];
+ slot = it->options[1];
+
+ if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ for_each_pci_dev(pcidev) {
+ if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
+ pcidev->device == PCI_DEVICE_ID_PCI8164) {
+ if (bus || slot) {
+ /* requested particular bus/slot */
+ if (pcidev->bus->number != bus
+ || PCI_SLOT(pcidev->devfn) != slot)
+ continue;
+ }
+ devpriv->pci_dev = pcidev;
+ if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
+ printk(KERN_ERR "comedi%d: Failed to enable "
+ "PCI device and request regions\n", dev->minor);
+ return -EIO;
+ }
+ dev->iobase = pci_resource_start(pcidev, 2);
+ printk(KERN_DEBUG "comedi: base addr %4lx\n",
+ dev->iobase);
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_msts;
+ s->insn_write = adl_pci8164_insn_write_cmd;
+
+ s = dev->subdevices + 1;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_ssts;
+ s->insn_write = adl_pci8164_insn_write_otp;
+
+ s = dev->subdevices + 2;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_buf0;
+ s->insn_write = adl_pci8164_insn_write_buf0;
+
+ s = dev->subdevices + 3;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_buf1;
+ s->insn_write = adl_pci8164_insn_write_buf1;
+
+ printk(KERN_INFO "comedi: attached\n");
+
+ return 1;
+ }
+ }
+
+ printk(KERN_ERR "comedi%d: no supported board found!"
+ "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
+ return -EIO;
}
-static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev)
+static void adl_pci8164_detach(struct comedi_device *dev)
{
- comedi_pci_auto_unconfig(dev);
+ if (devpriv && devpriv->pci_dev) {
+ if (dev->iobase)
+ comedi_pci_disable(devpriv->pci_dev);
+ pci_dev_put(devpriv->pci_dev);
+ }
}
-static struct pci_driver driver_adl_pci8164_pci_driver = {
- .id_table = adl_pci8164_pci_table,
- .probe = &driver_adl_pci8164_pci_probe,
- .remove = __devexit_p(&driver_adl_pci8164_pci_remove)
+static struct comedi_driver adl_pci8164_driver = {
+ .driver_name = "adl_pci8164",
+ .module = THIS_MODULE,
+ .attach = adl_pci8164_attach,
+ .detach = adl_pci8164_detach,
};
-static int __init driver_adl_pci8164_init_module(void)
+static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci8164);
- if (retval < 0)
- return retval;
-
- driver_adl_pci8164_pci_driver.name =
- (char *)driver_adl_pci8164.driver_name;
- return pci_register_driver(&driver_adl_pci8164_pci_driver);
+ return comedi_pci_auto_config(dev, &adl_pci8164_driver);
}
-static void __exit driver_adl_pci8164_cleanup_module(void)
+static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev)
{
- pci_unregister_driver(&driver_adl_pci8164_pci_driver);
- comedi_driver_unregister(&driver_adl_pci8164);
+ comedi_pci_auto_unconfig(dev);
}
-module_init(driver_adl_pci8164_init_module);
-module_exit(driver_adl_pci8164_cleanup_module);
+static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
+
+static struct pci_driver adl_pci8164_pci_driver = {
+ .name = "adl_pci8164",
+ .id_table = adl_pci8164_pci_table,
+ .probe = adl_pci8164_pci_probe,
+ .remove = __devexit_p(adl_pci8164_pci_remove),
+};
+module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 2a9bd88a..ccfb1a5 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -289,16 +289,6 @@ TODO:
PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
} while (0)
-/* Function prototypes */
-
-static int pci9111_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci9111_detach(struct comedi_device *dev);
-static void pci9111_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *data,
- unsigned int num_bytes,
- unsigned int start_chan_index);
-
static const struct comedi_lrange pci9111_hr_ai_range = {
5,
{
@@ -310,14 +300,6 @@ static const struct comedi_lrange pci9111_hr_ai_range = {
}
};
-static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
- /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
-
/* */
/* Board specification structure */
/* */
@@ -354,51 +336,6 @@ static const struct pci9111_board pci9111_boards[] = {
#define pci9111_board_nbr \
(sizeof(pci9111_boards)/sizeof(struct pci9111_board))
-static struct comedi_driver pci9111_driver = {
- .driver_name = PCI9111_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci9111_attach,
- .detach = pci9111_detach,
-};
-
-static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, pci9111_driver.driver_name);
-}
-
-static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver pci9111_driver_pci_driver = {
- .id_table = pci9111_pci_table,
- .probe = &pci9111_driver_pci_probe,
- .remove = __devexit_p(&pci9111_driver_pci_remove)
-};
-
-static int __init pci9111_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&pci9111_driver);
- if (retval < 0)
- return retval;
-
- pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name;
- return pci_register_driver(&pci9111_driver_pci_driver);
-}
-
-static void __exit pci9111_driver_cleanup_module(void)
-{
- pci_unregister_driver(&pci9111_driver_pci_driver);
- comedi_driver_unregister(&pci9111_driver);
-}
-
-module_init(pci9111_driver_init_module);
-module_exit(pci9111_driver_cleanup_module);
-
/* Private data structure */
struct pci9111_private_data {
@@ -1445,31 +1382,54 @@ found:
return 0;
}
-/* Detach */
-
-static int pci9111_detach(struct comedi_device *dev)
+static void pci9111_detach(struct comedi_device *dev)
{
- /* Reset device */
-
if (dev->private != NULL) {
if (dev_private->is_valid)
pci9111_reset(dev);
-
}
- /* Release previously allocated irq */
-
if (dev->irq != 0)
free_irq(dev->irq, dev);
-
if (dev_private != NULL && dev_private->pci_device != NULL) {
if (dev->iobase)
comedi_pci_disable(dev_private->pci_device);
pci_dev_put(dev_private->pci_device);
}
+}
- return 0;
+static struct comedi_driver adl_pci9111_driver = {
+ .driver_name = "adl_pci9111",
+ .module = THIS_MODULE,
+ .attach = pci9111_attach,
+ .detach = pci9111_detach,
+};
+
+static int __devinit pci9111_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci9111_driver);
}
+static void __devexit pci9111_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
+ /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
+
+static struct pci_driver adl_pci9111_pci_driver = {
+ .name = "adl_pci9111",
+ .id_table = pci9111_pci_table,
+ .probe = pci9111_pci_probe,
+ .remove = __devexit_p(pci9111_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index f17654e..7864586 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -221,10 +221,6 @@ static const struct comedi_lrange range_pci9118hg = { 8, {
* of BIP/UNI ranges
*/
-static int pci9118_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci9118_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* board name */
int vendor_id; /* PCI vendor a device ID of card */
@@ -252,81 +248,6 @@ struct boardtype {
};
-static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9118_pci_table);
-
-static const struct boardtype boardtypes[] = {
- {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
- &range_pci9118dg_hr, &range_bipolar10,
- 3000, 12, 512},
- {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
- &range_pci9118hg, &range_bipolar10,
- 3000, 12, 512},
- {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff,
- &range_pci9118dg_hr, &range_bipolar10,
- 10000, 40, 512},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci9118 = {
- .driver_name = "adl_pci9118",
- .module = THIS_MODULE,
- .attach = pci9118_attach,
- .detach = pci9118_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
-static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pci9118.driver_name);
-}
-
-static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci9118_pci_driver = {
- .id_table = pci9118_pci_table,
- .probe = &driver_pci9118_pci_probe,
- .remove = __devexit_p(&driver_pci9118_pci_remove)
-};
-
-static int __init driver_pci9118_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci9118);
- if (retval < 0)
- return retval;
-
- driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name;
- return pci_register_driver(&driver_pci9118_pci_driver);
-}
-
-static void __exit driver_pci9118_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci9118_pci_driver);
- comedi_driver_unregister(&driver_pci9118);
-}
-
-module_init(driver_pci9118_init_module);
-module_exit(driver_pci9118_cleanup_module);
-
struct pci9118_private {
unsigned long iobase_a; /* base+size for AMCC chip */
unsigned int master; /* master capable */
@@ -2190,9 +2111,6 @@ static int pci9118_reset(struct comedi_device *dev)
return 0;
}
-/*
-==============================================================================
-*/
static int pci9118_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -2435,10 +2353,7 @@ static int pci9118_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci9118_detach(struct comedi_device *dev)
+static void pci9118_detach(struct comedi_device *dev)
{
if (dev->private) {
if (devpriv->valid)
@@ -2458,13 +2373,100 @@ static int pci9118_detach(struct comedi_device *dev)
free_pages((unsigned long)devpriv->dmabuf_virt[1],
devpriv->dmabuf_pages[1]);
}
+}
- return 0;
+static const struct boardtype boardtypes[] = {
+ {
+ .name = "pci9118dg",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118dg_hr,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 3000,
+ .ai_pacer_min = 12,
+ .half_fifo_size = 512,
+ }, {
+ .name = "pci9118hg",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118hg,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 3000,
+ .ai_pacer_min = 12,
+ .half_fifo_size = 512,
+ }, {
+ .name = "pci9118hr",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0xffff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118dg_hr,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 10000,
+ .ai_pacer_min = 40,
+ .half_fifo_size = 512,
+ },
+};
+
+static struct comedi_driver adl_pci9118_driver = {
+ .driver_name = "adl_pci9118",
+ .module = THIS_MODULE,
+ .attach = pci9118_attach,
+ .detach = pci9118_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+
+static int __devinit adl_pci9118_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci9118_driver);
}
-/*
-==============================================================================
-*/
+static void __devexit adl_pci9118_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);
+
+static struct pci_driver adl_pci9118_pci_driver = {
+ .name = "adl_pci9118",
+ .id_table = adl_pci9118_pci_table,
+ .probe = adl_pci9118_pci_probe,
+ .remove = __devexit_p(adl_pci9118_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 5361f31..7d585a1 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -125,24 +125,6 @@ struct adq12b_board {
int do_chans;
};
-static const struct adq12b_board adq12b_boards[] = {
- {
- .name = "adq12b",
- .ai_se_chans = 16,
- .ai_diff_chans = 8,
- .ai_bits = 12,
- .di_chans = 5,
- .do_chans = 8}
-/* potentially, more adq-based deviced will be added */
-/*,
- .name = "adq12b",
- .ai_chans = 16, // this is just for reference, hardcoded again later
- .ai_bits = 12,
- .di_chans = 8,
- .do_chans = 5
- }*/
-};
-
#define thisboard ((const struct adq12b_board *)dev->board_ptr)
struct adq12b_private {
@@ -156,41 +138,88 @@ struct adq12b_private {
#define devpriv ((struct adq12b_private *)dev->private)
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * "instructions" read/write data in "one-shot" or "software-triggered"
+ * mode.
*/
-static int adq12b_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adq12b_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_adq12b = {
- .driver_name = "adq12b",
- .module = THIS_MODULE,
- .attach = adq12b_attach,
- .detach = adq12b_detach,
- .board_name = &adq12b_boards[0].name,
- .offset = sizeof(struct adq12b_board),
- .num_names = ARRAY_SIZE(adq12b_boards),
-};
static int adq12b_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ int n, i;
+ int range, channel;
+ unsigned char hi, lo, status;
+
+ /* change channel and range only if it is different from the previous */
+ range = CR_RANGE(insn->chanspec);
+ channel = CR_CHAN(insn->chanspec);
+ if (channel != devpriv->last_channel || range != devpriv->last_range) {
+ outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
+ udelay(50); /* wait for the mux to settle */
+ }
+
+ /* trigger conversion */
+ status = inb(dev->iobase + ADQ12B_ADLOW);
+
+ /* convert n samples */
+ for (n = 0; n < insn->n; n++) {
+
+ /* wait for end of conversion */
+ i = 0;
+ do {
+ /* udelay(1); */
+ status = inb(dev->iobase + ADQ12B_STINR);
+ status = status & ADQ12B_EOC;
+ } while (status == 0 && ++i < TIMEOUT);
+ /* } while (++i < 10); */
+
+ /* read data */
+ hi = inb(dev->iobase + ADQ12B_ADHIG);
+ lo = inb(dev->iobase + ADQ12B_ADLOW);
+
+ /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
+ channel, range, status, hi, lo); */
+ data[n] = (hi << 8) | lo;
+
+ }
+
+ /* return the number of samples read/written */
+ return n;
+}
+
static int adq12b_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ /* only bits 0-4 have information about digital inputs */
+ data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
+
+ return 2;
+}
+
static int adq12b_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int channel;
+
+ for (channel = 0; channel < 8; channel++)
+ if (((data[0] >> channel) & 0x01) != 0)
+ outb((((data[1] >> channel) & 0x01) << 3) | channel,
+ dev->iobase + ADQ12B_OUTBR);
+
+ /* store information to retrieve when asked for reading */
+ if (data[0]) {
+ devpriv->digital_state &= ~data[0];
+ devpriv->digital_state |= (data[0] & data[1]);
+ }
+
+ data[1] = devpriv->digital_state;
+
+ return 2;
+}
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -295,125 +324,34 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int adq12b_detach(struct comedi_device *dev)
+static void adq12b_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, ADQ12B_SIZE);
-
kfree(devpriv);
-
- printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor);
-
- return 0;
-}
-
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
-
-static int adq12b_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- int n, i;
- int range, channel;
- unsigned char hi, lo, status;
-
- /* change channel and range only if it is different from the previous */
- range = CR_RANGE(insn->chanspec);
- channel = CR_CHAN(insn->chanspec);
- if (channel != devpriv->last_channel || range != devpriv->last_range) {
- outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
- udelay(50); /* wait for the mux to settle */
- }
-
- /* trigger conversion */
- status = inb(dev->iobase + ADQ12B_ADLOW);
-
- /* convert n samples */
- for (n = 0; n < insn->n; n++) {
-
- /* wait for end of conversion */
- i = 0;
- do {
- /* udelay(1); */
- status = inb(dev->iobase + ADQ12B_STINR);
- status = status & ADQ12B_EOC;
- } while (status == 0 && ++i < TIMEOUT);
- /* } while (++i < 10); */
-
- /* read data */
- hi = inb(dev->iobase + ADQ12B_ADHIG);
- lo = inb(dev->iobase + ADQ12B_ADLOW);
-
- /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
- channel, range, status, hi, lo); */
- data[n] = (hi << 8) | lo;
-
- }
-
- /* return the number of samples read/written */
- return n;
-}
-
-static int adq12b_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- /* only bits 0-4 have information about digital inputs */
- data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
-
- return 2;
}
-static int adq12b_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel;
-
- for (channel = 0; channel < 8; channel++)
- if (((data[0] >> channel) & 0x01) != 0)
- outb((((data[1] >> channel) & 0x01) << 3) | channel,
- dev->iobase + ADQ12B_OUTBR);
-
- /* store information to retrieve when asked for reading */
- if (data[0]) {
- devpriv->digital_state &= ~data[0];
- devpriv->digital_state |= (data[0] & data[1]);
- }
-
- data[1] = devpriv->digital_state;
-
- return 2;
-}
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_adq12b_init_module(void)
-{
- return comedi_driver_register(&driver_adq12b);
-}
-
-static void __exit driver_adq12b_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_adq12b);
-}
+static const struct adq12b_board adq12b_boards[] = {
+ {
+ .name = "adq12b",
+ .ai_se_chans = 16,
+ .ai_diff_chans = 8,
+ .ai_bits = 12,
+ .di_chans = 5,
+ .do_chans = 8,
+ },
+};
-module_init(driver_adq12b_init_module);
-module_exit(driver_adq12b_cleanup_module);
+static struct comedi_driver adq12b_driver = {
+ .driver_name = "adq12b",
+ .module = THIS_MODULE,
+ .attach = adq12b_attach,
+ .detach = adq12b_detach,
+ .board_name = &adq12b_boards[0].name,
+ .offset = sizeof(struct adq12b_board),
+ .num_names = ARRAY_SIZE(adq12b_boards),
+};
+module_comedi_driver(adq12b_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 8318c82..de8c98c 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -191,10 +191,6 @@ static const struct comedi_lrange range_pci171x_da = { 2, {
}
};
-static int pci1710_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci1710_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* board name */
int device_id;
@@ -216,17 +212,6 @@ struct boardtype {
unsigned int fifo_half_size; /* size of FIFO/2 */
};
-static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
-
static const struct boardtype boardtypes[] = {
{"pci1710", 0x1710,
IORANGE_171x, 1, TYPE_PCI171X,
@@ -264,18 +249,6 @@ static const struct boardtype boardtypes[] = {
{.name = DRV_NAME},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci1710 = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = pci1710_attach,
- .detach = pci1710_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
struct pci1710_private {
struct pci_dev *pcidev; /* ptr to PCI device */
char valid; /* card is usable */
@@ -676,7 +649,9 @@ static void interrupt_pci1710_every_sample(void *d)
s->async->buf_int_count, s->async->buf_int_ptr,
s->async->buf_user_count, s->async->buf_user_ptr);
DPRINTK("adv_pci1710 EDBG: EOS2\n");
- if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
+ if ((!devpriv->neverending_ai) &&
+ (devpriv->ai_act_scan >= devpriv->ai_scans)) {
+ /* all data sampled */
pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -804,8 +779,8 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
irq);
if (!dev->attached) /* is device attached? */
return IRQ_NONE; /* no, exit */
-
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
+ /* is this interrupt from our board? */
+ if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
return IRQ_NONE; /* no, exit */
DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
@@ -814,7 +789,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
devpriv->ai_et = 0;
devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW; /* set software trigger */
+ devpriv->CntrlReg |= Control_SW; /* set software trigger */
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
outb(0, dev->iobase + PCI171x_CLRFIFO);
@@ -865,7 +840,8 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
devpriv->neverending_ai = 0;
devpriv->CntrlReg &= Control_CNT0;
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
+ /* don't we want wake up every scan? devpriv->ai_eos=1; */
+ if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
devpriv->ai_eos = 1;
} else {
devpriv->CntrlReg |= Control_ONEFH;
@@ -982,13 +958,13 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(1, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
+ err);
return 1;
}
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step2: make sure trigger srcs are unique and mutually compatible */
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
cmd->start_src = TRIG_NOW;
@@ -1015,9 +991,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(2, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
+ err);
return 2;
}
@@ -1065,9 +1041,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(3, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
+ err);
return 3;
}
@@ -1160,48 +1136,41 @@ static int check_channel_list(struct comedi_device *dev,
return 0;
}
- if (n_chan > 1) {
- chansegment[0] = chanlist[0]; /* first channel is every time ok */
- for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
- /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[0] == chanlist[i])
- break; /* we detect loop, this must by finish */
- if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
- comedi_error(dev,
- "Odd channel can't be differential input!\n");
- return 0;
- }
- nowmustbechan =
- (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
- if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
- nowmustbechan = (nowmustbechan + 1) % s->n_chan;
- if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
- printk
- ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
- i, CR_CHAN(chanlist[i]), nowmustbechan,
- CR_CHAN(chanlist[0]));
- return 0;
- }
- chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
+ if (n_chan == 1)
+ return 1; /* seglen=1 */
+
+ chansegment[0] = chanlist[0]; /* first channel is every time ok */
+ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
+ if (chanlist[0] == chanlist[i])
+ break; /* we detected a loop, stop */
+ if ((CR_CHAN(chanlist[i]) & 1) &&
+ (CR_AREF(chanlist[i]) == AREF_DIFF)) {
+ comedi_error(dev, "Odd channel cannot be differential input!\n");
+ return 0;
}
+ nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
+ if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
+ nowmustbechan = (nowmustbechan + 1) % s->n_chan;
+ if (nowmustbechan != CR_CHAN(chanlist[i])) {
+ printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+ i, CR_CHAN(chanlist[i]), nowmustbechan,
+ CR_CHAN(chanlist[0]));
+ return 0;
+ }
+ chansegment[i] = chanlist[i]; /* next correct channel in list */
+ }
- for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
- /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[i] != chansegment[i % seglen]) {
- printk
- ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
- return 0; /* chan/gain list is strange */
- }
+ for (i = 0, segpos = 0; i < n_chan; i++) {
+ if (chanlist[i] != chansegment[i % seglen]) {
+ printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+ i, CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(chanlist[i % seglen]),
+ CR_RANGE(chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
+ return 0;
}
- } else {
- seglen = 1;
}
return seglen;
}
@@ -1221,14 +1190,14 @@ static void setup_channel_list(struct comedi_device *dev,
DPRINTK("SegLen: %d\n", seglen);
for (i = 0; i < seglen; i++) { /* store range list to card */
chanprog = muxonechan[CR_CHAN(chanlist[i])];
- outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
+ outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
if (CR_AREF(chanlist[i]) == AREF_DIFF)
range |= 0x0020;
- outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
+ outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
#ifdef PCI171x_PARANOIDCHECK
devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ (CR_CHAN(chanlist[i]) << 12) & 0xf000;
#endif
DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
devpriv->act_chanlist[i]);
@@ -1236,13 +1205,14 @@ static void setup_channel_list(struct comedi_device *dev,
#ifdef PCI171x_PARANOIDCHECK
for ( ; i < n_chan; i++) { /* store remainder of channel list */
devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ (CR_CHAN(chanlist[i]) << 12) & 0xf000;
}
#endif
devpriv->ai_et_MuxVal =
- CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
- outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
+ CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
+ /* select channel interval to scan */
+ outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
DPRINTK("MUX: %4x L%4x.H%4x\n",
CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
@@ -1365,9 +1335,6 @@ static int pci1710_reset(struct comedi_device *dev)
DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
}
-/*
-==============================================================================
-*/
static int pci1710_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1398,13 +1365,13 @@ static int pci1710_attach(struct comedi_device *dev,
while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
PCI_ANY_ID, pcidev))) {
if (strcmp(this_board->name, DRV_NAME) == 0) {
- for (i = 0; i < n_boardtypes; ++i) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
if (pcidev->device == boardtypes[i].device_id) {
board_index = i;
break;
}
}
- if (i == n_boardtypes)
+ if (i == ARRAY_SIZE(boardtypes))
continue;
} else {
if (pcidev->device != boardtypes[board_index].device_id)
@@ -1584,12 +1551,8 @@ static int pci1710_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci1710_detach(struct comedi_device *dev)
+static void pci1710_detach(struct comedi_device *dev)
{
-
if (dev->private) {
if (devpriv->valid)
pci1710_reset(dev);
@@ -1598,57 +1561,49 @@ static int pci1710_detach(struct comedi_device *dev)
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
-
pci_dev_put(devpriv->pcidev);
}
}
-
- return 0;
}
-/*
-==============================================================================
-*/
-static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1710_driver = {
+ .driver_name = "adv_pci1710",
+ .module = THIS_MODULE,
+ .attach = pci1710_attach,
+ .detach = pci1710_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+
+static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci1710_driver);
}
-static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci1710_pci_driver = {
- .id_table = pci1710_pci_table,
- .probe = &driver_pci1710_pci_probe,
- .remove = __devexit_p(&driver_pci1710_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
-static int __init driver_pci1710_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci1710);
- if (retval < 0)
- return retval;
-
- driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
- return pci_register_driver(&driver_pci1710_pci_driver);
-}
-
-static void __exit driver_pci1710_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci1710_pci_driver);
- comedi_driver_unregister(&driver_pci1710);
-}
-
-module_init(driver_pci1710_init_module);
-module_exit(driver_pci1710_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci1710_pci_driver = {
+ .name = "adv_pci1710",
+ .id_table = adv_pci1710_pci_table,
+ .probe = adv_pci1710_pci_probe,
+ .remove = __devexit_p(adv_pci1710_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 29455a8..336addc 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -150,36 +150,6 @@ static const struct pci1723_board boardtypes[] = {
},
};
-/*
- * This is used by modprobe to translate PCI IDs to drivers.
- * Should only be used for PCI and ISA-PnP devices
- */
-static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1723_pci_table);
-
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci1723_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci1723_detach(struct comedi_device *dev);
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board))
-
-static struct comedi_driver driver_pci1723 = {
- .driver_name = "adv_pci1723",
- .module = THIS_MODULE,
- .attach = pci1723_attach,
- .detach = pci1723_detach,
-};
-
/* This structure is for data unique to this hardware driver. */
struct pci1723_private {
int valid; /* card is usable; */
@@ -319,10 +289,6 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev,
return 2;
}
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a pci1723 board.
- */
static int pci1723_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -465,73 +431,50 @@ static int pci1723_attach(struct comedi_device *dev,
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci1723_detach(struct comedi_device *dev)
+static void pci1723_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: pci1723: remove\n", dev->minor);
-
if (dev->private) {
if (devpriv->valid)
pci1723_reset(dev);
-
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
pci_dev_put(devpriv->pcidev);
}
}
-
- return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1723_driver = {
+ .driver_name = "adv_pci1723",
+ .module = THIS_MODULE,
+ .attach = pci1723_attach,
+ .detach = pci1723_detach,
+};
+
+static int __devinit adv_pci1723_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci1723.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci1723_driver);
}
-static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1723_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci1723_pci_driver = {
- .id_table = pci1723_pci_table,
- .probe = &driver_pci1723_pci_probe,
- .remove = __devexit_p(&driver_pci1723_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table);
-static int __init driver_pci1723_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci1723);
- if (retval < 0)
- return retval;
-
- driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name;
- return pci_register_driver(&driver_pci1723_pci_driver);
-}
-
-static void __exit driver_pci1723_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci1723_pci_driver);
- comedi_driver_unregister(&driver_pci1723);
-}
-
-module_init(driver_pci1723_init_module);
-module_exit(driver_pci1723_cleanup_module);
+static struct pci_driver adv_pci1723_pci_driver = {
+ .name = "adv_pci1723",
+ .id_table = adv_pci1723_pci_table,
+ .probe = adv_pci1723_pci_probe,
+ .remove = __devexit_p(adv_pci1723_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 7af068f..43a32dc 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -237,10 +237,6 @@ enum hw_io_access {
#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
-static int pci_dio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci_dio_detach(struct comedi_device *dev);
-
struct diosubd_data {
int chans; /* num of chans */
int addr; /* PCI address ofset */
@@ -263,26 +259,6 @@ struct dio_boardtype {
enum hw_io_access io_access;
};
-static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
-
static const struct dio_boardtype boardtypes[] = {
{"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
TYPE_PCI1730,
@@ -406,15 +382,6 @@ static const struct dio_boardtype boardtypes[] = {
IO_16b}
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype))
-
-static struct comedi_driver driver_pci_dio = {
- .driver_name = "adv_pci_dio",
- .module = THIS_MODULE,
- .attach = pci_dio_attach,
- .detach = pci_dio_detach
-};
-
struct pci_dio_private {
struct pci_dio_private *prev; /* previous private struct */
struct pci_dio_private *next; /* next private struct */
@@ -1116,9 +1083,6 @@ static int CheckAndAllocCard(struct comedi_device *dev,
return 1;
}
-/*
-==============================================================================
-*/
static int pci_dio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1134,7 +1098,7 @@ static int pci_dio_attach(struct comedi_device *dev,
for_each_pci_dev(pcidev) {
/* loop through cards supported by this driver */
- for (i = 0; i < n_boardtypes; ++i) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
if (boardtypes[i].vendor_id != pcidev->vendor)
continue;
if (boardtypes[i].device_id != pcidev->device)
@@ -1162,7 +1126,7 @@ static int pci_dio_attach(struct comedi_device *dev,
return -EIO;
}
- if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n");
return -EIO;
}
@@ -1246,10 +1210,7 @@ static int pci_dio_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci_dio_detach(struct comedi_device *dev)
+static void pci_dio_detach(struct comedi_device *dev)
{
int i, j;
struct comedi_subdevice *s;
@@ -1258,20 +1219,14 @@ static int pci_dio_detach(struct comedi_device *dev)
if (dev->private) {
if (devpriv->valid)
pci_dio_reset(dev);
-
-
- /* This shows the silliness of using this kind of
- * scheme for numbering subdevices. Don't do it. --ds */
subdev = 0;
for (i = 0; i < MAX_DI_SUBDEVS; i++) {
if (this_board->sdi[i].chans)
subdev++;
-
}
for (i = 0; i < MAX_DO_SUBDEVS; i++) {
if (this_board->sdo[i].chans)
subdev++;
-
}
for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
for (j = 0; j < this_board->sdio[i].regs; j++) {
@@ -1280,82 +1235,73 @@ static int pci_dio_detach(struct comedi_device *dev)
subdev++;
}
}
-
if (this_board->boardid.chans)
subdev++;
-
for (i = 0; i < MAX_8254_SUBDEVS; i++)
if (this_board->s8254[i].chans)
subdev++;
-
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
s->private = NULL;
}
-
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
-
pci_dev_put(devpriv->pcidev);
}
-
if (devpriv->prev)
devpriv->prev->next = devpriv->next;
else
pci_priv = devpriv->next;
-
if (devpriv->next)
devpriv->next->prev = devpriv->prev;
-
}
-
- return 0;
}
-/*
-==============================================================================
-*/
-static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci_dio_driver = {
+ .driver_name = "adv_pci_dio",
+ .module = THIS_MODULE,
+ .attach = pci_dio_attach,
+ .detach = pci_dio_detach
+};
+
+static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci_dio.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
}
-static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci_dio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci_dio_pci_driver = {
- .id_table = pci_dio_pci_table,
- .probe = &driver_pci_dio_pci_probe,
- .remove = __devexit_p(&driver_pci_dio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
-static int __init driver_pci_dio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci_dio);
- if (retval < 0)
- return retval;
-
- driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name;
- return pci_register_driver(&driver_pci_dio_pci_driver);
-}
-
-static void __exit driver_pci_dio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci_dio_pci_driver);
- comedi_driver_unregister(&driver_pci_dio);
-}
-
-module_init(driver_pci_dio_init_module);
-module_exit(driver_pci_dio_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci_dio_pci_driver = {
+ .name = "adv_pci_dio",
+ .id_table = adv_pci_dio_pci_table,
+ .probe = adv_pci_dio_pci_probe,
+ .remove = __devexit_p(adv_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index b0f98e5..64d82bc 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -209,36 +209,23 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
return 0;
}
-static int aio_aio12_8_detach(struct comedi_device *dev)
+static void aio_aio12_8_detach(struct comedi_device *dev)
{
subdev_8255_cleanup(dev, &dev->subdevices[2]);
if (dev->iobase)
release_region(dev->iobase, 24);
- return 0;
}
-static struct comedi_driver driver_aio_aio12_8 = {
- .driver_name = "aio_aio12_8",
- .module = THIS_MODULE,
- .attach = aio_aio12_8_attach,
- .detach = aio_aio12_8_detach,
- .board_name = &board_types[0].name,
- .num_names = 1,
- .offset = sizeof(struct aio12_8_boardtype),
+static struct comedi_driver aio_aio12_8_driver = {
+ .driver_name = "aio_aio12_8",
+ .module = THIS_MODULE,
+ .attach = aio_aio12_8_attach,
+ .detach = aio_aio12_8_detach,
+ .board_name = &board_types[0].name,
+ .num_names = ARRAY_SIZE(board_types),
+ .offset = sizeof(struct aio12_8_boardtype),
};
-
-static int __init driver_aio_aio12_8_init_module(void)
-{
- return comedi_driver_register(&driver_aio_aio12_8);
-}
-
-static void __exit driver_aio_aio12_8_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_aio_aio12_8);
-}
-
-module_init(driver_aio_aio12_8_init_module);
-module_exit(driver_aio_aio12_8_cleanup_module);
+module_comedi_driver(aio_aio12_8_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 160b0a0..04f6f94 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -67,30 +67,41 @@ struct aio_iiro_16_private {
#define devpriv ((struct aio_iiro_16_private *) dev->private)
-static int aio_iiro_16_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-
-static int aio_iiro_16_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_aio_iiro_16 = {
- .driver_name = "aio_iiro_16",
- .module = THIS_MODULE,
- .attach = aio_iiro_16_attach,
- .detach = aio_iiro_16_detach,
- .board_name = &aio_iiro_16_boards[0].name,
- .offset = sizeof(struct aio_iiro_16_board),
- .num_names = ARRAY_SIZE(aio_iiro_16_boards),
-};
+static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
+ outb((s->state >> 8) & 0xff,
+ dev->iobase + AIO_IIRO_16_RELAY_8_15);
+ }
+
+ data[1] = s->state;
+
+ return 2;
+}
static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ data[1] = 0;
+ data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
+ data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+
+ return 2;
+}
static int aio_iiro_16_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -138,64 +149,22 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
return 1;
}
-static int aio_iiro_16_detach(struct comedi_device *dev)
+static void aio_iiro_16_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, AIO_IIRO_16_SIZE);
-
- return 0;
-}
-
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
- outb((s->state >> 8) & 0xff,
- dev->iobase + AIO_IIRO_16_RELAY_8_15);
- }
-
- data[1] = s->state;
-
- return 2;
-}
-
-static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = 0;
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
-
- return 2;
-}
-
-static int __init driver_aio_iiro_16_init_module(void)
-{
- return comedi_driver_register(&driver_aio_iiro_16);
}
-static void __exit driver_aio_iiro_16_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_aio_iiro_16);
-}
-
-module_init(driver_aio_iiro_16_init_module);
-module_exit(driver_aio_iiro_16_cleanup_module);
+static struct comedi_driver aio_iiro_16_driver = {
+ .driver_name = "aio_iiro_16",
+ .module = THIS_MODULE,
+ .attach = aio_iiro_16_attach,
+ .detach = aio_iiro_16_detach,
+ .board_name = &aio_iiro_16_boards[0].name,
+ .offset = sizeof(struct aio_iiro_16_board),
+ .num_names = ARRAY_SIZE(aio_iiro_16_boards),
+};
+module_comedi_driver(aio_iiro_16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 566cc44..c9c5d97 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -217,6 +217,14 @@ order they appear in the channel list.
#define DIO200_DRIVER_NAME "amplc_dio200"
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_PCI
+#endif
+
/* PCI IDs */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -274,10 +282,14 @@ enum dio200_model {
};
enum dio200_layout {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
pc212_layout,
pc214_layout,
+#endif
pc215_layout,
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
pc218_layout,
+#endif
pc272_layout
};
@@ -290,6 +302,7 @@ struct dio200_board {
};
static const struct dio200_board dio200_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
{
.name = "pc212e",
.bustype = isa_bustype,
@@ -308,15 +321,6 @@ static const struct dio200_board dio200_boards[] = {
.model = pc215e_model,
.layout = pc215_layout,
},
-#ifdef CONFIG_COMEDI_PCI
- {
- .name = "pci215",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
- .bustype = pci_bustype,
- .model = pci215_model,
- .layout = pc215_layout,
- },
-#endif
{
.name = "pc218e",
.bustype = isa_bustype,
@@ -329,7 +333,15 @@ static const struct dio200_board dio200_boards[] = {
.model = pc272e_model,
.layout = pc272_layout,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+ {
+ .name = "pci215",
+ .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
+ .bustype = pci_bustype,
+ .model = pci215_model,
+ .layout = pc215_layout,
+ },
{
.name = "pci272",
.devid = PCI_DEVICE_ID_AMPLICON_PCI272,
@@ -337,8 +349,6 @@ static const struct dio200_board dio200_boards[] = {
.model = pci272_model,
.layout = pc272_layout,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = DIO200_DRIVER_NAME,
.devid = PCI_DEVICE_ID_INVALID,
@@ -367,6 +377,7 @@ struct dio200_layout_struct {
};
static const struct dio200_layout_struct dio200_layouts[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
[pc212_layout] = {
.n_subdevs = 6,
.sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -385,6 +396,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 0,
.has_clk_gat_sce = 0,
},
+#endif
[pc215_layout] = {
.n_subdevs = 5,
.sdtype = {sd_8255, sd_8255, sd_8254,
@@ -394,6 +406,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 1,
.has_clk_gat_sce = 1,
},
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
[pc218_layout] = {
.n_subdevs = 7,
.sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -405,6 +418,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 1,
.has_clk_gat_sce = 1,
},
+#endif
[pc272_layout] = {
.n_subdevs = 4,
.sdtype = {sd_8255, sd_8255, sd_8255,
@@ -419,7 +433,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
* PCI driver table.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
@@ -427,7 +441,7 @@ static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
};
MODULE_DEVICE_TABLE(pci, dio200_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_DIO200_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -441,7 +455,7 @@ MODULE_DEVICE_TABLE(pci, dio200_pci_table);
feel free to suggest moving the variable to the struct comedi_device struct.
*/
struct dio200_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
struct pci_dev *pci_dev; /* PCI device */
#endif
int intr_sd;
@@ -479,7 +493,7 @@ struct dio200_subdev_intr {
*/
static int dio200_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dio200_detach(struct comedi_device *dev);
+static void dio200_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_dio200 = {
.driver_name = DIO200_DRIVER_NAME,
.module = THIS_MODULE,
@@ -490,12 +504,12 @@ static struct comedi_driver driver_amplc_dio200 = {
.num_names = ARRAY_SIZE(dio200_boards),
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_dio200);
}
static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
@@ -549,7 +563,7 @@ module_exit(driver_amplc_dio200_cleanup_module);
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static int
dio200_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -611,6 +625,7 @@ dio200_find_pci(struct comedi_device *dev, int bus, int slot,
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
static int
dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
{
@@ -621,6 +636,7 @@ dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
}
return 0;
}
+#endif
/*
* 'insn_bits' function for an 'INTERRUPT' subdevice.
@@ -1332,7 +1348,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
unsigned long iobase = 0;
unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -1354,12 +1370,14 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
case isa_bustype:
iobase = it->options[0];
irq = it->options[1];
share_irq = 0;
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -1382,7 +1400,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->intr_sd = -1;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
if (ret < 0) {
@@ -1396,9 +1414,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -1474,12 +1494,19 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+ case pci_bustype:
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -1491,22 +1518,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dio200_detach(struct comedi_device *dev)
+static void dio200_detach(struct comedi_device *dev)
{
const struct dio200_layout_struct *layout;
unsigned n;
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- DIO200_DRIVER_NAME);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->subdevices) {
@@ -1529,7 +1545,7 @@ static int dio200_detach(struct comedi_device *dev)
}
}
if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -1537,15 +1553,12 @@ static int dio200_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
if (dev->iobase)
release_region(dev->iobase, DIO200_IO_SIZE);
+#endif
}
}
- if (dev->board_name)
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
-
- return 0;
}
MODULE_AUTHOR("Comedi http://www.comedi.org");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 7972cad..57ba322 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -63,6 +63,14 @@ unused.
#define PC236_DRIVER_NAME "amplc_pc236"
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_PCI
+#endif
+
/* PCI236 PCI configuration register information */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -106,13 +114,15 @@ struct pc236_board {
enum pc236_model model;
};
static const struct pc236_board pc236_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
{
.name = "pc36at",
.fancy_name = "PC36AT",
.bustype = isa_bustype,
.model = pc36at_model,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
{
.name = "pci236",
.fancy_name = "PCI236",
@@ -120,8 +130,6 @@ static const struct pc236_board pc236_boards[] = {
.bustype = pci_bustype,
.model = pci236_model,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = PC236_DRIVER_NAME,
.fancy_name = PC236_DRIVER_NAME,
@@ -132,14 +140,14 @@ static const struct pc236_board pc236_boards[] = {
#endif
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
{0}
};
MODULE_DEVICE_TABLE(pci, pc236_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC236_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -151,7 +159,7 @@ MODULE_DEVICE_TABLE(pci, pc236_pci_table);
feel free to suggest moving the variable to the struct comedi_device struct.
*/
struct pc236_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
/* PCI device */
struct pci_dev *pci_dev;
unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
@@ -168,7 +176,7 @@ struct pc236_private {
* the device code.
*/
static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc236_detach(struct comedi_device *dev);
+static void pc236_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_pc236 = {
.driver_name = PC236_DRIVER_NAME,
.module = THIS_MODULE,
@@ -179,12 +187,12 @@ static struct comedi_driver driver_amplc_pc236 = {
.num_names = ARRAY_SIZE(pc236_boards),
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_pc236);
}
static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev)
@@ -234,8 +242,10 @@ module_init(driver_amplc_pc236_init_module);
module_exit(driver_amplc_pc236_cleanup_module);
#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
static int pc236_request_region(unsigned minor, unsigned long from,
unsigned long extent);
+#endif
static void pc236_intr_disable(struct comedi_device *dev);
static void pc236_intr_enable(struct comedi_device *dev);
static int pc236_intr_check(struct comedi_device *dev);
@@ -255,7 +265,7 @@ static irqreturn_t pc236_interrupt(int irq, void *d);
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static int
pc236_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -324,7 +334,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
unsigned long iobase = 0;
unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -345,12 +355,14 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
case isa_bustype:
iobase = it->options[0];
irq = it->options[1];
share_irq = 0;
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -361,7 +373,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
devpriv->pci_dev = pci_dev;
break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
default:
printk(KERN_ERR
"comedi%d: %s: BUG! cannot determine board type!\n",
@@ -376,7 +388,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->board_name = thisboard->name;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
@@ -392,9 +404,11 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -439,12 +453,19 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
}
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
+ case pci_bustype:
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -456,27 +477,16 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc236_detach(struct comedi_device *dev)
+static void pc236_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- PC236_DRIVER_NAME);
if (devpriv)
pc236_intr_disable(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 0);
if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -484,21 +494,19 @@ static int pc236_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
if (dev->iobase)
release_region(dev->iobase, PC236_IO_SIZE);
+#endif
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
- return 0;
}
/*
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
static int pc236_request_region(unsigned minor, unsigned long from,
unsigned long extent)
{
@@ -509,6 +517,7 @@ static int pc236_request_region(unsigned minor, unsigned long from,
}
return 0;
}
+#endif
/*
* This function is called to mark the interrupt as disabled (no command
@@ -521,7 +530,7 @@ static void pc236_intr_disable(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->enable_irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase)
outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
#endif
@@ -539,7 +548,7 @@ static void pc236_intr_enable(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->enable_irq = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase)
outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
#endif
@@ -561,7 +570,7 @@ static int pc236_intr_check(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
if (devpriv->enable_irq) {
retval = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase) {
if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
& PLX9052_INTCSR_LI1STAT_MASK)
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 191ac0d..974d745 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -50,6 +50,14 @@ The state of the outputs can be read.
#define PC263_DRIVER_NAME "amplc_pc263"
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_PCI
+#endif
+
/* PCI263 PCI configuration register information */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -73,13 +81,15 @@ struct pc263_board {
enum pc263_model model;
};
static const struct pc263_board pc263_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
{
.name = "pc263",
.fancy_name = "PC263",
.bustype = isa_bustype,
.model = pc263_model,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
{
.name = "pci263",
.fancy_name = "PCI263",
@@ -87,8 +97,6 @@ static const struct pc263_board pc263_boards[] = {
.bustype = pci_bustype,
.model = pci263_model,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = PC263_DRIVER_NAME,
.fancy_name = PC263_DRIVER_NAME,
@@ -99,14 +107,14 @@ static const struct pc263_board pc263_boards[] = {
#endif
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
{0}
};
MODULE_DEVICE_TABLE(pci, pc263_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -117,14 +125,14 @@ MODULE_DEVICE_TABLE(pci, pc263_pci_table);
several hardware drivers keep similar information in this structure,
feel free to suggest moving the variable to the struct comedi_device struct.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
struct pc263_private {
/* PCI device. */
struct pci_dev *pci_dev;
};
#define devpriv ((struct pc263_private *)dev->private)
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
/*
* The struct comedi_driver structure tells the Comedi core module
@@ -133,7 +141,7 @@ struct pc263_private {
* the device code.
*/
static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc263_detach(struct comedi_device *dev);
+static void pc263_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_pc263 = {
.driver_name = PC263_DRIVER_NAME,
.module = THIS_MODULE,
@@ -144,8 +152,10 @@ static struct comedi_driver driver_amplc_pc263 = {
.num_names = ARRAY_SIZE(pc263_boards),
};
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
static int pc263_request_region(unsigned minor, unsigned long from,
unsigned long extent);
+#endif
static int pc263_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -157,7 +167,7 @@ static int pc263_dio_insn_config(struct comedi_device *dev,
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static int
pc263_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -225,7 +235,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
unsigned long iobase = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -237,7 +247,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* Allocate the private structure area. alloc_private() is a
* convenient macro defined in comedidev.h.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
ret = alloc_private(dev, sizeof(struct pc263_private));
if (ret < 0) {
printk(KERN_ERR "comedi%d: error! out of memory!\n",
@@ -247,10 +257,12 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
case isa_bustype:
iobase = it->options[0];
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -260,7 +272,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
devpriv->pci_dev = pci_dev;
break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
default:
printk(KERN_ERR
"comedi%d: %s: BUG! cannot determine board type!\n",
@@ -275,7 +287,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->board_name = thisboard->name;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
if (ret < 0) {
@@ -289,9 +301,11 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -322,12 +336,18 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->state = s->state | (inb(dev->iobase) << 8);
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
printk("attached\n");
@@ -335,23 +355,13 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc263_detach(struct comedi_device *dev)
+static void pc263_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- PC263_DRIVER_NAME);
-
-#ifdef CONFIG_COMEDI_PCI
- if (devpriv) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
+ if (devpriv)
#endif
-#ifdef CONFIG_COMEDI_PCI
+ {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -359,21 +369,19 @@ static int pc263_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
if (dev->iobase)
release_region(dev->iobase, PC263_IO_SIZE);
+#endif
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
- return 0;
}
/*
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
static int pc263_request_region(unsigned minor, unsigned long from,
unsigned long extent)
{
@@ -384,6 +392,7 @@ static int pc263_request_region(unsigned minor, unsigned long from,
}
return 0;
}
+#endif
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -429,12 +438,12 @@ static int pc263_dio_insn_config(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_pc263);
}
static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index b278917c..fbf19ca 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -380,18 +380,6 @@ static const struct pci224_board pci224_boards[] = {
};
/*
- * PCI driver table.
- */
-
-static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci224_pci_table);
-
-/*
* Useful for shorthand access to the particular board structure
*/
#define thisboard ((struct pci224_board *)dev->board_ptr)
@@ -422,65 +410,6 @@ struct pci224_private {
#define devpriv ((struct pci224_private *)dev->private)
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci224_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci224_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci224 = {
- .driver_name = DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci224_attach,
- .detach = pci224_detach,
- .board_name = &pci224_boards[0].name,
- .offset = sizeof(struct pci224_board),
- .num_names = ARRAY_SIZE(pci224_boards),
-};
-
-static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name);
-}
-
-static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci224_pci_driver = {
- .id_table = pci224_pci_table,
- .probe = &driver_amplc_pci224_pci_probe,
- .remove = __devexit_p(&driver_amplc_pci224_pci_remove)
-};
-
-static int __init driver_amplc_pci224_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_amplc_pci224);
- if (retval < 0)
- return retval;
-
- driver_amplc_pci224_pci_driver.name =
- (char *)driver_amplc_pci224.driver_name;
- return pci_register_driver(&driver_amplc_pci224_pci_driver);
-}
-
-static void __exit driver_amplc_pci224_cleanup_module(void)
-{
- pci_unregister_driver(&driver_amplc_pci224_pci_driver);
- comedi_driver_unregister(&driver_amplc_pci224);
-}
-
-module_init(driver_amplc_pci224_init_module);
-module_exit(driver_amplc_pci224_cleanup_module);
-
-/*
* Called from the 'insn_write' function to perform a single write.
*/
static void
@@ -1312,6 +1241,20 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
}
/*
+ * This function looks for a board matching the supplied PCI device.
+ */
+static const struct pci224_board
+*pci224_find_pci_board(struct pci_dev *pci_dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pci224_boards); i++)
+ if (pci_dev->device == pci224_boards[i].devid)
+ return &pci224_boards[i];
+ return NULL;
+}
+
+/*
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
@@ -1336,17 +1279,12 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
}
if (thisboard->model == any_model) {
/* Match any supported model. */
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) {
- if (pci_dev->device == pci224_boards[i].devid) {
- /* Change board_ptr to matched board. */
- dev->board_ptr = &pci224_boards[i];
- break;
- }
- }
- if (i == ARRAY_SIZE(pci224_boards))
+ const struct pci224_board *board_ptr;
+ board_ptr = pci224_find_pci_board(pci_dev);
+ if (board_ptr == NULL)
continue;
+ /* Change board_ptr to matched board. */
+ dev->board_ptr = board_ptr;
} else {
/* Match specific model name. */
if (thisboard->devid != pci_dev->device)
@@ -1370,35 +1308,16 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
}
/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
+ * Common part of attach and attach_pci.
*/
-static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int pci224_attach_common(struct comedi_device *dev,
+ struct pci_dev *pci_dev, int *options)
{
struct comedi_subdevice *s;
- struct pci_dev *pci_dev;
unsigned int irq;
- int bus = 0, slot = 0;
unsigned n;
int ret;
- printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
-
- bus = it->options[0];
- slot = it->options[1];
- ret = alloc_private(dev, sizeof(struct pci224_private));
- if (ret < 0) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n",
- dev->minor);
- return ret;
- }
-
- ret = pci224_find_pci(dev, bus, slot, &pci_dev);
- if (ret < 0)
- return ret;
-
devpriv->pci_dev = pci_dev;
ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
if (ret < 0) {
@@ -1483,24 +1402,26 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!s->range_table_list)
return -ENOMEM;
- for (n = 2; n < 3 + s->n_chan; n++) {
- if (it->options[n] < 0 || it->options[n] > 1) {
- printk(KERN_WARNING "comedi%d: %s: warning! "
- "bad options[%u]=%d\n",
- dev->minor, DRIVER_NAME, n,
- it->options[n]);
+ if (options) {
+ for (n = 2; n < 3 + s->n_chan; n++) {
+ if (options[n] < 0 || options[n] > 1) {
+ printk(KERN_WARNING
+ "comedi%d: %s: warning! bad options[%u]=%d\n",
+ dev->minor, DRIVER_NAME, n,
+ options[n]);
+ }
}
}
for (n = 0; n < s->n_chan; n++) {
- if (n < COMEDI_NDEVCONFOPTS - 3 &&
- it->options[3 + n] == 1) {
- if (it->options[2] == 1)
+ if (n < COMEDI_NDEVCONFOPTS - 3 && options &&
+ options[3 + n] == 1) {
+ if (options[2] == 1)
range_table_list[n] = &range_pci234_ext;
else
range_table_list[n] = &range_bipolar5;
} else {
- if (it->options[2] == 1) {
+ if (options && options[2] == 1) {
range_table_list[n] =
&range_pci234_ext2;
} else {
@@ -1511,14 +1432,14 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->hwrange = hwrange_pci234;
} else {
/* PCI224 range options. */
- if (it->options[2] == 1) {
+ if (options && options[2] == 1) {
s->range_table = &range_pci224_external;
devpriv->hwrange = hwrange_pci224_external;
} else {
- if (it->options[2] != 0) {
+ if (options && options[2] != 0) {
printk(KERN_WARNING "comedi%d: %s: warning! "
"bad options[2]=%d\n",
- dev->minor, DRIVER_NAME, it->options[2]);
+ dev->minor, DRIVER_NAME, options[2]);
}
s->range_table = &range_pci224_internal;
devpriv->hwrange = hwrange_pci224_internal;
@@ -1552,21 +1473,59 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci224_detach(struct comedi_device *dev)
+static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct pci_dev *pci_dev;
+ int bus, slot;
+ int ret;
+
+ printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
+
+ bus = it->options[0];
+ slot = it->options[1];
+ ret = alloc_private(dev, sizeof(struct pci224_private));
+ if (ret < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
+ return ret;
+ }
+
+ ret = pci224_find_pci(dev, bus, slot, &pci_dev);
+ if (ret < 0)
+ return ret;
+
+ return pci224_attach_common(dev, pci_dev, it->options);
+}
+
+static int
+pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME);
+ int ret;
+
+ printk(KERN_DEBUG "comedi%d: %s: attach_pci %s\n", dev->minor,
+ DRIVER_NAME, pci_name(pci_dev));
+
+ ret = alloc_private(dev, sizeof(struct pci224_private));
+ if (ret < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
+ return ret;
+ }
+ dev->board_ptr = pci224_find_pci_board(pci_dev);
+ if (dev->board_ptr == NULL) {
+ printk(KERN_ERR
+ "comedi%d: %s: BUG! cannot determine board type!\n",
+ dev->minor, DRIVER_NAME);
+ return -EINVAL;
+ }
+ return pci224_attach_common(dev, pci_dev, NULL);
+}
+
+static void pci224_detach(struct comedi_device *dev)
+{
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->subdevices) {
struct comedi_subdevice *s;
@@ -1581,18 +1540,49 @@ static int pci224_detach(struct comedi_device *dev)
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
+}
- return 0;
+static struct comedi_driver amplc_pci224_driver = {
+ .driver_name = "amplc_pci224",
+ .module = THIS_MODULE,
+ .attach = pci224_attach,
+ .detach = pci224_detach,
+ .attach_pci = pci224_attach_pci,
+ .board_name = &pci224_boards[0].name,
+ .offset = sizeof(struct pci224_board),
+ .num_names = ARRAY_SIZE(pci224_boards),
+};
+
+static int __devinit amplc_pci224_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, &amplc_pci224_driver);
}
+static void __devexit amplc_pci224_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
+
+static struct pci_driver amplc_pci224_pci_driver = {
+ .name = "amplc_pci224",
+ .id_table = amplc_pci224_pci_table,
+ .probe = amplc_pci224_pci_probe,
+ .remove = __devexit_p(amplc_pci224_pci_remove),
+};
+module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 5389795..d4c80b1 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -500,13 +500,6 @@ static const struct pci230_board pci230_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci230_pci_table);
/*
* Useful for shorthand access to the particular board structure
*/
@@ -595,65 +588,6 @@ static const struct comedi_lrange pci230_ao_range = { 2, {
/* PCI230 daccon bipolar flag for each analogue output range. */
static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci230_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci230 = {
- .driver_name = "amplc_pci230",
- .module = THIS_MODULE,
- .attach = pci230_attach,
- .detach = pci230_detach,
- .board_name = &pci230_boards[0].name,
- .offset = sizeof(pci230_boards[0]),
- .num_names = ARRAY_SIZE(pci230_boards),
-};
-
-static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name);
-}
-
-static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci230_pci_driver = {
- .id_table = pci230_pci_table,
- .probe = &driver_amplc_pci230_pci_probe,
- .remove = __devexit_p(&driver_amplc_pci230_pci_remove)
-};
-
-static int __init driver_amplc_pci230_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_amplc_pci230);
- if (retval < 0)
- return retval;
-
- driver_amplc_pci230_pci_driver.name =
- (char *)driver_amplc_pci230.driver_name;
- return pci_register_driver(&driver_amplc_pci230_pci_driver);
-}
-
-static void __exit driver_amplc_pci230_cleanup_module(void)
-{
- pci_unregister_driver(&driver_amplc_pci230_pci_driver);
- comedi_driver_unregister(&driver_amplc_pci230);
-}
-
-module_init(driver_amplc_pci230_init_module);
-module_exit(driver_amplc_pci230_cleanup_module);
-
static int pci230_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data);
@@ -1003,35 +937,19 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci230_detach(struct comedi_device *dev)
+static void pci230_detach(struct comedi_device *dev)
{
- printk("comedi%d: amplc_pci230: remove\n", dev->minor);
-
if (dev->subdevices && thisboard->have_dio)
- /* Clean up dio subdevice. */
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
-
- return 0;
}
static int get_resources(struct comedi_device *dev, unsigned int res_mask,
@@ -3048,6 +2966,42 @@ static int pci230_ai_cancel(struct comedi_device *dev,
return 0;
}
+static struct comedi_driver amplc_pci230_driver = {
+ .driver_name = "amplc_pci230",
+ .module = THIS_MODULE,
+ .attach = pci230_attach,
+ .detach = pci230_detach,
+ .board_name = &pci230_boards[0].name,
+ .offset = sizeof(pci230_boards[0]),
+ .num_names = ARRAY_SIZE(pci230_boards),
+};
+
+static int __devinit amplc_pci230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &amplc_pci230_driver);
+}
+
+static void __devexit amplc_pci230_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table);
+
+static struct pci_driver amplc_pci230_pci_driver = {
+ .name = "amplc_pci230",
+ .id_table = amplc_pci230_pci_table,
+ .probe = amplc_pci230_pci_probe,
+ .remove = __devexit_p(amplc_pci230_pci_remove)
+};
+module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 11cdaf2..fb9951a 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -97,16 +97,6 @@ union encvaluetype {
#define C6XDIGIO_TIME_OUT 20
-static int c6xdigio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int c6xdigio_detach(struct comedi_device *dev);
-struct comedi_driver driver_c6xdigio = {
- .driver_name = "c6xdigio",
- .module = THIS_MODULE,
- .attach = c6xdigio_attach,
- .detach = c6xdigio_detach,
-};
-
static void C6X_pwmInit(unsigned long baseAddr)
{
int timeout = 0;
@@ -407,10 +397,6 @@ static void board_init(struct comedi_device *dev)
}
-/* static void board_halt(struct comedi_device *dev) { */
-/* C6X_pwmInit(dev->iobase); */
-/* } */
-
/*
options[0] - I/O port
options[1] - irq
@@ -500,36 +486,22 @@ static int c6xdigio_attach(struct comedi_device *dev,
return 0;
}
-static int c6xdigio_detach(struct comedi_device *dev)
+static void c6xdigio_detach(struct comedi_device *dev)
{
- /* board_halt(dev); may not need this */
-
- printk(KERN_DEBUG "comedi%d: c6xdigio: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, C6XDIGIO_SIZE);
-
- /* Not using IRQ so I am not sure if I need this */
if (dev->irq)
free_irq(dev->irq, dev);
-
pnp_unregister_driver(&c6xdigio_pnp_driver);
-
- return 0;
-}
-
-static int __init driver_c6xdigio_init_module(void)
-{
- return comedi_driver_register(&driver_c6xdigio);
}
-static void __exit driver_c6xdigio_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_c6xdigio);
-}
-
-module_init(driver_c6xdigio_init_module);
-module_exit(driver_c6xdigio_cleanup_module);
+static struct comedi_driver c6xdigio_driver = {
+ .driver_name = "c6xdigio",
+ .module = THIS_MODULE,
+ .attach = c6xdigio_attach,
+ .detach = c6xdigio_detach,
+};
+module_comedi_driver(c6xdigio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 49404f4..3515923 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -91,7 +91,7 @@ struct das16cs_private {
static int das16cs_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int das16cs_detach(struct comedi_device *dev);
+static void das16cs_detach(struct comedi_device *dev);
static struct comedi_driver driver_das16cs = {
.driver_name = "cb_das16_cs",
.module = THIS_MODULE,
@@ -255,15 +255,10 @@ static int das16cs_attach(struct comedi_device *dev,
return 1;
}
-static int das16cs_detach(struct comedi_device *dev)
+static void das16cs_detach(struct comedi_device *dev)
{
- dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
-
- return 0;
}
static irqreturn_t das16cs_interrupt(int irq, void *d)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 7e4ffcf..ee9e084b 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -405,20 +405,6 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -462,22 +448,6 @@ struct cb_pcidas_private {
*/
#define devpriv ((struct cb_pcidas_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcidas_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcidas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
- .driver_name = "cb_pcidas",
- .module = THIS_MODULE,
- .attach = cb_pcidas_attach,
- .detach = cb_pcidas_detach,
-};
-
static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -756,26 +726,12 @@ found:
return 1;
}
-/*
- * cb_pcidas_detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidas_detach(struct comedi_device *dev)
+static void cb_pcidas_detach(struct comedi_device *dev)
{
-
if (devpriv) {
if (devpriv->s5933_config) {
- /* disable and clear interrupts on amcc s5933 */
outl(INTCSR_INBOX_INTR_STATUS,
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
-#ifdef CB_PCIDAS_DEBUG
- dev_dbg(dev->hw_dev, "detaching, incsr is 0x%x\n",
- inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR));
-#endif
}
}
if (dev->irq)
@@ -787,8 +743,6 @@ static int cb_pcidas_detach(struct comedi_device *dev)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
}
/*
@@ -1918,47 +1872,44 @@ static int nvram_read(struct comedi_device *dev, unsigned int address,
return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidas_driver = {
+ .driver_name = "cb_pcidas",
+ .module = THIS_MODULE,
+ .attach = cb_pcidas_attach,
+ .detach = cb_pcidas_detach,
+};
+
+static int __devinit cb_pcidas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidas_driver);
}
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidas_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidas_pci_driver = {
- .id_table = cb_pcidas_pci_table,
- .probe = &driver_cb_pcidas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
-static int __init driver_cb_pcidas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
- return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
+static struct pci_driver cb_pcidas_pci_driver = {
+ .name = "cb_pcidas",
+ .id_table = cb_pcidas_pci_table,
+ .probe = cb_pcidas_pci_probe,
+ .remove = __devexit_p(cb_pcidas_pci_remove)
+};
+module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 915157d..9d0b875 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1026,31 +1026,6 @@ static const struct pcidas64_board pcidas64_boards[] = {
#endif
};
-static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidas64_pci_table);
-
static inline struct pcidas64_board *board(const struct comedi_device *dev)
{
return (struct pcidas64_board *)dev->board_ptr;
@@ -1127,21 +1102,6 @@ static inline struct pcidas64_private *priv(struct comedi_device *dev)
return dev->private;
}
-/*
- * The comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
- .driver_name = "cb_pcidas64",
- .module = THIS_MODULE,
- .attach = attach,
- .detach = detach,
-};
-
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -1216,44 +1176,6 @@ static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags);
static void load_ao_dma(struct comedi_device *dev,
const struct comedi_cmd *cmd);
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
-}
-
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_cb_pcidas_pci_driver = {
- .id_table = pcidas64_pci_table,
- .probe = &driver_cb_pcidas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
-};
-
-static int __init driver_cb_pcidas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
- return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
-
static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
{
@@ -1781,7 +1703,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
- if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n");
return -EIO;
}
@@ -1868,15 +1790,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
{
unsigned int i;
@@ -1938,8 +1852,6 @@ static int detach(struct comedi_device *dev)
}
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
- return 0;
}
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -4315,6 +4227,56 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
i2c_stop(dev);
}
+static struct comedi_driver cb_pcidas64_driver = {
+ .driver_name = "cb_pcidas64",
+ .module = THIS_MODULE,
+ .attach = attach,
+ .detach = detach,
+};
+
+static int __devinit cb_pcidas64_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &cb_pcidas64_driver);
+}
+
+static void __devexit cb_pcidas64_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table);
+
+static struct pci_driver cb_pcidas64_pci_driver = {
+ .name = "cb_pcidas64",
+ .id_table = cb_pcidas64_pci_table,
+ .probe = cb_pcidas64_pci_probe,
+ .remove = __devexit_p(cb_pcidas64_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index abba220..25ebca1 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -51,9 +51,12 @@ Please report success/failure with other different cards to
#include "comedi_pci.h"
#include "8255.h"
-#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */
+
+/* PCI vendor number of ComputerBoards */
+#define PCI_VENDOR_ID_CB 0x1307
#define EEPROM_SIZE 128 /* number of entries in eeprom */
-#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */
+/* maximum number of ao channels for supported boards */
+#define MAX_AO_CHANNELS 8
/* PCI-DDA base addresses */
#define DIGITALIO_BADRINDEX 2
@@ -94,20 +97,26 @@ Please report success/failure with other different cards to
#define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */
/* write bits */
-#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */
+/* serial data input for eeprom, caldacs, reference dac */
+#define SERIAL_IN_BIT 0x1
#define CAL_CHANNEL_MASK (0x7 << 1)
#define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK)
/* read bits */
#define CAL_COUNTER_MASK 0x1f
-#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */
-#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */
+/* calibration counter overflow status bit */
+#define CAL_COUNTER_OVERFLOW_BIT 0x20
+/* analog output is less than reference dac voltage */
+#define AO_BELOW_REF_BIT 0x40
#define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */
#define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */
#define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */
-#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */
-#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */
-#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */
+/* don't send serial data to MAX542 reference dac */
+#define DESELECT_REF_DAC_BIT 0x2
+/* don't send serial data to caldac n */
+#define DESELECT_CALDAC_BIT(n) (0x4 << (n))
+/* manual says to set this bit with no explanation */
+#define DUMMY_BIT 0x40
#define DADATA 8 /* FIRST D/A DATA REGISTER (0) */
@@ -195,26 +204,17 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr)
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+/*
+ * this structure is for data unique to this hardware driver. If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
struct cb_pcidda_private {
int data;
@@ -227,8 +227,10 @@ struct cb_pcidda_private {
/* unsigned long control_status; */
/* unsigned long adc_fifo; */
- unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */
- unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */
+ /* bits last written to da calibration register 1 */
+ unsigned int dac_cal1_bits;
+ /* current range settings for output channels */
+ unsigned int ao_range[MAX_AO_CHANNELS];
u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */
};
@@ -238,9 +240,6 @@ struct cb_pcidda_private {
*/
#define devpriv ((struct cb_pcidda_private *)dev->private)
-static int cb_pcidda_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcidda_detach(struct comedi_device *dev);
/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
static int cb_pcidda_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -259,19 +258,6 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
unsigned int range);
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static struct comedi_driver driver_cb_pcidda = {
- .driver_name = "cb_pcidda",
- .module = THIS_MODULE,
- .attach = cb_pcidda_attach,
- .detach = cb_pcidda_detach,
-};
-
-/*
* Attach is called by the Comedi core to configure the driver
* for a particular board.
*/
@@ -377,7 +363,8 @@ found:
dev_dbg(dev->hw_dev, "eeprom:\n");
for (index = 0; index < EEPROM_SIZE; index++) {
devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
- dev_dbg(dev->hw_dev, "%i:0x%x\n", index, devpriv->eeprom_data[index]);
+ dev_dbg(dev->hw_dev, "%i:0x%x\n", index,
+ devpriv->eeprom_data[index]);
}
/* set calibrations dacs */
@@ -387,19 +374,8 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidda_detach(struct comedi_device *dev)
+static void cb_pcidda_detach(struct comedi_device *dev)
{
-/*
- * Deallocate the I/O ports.
- */
if (devpriv) {
if (devpriv->pci_dev) {
if (devpriv->dac)
@@ -407,13 +383,10 @@ static int cb_pcidda_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
- /* cleanup 8255 */
if (dev->subdevices) {
subdev_8255_cleanup(dev, dev->subdevices + 1);
subdev_8255_cleanup(dev, dev->subdevices + 2);
}
-
- return 0;
}
/*
@@ -484,7 +457,10 @@ static int cb_pcidda_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources are unique and mutually
+ * compatible
+ */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER
@@ -696,8 +672,10 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
unsigned int i;
unsigned int cal2_bits;
unsigned int value;
- const int max_num_caldacs = 4; /* one caldac for every two dac channels */
- const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */
+ /* one caldac for every two dac channels */
+ const int max_num_caldacs = 4;
+ /* bits to send to tell eeprom we want to read */
+ const int read_instruction = 0x6;
const int instruction_length = 3;
const int address_length = 8;
@@ -729,9 +707,11 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev,
{
unsigned int cal2_bits;
unsigned int i;
- const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */
+ /* caldacs use 3 bit channel specification */
+ const int num_channel_bits = 3;
const int num_caldac_bits = 8; /* 8 bit calibration dacs */
- const int max_num_caldacs = 4; /* one caldac for every two dac channels */
+ /* one caldac for every two dac channels */
+ const int max_num_caldacs = 4;
/* write 3 bit channel */
cb_pcidda_serial_out(dev, channel, num_channel_bits);
@@ -790,14 +770,20 @@ static unsigned int offset_eeprom_address(unsigned int ao_channel,
return 0x7 + 2 * range + 12 * ao_channel;
}
-/* returns eeprom address that provides gain calibration for given ao channel and range */
+/*
+ * returns eeprom address that provides gain calibration for given ao
+ * channel and range
+ */
static unsigned int gain_eeprom_address(unsigned int ao_channel,
unsigned int range)
{
return 0x8 + 2 * range + 12 * ao_channel;
}
-/* returns upper byte of eeprom entry, which gives the coarse adjustment values */
+/*
+ * returns upper byte of eeprom entry, which gives the coarse adjustment
+ * values
+ */
static unsigned int eeprom_coarse_byte(unsigned int word)
{
return (word >> 8) & 0xff;
@@ -815,7 +801,7 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
{
unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
- /* remember range so we can tell when we need to readjust calibration */
+ /* remember range so we can tell when we need to readjust calibration */
devpriv->ao_range[channel] = range;
/* get values from eeprom data */
@@ -843,47 +829,42 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
fine_gain_channel(channel), fine_gain);
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidda_driver = {
+ .driver_name = "cb_pcidda",
+ .module = THIS_MODULE,
+ .attach = cb_pcidda_attach,
+ .detach = cb_pcidda_detach,
+};
+
+static int __devinit cb_pcidda_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidda_driver);
}
-static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidda_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidda_pci_driver = {
- .id_table = cb_pcidda_pci_table,
- .probe = &driver_cb_pcidda_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidda_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
-static int __init driver_cb_pcidda_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidda);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name;
- return pci_register_driver(&driver_cb_pcidda_pci_driver);
-}
-
-static void __exit driver_cb_pcidda_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidda_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidda);
-}
-
-module_init(driver_cb_pcidda_init_module);
-module_exit(driver_cb_pcidda_cleanup_module);
+static struct pci_driver cb_pcidda_pci_driver = {
+ .name = "cb_pcidda",
+ .id_table = cb_pcidda_pci_table,
+ .probe = cb_pcidda_pci_probe,
+ .remove = __devexit_p(cb_pcidda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 8f32152..713132c 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -86,19 +86,6 @@ static const struct pcidio_board pcidio_boards[] = {
},
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidio_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -125,59 +112,6 @@ struct pcidio_private {
*/
#define devpriv ((struct pcidio_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcidio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcidio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidio = {
- .driver_name = "cb_pcidio",
- .module = THIS_MODULE,
- .attach = pcidio_attach,
- .detach = pcidio_detach,
-
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcidio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
-
-/* The following fields should NOT be initialized if you are dealing
- * with PCI devices
- *
- * .board_name = pcidio_boards,
- * .offset = sizeof(struct pcidio_board),
- * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board),
- */
-
-};
-
-/*------------------------------- FUNCTIONS -----------------------------------*/
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pcidev = NULL;
@@ -261,15 +195,7 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcidio_detach(struct comedi_device *dev)
+static void pcidio_detach(struct comedi_device *dev)
{
if (devpriv) {
if (devpriv->pci_dev) {
@@ -283,50 +209,41 @@ static int pcidio_detach(struct comedi_device *dev)
for (i = 0; i < thisboard->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
}
- return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev,
+static struct comedi_driver cb_pcidio_driver = {
+ .driver_name = "cb_pcidio",
+ .module = THIS_MODULE,
+ .attach = pcidio_attach,
+ .detach = pcidio_detach,
+};
+
+static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidio_driver);
}
-static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidio_pci_driver = {
- .id_table = pcidio_pci_table,
- .probe = &driver_cb_pcidio_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table);
-static int __init driver_cb_pcidio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidio);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name;
- return pci_register_driver(&driver_cb_pcidio_pci_driver);
-}
-
-static void __exit driver_cb_pcidio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidio_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidio);
-}
-
-module_init(driver_cb_pcidio_init_module);
-module_exit(driver_cb_pcidio_cleanup_module);
+static struct pci_driver cb_pcidio_pci_driver = {
+ .name = "cb_pcidio",
+ .id_table = cb_pcidio_pci_table,
+ .probe = cb_pcidio_pci_probe,
+ .remove = __devexit_p(cb_pcidio_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 8ba6942..5f834d0 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -123,15 +123,6 @@ static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
},
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
-
#define N_BOARDS 1 /* Max number of boards supported */
/*
@@ -139,9 +130,12 @@ MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
*/
#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+/*
+ * this structure is for data unique to this hardware driver. If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
struct cb_pcimdas_private {
int data;
@@ -172,22 +166,6 @@ struct cb_pcimdas_private {
*/
#define devpriv ((struct cb_pcimdas_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcimdas_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcimdas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcimdas = {
- .driver_name = "cb_pcimdas",
- .module = THIS_MODULE,
- .attach = cb_pcimdas_attach,
- .detach = cb_pcimdas_detach,
-};
-
static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -317,7 +295,8 @@ found:
s->subdev_flags = SDF_WRITABLE;
s->n_chan = thisboard->ao_nchan;
s->maxdata = 1 << thisboard->ao_bits;
- s->range_table = &range_unknown; /* ranges are hardware settable, but not software readable. */
+ /* ranges are hardware settable, but not software readable. */
+ s->range_table = &range_unknown;
s->insn_write = &cb_pcimdas_ao_winsn;
s->insn_read = &cb_pcimdas_ao_rinsn;
@@ -331,29 +310,8 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcimdas_detach(struct comedi_device *dev)
+static void cb_pcimdas_detach(struct comedi_device *dev)
{
- if (devpriv) {
- dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n",
- devpriv->BADR0);
- dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n",
- devpriv->BADR1);
- dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n",
- devpriv->BADR2);
- dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n",
- devpriv->BADR3);
- dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n",
- devpriv->BADR4);
- }
-
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
@@ -363,8 +321,6 @@ static int cb_pcimdas_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
-
- return 0;
}
/*
@@ -402,7 +358,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */
outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */
- /* write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */
+ /*
+ * write channel limits to multiplexer, set Low (bits 0-3) and
+ * High (bits 4-7) channels to chan.
+ */
chanlims = chan | (chan << 4);
outb(chanlims, devpriv->BADR3 + 0);
@@ -479,49 +438,37 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
return i;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver cb_pcimdas_driver = {
+ .driver_name = "cb_pcimdas",
+ .module = THIS_MODULE,
+ .attach = cb_pcimdas_attach,
+ .detach = cb_pcimdas_detach,
+};
+
+static int __devinit cb_pcimdas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcimdas_driver);
}
-static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcimdas_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcimdas_pci_driver = {
- .id_table = cb_pcimdas_pci_table,
- .probe = &driver_cb_pcimdas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcimdas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
-static int __init driver_cb_pcimdas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcimdas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcimdas_pci_driver.name =
- (char *)driver_cb_pcimdas.driver_name;
- return pci_register_driver(&driver_cb_pcimdas_pci_driver);
-}
-
-static void __exit driver_cb_pcimdas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcimdas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcimdas);
-}
-
-module_init(driver_cb_pcimdas_init_module);
-module_exit(driver_cb_pcimdas_cleanup_module);
+static struct pci_driver cb_pcimdas_pci_driver = {
+ .name = "cb_pcimdas",
+ .id_table = cb_pcimdas_pci_table,
+ .probe = cb_pcimdas_pci_probe,
+ .remove = __devexit_p(cb_pcimdas_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 40bddfa..b339685 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -140,17 +140,6 @@ static const struct board_struct boards[] = {
#define REG_SZ (thisboard->reg_sz)
#define REGS_BADRINDEX (thisboard->regs_badrindex)
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_table);
-
/*
* this structure is for data unique to this hardware driver. If
* several hardware drivers keep similar information in this structure,
@@ -161,7 +150,6 @@ struct board_private_struct {
unsigned long registers; /* set by probe */
unsigned long dio_registers;
char attached_to_8255; /* boolean */
- char attached_successfully; /* boolean */
/* would be useful for a PCI device */
struct pci_dev *pci_dev;
@@ -177,66 +165,6 @@ struct board_private_struct {
*/
#define devpriv ((struct board_private_struct *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver cb_pcimdda_driver = {
- .driver_name = "cb_pcimdda",
- .module = THIS_MODULE,
- .attach = attach,
- .detach = detach,
-};
-
-MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
-MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
- "series. Currently only supports PCIM-DDA06-16 (which "
- "also happens to be the only board in this series. :) ) ");
-MODULE_LICENSE("GPL");
-static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
-}
-
-static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cb_pcimdda_driver_pci_driver = {
- .id_table = pci_table,
- .probe = &cb_pcimdda_driver_pci_probe,
- .remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
-};
-
-static int __init cb_pcimdda_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&cb_pcimdda_driver);
- if (retval < 0)
- return retval;
-
- cb_pcimdda_driver_pci_driver.name =
- (char *)cb_pcimdda_driver.driver_name;
- return pci_register_driver(&cb_pcimdda_driver_pci_driver);
-}
-
-static void __exit cb_pcimdda_driver_cleanup_module(void)
-{
- pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
- comedi_driver_unregister(&cb_pcimdda_driver);
-}
-
-module_init(cb_pcimdda_driver_init_module);
-module_exit(cb_pcimdda_driver_cleanup_module);
-
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -354,44 +282,24 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_UNUSED;
}
- devpriv->attached_successfully = 1;
-
printk("attached\n");
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
{
if (devpriv) {
-
if (dev->subdevices && devpriv->attached_to_8255) {
- /* de-register us from the 8255 driver */
subdev_8255_cleanup(dev, dev->subdevices + 2);
devpriv->attached_to_8255 = 0;
}
-
if (devpriv->pci_dev) {
if (devpriv->registers)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- if (devpriv->attached_successfully && thisboard)
- printk("comedi%d: %s: detached\n", dev->minor,
- thisboard->name);
-
}
-
- return 0;
}
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -515,3 +423,41 @@ static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
"card found at the requested position\n");
return -ENODEV;
}
+
+static struct comedi_driver cb_pcimdda_driver = {
+ .driver_name = "cb_pcimdda",
+ .module = THIS_MODULE,
+ .attach = attach,
+ .detach = detach,
+};
+
+static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
+}
+
+static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
+
+static struct pci_driver cb_pcimdda_driver_pci_driver = {
+ .name = "cb_pcimdda",
+ .id_table = cb_pcimdda_pci_table,
+ .probe = cb_pcimdda_pci_probe,
+ .remove = __devexit_p(cb_pcimdda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
+
+MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
+MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
+ "series. Currently only supports PCIM-DDA06-16 (which "
+ "also happens to be the only board in this series. :) ) ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index d8aefb2..29412de 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -60,7 +60,6 @@ Configuration Options:
#define MAX_CHANS 256
#define MODULE_NAME "comedi_bond"
-MODULE_LICENSE("GPL");
#ifndef STR
# define STR1(x) #x
# define STR(x) STR1(x)
@@ -79,10 +78,6 @@ MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
} while (0)
#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
-MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
- "devices together as one. In the words of John Lennon: "
- "'And the world will live as one...'");
/*
* Board descriptions for two imaginary boards. Describing the
@@ -93,12 +88,6 @@ struct BondingBoard {
const char *name;
};
-static const struct BondingBoard bondingBoards[] = {
- {
- .name = MODULE_NAME,
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -133,129 +122,6 @@ struct Private {
*/
#define devpriv ((struct Private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int bonding_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int bonding_detach(struct comedi_device *dev);
-/** Build Private array of all devices.. */
-static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
-static void doDevUnconfig(struct comedi_device *dev);
-/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
- * what can I say? I like to do wasteful memcopies.. :) */
-static void *Realloc(const void *ptr, size_t len, size_t old_len);
-
-static struct comedi_driver driver_bonding = {
- .driver_name = MODULE_NAME,
- .module = THIS_MODULE,
- .attach = bonding_attach,
- .detach = bonding_detach,
- /* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in skel_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &bondingBoards[0].name,
- .offset = sizeof(struct BondingBoard),
- .num_names = ARRAY_SIZE(bondingBoards),
-};
-
-static int bonding_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int bonding_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int bonding_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
-
- LOG_MSG("comedi%d\n", dev->minor);
-
- /*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct Private)) < 0)
- return -ENOMEM;
-
- /*
- * Setup our bonding from config params.. sets up our Private struct..
- */
- if (!doDevConfig(dev, it))
- return -EINVAL;
-
- /*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = devpriv->name;
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = devpriv->nchans;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = bonding_dio_insn_bits;
- s->insn_config = bonding_dio_insn_config;
-
- LOG_MSG("attached with %u DIO channels coming from %u different "
- "subdevices all bonded together. "
- "John Lennon would be proud!\n",
- devpriv->nchans, devpriv->ndevs);
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int bonding_detach(struct comedi_device *dev)
-{
- LOG_MSG("comedi%d: remove\n", dev->minor);
- doDevUnconfig(dev);
- return 0;
-}
-
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
* useful to applications if you implement the insn_bits interface.
@@ -466,7 +332,57 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-static void doDevUnconfig(struct comedi_device *dev)
+static int bonding_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+
+ LOG_MSG("comedi%d\n", dev->minor);
+
+ /*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct Private)) < 0)
+ return -ENOMEM;
+
+ /*
+ * Setup our bonding from config params.. sets up our Private struct..
+ */
+ if (!doDevConfig(dev, it))
+ return -EINVAL;
+
+ /*
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
+ */
+ dev->board_name = devpriv->name;
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = devpriv->nchans;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = bonding_dio_insn_bits;
+ s->insn_config = bonding_dio_insn_config;
+
+ LOG_MSG("attached with %u DIO channels coming from %u different "
+ "subdevices all bonded together. "
+ "John Lennon would be proud!\n",
+ devpriv->nchans, devpriv->ndevs);
+
+ return 1;
+}
+
+static void bonding_detach(struct comedi_device *dev)
{
unsigned long devs_closed = 0;
@@ -490,15 +406,25 @@ static void doDevUnconfig(struct comedi_device *dev)
}
}
-static int __init init(void)
-{
- return comedi_driver_register(&driver_bonding);
-}
+static const struct BondingBoard bondingBoards[] = {
+ {
+ .name = "comedi_bond",
+ },
+};
-static void __exit cleanup(void)
-{
- comedi_driver_unregister(&driver_bonding);
-}
+static struct comedi_driver bonding_driver = {
+ .driver_name = "comedi_bond",
+ .module = THIS_MODULE,
+ .attach = bonding_attach,
+ .detach = bonding_detach,
+ .board_name = &bondingBoards[0].name,
+ .offset = sizeof(struct BondingBoard),
+ .num_names = ARRAY_SIZE(bondingBoards),
+};
+module_comedi_driver(bonding_driver);
-module_init(init);
-module_exit(cleanup);
+MODULE_AUTHOR("Calin A. Culianu");
+MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
+ "devices together as one. In the words of John Lennon: "
+ "'And the world will live as one...'");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 21d834d..bff5dcd 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -91,29 +91,6 @@ pin, which can be used to wake up tasks.
#define PARPORT_B 1
#define PARPORT_C 2
-static int parport_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int parport_detach(struct comedi_device *dev);
-static struct comedi_driver driver_parport = {
- .driver_name = "comedi_parport",
- .module = THIS_MODULE,
- .attach = parport_attach,
- .detach = parport_detach,
-};
-
-static int __init driver_parport_init_module(void)
-{
- return comedi_driver_register(&driver_parport);
-}
-
-static void __exit driver_parport_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_parport);
-}
-
-module_init(driver_parport_init_module);
-module_exit(driver_parport_cleanup_module);
-
struct parport_private {
unsigned int a_data;
unsigned int c_data;
@@ -395,19 +372,22 @@ static int parport_attach(struct comedi_device *dev,
return 1;
}
-static int parport_detach(struct comedi_device *dev)
+static void parport_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: parport: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PARPORT_SIZE);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static struct comedi_driver parport_driver = {
+ .driver_name = "comedi_parport",
+ .module = THIS_MODULE,
+ .attach = parport_attach,
+ .detach = parport_detach,
+};
+module_comedi_driver(parport_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index a804742..873e374 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -67,15 +67,6 @@ struct waveform_board {
#define N_CHANS 8
-static const struct waveform_board waveform_boards[] = {
- {
- .name = "comedi_test",
- .ai_chans = N_CHANS,
- .ai_bits = 16,
- .have_dio = 0,
- },
-};
-
#define thisboard ((const struct waveform_board *)dev->board_ptr)
/* Data unique to this driver */
@@ -94,54 +85,6 @@ struct waveform_private {
};
#define devpriv ((struct waveform_private *)dev->private)
-static int waveform_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int waveform_detach(struct comedi_device *dev);
-static struct comedi_driver driver_waveform = {
- .driver_name = "comedi_test",
- .module = THIS_MODULE,
- .attach = waveform_attach,
- .detach = waveform_detach,
- .board_name = &waveform_boards[0].name,
- .offset = sizeof(struct waveform_board),
- .num_names = ARRAY_SIZE(waveform_boards),
-};
-
-static int __init driver_waveform_init_module(void)
-{
- return comedi_driver_register(&driver_waveform);
-}
-
-static void __exit driver_waveform_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_waveform);
-}
-
-module_init(driver_waveform_init_module);
-module_exit(driver_waveform_cleanup_module);
-
-static int waveform_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int waveform_ai_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int waveform_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int waveform_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int waveform_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_squarewave(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_flatline(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
- unsigned int range, unsigned long current_time);
-
/* 1000 nanosec in a microsec */
static const int nano_per_micro = 1000;
@@ -154,6 +97,78 @@ static const struct comedi_lrange waveform_ai_ranges = {
}
};
+static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
+ unsigned long current_time)
+{
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int offset = s->maxdata / 2;
+ u64 value;
+ const struct comedi_krange *krange =
+ &s->range_table->range[range_index];
+ u64 binary_amplitude;
+
+ binary_amplitude = s->maxdata;
+ binary_amplitude *= devpriv->uvolt_amplitude;
+ do_div(binary_amplitude, krange->max - krange->min);
+
+ current_time %= devpriv->usec_period;
+ value = current_time;
+ value *= binary_amplitude * 2;
+ do_div(value, devpriv->usec_period);
+ value -= binary_amplitude; /* get rid of sawtooth's dc offset */
+
+ return offset + value;
+}
+
+static short fake_squarewave(struct comedi_device *dev,
+ unsigned int range_index,
+ unsigned long current_time)
+{
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int offset = s->maxdata / 2;
+ u64 value;
+ const struct comedi_krange *krange =
+ &s->range_table->range[range_index];
+ current_time %= devpriv->usec_period;
+
+ value = s->maxdata;
+ value *= devpriv->uvolt_amplitude;
+ do_div(value, krange->max - krange->min);
+
+ if (current_time < devpriv->usec_period / 2)
+ value *= -1;
+
+ return offset + value;
+}
+
+static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
+ unsigned long current_time)
+{
+ return dev->read_subdev->maxdata / 2;
+}
+
+/* generates a different waveform depending on what channel is read */
+static short fake_waveform(struct comedi_device *dev, unsigned int channel,
+ unsigned int range, unsigned long current_time)
+{
+ enum {
+ SAWTOOTH_CHAN,
+ SQUARE_CHAN,
+ };
+ switch (channel) {
+ case SAWTOOTH_CHAN:
+ return fake_sawtooth(dev, range, current_time);
+ break;
+ case SQUARE_CHAN:
+ return fake_squarewave(dev, range, current_time);
+ break;
+ default:
+ break;
+ }
+
+ return fake_flatline(dev, range, current_time);
+}
+
/*
This is the background routine used to generate arbitrary data.
It should run in the background; therefore it is scheduled by
@@ -217,84 +232,6 @@ static void waveform_ai_interrupt(unsigned long arg)
comedi_event(dev, dev->read_subdev);
}
-static int waveform_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int amplitude = it->options[0];
- int period = it->options[1];
- int i;
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
- return -ENOMEM;
-
- /* set default amplitude and period */
- if (amplitude <= 0)
- amplitude = 1000000; /* 1 volt */
- if (period <= 0)
- period = 100000; /* 0.1 sec */
-
- devpriv->uvolt_amplitude = amplitude;
- devpriv->usec_period = period;
-
- dev->n_subdevices = 2;
- if (alloc_subdevices(dev, dev->n_subdevices) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- dev->read_subdev = s;
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
- s->n_chan = thisboard->ai_chans;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = &waveform_ai_ranges;
- s->len_chanlist = s->n_chan * 2;
- s->insn_read = waveform_ai_insn_read;
- s->do_cmd = waveform_ai_cmd;
- s->do_cmdtest = waveform_ai_cmdtest;
- s->cancel = waveform_ai_cancel;
-
- s = dev->subdevices + 1;
- dev->write_subdev = s;
- /* analog output subdevice (loopback) */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
- s->n_chan = thisboard->ai_chans;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = &waveform_ai_ranges;
- s->len_chanlist = s->n_chan * 2;
- s->insn_write = waveform_ao_insn_write;
- s->do_cmd = NULL;
- s->do_cmdtest = NULL;
- s->cancel = NULL;
-
- /* Our default loopback value is just a 0V flatline */
- for (i = 0; i < s->n_chan; i++)
- devpriv->ao_loopbacks[i] = s->maxdata / 2;
-
- init_timer(&(devpriv->timer));
- devpriv->timer.function = waveform_ai_interrupt;
- devpriv->timer.data = (unsigned long)dev;
-
- printk(KERN_INFO "comedi%d: comedi_test: "
- "%i microvolt, %li microsecond waveform attached\n", dev->minor,
- devpriv->uvolt_amplitude, devpriv->usec_period);
- return 1;
-}
-
-static int waveform_detach(struct comedi_device *dev)
-{
- printk("comedi%d: comedi_test: remove\n", dev->minor);
-
- if (dev->private)
- waveform_ai_cancel(dev, dev->read_subdev);
-
- return 0;
-}
-
static int waveform_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -465,78 +402,6 @@ static int waveform_ai_cancel(struct comedi_device *dev,
return 0;
}
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
- unsigned long current_time)
-{
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int offset = s->maxdata / 2;
- u64 value;
- const struct comedi_krange *krange =
- &s->range_table->range[range_index];
- u64 binary_amplitude;
-
- binary_amplitude = s->maxdata;
- binary_amplitude *= devpriv->uvolt_amplitude;
- do_div(binary_amplitude, krange->max - krange->min);
-
- current_time %= devpriv->usec_period;
- value = current_time;
- value *= binary_amplitude * 2;
- do_div(value, devpriv->usec_period);
- value -= binary_amplitude; /* get rid of sawtooth's dc offset */
-
- return offset + value;
-}
-
-static short fake_squarewave(struct comedi_device *dev,
- unsigned int range_index,
- unsigned long current_time)
-{
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int offset = s->maxdata / 2;
- u64 value;
- const struct comedi_krange *krange =
- &s->range_table->range[range_index];
- current_time %= devpriv->usec_period;
-
- value = s->maxdata;
- value *= devpriv->uvolt_amplitude;
- do_div(value, krange->max - krange->min);
-
- if (current_time < devpriv->usec_period / 2)
- value *= -1;
-
- return offset + value;
-}
-
-static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
- unsigned long current_time)
-{
- return dev->read_subdev->maxdata / 2;
-}
-
-/* generates a different waveform depending on what channel is read */
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
- unsigned int range, unsigned long current_time)
-{
- enum {
- SAWTOOTH_CHAN,
- SQUARE_CHAN,
- };
- switch (channel) {
- case SAWTOOTH_CHAN:
- return fake_sawtooth(dev, range, current_time);
- break;
- case SQUARE_CHAN:
- return fake_squarewave(dev, range, current_time);
- break;
- default:
- break;
- }
-
- return fake_flatline(dev, range, current_time);
-}
-
static int waveform_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -561,6 +426,100 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
+static int waveform_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int amplitude = it->options[0];
+ int period = it->options[1];
+ int i;
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
+ return -ENOMEM;
+
+ /* set default amplitude and period */
+ if (amplitude <= 0)
+ amplitude = 1000000; /* 1 volt */
+ if (period <= 0)
+ period = 100000; /* 0.1 sec */
+
+ devpriv->uvolt_amplitude = amplitude;
+ devpriv->usec_period = period;
+
+ dev->n_subdevices = 2;
+ if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ dev->read_subdev = s;
+ /* analog input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+ s->n_chan = thisboard->ai_chans;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = &waveform_ai_ranges;
+ s->len_chanlist = s->n_chan * 2;
+ s->insn_read = waveform_ai_insn_read;
+ s->do_cmd = waveform_ai_cmd;
+ s->do_cmdtest = waveform_ai_cmdtest;
+ s->cancel = waveform_ai_cancel;
+
+ s = dev->subdevices + 1;
+ dev->write_subdev = s;
+ /* analog output subdevice (loopback) */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
+ s->n_chan = thisboard->ai_chans;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = &waveform_ai_ranges;
+ s->len_chanlist = s->n_chan * 2;
+ s->insn_write = waveform_ao_insn_write;
+ s->do_cmd = NULL;
+ s->do_cmdtest = NULL;
+ s->cancel = NULL;
+
+ /* Our default loopback value is just a 0V flatline */
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->ao_loopbacks[i] = s->maxdata / 2;
+
+ init_timer(&(devpriv->timer));
+ devpriv->timer.function = waveform_ai_interrupt;
+ devpriv->timer.data = (unsigned long)dev;
+
+ printk(KERN_INFO "comedi%d: comedi_test: "
+ "%i microvolt, %li microsecond waveform attached\n", dev->minor,
+ devpriv->uvolt_amplitude, devpriv->usec_period);
+ return 1;
+}
+
+static void waveform_detach(struct comedi_device *dev)
+{
+ if (dev->private)
+ waveform_ai_cancel(dev, dev->read_subdev);
+}
+
+static const struct waveform_board waveform_boards[] = {
+ {
+ .name = "comedi_test",
+ .ai_chans = N_CHANS,
+ .ai_bits = 16,
+ .have_dio = 0,
+ },
+};
+
+static struct comedi_driver waveform_driver = {
+ .driver_name = "comedi_test",
+ .module = THIS_MODULE,
+ .attach = waveform_attach,
+ .detach = waveform_detach,
+ .board_name = &waveform_boards[0].name,
+ .offset = sizeof(struct waveform_board),
+ .num_names = ARRAY_SIZE(waveform_boards),
+};
+module_comedi_driver(waveform_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index e3659bd..b8bac80 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -56,13 +56,6 @@ static const struct contec_board contec_boards[] = {
};
#define PCI_DEVICE_ID_PIO1616L 0x8172
-static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
- .driver_data = PIO1616L },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, contec_pci_table);
#define thisboard ((const struct contec_board *)dev->board_ptr)
@@ -75,30 +68,42 @@ struct contec_private {
#define devpriv ((struct contec_private *)dev->private)
-static int contec_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int contec_detach(struct comedi_device *dev);
-static struct comedi_driver driver_contec = {
- .driver_name = "contec_pci_dio",
- .module = THIS_MODULE,
- .attach = contec_attach,
- .detach = contec_detach,
-};
+static int contec_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
+ dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
+
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
+ dev->iobase + thisboard->out_offs);
+ outw(s->state, dev->iobase + thisboard->out_offs);
+ }
+ return 2;
+}
-/* Classic digital IO */
static int contec_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int contec_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
+ dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
+ if (insn->n != 2)
+ return -EINVAL;
-static int contec_ns_to_timer(unsigned int *ns, int round);
-#endif
+ data[1] = inw(dev->iobase + thisboard->in_offs);
+
+ return 2;
+}
static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
@@ -164,107 +169,47 @@ static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EIO;
}
-static int contec_detach(struct comedi_device *dev)
+static void contec_detach(struct comedi_device *dev)
{
- printk("comedi%d: contec: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
-}
-
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- printk("contec_cmdtest called\n");
- return 0;
-}
-
-static int contec_ns_to_timer(unsigned int *ns, int round)
-{
- return *ns;
-}
-#endif
-
-static int contec_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
- dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
- dev->iobase + thisboard->out_offs);
- outw(s->state, dev->iobase + thisboard->out_offs);
- }
- return 2;
}
-static int contec_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
- dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inw(dev->iobase + thisboard->in_offs);
-
- return 2;
-}
+static struct comedi_driver contec_pci_dio_driver = {
+ .driver_name = "contec_pci_dio",
+ .module = THIS_MODULE,
+ .attach = contec_attach,
+ .detach = contec_detach,
+};
-static int __devinit driver_contec_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit contec_pci_dio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_contec.driver_name);
+ return comedi_pci_auto_config(dev, &contec_pci_dio_driver);
}
-static void __devexit driver_contec_pci_remove(struct pci_dev *dev)
+static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_contec_pci_driver = {
- .id_table = contec_pci_table,
- .probe = &driver_contec_pci_probe,
- .remove = __devexit_p(&driver_contec_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
+ .driver_data = PIO1616L },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
-static int __init driver_contec_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_contec);
- if (retval < 0)
- return retval;
-
- driver_contec_pci_driver.name = (char *)driver_contec.driver_name;
- return pci_register_driver(&driver_contec_pci_driver);
-}
-
-static void __exit driver_contec_cleanup_module(void)
-{
- pci_unregister_driver(&driver_contec_pci_driver);
- comedi_driver_unregister(&driver_contec);
-}
-
-module_init(driver_contec_init_module);
-module_exit(driver_contec_cleanup_module);
+static struct pci_driver contec_pci_dio_pci_driver = {
+ .name = "contec_pci_dio",
+ .id_table = contec_pci_dio_pci_table,
+ .probe = contec_pci_dio_pci_probe,
+ .remove = __devexit_p(contec_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index e61c6a8..696b58c 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -301,17 +301,6 @@ struct daqboard2000_hw {
#define DAQBOARD2000_PosRefDacSelect 0x0100
#define DAQBOARD2000_NegRefDacSelect 0x0000
-static int daqboard2000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int daqboard2000_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_daqboard2000 = {
- .driver_name = "daqboard2000",
- .module = THIS_MODULE,
- .attach = daqboard2000_attach,
- .detach = daqboard2000_detach,
-};
-
struct daq200_boardtype {
const char *name;
int id;
@@ -321,16 +310,8 @@ static const struct daq200_boardtype boardtypes[] = {
{"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype))
#define this_board ((const struct daq200_boardtype *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
- { PCI_DEVICE(0x1616, 0x0409) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
-
struct daqboard2000_private {
enum {
card_daqboard_2000
@@ -412,9 +393,12 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev,
DAQBOARD2000_AcqResetScanListFifo |
DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
- /* If pacer clock is not set to some high value (> 10 us), we
- risk multiple samples to be put into the result FIFO. */
- fpga->acqPacerClockDivLow = 1000000; /* 1 second, should be long enough */
+ /*
+ * If pacer clock is not set to some high value (> 10 us), we
+ * risk multiple samples to be put into the result FIFO.
+ */
+ /* 1 second, should be long enough */
+ fpga->acqPacerClockDivLow = 1000000;
fpga->acqPacerClockDivHigh = 0;
gain = CR_RANGE(insn->chanspec);
@@ -761,7 +745,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
devpriv->pci_dev = card;
id = ((u32) card->
subsystem_device << 16) | card->subsystem_vendor;
- for (i = 0; i < n_boardtypes; i++) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
if (boardtypes[i].id == id) {
dev_dbg(dev->hw_dev, "%s\n",
boardtypes[i].name);
@@ -852,14 +836,12 @@ out:
return result;
}
-static int daqboard2000_detach(struct comedi_device *dev)
+static void daqboard2000_detach(struct comedi_device *dev)
{
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->daq)
iounmap(devpriv->daq);
@@ -871,48 +853,39 @@ static int daqboard2000_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
- return 0;
}
-static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver daqboard2000_driver = {
+ .driver_name = "daqboard2000",
+ .module = THIS_MODULE,
+ .attach = daqboard2000_attach,
+ .detach = daqboard2000_detach,
+};
+
+static int __devinit daqboard2000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name);
+ return comedi_pci_auto_config(dev, &daqboard2000_driver);
}
-static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev)
+static void __devexit daqboard2000_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_daqboard2000_pci_driver = {
- .id_table = daqboard2000_pci_table,
- .probe = &driver_daqboard2000_pci_probe,
- .remove = __devexit_p(&driver_daqboard2000_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
+ { PCI_DEVICE(0x1616, 0x0409) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
-static int __init driver_daqboard2000_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_daqboard2000);
- if (retval < 0)
- return retval;
-
- driver_daqboard2000_pci_driver.name =
- (char *)driver_daqboard2000.driver_name;
- return pci_register_driver(&driver_daqboard2000_pci_driver);
-}
-
-static void __exit driver_daqboard2000_cleanup_module(void)
-{
- pci_unregister_driver(&driver_daqboard2000_pci_driver);
- comedi_driver_unregister(&driver_daqboard2000);
-}
-
-module_init(driver_daqboard2000_init_module);
-module_exit(driver_daqboard2000_cleanup_module);
+static struct pci_driver daqboard2000_pci_driver = {
+ .name = "daqboard2000",
+ .id_table = daqboard2000_pci_table,
+ .probe = daqboard2000_pci_probe,
+ .remove = __devexit_p(daqboard2000_pci_remove),
+};
+module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index c2dd0ed..1f31943 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -61,6 +61,20 @@
#define DRV_NAME "das08"
+#ifdef CONFIG_COMEDI_DAS08_ISA_MODULE
+#define CONFIG_COMEDI_DAS08_ISA
+#endif
+#ifdef CONFIG_COMEDI_DAS08_PCI_MODULE
+#define CONFIG_COMEDI_DAS08_PCI
+#endif
+#ifdef CONFIG_COMEDI_DAS08_CS_MODULE
+#define CONFIG_COMEDI_DAS08_CS
+#endif
+
+#if defined(CONFIG_COMEDI_DAS08_ISA) || defined(CONFIG_COMEDI_DAS08_PCI)
+#define DO_COMEDI_DRIVER_REGISTER
+#endif
+
#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
#define PCI_DEVICE_ID_PCIDAS08 0x29
#define PCIDAS08_SIZE 0x54
@@ -160,6 +174,7 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_di_rbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -172,6 +187,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
static int das08ao_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
+#endif
static void i8254_set_mode_low(unsigned int base, int channel,
unsigned int mode);
@@ -253,7 +269,9 @@ static const int *const das08_gainlists[] = {
das08_pgm_gainlist,
};
+#ifdef DO_COMEDI_DRIVER_REGISTER
static const struct das08_board_struct das08_boards[] = {
+#ifdef CONFIG_COMEDI_DAS08_ISA
{
.name = "isa-das08", /* cio-das08.pdf */
.bustype = isa,
@@ -395,25 +413,6 @@ static const struct das08_board_struct das08_boards[] = {
.i8254_offset = 0x04,
.iosize = 16, /* unchecked */
},
-#ifdef CONFIG_COMEDI_PCI
- {
- .name = "das08", /* pci-das08 */
- .id = PCI_DEVICE_ID_PCIDAS08,
- .bustype = pci,
- .ai = das08_ai_rinsn,
- .ai_nbits = 12,
- .ai_pg = das08_bipolar5,
- .ai_encoding = das08_encode12,
- .ao = NULL,
- .ao_nbits = 0,
- .di = das08_di_rbits,
- .do_ = das08_do_wbits,
- .do_nchan = 4,
- .i8255_offset = 0,
- .i8254_offset = 4,
- .iosize = 8,
- },
-#endif
{
.name = "pc104-das08",
.bustype = pc104,
@@ -462,9 +461,30 @@ static const struct das08_board_struct das08_boards[] = {
.name = "das08-pga-g2", /* a KM board */
},
#endif
+#endif /* CONFIG_COMEDI_DAS08_ISA */
+#ifdef CONFIG_COMEDI_DAS08_PCI
+ {
+ .name = "das08", /* pci-das08 */
+ .id = PCI_DEVICE_ID_PCIDAS08,
+ .bustype = pci,
+ .ai = das08_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_pg = das08_bipolar5,
+ .ai_encoding = das08_encode12,
+ .ao = NULL,
+ .ao_nbits = 0,
+ .di = das08_di_rbits,
+ .do_ = das08_do_wbits,
+ .do_nchan = 4,
+ .i8255_offset = 0,
+ .i8254_offset = 4,
+ .iosize = 8,
+ },
+#endif /* CONFIG_COMEDI_DAS08_PCI */
};
+#endif /* DO_COMEDI_DRIVER_REGISTER */
-#ifdef CONFIG_COMEDI_PCMCIA
+#ifdef CONFIG_COMEDI_DAS08_CS
struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
{
.name = "pcm-das08",
@@ -504,7 +524,7 @@ struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
};
#endif
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
{0}
@@ -619,6 +639,7 @@ static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
return 2;
}
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_di_rbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -628,7 +649,9 @@ static int das08jr_di_rbits(struct comedi_device *dev,
return 2;
}
+#endif
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_do_wbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -643,7 +666,9 @@ static int das08jr_do_wbits(struct comedi_device *dev,
return 2;
}
+#endif
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -672,6 +697,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
return n;
}
+#endif
/*
*
@@ -679,6 +705,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
* a different method to force an update.
*
*/
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08ao_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -707,6 +734,7 @@ static int das08ao_ao_winsn(struct comedi_device *dev,
return n;
}
+#endif
static unsigned int i8254_read_channel_low(unsigned int base, int chan)
{
@@ -842,6 +870,7 @@ static int das08_counter_config(struct comedi_device *dev,
return 2;
}
+#ifdef DO_COMEDI_DRIVER_REGISTER
static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it);
static struct comedi_driver driver_das08 = {
@@ -853,6 +882,7 @@ static struct comedi_driver driver_das08 = {
.num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
.offset = sizeof(struct das08_board_struct),
};
+#endif
int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
{
@@ -972,11 +1002,12 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
}
EXPORT_SYMBOL_GPL(das08_common_attach);
+#ifdef DO_COMEDI_DRIVER_REGISTER
static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
unsigned long iobase;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
unsigned long pci_iobase = 0;
struct pci_dev *pdev = NULL;
#endif
@@ -986,9 +1017,9 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
printk(KERN_INFO "comedi%d: das08: ", dev->minor);
+#ifdef CONFIG_COMEDI_DAS08_PCI
/* deal with a pci board */
if (thisboard->bustype == pci) {
-#ifdef CONFIG_COMEDI_PCI
if (it->options[0] || it->options[1]) {
printk("bus %i slot %i ",
it->options[0], it->options[1]);
@@ -1037,32 +1068,26 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Enable local interrupt 1 and pci interrupt */
outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
#endif
-#else /* CONFIG_COMEDI_PCI */
- printk(KERN_ERR "this driver has not been built with PCI support.\n");
- return -EINVAL;
-#endif /* CONFIG_COMEDI_PCI */
- } else {
+ } else
+#endif /* CONFIG_COMEDI_DAS08_PCI */
+ {
iobase = it->options[0];
}
printk(KERN_INFO "\n");
return das08_common_attach(dev, iobase);
}
+#endif /* DO_COMEDI_DRIVER_REGISTER */
-
-int das08_common_detach(struct comedi_device *dev)
+void das08_common_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
- /* deallocate ioports for non-pcmcia, non-pci boards */
if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) {
if (dev->iobase)
release_region(dev->iobase, thisboard->iosize);
}
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
if (devpriv) {
if (devpriv->pdev) {
if (devpriv->pci_iobase)
@@ -1072,16 +1097,14 @@ int das08_common_detach(struct comedi_device *dev)
}
}
#endif
-
- return 0;
}
EXPORT_SYMBOL_GPL(das08_common_detach);
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
static int __devinit driver_das08_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_das08.driver_name);
+ return comedi_pci_auto_config(dev, &driver_das08);
}
static void __devexit driver_das08_pci_remove(struct pci_dev *dev)
@@ -1094,43 +1117,38 @@ static struct pci_driver driver_das08_pci_driver = {
.probe = &driver_das08_pci_probe,
.remove = __devexit_p(&driver_das08_pci_remove)
};
+#endif /* CONFIG_COMEDI_DAS08_PCI */
static int __init driver_das08_init_module(void)
{
- int retval;
+ int retval = 0;
+#ifdef DO_COMEDI_DRIVER_REGISTER
retval = comedi_driver_register(&driver_das08);
if (retval < 0)
return retval;
-
+#endif
+#ifdef CONFIG_COMEDI_DAS08_PCI
driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
- return pci_register_driver(&driver_das08_pci_driver);
+ retval = pci_register_driver(&driver_das08_pci_driver);
+#endif
+ return retval;
}
static void __exit driver_das08_cleanup_module(void)
{
+#ifdef CONFIG_COMEDI_DAS08_PCI
pci_unregister_driver(&driver_das08_pci_driver);
+#endif
+#ifdef DO_COMEDI_DRIVER_REGISTER
comedi_driver_unregister(&driver_das08);
+#endif
}
module_init(driver_das08_init_module);
module_exit(driver_das08_cleanup_module);
-#else
-static int __init driver_das08_init_module(void)
-{
- return comedi_driver_register(&driver_das08);
-}
-
-static void __exit driver_das08_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das08);
-}
-
-module_init(driver_das08_init_module);
-module_exit(driver_das08_cleanup_module);
-#endif
-#ifdef CONFIG_COMEDI_PCMCIA
+#ifdef CONFIG_COMEDI_DAS08_CS
EXPORT_SYMBOL_GPL(das08_cs_boards);
#endif
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 2a30d76..0b92f24 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -74,6 +74,6 @@ struct das08_private_struct {
extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS];
int das08_common_attach(struct comedi_device *dev, unsigned long iobase);
-int das08_common_detach(struct comedi_device *dev);
+void das08_common_detach(struct comedi_device *dev);
#endif /* _DAS08_H */
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index e7905ba..998444c 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -339,38 +339,6 @@ struct munge_info {
unsigned have_byte:1;
};
-static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int das16_cmd_exec(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static void das16_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *array,
- unsigned int num_bytes,
- unsigned int start_chan_index);
-
-static void das16_reset(struct comedi_device *dev);
-static irqreturn_t das16_dma_interrupt(int irq, void *d);
-static void das16_timer_interrupt(unsigned long arg);
-static void das16_interrupt(struct comedi_device *dev);
-
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
- int flags);
-static int das1600_mode_detect(struct comedi_device *dev);
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- struct comedi_cmd cmd);
-
-static void reg_dump(struct comedi_device *dev);
-
struct das16_board {
const char *name;
void *ai;
@@ -389,344 +357,6 @@ struct das16_board {
unsigned int id;
};
-static const struct das16_board das16_boards[] = {
- {
- .name = "das-16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "das-16g",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "das-16f",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 8500,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "cio-das16", /* cio-das16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- },
- {
- .name = "cio-das16/f", /* das16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- },
- {
- .name = "cio-das16/jr", /* cio-das16jr.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 7692,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "pc104-das16jr", /* pc104-das16jr_xx.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3300,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "cio-das16jr/16", /* cio-das16jr_16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "pc104-das16jr/16", /* pc104-das16jr_xx.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "das-1201", /* 4924.pdf (keithley user's manual) */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- },
- {
- .name = "das-1202", /* 4924.pdf (keithley user's manual) */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- },
- {
- /* 4919.pdf and 4922.pdf (keithley user's manual) */
- .name = "das-1401",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
- },
- {
- /* 4919.pdf and 4922.pdf (keithley user's manual) */
- .name = "das-1402",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
- },
- {
- .name = "das-1601", /* 4919.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "das-1602", /* 4919.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1401/12", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1402/12", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1402/16", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1601/12", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1602/12", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1602/16", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das16/330", /* ? */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3030,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0xf0},
-#if 0
- {
- .name = "das16/330i", /* ? */
- },
- {
- .name = "das16/jr/ctr5", /* ? */
- },
- {
- /* cio-das16_m1_16.pdf, this board is a bit quirky, no dma */
- .name = "cio-das16/m1/16",
- },
-#endif
-};
-
-static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int das16_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16 = {
- .driver_name = "das16",
- .module = THIS_MODULE,
- .attach = das16_attach,
- .detach = das16_detach,
- .board_name = &das16_boards[0].name,
- .num_names = ARRAY_SIZE(das16_boards),
- .offset = sizeof(das16_boards[0]),
-};
-
#define DAS16_TIMEOUT 1000
/* Period for timer interrupt in jiffies. It's a function
@@ -926,6 +556,62 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
+ struct comedi_cmd cmd)
+{
+ unsigned int size;
+ unsigned int freq;
+
+ /* if we are using timer interrupt, we don't care how long it
+ * will take to complete transfer since it will be interrupted
+ * by timer interrupt */
+ if (devpriv->timer_mode)
+ return DAS16_DMA_SIZE;
+
+ /* otherwise, we are relying on dma terminal count interrupt,
+ * so pick a reasonable size */
+ if (cmd.convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd.convert_arg;
+ else if (cmd.scan_begin_src == TRIG_TIMER)
+ freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
+ /* return some default value */
+ else
+ freq = 0xffffffff;
+
+ if (cmd.flags & TRIG_WAKE_EOS) {
+ size = sample_size * cmd.chanlist_len;
+ } else {
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+ }
+
+ /* set a minimum and maximum size allowed */
+ if (size > DAS16_DMA_SIZE)
+ size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
+ size = devpriv->adc_byte_count;
+
+ return size;
+}
+
+static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
+ int rounding_flags)
+{
+ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
+ &(devpriv->divisor2), &ns,
+ rounding_flags & TRIG_ROUND_MASK);
+
+ /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+ i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
+ i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+
+ return ns;
+}
+
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
@@ -1170,34 +856,6 @@ static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
-static irqreturn_t das16_dma_interrupt(int irq, void *d)
-{
- int status;
- struct comedi_device *dev = d;
-
- status = inb(dev->iobase + DAS16_STATUS);
-
- if ((status & DAS16_INT) == 0) {
- DEBUG_PRINT("spurious interrupt\n");
- return IRQ_NONE;
- }
-
- /* clear interrupt */
- outb(0x00, dev->iobase + DAS16_STATUS);
- das16_interrupt(dev);
- return IRQ_HANDLED;
-}
-
-static void das16_timer_interrupt(unsigned long arg)
-{
- struct comedi_device *dev = (struct comedi_device *)arg;
-
- das16_interrupt(dev);
-
- if (devpriv->timer_running)
- mod_timer(&devpriv->timer, jiffies + timer_period());
-}
-
/* the pc104-das16jr (at least) has problems if the dma
transfer is interrupted in the middle of transferring
a 16 bit sample, so this function takes care to get
@@ -1309,18 +967,32 @@ static void das16_interrupt(struct comedi_device *dev)
cfc_handle_events(dev, s);
}
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
- int rounding_flags)
+static irqreturn_t das16_dma_interrupt(int irq, void *d)
{
- i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
- &(devpriv->divisor2), &ns,
- rounding_flags & TRIG_ROUND_MASK);
+ int status;
+ struct comedi_device *dev = d;
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+ status = inb(dev->iobase + DAS16_STATUS);
- return ns;
+ if ((status & DAS16_INT) == 0) {
+ DEBUG_PRINT("spurious interrupt\n");
+ return IRQ_NONE;
+ }
+
+ /* clear interrupt */
+ outb(0x00, dev->iobase + DAS16_STATUS);
+ das16_interrupt(dev);
+ return IRQ_HANDLED;
+}
+
+static void das16_timer_interrupt(unsigned long arg)
+{
+ struct comedi_device *dev = (struct comedi_device *)arg;
+
+ das16_interrupt(dev);
+
+ if (devpriv->timer_running)
+ mod_timer(&devpriv->timer, jiffies + timer_period());
}
static void reg_dump(struct comedi_device *dev)
@@ -1394,6 +1066,22 @@ static int das1600_mode_detect(struct comedi_device *dev)
return 0;
}
+static void das16_ai_munge(struct comedi_device *dev,
+ struct comedi_subdevice *s, void *array,
+ unsigned int num_bytes,
+ unsigned int start_chan_index)
+{
+ unsigned int i, num_samples = num_bytes / sizeof(short);
+ short *data = array;
+
+ for (i = 0; i < num_samples; i++) {
+ data[i] = le16_to_cpu(data[i]);
+ if (thisboard->ai_nbits == 12)
+ data[i] = (data[i] >> 4) & 0xfff;
+
+ }
+}
+
/*
*
* Options list:
@@ -1402,7 +1090,6 @@ static int das1600_mode_detect(struct comedi_device *dev)
* 2 DMA
* 3 Clock speed (in MHz)
*/
-
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -1675,15 +1362,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int das16_detach(struct comedi_device *dev)
+static void das16_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: das16: remove\n", dev->minor);
-
das16_reset(dev);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
if (devpriv) {
int i;
for (i = 0; i < 2; i++) {
@@ -1698,10 +1381,8 @@ static int das16_detach(struct comedi_device *dev)
kfree(devpriv->user_ai_range_table);
kfree(devpriv->user_ao_range_table);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase) {
if (thisboard->size < 0x400) {
release_region(dev->iobase, thisboard->size);
@@ -1711,80 +1392,318 @@ static int das16_detach(struct comedi_device *dev)
thisboard->size & 0x3ff);
}
}
-
- return 0;
}
-static int __init driver_das16_init_module(void)
-{
- return comedi_driver_register(&driver_das16);
-}
-
-static void __exit driver_das16_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das16);
-}
-
-module_init(driver_das16_init_module);
-module_exit(driver_das16_cleanup_module);
-
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- struct comedi_cmd cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- /* if we are using timer interrupt, we don't care how long it
- * will take to complete transfer since it will be interrupted
- * by timer interrupt */
- if (devpriv->timer_mode)
- return DAS16_DMA_SIZE;
-
- /* otherwise, we are relying on dma terminal count interrupt,
- * so pick a reasonable size */
- if (cmd.convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd.convert_arg;
- else if (cmd.scan_begin_src == TRIG_TIMER)
- freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- if (cmd.flags & TRIG_WAKE_EOS) {
- size = sample_size * cmd.chanlist_len;
- } else {
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
- }
-
- /* set a minimum and maximum size allowed */
- if (size > DAS16_DMA_SIZE)
- size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
- size = devpriv->adc_byte_count;
-
- return size;
-}
-
-static void das16_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *array,
- unsigned int num_bytes,
- unsigned int start_chan_index)
-{
- unsigned int i, num_samples = num_bytes / sizeof(short);
- short *data = array;
-
- for (i = 0; i < num_samples; i++) {
- data[i] = le16_to_cpu(data[i]);
- if (thisboard->ai_nbits == 12)
- data[i] = (data[i] >> 4) & 0xfff;
+static const struct das16_board das16_boards[] = {
+ {
+ .name = "das-16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16g",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16f",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 8500,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/f",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/jr",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 7692,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 3300,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16jr/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "das-1201",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1202",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1401",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1402",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1601",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1602",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1401/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1601/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das16/330",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 3030,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0xf0,
+ },
+};
- }
-}
+static struct comedi_driver das16_driver = {
+ .driver_name = "das16",
+ .module = THIS_MODULE,
+ .attach = das16_attach,
+ .detach = das16_detach,
+ .board_name = &das16_boards[0].name,
+ .num_names = ARRAY_SIZE(das16_boards),
+ .offset = sizeof(das16_boards[0]),
+};
+module_comedi_driver(das16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 5376e71..d2e1490 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -132,57 +132,11 @@ static const struct comedi_lrange range_das16m1 = { 9,
}
};
-static int das16m1_do_wbits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16m1_di_rbits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16m1_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int das16m1_cmd_test(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int das16m1_cmd_exec(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int das16m1_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t das16m1_interrupt(int irq, void *d);
-static void das16m1_handler(struct comedi_device *dev, unsigned int status);
-
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
- unsigned int ns, int round_flag);
-
-static int das16m1_irq_bits(unsigned int irq);
-
struct das16m1_board {
const char *name;
unsigned int ai_speed;
};
-static const struct das16m1_board das16m1_boards[] = {
- {
- .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */
- .ai_speed = 1000, /* 1MHz max speed */
- },
-};
-
-static int das16m1_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das16m1_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16m1 = {
- .driver_name = "das16m1",
- .module = THIS_MODULE,
- .attach = das16m1_attach,
- .detach = das16m1_detach,
- .board_name = &das16m1_boards[0].name,
- .num_names = ARRAY_SIZE(das16m1_boards),
- .offset = sizeof(das16m1_boards[0]),
-};
-
struct das16m1_private_struct {
unsigned int control_state;
volatile unsigned int adc_count; /* number of samples completed */
@@ -198,22 +152,17 @@ struct das16m1_private_struct {
#define devpriv ((struct das16m1_private_struct *)(dev->private))
#define thisboard ((const struct das16m1_board *)(dev->board_ptr))
-static int __init driver_das16m1_init_module(void)
+static inline short munge_sample(short data)
{
- return comedi_driver_register(&driver_das16m1);
+ return (data >> 4) & 0xfff;
}
-static void __exit driver_das16m1_cleanup_module(void)
+static void munge_sample_array(short *array, unsigned int num_elements)
{
- comedi_driver_unregister(&driver_das16m1);
-}
-
-module_init(driver_das16m1_init_module);
-module_exit(driver_das16m1_cleanup_module);
+ unsigned int i;
-static inline short munge_sample(short data)
-{
- return (data >> 4) & 0xfff;
+ for (i = 0; i < num_elements; i++)
+ array[i] = munge_sample(array[i]);
}
static int das16m1_cmd_test(struct comedi_device *dev,
@@ -340,6 +289,25 @@ static int das16m1_cmd_test(struct comedi_device *dev,
return 0;
}
+/* This function takes a time in nanoseconds and sets the *
+ * 2 pacer clocks to the closest frequency possible. It also *
+ * returns the actual sampling period. */
+static unsigned int das16m1_set_pacer(struct comedi_device *dev,
+ unsigned int ns, int rounding_flags)
+{
+ i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
+ &(devpriv->divisor2), &ns,
+ rounding_flags & TRIG_ROUND_MASK);
+
+ /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
+ 2);
+ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
+ 2);
+
+ return ns;
+}
+
static int das16m1_cmd_exec(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -484,57 +452,6 @@ static int das16m1_do_wbits(struct comedi_device *dev,
return 2;
}
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- unsigned long flags;
- unsigned int status;
-
- /* prevent race with interrupt handler */
- spin_lock_irqsave(&dev->spinlock, flags);
- status = inb(dev->iobase + DAS16M1_CS);
- das16m1_handler(dev, status);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- return s->async->buf_write_count - s->async->buf_read_count;
-}
-
-static irqreturn_t das16m1_interrupt(int irq, void *d)
-{
- int status;
- struct comedi_device *dev = d;
-
- if (dev->attached == 0) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
- /* prevent race with comedi_poll() */
- spin_lock(&dev->spinlock);
-
- status = inb(dev->iobase + DAS16M1_CS);
-
- if ((status & (IRQDATA | OVRUN)) == 0) {
- comedi_error(dev, "spurious interrupt");
- spin_unlock(&dev->spinlock);
- return IRQ_NONE;
- }
-
- das16m1_handler(dev, status);
-
- /* clear interrupt */
- outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
-
- spin_unlock(&dev->spinlock);
- return IRQ_HANDLED;
-}
-
-static void munge_sample_array(short *array, unsigned int num_elements)
-{
- unsigned int i;
-
- for (i = 0; i < num_elements; i++)
- array[i] = munge_sample(array[i]);
-}
-
static void das16m1_handler(struct comedi_device *dev, unsigned int status)
{
struct comedi_subdevice *s;
@@ -596,23 +513,47 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
}
-/* This function takes a time in nanoseconds and sets the *
- * 2 pacer clocks to the closest frequency possible. It also *
- * returns the actual sampling period. */
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
- unsigned int ns, int rounding_flags)
+static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
- i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
- &(devpriv->divisor2), &ns,
- rounding_flags & TRIG_ROUND_MASK);
+ unsigned long flags;
+ unsigned int status;
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
- 2);
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
- 2);
+ /* prevent race with interrupt handler */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ status = inb(dev->iobase + DAS16M1_CS);
+ das16m1_handler(dev, status);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- return ns;
+ return s->async->buf_write_count - s->async->buf_read_count;
+}
+
+static irqreturn_t das16m1_interrupt(int irq, void *d)
+{
+ int status;
+ struct comedi_device *dev = d;
+
+ if (dev->attached == 0) {
+ comedi_error(dev, "premature interrupt");
+ return IRQ_HANDLED;
+ }
+ /* prevent race with comedi_poll() */
+ spin_lock(&dev->spinlock);
+
+ status = inb(dev->iobase + DAS16M1_CS);
+
+ if ((status & (IRQDATA | OVRUN)) == 0) {
+ comedi_error(dev, "spurious interrupt");
+ spin_unlock(&dev->spinlock);
+ return IRQ_NONE;
+ }
+
+ das16m1_handler(dev, status);
+
+ /* clear interrupt */
+ outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
+
+ spin_unlock(&dev->spinlock);
+ return IRQ_HANDLED;
}
static int das16m1_irq_bits(unsigned int irq)
@@ -656,7 +597,6 @@ static int das16m1_irq_bits(unsigned int irq)
* 0 I/O base
* 1 IRQ
*/
-
static int das16m1_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -673,12 +613,12 @@ static int das16m1_attach(struct comedi_device *dev,
dev->board_name = thisboard->name;
- if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) {
+ if (!request_region(iobase, DAS16M1_SIZE, dev->driver->driver_name)) {
comedi_error(dev, "I/O port conflict\n");
return -EIO;
}
if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2,
- driver_das16m1.driver_name)) {
+ dev->driver->driver_name)) {
release_region(iobase, DAS16M1_SIZE);
comedi_error(dev, "I/O port conflict\n");
return -EIO;
@@ -690,7 +630,7 @@ static int das16m1_attach(struct comedi_device *dev,
/* make sure it is valid */
if (das16m1_irq_bits(irq) >= 0) {
ret = request_irq(irq, das16m1_interrupt, 0,
- driver_das16m1.driver_name, dev);
+ dev->driver->driver_name, dev);
if (ret < 0)
return ret;
dev->irq = irq;
@@ -763,25 +703,36 @@ static int das16m1_attach(struct comedi_device *dev,
return 0;
}
-static int das16m1_detach(struct comedi_device *dev)
+static void das16m1_detach(struct comedi_device *dev)
{
-
-/* das16m1_reset(dev); */
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase) {
release_region(dev->iobase, DAS16M1_SIZE);
release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2);
}
-
- return 0;
}
+static const struct das16m1_board das16m1_boards[] = {
+ {
+ .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */
+ .ai_speed = 1000, /* 1MHz max speed */
+ },
+};
+
+static struct comedi_driver das16m1_driver = {
+ .driver_name = "das16m1",
+ .module = THIS_MODULE,
+ .attach = das16m1_attach,
+ .detach = das16m1_detach,
+ .board_name = &das16m1_boards[0].name,
+ .num_names = ARRAY_SIZE(das16m1_boards),
+ .offset = sizeof(das16m1_boards[0]),
+};
+module_comedi_driver(das16m1_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 99ada5a..2ac3443 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -183,9 +183,6 @@ enum {
das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao
};
-static int das1800_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das1800_detach(struct comedi_device *dev);
static int das1800_probe(struct comedi_device *dev);
static int das1800_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
@@ -518,33 +515,6 @@ static const struct comedi_lrange range_ao_2 = {
};
*/
-static struct comedi_driver driver_das1800 = {
- .driver_name = "das1800",
- .module = THIS_MODULE,
- .attach = das1800_attach,
- .detach = das1800_detach,
- .num_names = ARRAY_SIZE(das1800_boards),
- .board_name = &das1800_boards[0].name,
- .offset = sizeof(struct das1800_board),
-};
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_das1800_init_module(void)
-{
- return comedi_driver_register(&driver_das1800);
-}
-
-static void __exit driver_das1800_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das1800);
-}
-
-module_init(driver_das1800_init_module);
-module_exit(driver_das1800_cleanup_module);
-
static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
unsigned int dma1)
{
@@ -579,7 +549,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
return -EINVAL;
break;
}
- if (request_dma(dma0, driver_das1800.driver_name)) {
+ if (request_dma(dma0, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
dma0);
return -EINVAL;
@@ -587,7 +557,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
devpriv->dma0 = dma0;
devpriv->dma_current = dma0;
if (dma1) {
- if (request_dma(dma1, driver_das1800.driver_name)) {
+ if (request_dma(dma1, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
dma1);
return -EINVAL;
@@ -633,7 +603,7 @@ static int das1800_attach(struct comedi_device *dev,
return -ENOMEM;
printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
- driver_das1800.driver_name, iobase);
+ dev->driver->driver_name, iobase);
if (irq) {
printk(KERN_CONT ", irq %u", irq);
if (dma0) {
@@ -650,7 +620,7 @@ static int das1800_attach(struct comedi_device *dev,
}
/* check if io addresses are available */
- if (!request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name)) {
+ if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
printk
(" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
iobase, iobase + DAS1800_SIZE - 1);
@@ -671,7 +641,7 @@ static int das1800_attach(struct comedi_device *dev,
if (thisboard->ao_ability == 2) {
iobase2 = iobase + IOBASE2;
if (!request_region(iobase2, DAS1800_SIZE,
- driver_das1800.driver_name)) {
+ dev->driver->driver_name)) {
printk
(" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
iobase2, iobase2 + DAS1800_SIZE - 1);
@@ -683,7 +653,7 @@ static int das1800_attach(struct comedi_device *dev,
/* grab our IRQ */
if (irq) {
if (request_irq(irq, das1800_interrupt, 0,
- driver_das1800.driver_name, dev)) {
+ dev->driver->driver_name, dev)) {
dev_dbg(dev->hw_dev, "unable to allocate irq %u\n",
irq);
return -EINVAL;
@@ -797,9 +767,8 @@ static int das1800_attach(struct comedi_device *dev,
return 0;
};
-static int das1800_detach(struct comedi_device *dev)
+static void das1800_detach(struct comedi_device *dev)
{
- /* only free stuff if it has been allocated by _attach */
if (dev->iobase)
release_region(dev->iobase, DAS1800_SIZE);
if (dev->irq)
@@ -814,11 +783,6 @@ static int das1800_detach(struct comedi_device *dev)
kfree(devpriv->ai_buf0);
kfree(devpriv->ai_buf1);
}
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
- driver_das1800.driver_name);
-
- return 0;
};
/* probes and checks das-1800 series board type
@@ -1811,6 +1775,17 @@ static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
return size;
}
+static struct comedi_driver das1800_driver = {
+ .driver_name = "das1800",
+ .module = THIS_MODULE,
+ .attach = das1800_attach,
+ .detach = das1800_detach,
+ .num_names = ARRAY_SIZE(das1800_boards),
+ .board_name = &das1800_boards[0].name,
+ .offset = sizeof(struct das1800_board),
+};
+module_comedi_driver(das1800_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index f2568414..881f392 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -99,29 +99,6 @@ This driver has suffered bitrot.
#define C2 0x80
#define RWLH 0x30
-static int das6402_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das6402_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das6402 = {
- .driver_name = "das6402",
- .module = THIS_MODULE,
- .attach = das6402_attach,
- .detach = das6402_detach,
-};
-
-static int __init driver_das6402_init_module(void)
-{
- return comedi_driver_register(&driver_das6402);
-}
-
-static void __exit driver_das6402_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das6402);
-}
-
-module_init(driver_das6402_init_module);
-module_exit(driver_das6402_cleanup_module);
-
struct das6402_private {
int ai_bytes_to_read;
@@ -130,7 +107,14 @@ struct das6402_private {
#define devpriv ((struct das6402_private *)dev->private)
static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s);
+ struct comedi_subdevice *s)
+{
+ while (1) {
+ if (!(inb(dev->iobase + 8) & 0x01))
+ return;
+ comedi_buf_put(s->async, inw(dev->iobase));
+ }
+}
static void das6402_setcounter(struct comedi_device *dev)
{
@@ -209,16 +193,6 @@ static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
}
#endif
-static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- while (1) {
- if (!(inb(dev->iobase + 8) & 0x01))
- return;
- comedi_buf_put(s->async, inw(dev->iobase));
- }
-}
-
static int das6402_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -300,16 +274,6 @@ static int board_init(struct comedi_device *dev)
return 0;
}
-static int das6402_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DAS6402_SIZE);
-
- return 0;
-}
-
static int das6402_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -363,6 +327,22 @@ static int das6402_attach(struct comedi_device *dev,
return 0;
}
+static void das6402_detach(struct comedi_device *dev)
+{
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, DAS6402_SIZE);
+}
+
+static struct comedi_driver das6402_driver = {
+ .driver_name = "das6402",
+ .module = THIS_MODULE,
+ .attach = das6402_attach,
+ .detach = das6402_detach,
+};
+module_comedi_driver(das6402_driver)
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 6e347b4..a3a54e1 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -245,7 +245,7 @@ struct das800_private {
static int das800_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int das800_detach(struct comedi_device *dev);
+static void das800_detach(struct comedi_device *dev);
static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
static struct comedi_driver driver_das800 = {
@@ -556,16 +556,12 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int das800_detach(struct comedi_device *dev)
+static void das800_detach(struct comedi_device *dev)
{
- dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor);
-
- /* only free stuff if it has been allocated by _attach */
if (dev->iobase)
release_region(dev->iobase, DAS800_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
- return 0;
};
static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 2b4e6e6..8382890 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -224,7 +224,7 @@ struct dmm32at_private {
*/
static int dmm32at_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dmm32at_detach(struct comedi_device *dev);
+static void dmm32at_detach(struct comedi_device *dev);
static struct comedi_driver driver_dmm32at = {
.driver_name = "dmm32at",
.module = THIS_MODULE,
@@ -450,23 +450,12 @@ static int dmm32at_attach(struct comedi_device *dev,
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dmm32at_detach(struct comedi_device *dev)
+static void dmm32at_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor);
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->iobase)
release_region(dev->iobase, DMM32AT_MEMSIZE);
-
- return 0;
}
/*
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index b85c836..625bd61 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -88,29 +88,6 @@ Configuration options:
#define DT2801_STATUS 1
#define DT2801_CMD 1
-static int dt2801_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2801_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2801 = {
- .driver_name = "dt2801",
- .module = THIS_MODULE,
- .attach = dt2801_attach,
- .detach = dt2801_detach,
-};
-
-static int __init driver_dt2801_init_module(void)
-{
- return comedi_driver_register(&driver_dt2801);
-}
-
-static void __exit driver_dt2801_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2801);
-}
-
-module_init(driver_dt2801_init_module);
-module_exit(driver_dt2801_cleanup_module);
-
#if 0
/* ignore 'defined but not used' warning */
static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
@@ -258,22 +235,6 @@ struct dt2801_private {
#define devpriv ((struct dt2801_private *)dev->private)
-static int dt2801_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/* These are the low-level routines:
writecommand: write a command to the board
writedata: write data byte
@@ -503,6 +464,123 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt)
return &range_unknown;
}
+static int dt2801_error(struct comedi_device *dev, int stat)
+{
+ if (stat < 0) {
+ if (stat == -ETIME)
+ printk("dt2801: timeout\n");
+ else
+ printk("dt2801: error %d\n", stat);
+ return stat;
+ }
+ printk("dt2801: error status 0x%02x, resetting...\n", stat);
+
+ dt2801_reset(dev);
+ dt2801_reset(dev);
+
+ return -EIO;
+}
+
+static int dt2801_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int d;
+ int stat;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
+ dt2801_writedata(dev, CR_RANGE(insn->chanspec));
+ dt2801_writedata(dev, CR_CHAN(insn->chanspec));
+ stat = dt2801_readdata2(dev, &d);
+
+ if (stat != 0)
+ return dt2801_error(dev, stat);
+
+ data[i] = d;
+ }
+
+ return i;
+}
+
+static int dt2801_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
+
+ return 1;
+}
+
+static int dt2801_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ dt2801_writecmd(dev, DT_C_WRITE_DAIM);
+ dt2801_writedata(dev, CR_CHAN(insn->chanspec));
+ dt2801_writedata2(dev, data[0]);
+
+ devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
+
+ return 1;
+}
+
+static int dt2801_dio_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int which = 0;
+
+ if (s == dev->subdevices + 4)
+ which = 1;
+
+ if (insn->n != 2)
+ return -EINVAL;
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+ dt2801_writecmd(dev, DT_C_WRITE_DIG);
+ dt2801_writedata(dev, which);
+ dt2801_writedata(dev, s->state);
+ }
+ dt2801_writecmd(dev, DT_C_READ_DIG);
+ dt2801_writedata(dev, which);
+ dt2801_readdata(dev, data + 1);
+
+ return 2;
+}
+
+static int dt2801_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int which = 0;
+
+ if (s == dev->subdevices + 4)
+ which = 1;
+
+ /* configure */
+ switch (data[0]) {
+ case INSN_CONFIG_DIO_OUTPUT:
+ s->io_bits = 0xff;
+ dt2801_writecmd(dev, DT_C_SET_DIGOUT);
+ break;
+ case INSN_CONFIG_DIO_INPUT:
+ s->io_bits = 0;
+ dt2801_writecmd(dev, DT_C_SET_DIGIN);
+ break;
+ case INSN_CONFIG_DIO_QUERY:
+ data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
+ return insn->n;
+ default:
+ return -EINVAL;
+ }
+ dt2801_writedata(dev, which);
+
+ return 1;
+}
+
/*
options:
[0] - i/o base
@@ -615,130 +693,19 @@ out:
return ret;
}
-static int dt2801_detach(struct comedi_device *dev)
+static void dt2801_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, DT2801_IOSIZE);
-
- return 0;
-}
-
-static int dt2801_error(struct comedi_device *dev, int stat)
-{
- if (stat < 0) {
- if (stat == -ETIME)
- printk("dt2801: timeout\n");
- else
- printk("dt2801: error %d\n", stat);
- return stat;
- }
- printk("dt2801: error status 0x%02x, resetting...\n", stat);
-
- dt2801_reset(dev);
- dt2801_reset(dev);
-
- return -EIO;
-}
-
-static int dt2801_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int d;
- int stat;
- int i;
-
- for (i = 0; i < insn->n; i++) {
- stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
- dt2801_writedata(dev, CR_RANGE(insn->chanspec));
- dt2801_writedata(dev, CR_CHAN(insn->chanspec));
- stat = dt2801_readdata2(dev, &d);
-
- if (stat != 0)
- return dt2801_error(dev, stat);
-
- data[i] = d;
- }
-
- return i;
-}
-
-static int dt2801_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int dt2801_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- dt2801_writecmd(dev, DT_C_WRITE_DAIM);
- dt2801_writedata(dev, CR_CHAN(insn->chanspec));
- dt2801_writedata2(dev, data[0]);
-
- devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
-
- return 1;
-}
-
-static int dt2801_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int which = 0;
-
- if (s == dev->subdevices + 4)
- which = 1;
-
- if (insn->n != 2)
- return -EINVAL;
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
- dt2801_writecmd(dev, DT_C_WRITE_DIG);
- dt2801_writedata(dev, which);
- dt2801_writedata(dev, s->state);
- }
- dt2801_writecmd(dev, DT_C_READ_DIG);
- dt2801_writedata(dev, which);
- dt2801_readdata(dev, data + 1);
-
- return 2;
}
-static int dt2801_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int which = 0;
-
- if (s == dev->subdevices + 4)
- which = 1;
-
- /* configure */
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits = 0xff;
- dt2801_writecmd(dev, DT_C_SET_DIGOUT);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits = 0;
- dt2801_writecmd(dev, DT_C_SET_DIGIN);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
- dt2801_writedata(dev, which);
-
- return 1;
-}
+static struct comedi_driver dt2801_driver = {
+ .driver_name = "dt2801",
+ .module = THIS_MODULE,
+ .attach = dt2801_attach,
+ .detach = dt2801_detach,
+};
+module_comedi_driver(dt2801_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 0131d52..106ffea 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -211,61 +211,8 @@ struct dt2811_board {
const struct comedi_lrange *unip_5;
};
-static const struct dt2811_board boardtypes[] = {
- {"dt2811-pgh",
- &range_dt2811_pgh_ai_5_bipolar,
- &range_dt2811_pgh_ai_2_5_bipolar,
- &range_dt2811_pgh_ai_5_unipolar,
- },
- {"dt2811-pgl",
- &range_dt2811_pgl_ai_5_bipolar,
- &range_dt2811_pgl_ai_2_5_bipolar,
- &range_dt2811_pgl_ai_5_unipolar,
- },
-};
-
#define this_board ((const struct dt2811_board *)dev->board_ptr)
-static int dt2811_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2811_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2811 = {
- .driver_name = "dt2811",
- .module = THIS_MODULE,
- .attach = dt2811_attach,
- .detach = dt2811_detach,
- .board_name = &boardtypes[0].name,
- .num_names = ARRAY_SIZE(boardtypes),
- .offset = sizeof(struct dt2811_board),
-};
-
-static int __init driver_dt2811_init_module(void)
-{
- return comedi_driver_register(&driver_dt2811);
-}
-
-static void __exit driver_dt2811_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2811);
-}
-
-module_init(driver_dt2811_init_module);
-module_exit(driver_dt2811_cleanup_module);
-
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
enum { card_2811_pgh, card_2811_pgl };
struct dt2811_private {
@@ -317,6 +264,120 @@ static irqreturn_t dt2811_interrupt(int irq, void *d)
}
#endif
+static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int chan = CR_CHAN(insn->chanspec);
+ int timeout = DT2811_TIMEOUT;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ outb(chan, dev->iobase + DT2811_ADGCR);
+
+ while (timeout
+ && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
+ timeout--;
+ if (!timeout)
+ return -ETIME;
+
+ data[i] = inb(dev->iobase + DT2811_ADDATLO);
+ data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
+ data[i] &= 0xfff;
+ }
+
+ return i;
+}
+
+#if 0
+/* Wow. This is code from the Comedi stone age. But it hasn't been
+ * replaced, so I'll let it stay. */
+int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
+{
+ struct comedi_device *dev = comedi_devices + minor;
+
+ if (adtrig->n < 1)
+ return 0;
+ dev->curadchan = adtrig->chan;
+ switch (dev->i_admode) {
+ case COMEDI_MDEMAND:
+ dev->ntrig = adtrig->n - 1;
+ /* not necessary */
+ /*printk("dt2811: AD soft trigger\n"); */
+ /*outb(DT2811_CLRERROR|DT2811_INTENB,
+ dev->iobase+DT2811_ADCSR); */
+ outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
+ do_gettimeofday(&trigtime);
+ break;
+ case COMEDI_MCONTS:
+ dev->ntrig = adtrig->n;
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int i;
+ int chan;
+
+ chan = CR_CHAN(insn->chanspec);
+
+ for (i = 0; i < insn->n; i++) {
+ outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
+ outb((data[i] >> 8) & 0xff,
+ dev->iobase + DT2811_DADAT0HI + 2 * chan);
+ devpriv->ao_readback[chan] = data[i];
+ }
+
+ return i;
+}
+
+static int dt2811_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int i;
+ int chan;
+
+ chan = CR_CHAN(insn->chanspec);
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return i;
+}
+
+static int dt2811_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ data[1] = inb(dev->iobase + DT2811_DIO);
+
+ return 2;
+}
+
+static int dt2811_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ outb(s->state, dev->iobase + DT2811_DIO);
+
+ data[1] = s->state;
+
+ return 2;
+}
+
/*
options[0] Board base address
options[1] IRQ
@@ -337,7 +398,6 @@ static irqreturn_t dt2811_interrupt(int irq, void *d)
1 == bipolar 2.5V (-2.5V -- +2.5V)
2 == unipolar 5V (0V -- +5V)
*/
-
static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
/* int i, irq; */
@@ -511,131 +571,38 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2811_detach(struct comedi_device *dev)
+static void dt2811_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->iobase)
release_region(dev->iobase, DT2811_SIZE);
-
- return 0;
-}
-
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int chan = CR_CHAN(insn->chanspec);
- int timeout = DT2811_TIMEOUT;
- int i;
-
- for (i = 0; i < insn->n; i++) {
- outb(chan, dev->iobase + DT2811_ADGCR);
-
- while (timeout
- && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
- timeout--;
- if (!timeout)
- return -ETIME;
-
- data[i] = inb(dev->iobase + DT2811_ADDATLO);
- data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
- data[i] &= 0xfff;
- }
-
- return i;
}
-#if 0
-/* Wow. This is code from the Comedi stone age. But it hasn't been
- * replaced, so I'll let it stay. */
-int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
-{
- struct comedi_device *dev = comedi_devices + minor;
-
- if (adtrig->n < 1)
- return 0;
- dev->curadchan = adtrig->chan;
- switch (dev->i_admode) {
- case COMEDI_MDEMAND:
- dev->ntrig = adtrig->n - 1;
- /* not necessary */
- /*printk("dt2811: AD soft trigger\n"); */
- /*outb(DT2811_CLRERROR|DT2811_INTENB,
- dev->iobase+DT2811_ADCSR); */
- outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
- do_gettimeofday(&trigtime);
- break;
- case COMEDI_MCONTS:
- dev->ntrig = adtrig->n;
- break;
- }
-
- return 0;
-}
-#endif
-
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++) {
- outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
- outb((data[i] >> 8) & 0xff,
- dev->iobase + DT2811_DADAT0HI + 2 * chan);
- devpriv->ao_readback[chan] = data[i];
- }
-
- return i;
-}
-
-static int dt2811_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
-}
-
-static int dt2811_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inb(dev->iobase + DT2811_DIO);
-
- return 2;
-}
-
-static int dt2811_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- outb(s->state, dev->iobase + DT2811_DIO);
-
- data[1] = s->state;
+static const struct dt2811_board boardtypes[] = {
+ {
+ .name = "dt2811-pgh",
+ .bip_5 = &range_dt2811_pgh_ai_5_bipolar,
+ .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar,
+ .unip_5 = &range_dt2811_pgh_ai_5_unipolar,
+ }, {
+ .name = "dt2811-pgl",
+ .bip_5 = &range_dt2811_pgl_ai_5_bipolar,
+ .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar,
+ .unip_5 = &range_dt2811_pgl_ai_5_unipolar,
+ },
+};
- return 2;
-}
+static struct comedi_driver dt2811_driver = {
+ .driver_name = "dt2811",
+ .module = THIS_MODULE,
+ .attach = dt2811_attach,
+ .detach = dt2811_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct dt2811_board),
+};
+module_comedi_driver(dt2811_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 1c6248c..fa4ade6 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -60,31 +60,6 @@ addition, the clock does not seem to be very accurate.
#define DT2814_ENB 0x10
#define DT2814_CHANMASK 0x0f
-static int dt2814_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2814_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2814 = {
- .driver_name = "dt2814",
- .module = THIS_MODULE,
- .attach = dt2814_attach,
- .detach = dt2814_detach,
-};
-
-static int __init driver_dt2814_init_module(void)
-{
- return comedi_driver_register(&driver_dt2814);
-}
-
-static void __exit driver_dt2814_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2814);
-}
-
-module_init(driver_dt2814_init_module);
-module_exit(driver_dt2814_cleanup_module);
-
-static irqreturn_t dt2814_interrupt(int irq, void *dev);
-
struct dt2814_private {
int ntrig;
@@ -260,6 +235,45 @@ static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
+static irqreturn_t dt2814_interrupt(int irq, void *d)
+{
+ int lo, hi;
+ struct comedi_device *dev = d;
+ struct comedi_subdevice *s;
+ int data;
+
+ if (!dev->attached) {
+ comedi_error(dev, "spurious interrupt");
+ return IRQ_HANDLED;
+ }
+
+ s = dev->subdevices + 0;
+
+ hi = inb(dev->iobase + DT2814_DATA);
+ lo = inb(dev->iobase + DT2814_DATA);
+
+ data = (hi << 4) | (lo >> 4);
+
+ if (!(--devpriv->ntrig)) {
+ int i;
+
+ outb(0, dev->iobase + DT2814_CSR);
+ /* note: turning off timed mode triggers another
+ sample. */
+
+ for (i = 0; i < DT2814_TIMEOUT; i++) {
+ if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
+ break;
+ }
+ inb(dev->iobase + DT2814_DATA);
+ inb(dev->iobase + DT2814_DATA);
+
+ s->async->events |= COMEDI_CB_EOA;
+ }
+ comedi_event(dev, s);
+ return IRQ_HANDLED;
+}
+
static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int i, irq;
@@ -347,57 +361,21 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2814_detach(struct comedi_device *dev)
+static void dt2814_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase)
release_region(dev->iobase, DT2814_SIZE);
-
- return 0;
}
-static irqreturn_t dt2814_interrupt(int irq, void *d)
-{
- int lo, hi;
- struct comedi_device *dev = d;
- struct comedi_subdevice *s;
- int data;
-
- if (!dev->attached) {
- comedi_error(dev, "spurious interrupt");
- return IRQ_HANDLED;
- }
-
- s = dev->subdevices + 0;
-
- hi = inb(dev->iobase + DT2814_DATA);
- lo = inb(dev->iobase + DT2814_DATA);
-
- data = (hi << 4) | (lo >> 4);
-
- if (!(--devpriv->ntrig)) {
- int i;
-
- outb(0, dev->iobase + DT2814_CSR);
- /* note: turning off timed mode triggers another
- sample. */
-
- for (i = 0; i < DT2814_TIMEOUT; i++) {
- if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
- break;
- }
- inb(dev->iobase + DT2814_DATA);
- inb(dev->iobase + DT2814_DATA);
-
- s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
-}
+static struct comedi_driver dt2814_driver = {
+ .driver_name = "dt2814",
+ .module = THIS_MODULE,
+ .attach = dt2814_attach,
+ .detach = dt2814_detach,
+};
+module_comedi_driver(dt2814_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 4155da4..bbab712 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -72,31 +72,6 @@ static const struct comedi_lrange
#define DT2815_DATA 0
#define DT2815_STATUS 1
-static int dt2815_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2815_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2815 = {
- .driver_name = "dt2815",
- .module = THIS_MODULE,
- .attach = dt2815_attach,
- .detach = dt2815_detach,
-};
-
-static int __init driver_dt2815_init_module(void)
-{
- return comedi_driver_register(&driver_dt2815);
-}
-
-static void __exit driver_dt2815_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2815);
-}
-
-module_init(driver_dt2815_init_module);
-module_exit(driver_dt2815_cleanup_module);
-
-static void dt2815_free_resources(struct comedi_device *dev);
-
struct dt2815_private {
const struct comedi_lrange *range_type_list[8];
@@ -252,20 +227,19 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void dt2815_free_resources(struct comedi_device *dev)
+static void dt2815_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, DT2815_SIZE);
}
-static int dt2815_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor);
-
- dt2815_free_resources(dev);
-
- return 0;
-}
+static struct comedi_driver dt2815_driver = {
+ .driver_name = "dt2815",
+ .module = THIS_MODULE,
+ .attach = dt2815_attach,
+ .detach = dt2815_detach,
+};
+module_comedi_driver(dt2815_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 99c1584..1ee10e7b 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -47,29 +47,6 @@ Configuration options:
#define DT2817_CR 0
#define DT2817_DATA 1
-static int dt2817_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2817_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2817 = {
- .driver_name = "dt2817",
- .module = THIS_MODULE,
- .attach = dt2817_attach,
- .detach = dt2817_detach,
-};
-
-static int __init driver_dt2817_init_module(void)
-{
- return comedi_driver_register(&driver_dt2817);
-}
-
-static void __exit driver_dt2817_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2817);
-}
-
-module_init(driver_dt2817_init_module);
-module_exit(driver_dt2817_cleanup_module);
-
static int dt2817_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -182,16 +159,20 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2817_detach(struct comedi_device *dev)
+static void dt2817_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2817: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, DT2817_SIZE);
-
- return 0;
}
+static struct comedi_driver dt2817_driver = {
+ .driver_name = "dt2817",
+ .module = THIS_MODULE,
+ .attach = dt2817_attach,
+ .detach = dt2817_detach,
+};
+module_comedi_driver(dt2817_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 95ebc26..736d8fa 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -221,136 +221,6 @@ struct dt282x_board {
int dabits;
};
-static const struct dt282x_board boardtypes[] = {
- {.name = "dt2821",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2821-f",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 6500,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2821-g",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 4000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2823",
- .adbits = 16,
- .adchan_se = 0,
- .adchan_di = 4,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 16,
- },
- {.name = "dt2824-pgh",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt2824-pgl",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 1,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt2825",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 1,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2827",
- .adbits = 16,
- .adchan_se = 0,
- .adchan_di = 4,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2828",
- .adbits = 12,
- .adchan_se = 4,
- .adchan_di = 0,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2829",
- .adbits = 16,
- .adchan_se = 8,
- .adchan_di = 0,
- .ai_speed = 33250,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 16,
- },
- {.name = "dt21-ez",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt23-ez",
- .adbits = 16,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt24-ez",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt24-ez-pgl",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 1,
- .dachan = 0,
- .dabits = 0,
- },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
#define this_board ((const struct dt282x_board *)dev->board_ptr)
struct dt282x_private {
@@ -411,33 +281,6 @@ struct dt282x_private {
b \
} while (0)
-static int dt282x_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt282x_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt282x = {
- .driver_name = "dt282x",
- .module = THIS_MODULE,
- .attach = dt282x_attach,
- .detach = dt282x_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct dt282x_board),
-};
-
-static int __init driver_dt282x_init_module(void)
-{
- return comedi_driver_register(&driver_dt282x);
-}
-
-static void __exit driver_dt282x_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt282x);
-}
-
-module_init(driver_dt282x_init_module);
-module_exit(driver_dt282x_cleanup_module);
-
-static void free_resources(struct comedi_device *dev);
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
static int dt282x_ai_cancel(struct comedi_device *dev,
@@ -1271,6 +1114,52 @@ enum { /* i/o base, irq, dma channels */
opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
};
+static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
+{
+ int ret;
+
+ devpriv->usedma = 0;
+
+ if (!dma1 && !dma2) {
+ printk(KERN_ERR " (no dma)");
+ return 0;
+ }
+
+ if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
+ return -EINVAL;
+
+ if (dma2 < dma1) {
+ int i;
+ i = dma1;
+ dma1 = dma2;
+ dma2 = i;
+ }
+
+ ret = request_dma(dma1, "dt282x A");
+ if (ret)
+ return -EBUSY;
+ devpriv->dma[0].chan = dma1;
+
+ ret = request_dma(dma2, "dt282x B");
+ if (ret)
+ return -EBUSY;
+ devpriv->dma[1].chan = dma2;
+
+ devpriv->dma_maxsize = PAGE_SIZE;
+ devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
+ printk(KERN_ERR " can't get DMA memory");
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
+
+ devpriv->usedma = 1;
+
+ return 0;
+}
+
/*
options:
0 i/o base
@@ -1442,7 +1331,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void free_resources(struct comedi_device *dev)
+static void dt282x_detach(struct comedi_device *dev)
{
if (dev->irq)
free_irq(dev->irq, dev);
@@ -1460,60 +1349,146 @@ static void free_resources(struct comedi_device *dev)
}
}
-static int dt282x_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
-
- free_resources(dev);
-
- return 0;
-}
-
-static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
-{
- int ret;
-
- devpriv->usedma = 0;
-
- if (!dma1 && !dma2) {
- printk(KERN_ERR " (no dma)");
- return 0;
- }
-
- if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
- return -EINVAL;
-
- if (dma2 < dma1) {
- int i;
- i = dma1;
- dma1 = dma2;
- dma2 = i;
- }
-
- ret = request_dma(dma1, "dt282x A");
- if (ret)
- return -EBUSY;
- devpriv->dma[0].chan = dma1;
-
- ret = request_dma(dma2, "dt282x B");
- if (ret)
- return -EBUSY;
- devpriv->dma[1].chan = dma2;
-
- devpriv->dma_maxsize = PAGE_SIZE;
- devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
- printk(KERN_ERR " can't get DMA memory");
- return -ENOMEM;
- }
-
- printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
-
- devpriv->usedma = 1;
+static const struct dt282x_board boardtypes[] = {
+ {
+ .name = "dt2821",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2821-f",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 6500,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2821-g",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 4000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2823",
+ .adbits = 16,
+ .adchan_se = 0,
+ .adchan_di = 4,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 16,
+ }, {
+ .name = "dt2824-pgh",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt2824-pgl",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 1,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt2825",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 1,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2827",
+ .adbits = 16,
+ .adchan_se = 0,
+ .adchan_di = 4,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2828",
+ .adbits = 12,
+ .adchan_se = 4,
+ .adchan_di = 0,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2829",
+ .adbits = 16,
+ .adchan_se = 8,
+ .adchan_di = 0,
+ .ai_speed = 33250,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 16,
+ }, {
+ .name = "dt21-ez",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt23-ez",
+ .adbits = 16,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt24-ez",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt24-ez-pgl",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 1,
+ .dachan = 0,
+ .dabits = 0,
+ },
+};
- return 0;
-}
+static struct comedi_driver dt282x_driver = {
+ .driver_name = "dt282x",
+ .module = THIS_MODULE,
+ .attach = dt282x_attach,
+ .detach = dt282x_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct dt282x_board),
+};
+module_comedi_driver(dt282x_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 0a7979e..0d27326 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -164,19 +164,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = {
#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
#define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
-
#define DT3000_SIZE (4*0x1000)
/* dual-ported RAM location definitions */
@@ -276,54 +263,6 @@ struct dt3k_private {
#define devpriv ((struct dt3k_private *)dev->private)
-static int dt3000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt3000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt3000 = {
- .driver_name = "dt3000",
- .module = THIS_MODULE,
- .attach = dt3000_attach,
- .detach = dt3000_detach,
-};
-
-static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
-}
-
-static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_dt3000_pci_driver = {
- .id_table = dt3k_pci_table,
- .probe = &driver_dt3000_pci_probe,
- .remove = __devexit_p(&driver_dt3000_pci_remove)
-};
-
-static int __init driver_dt3000_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_dt3000);
- if (retval < 0)
- return retval;
-
- driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
- return pci_register_driver(&driver_dt3000_pci_driver);
-}
-
-static void __exit driver_dt3000_cleanup_module(void)
-{
- pci_unregister_driver(&driver_dt3000_pci_driver);
- comedi_driver_unregister(&driver_dt3000);
-}
-
-module_init(driver_dt3000_init_module);
-module_exit(driver_dt3000_cleanup_module);
-
static void dt3k_ai_empty_fifo(struct comedi_device *dev,
struct comedi_subdevice *s);
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
@@ -841,7 +780,77 @@ static int dt3k_mem_insn_read(struct comedi_device *dev,
return i;
}
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
+static int setup_pci(struct comedi_device *dev)
+{
+ resource_size_t addr;
+ int ret;
+
+ ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
+ if (ret < 0)
+ return ret;
+
+ addr = pci_resource_start(devpriv->pci_dev, 0);
+ devpriv->phys_addr = addr;
+ devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
+ if (!devpriv->io_addr)
+ return -ENOMEM;
+#if DEBUG
+ printk("0x%08llx mapped to %p, ",
+ (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
+#endif
+
+ return 0;
+}
+
+static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
+{
+ int i;
+
+ for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
+ from != NULL;
+ from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
+ for (i = 0; i < n_dt3k_boards; i++) {
+ if (from->device == dt3k_boardtypes[i].device_id) {
+ *board = i;
+ return from;
+ }
+ }
+ printk
+ ("unknown Data Translation PCI device found with device_id=0x%04x\n",
+ from->device);
+ }
+ *board = -1;
+ return from;
+}
+
+static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+{
+ int board;
+ int ret;
+ struct pci_dev *pcidev;
+
+ pcidev = NULL;
+ while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
+ if ((bus == 0 && slot == 0) ||
+ (pcidev->bus->number == bus &&
+ PCI_SLOT(pcidev->devfn) == slot)) {
+ break;
+ }
+ }
+ devpriv->pci_dev = pcidev;
+
+ if (board >= 0)
+ dev->board_ptr = dt3k_boardtypes + board;
+
+ if (!devpriv->pci_dev)
+ return 0;
+
+ ret = setup_pci(dev);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
@@ -935,11 +944,10 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt3000_detach(struct comedi_device *dev)
+static void dt3000_detach(struct comedi_device *dev)
{
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->pci_dev) {
if (devpriv->phys_addr)
@@ -949,85 +957,45 @@ static int dt3000_detach(struct comedi_device *dev)
if (devpriv->io_addr)
iounmap(devpriv->io_addr);
}
- /* XXX */
-
- return 0;
}
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
-static int setup_pci(struct comedi_device *dev);
+static struct comedi_driver dt3000_driver = {
+ .driver_name = "dt3000",
+ .module = THIS_MODULE,
+ .attach = dt3000_attach,
+ .detach = dt3000_detach,
+};
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+static int __devinit dt3000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int board;
- int ret;
- struct pci_dev *pcidev;
-
- pcidev = NULL;
- while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
- if ((bus == 0 && slot == 0) ||
- (pcidev->bus->number == bus &&
- PCI_SLOT(pcidev->devfn) == slot)) {
- break;
- }
- }
- devpriv->pci_dev = pcidev;
-
- if (board >= 0)
- dev->board_ptr = dt3k_boardtypes + board;
-
- if (!devpriv->pci_dev)
- return 0;
-
- ret = setup_pci(dev);
- if (ret < 0)
- return ret;
-
- return 1;
+ return comedi_pci_auto_config(dev, &dt3000_driver);
}
-static int setup_pci(struct comedi_device *dev)
+static void __devexit dt3000_pci_remove(struct pci_dev *dev)
{
- resource_size_t addr;
- int ret;
-
- ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
- if (ret < 0)
- return ret;
-
- addr = pci_resource_start(devpriv->pci_dev, 0);
- devpriv->phys_addr = addr;
- devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
- if (!devpriv->io_addr)
- return -ENOMEM;
-#if DEBUG
- printk("0x%08llx mapped to %p, ",
- (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
-#endif
-
- return 0;
+ comedi_pci_auto_unconfig(dev);
}
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
-{
- int i;
+static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
- for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
- from != NULL;
- from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
- for (i = 0; i < n_dt3k_boards; i++) {
- if (from->device == dt3k_boardtypes[i].device_id) {
- *board = i;
- return from;
- }
- }
- printk
- ("unknown Data Translation PCI device found with device_id=0x%04x\n",
- from->device);
- }
- *board = -1;
- return from;
-}
+static struct pci_driver dt3000_pci_driver = {
+ .name = "dt3000",
+ .id_table = dt3000_pci_table,
+ .probe = dt3000_pci_probe,
+ .remove = __devexit_p(dt3000_pci_remove),
+};
+module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index e86ab58..22cda5c 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -196,7 +196,7 @@ struct dt9812_flash_data {
};
#define DT9812_MAX_NUM_MULTI_BYTE_RDS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
struct dt9812_read_multi {
u8 count;
@@ -209,8 +209,8 @@ struct dt9812_write_byte {
};
#define DT9812_MAX_NUM_MULTI_BYTE_WRTS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
- sizeof(struct dt9812_write_byte))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+ sizeof(struct dt9812_write_byte))
struct dt9812_write_multi {
u8 count;
@@ -224,7 +224,8 @@ struct dt9812_rmw_byte {
};
#define DT9812_MAX_NUM_MULTI_BYTE_RMWS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(struct dt9812_rmw_byte))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+ sizeof(struct dt9812_rmw_byte))
struct dt9812_rmw_multi {
u8 count;
@@ -365,7 +366,7 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf,
}
static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count,
- u8 * address, u8 * value)
+ u8 *address, u8 *value)
{
struct dt9812_usb_cmd cmd;
int i, count, retval;
@@ -391,8 +392,8 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count,
}
static int dt9812_write_multiple_registers(struct usb_dt9812 *dev,
- int reg_count, u8 * address,
- u8 * value)
+ int reg_count, u8 *address,
+ u8 *value)
{
struct dt9812_usb_cmd cmd;
int i, count, retval;
@@ -430,7 +431,7 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count,
return retval;
}
-static int dt9812_digital_in(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_in(struct slot_dt9812 *slot, u8 *bits)
{
int result = -ENODEV;
@@ -476,7 +477,7 @@ static int dt9812_digital_out(struct slot_dt9812 *slot, u8 bits)
return result;
}
-static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 *bits)
{
int result = -ENODEV;
@@ -547,12 +548,12 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev,
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2;
break;
default:
- err("Illegal gain %d\n", gain);
+ dev_err(&dev->interface->dev, "Illegal gain %d\n", gain);
}
}
-static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value,
+static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value,
enum dt9812_gain gain)
{
struct dt9812_rmw_byte rmw[3];
@@ -619,7 +620,7 @@ exit:
}
static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel,
- u16 * value)
+ u16 *value)
{
int result = -ENODEV;
@@ -715,7 +716,7 @@ static int dt9812_probe(struct usb_interface *interface,
iface_desc = interface->cur_altsetting;
if (iface_desc->desc.bNumEndpoints != 5) {
- err("Wrong number of endpints.");
+ dev_err(&interface->dev, "Wrong number of endpoints.\n");
retval = -ENODEV;
goto error;
}
@@ -781,22 +782,22 @@ static int dt9812_probe(struct usb_interface *interface,
}
if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) {
- err("Failed to read vendor.");
+ dev_err(&interface->dev, "Failed to read vendor.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) {
- err("Failed to read product.");
+ dev_err(&interface->dev, "Failed to read product.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) {
- err("Failed to read device.");
+ dev_err(&interface->dev, "Failed to read device.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) {
- err("Failed to read serial.");
+ dev_err(&interface->dev, "Failed to read serial.\n");
retval = -ENODEV;
goto error;
}
@@ -1110,9 +1111,9 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt9812_detach(struct comedi_device *dev)
+static void dt9812_detach(struct comedi_device *dev)
{
- return 0;
+ /* Nothing to cleanup */
}
static struct comedi_driver dt9812_comedi_driver = {
@@ -1146,7 +1147,9 @@ static int __init usb_dt9812_init(void)
result = comedi_driver_register(&dt9812_comedi_driver);
if (result) {
usb_deregister(&dt9812_usb_driver);
- err("comedi_driver_register failed. Error number %d", result);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": comedi_driver_register failed. Error number %d\n",
+ result);
}
return result;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index da8a2bf..b0cec7b 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -48,17 +48,6 @@
static DEFINE_MUTEX(start_stop_sem);
-static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
-
-static int dyna_pci10xx_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dyna_pci10xx_detach(struct comedi_device *dev);
-
static const struct comedi_lrange range_pci1050_ai = { 3, {
BIP_RANGE(10),
BIP_RANGE(5),
@@ -113,16 +102,6 @@ static const struct boardtype boardtypes[] = {
{.name = DRV_NAME},
};
-static struct comedi_driver driver_dyna_pci10xx = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = dyna_pci10xx_attach,
- .detach = dyna_pci10xx_detach,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
- .num_names = ARRAY_SIZE(boardtypes),
-};
-
struct dyna_pci10xx_private {
struct pci_dev *pci_dev; /* ptr to PCI device */
char valid; /* card is usable */
@@ -408,54 +387,48 @@ found:
return 1;
}
-static int dyna_pci10xx_detach(struct comedi_device *dev)
+static void dyna_pci10xx_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->pci_dev) {
comedi_pci_disable(devpriv->pci_dev);
mutex_destroy(&devpriv->mutex);
}
-
- return 0;
}
-static int __devinit driver_dyna_pci10xx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver dyna_pci10xx_driver = {
+ .driver_name = "dyna_pci10xx",
+ .module = THIS_MODULE,
+ .attach = dyna_pci10xx_attach,
+ .detach = dyna_pci10xx_detach,
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+ .num_names = ARRAY_SIZE(boardtypes),
+};
+
+static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_dyna_pci10xx.driver_name);
+ return comedi_pci_auto_config(dev, &dyna_pci10xx_driver);
}
-static void __devexit driver_dyna_pci10xx_pci_remove(struct pci_dev *dev)
+static void __devexit dyna_pci10xx_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_dyna_pci10xx_pci_driver = {
- .id_table = dyna_pci10xx_pci_table,
- .probe = &driver_dyna_pci10xx_pci_probe,
- .remove = __devexit_p(&driver_dyna_pci10xx_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
-static int __init driver_dyna_pci10xx_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_dyna_pci10xx);
- if (retval < 0)
- return retval;
-
- driver_dyna_pci10xx_pci_driver.name =
- (char *)driver_dyna_pci10xx.driver_name;
- return pci_register_driver(&driver_dyna_pci10xx_pci_driver);
-}
-
-static void __exit driver_dyna_pci10xx_cleanup_module(void)
-{
- pci_unregister_driver(&driver_dyna_pci10xx_pci_driver);
- comedi_driver_unregister(&driver_dyna_pci10xx);
-}
-
-module_init(driver_dyna_pci10xx_init_module);
-module_exit(driver_dyna_pci10xx_cleanup_module);
+static struct pci_driver dyna_pci10xx_pci_driver = {
+ .name = "dyna_pci10xx",
+ .id_table = dyna_pci10xx_pci_table,
+ .probe = dyna_pci10xx_pci_probe,
+ .remove = __devexit_p(dyna_pci10xx_pci_remove),
+};
+module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 7f49add..d2381445 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -42,38 +42,6 @@ static const struct comedi_lrange range_fl512 = { 4, {
}
};
-static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int fl512_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_fl512 = {
- .driver_name = "fl512",
- .module = THIS_MODULE,
- .attach = fl512_attach,
- .detach = fl512_detach,
-};
-
-static int __init driver_fl512_init_module(void)
-{
- return comedi_driver_register(&driver_fl512);
-}
-
-static void __exit driver_fl512_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_fl512);
-}
-
-module_init(driver_fl512_init_module);
-module_exit(driver_fl512_cleanup_module);
-
-static int fl512_ai_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int fl512_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int fl512_ao_insn_readback(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/*
* fl512_ai_insn : this is the analog input function
*/
@@ -140,9 +108,6 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
return n;
}
-/*
- * start attach
- */
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
unsigned long iobase;
@@ -209,14 +174,20 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-static int fl512_detach(struct comedi_device *dev)
+static void fl512_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, FL512_SIZE);
- printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor);
- return 0;
}
+static struct comedi_driver fl512_driver = {
+ .driver_name = "fl512",
+ .module = THIS_MODULE,
+ .attach = fl512_attach,
+ .detach = fl512_detach,
+};
+module_comedi_driver(fl512_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index bc020de..8aece08 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -53,8 +53,6 @@ support could be added to this driver.
#include "plx9080.h"
#include "comedi_fc.h"
-static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int hpdi_detach(struct comedi_device *dev);
static void abort_dma(struct comedi_device *dev, unsigned int channel);
static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -287,15 +285,6 @@ static const struct hpdi_board hpdi_boards[] = {
#endif
};
-static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = {
- {
- PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
- 0x2400, 0, 0, 0}, {
- 0}
-};
-
-MODULE_DEVICE_TABLE(pci, hpdi_pci_table);
-
static inline struct hpdi_board *board(const struct comedi_device *dev)
{
return (struct hpdi_board *)dev->board_ptr;
@@ -338,51 +327,6 @@ static inline struct hpdi_private *priv(struct comedi_device *dev)
return dev->private;
}
-static struct comedi_driver driver_hpdi = {
- .driver_name = "gsc_hpdi",
- .module = THIS_MODULE,
- .attach = hpdi_attach,
- .detach = hpdi_detach,
-};
-
-static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_hpdi.driver_name);
-}
-
-static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_hpdi_pci_driver = {
- .id_table = hpdi_pci_table,
- .probe = &driver_hpdi_pci_probe,
- .remove = __devexit_p(&driver_hpdi_pci_remove)
-};
-
-static int __init driver_hpdi_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_hpdi);
- if (retval < 0)
- return retval;
-
- driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name;
- return pci_register_driver(&driver_hpdi_pci_driver);
-}
-
-static void __exit driver_hpdi_cleanup_module(void)
-{
- pci_unregister_driver(&driver_hpdi_pci_driver);
- comedi_driver_unregister(&driver_hpdi);
-}
-
-module_init(driver_hpdi_init_module);
-module_exit(driver_hpdi_cleanup_module);
-
static int dio_config_insn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -645,7 +589,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
- if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
printk(KERN_WARNING
" failed enable PCI device and request regions\n");
return -EIO;
@@ -679,7 +623,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* get irq */
if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
- driver_hpdi.driver_name, dev)) {
+ dev->driver->driver_name, dev)) {
printk(KERN_WARNING
" unable to allocate irq %u\n", pcidev->irq);
return -EINVAL;
@@ -720,12 +664,10 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return init_hpdi(dev);
}
-static int hpdi_detach(struct comedi_device *dev)
+static void hpdi_detach(struct comedi_device *dev)
{
unsigned int i;
- printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
if ((priv(dev)) && (priv(dev)->hw_dev)) {
@@ -758,7 +700,6 @@ static int hpdi_detach(struct comedi_device *dev)
comedi_pci_disable(priv(dev)->hw_dev);
pci_dev_put(priv(dev)->hw_dev);
}
- return 0;
}
static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
@@ -1113,6 +1054,39 @@ static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static struct comedi_driver gsc_hpdi_driver = {
+ .driver_name = "gsc_hpdi",
+ .module = THIS_MODULE,
+ .attach = hpdi_attach,
+ .detach = hpdi_detach,
+};
+
+static int __devinit gsc_hpdi_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &gsc_hpdi_driver);
+}
+
+static void __devexit gsc_hpdi_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = {
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
+ 0x2400, 0, 0, 0},
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table);
+
+static struct pci_driver gsc_hpdi_pci_driver = {
+ .name = "gsc_hpdi",
+ .id_table = gsc_hpdi_pci_table,
+ .probe = gsc_hpdi_pci_probe,
+ .remove = __devexit_p(gsc_hpdi_pci_remove)
+};
+module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 126550f..fdc596f 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -121,15 +121,6 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
/*
==============================================================================
- Forward declarations
-==============================================================================
-*/
-static int icp_multi_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int icp_multi_detach(struct comedi_device *dev);
-
-/*
-==============================================================================
Data & Structure declarations
==============================================================================
*/
@@ -154,50 +145,6 @@ struct boardtype {
const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
};
-static const struct boardtype boardtypes[] = {
- {"icp_multi", /* Driver name */
- DEVICE_ID, /* PCI device ID */
- IORANGE_ICP_MULTI, /* I/O range length */
- 1, /* 1=Card supports interrupts */
- TYPE_ICP_MULTI, /* Card type = ICP MULTI */
- 16, /* Num of A/D channels */
- 8, /* Num of A/D channels in diff mode */
- 4, /* Num of D/A channels */
- 16, /* Num of digital inputs */
- 8, /* Num of digital outputs */
- 4, /* Num of counters */
- 0x0fff, /* Resolution of A/D */
- 0x0fff, /* Resolution of D/A */
- &range_analog, /* Rangelist for A/D */
- range_codes_analog, /* Range codes for programming */
- &range_analog}, /* Rangelist for D/A */
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_icp_multi = {
- .driver_name = "icp_multi",
- .module = THIS_MODULE,
- .attach = icp_multi_attach,
- .detach = icp_multi_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
-static int __init driver_icp_multi_init_module(void)
-{
- return comedi_driver_register(&driver_icp_multi);
-}
-
-static void __exit driver_icp_multi_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_icp_multi);
-}
-
-module_init(driver_icp_multi_init_module);
-module_exit(driver_icp_multi_cleanup_module);
-
struct icp_multi_private {
struct pcilst_struct *card; /* pointer to card */
char valid; /* card is usable */
@@ -222,25 +169,81 @@ struct icp_multi_private {
/*
==============================================================================
- More forward declarations
+
+Name: setup_channel_list
+
+Description:
+ This function sets the appropriate channel selection,
+ differential input mode and range bits in the ADC Command/
+ Status register.
+
+Parameters:
+ struct comedi_device *dev Pointer to current service structure
+ struct comedi_subdevice *s Pointer to current subdevice structure
+ unsigned int *chanlist Pointer to packed channel list
+ unsigned int n_chan Number of channels to scan
+
+Returns:Void
+
==============================================================================
*/
-
-#if 0
-static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-#endif
static void setup_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-static int icp_multi_reset(struct comedi_device *dev);
+ unsigned int *chanlist, unsigned int n_chan)
+{
+ unsigned int i, range, chanprog;
+ unsigned int diff;
-/*
-==============================================================================
- Functions
-==============================================================================
-*/
+#ifdef ICP_MULTI_EXTDEBUG
+ printk(KERN_DEBUG
+ "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
+#endif
+ devpriv->act_chanlist_len = n_chan;
+ devpriv->act_chanlist_pos = 0;
+
+ for (i = 0; i < n_chan; i++) {
+ /* Get channel */
+ chanprog = CR_CHAN(chanlist[i]);
+
+ /* Determine if it is a differential channel (Bit 15 = 1) */
+ if (CR_AREF(chanlist[i]) == AREF_DIFF) {
+ diff = 1;
+ chanprog &= 0x0007;
+ } else {
+ diff = 0;
+ chanprog &= 0x000f;
+ }
+
+ /* Clear channel, range and input mode bits
+ * in A/D command/status register */
+ devpriv->AdcCmdStatus &= 0xf00f;
+
+ /* Set channel number and differential mode status bit */
+ if (diff) {
+ /* Set channel number, bits 9-11 & mode, bit 6 */
+ devpriv->AdcCmdStatus |= (chanprog << 9);
+ devpriv->AdcCmdStatus |= ADC_DI;
+ } else
+ /* Set channel number, bits 8-11 */
+ devpriv->AdcCmdStatus |= (chanprog << 8);
+
+ /* Get range for current channel */
+ range = this_board->rangecode[CR_RANGE(chanlist[i])];
+ /* Set range. bits 4-5 */
+ devpriv->AdcCmdStatus |= range;
+
+ /* Output channel, range, mode to ICP Multi */
+ writew(devpriv->AdcCmdStatus,
+ devpriv->io_addr + ICP_MULTI_ADC_CSR);
+
+#ifdef ICP_MULTI_EXTDEBUG
+ printk(KERN_DEBUG
+ "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
+ devpriv->act_chanlist[i]);
+#endif
+ }
+
+}
/*
==============================================================================
@@ -764,84 +767,6 @@ static int check_channel_list(struct comedi_device *dev,
/*
==============================================================================
-Name: setup_channel_list
-
-Description:
- This function sets the appropriate channel selection,
- differential input mode and range bits in the ADC Command/
- Status register.
-
-Parameters:
- struct comedi_device *dev Pointer to current service structure
- struct comedi_subdevice *s Pointer to current subdevice structure
- unsigned int *chanlist Pointer to packed channel list
- unsigned int n_chan Number of channels to scan
-
-Returns:Void
-
-==============================================================================
-*/
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan)
-{
- unsigned int i, range, chanprog;
- unsigned int diff;
-
-#ifdef ICP_MULTI_EXTDEBUG
- printk(KERN_DEBUG
- "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
-#endif
- devpriv->act_chanlist_len = n_chan;
- devpriv->act_chanlist_pos = 0;
-
- for (i = 0; i < n_chan; i++) {
- /* Get channel */
- chanprog = CR_CHAN(chanlist[i]);
-
- /* Determine if it is a differential channel (Bit 15 = 1) */
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
- diff = 1;
- chanprog &= 0x0007;
- } else {
- diff = 0;
- chanprog &= 0x000f;
- }
-
- /* Clear channel, range and input mode bits
- * in A/D command/status register */
- devpriv->AdcCmdStatus &= 0xf00f;
-
- /* Set channel number and differential mode status bit */
- if (diff) {
- /* Set channel number, bits 9-11 & mode, bit 6 */
- devpriv->AdcCmdStatus |= (chanprog << 9);
- devpriv->AdcCmdStatus |= ADC_DI;
- } else
- /* Set channel number, bits 8-11 */
- devpriv->AdcCmdStatus |= (chanprog << 8);
-
- /* Get range for current channel */
- range = this_board->rangecode[CR_RANGE(chanlist[i])];
- /* Set range. bits 4-5 */
- devpriv->AdcCmdStatus |= range;
-
- /* Output channel, range, mode to ICP Multi */
- writew(devpriv->AdcCmdStatus,
- devpriv->io_addr + ICP_MULTI_ADC_CSR);
-
-#ifdef ICP_MULTI_EXTDEBUG
- printk(KERN_DEBUG
- "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
- devpriv->act_chanlist[i]);
-#endif
- }
-
-}
-
-/*
-==============================================================================
-
Name: icp_multi_reset
Description:
@@ -897,23 +822,6 @@ static int icp_multi_reset(struct comedi_device *dev)
return 0;
}
-/*
-==============================================================================
-
-Name: icp_multi_attach
-
-Description:
- This function sets up all the appropriate data for the current
- device.
-
-Parameters:
- struct comedi_device *dev Pointer to current device structure
- struct comedi_devconfig *it Pointer to current device configuration
-
-Returns:int 0 = success
-
-==============================================================================
-*/
static int icp_multi_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1099,44 +1007,53 @@ static int icp_multi_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-
-Name: icp_multi_detach
-
-Description:
- This function releases all the resources used by the current
- device.
-
-Parameters:
- struct comedi_device *dev Pointer to current device structure
-
-Returns:int 0 = success
-
-==============================================================================
-*/
-static int icp_multi_detach(struct comedi_device *dev)
+static void icp_multi_detach(struct comedi_device *dev)
{
-
if (dev->private)
if (devpriv->valid)
icp_multi_reset(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private && devpriv->io_addr)
iounmap(devpriv->io_addr);
-
if (dev->private && devpriv->card)
pci_card_free(devpriv->card);
-
if (--pci_list_builded == 0)
pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
-
- return 0;
}
+static const struct boardtype boardtypes[] = {
+ {
+ .name = "icp_multi",
+ .device_id = DEVICE_ID,
+ .iorange = IORANGE_ICP_MULTI,
+ .have_irq = 1,
+ .cardtype = TYPE_ICP_MULTI,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .n_aochan = 4,
+ .n_dichan = 16,
+ .n_dochan = 8,
+ .n_ctrs = 4,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_analog,
+ .rangecode = range_codes_analog,
+ .rangelist_ao = &range_analog,
+ },
+};
+
+static struct comedi_driver icp_multi_driver = {
+ .driver_name = "icp_multi",
+ .module = THIS_MODULE,
+ .attach = icp_multi_attach,
+ .detach = icp_multi_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+module_comedi_driver(icp_multi_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index e4711ef..f0a579a 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -159,17 +159,6 @@ struct pci20xxx_private {
#define devpriv ((struct pci20xxx_private *)dev->private)
#define CHAN (CR_CHAN(it->chanlist[0]))
-static int pci20xxx_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci20xxx_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci20xxx = {
- .driver_name = "ii_pci20kc",
- .module = THIS_MODULE,
- .attach = pci20xxx_attach,
- .detach = pci20xxx_detach,
-};
-
static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
int opt0, int opt1);
static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -275,11 +264,9 @@ static int pci20xxx_attach(struct comedi_device *dev,
return 1;
}
-static int pci20xxx_detach(struct comedi_device *dev)
+static void pci20xxx_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor);
-
- return 0;
+ /* Nothing to cleanup */
}
/* pci20006m */
@@ -666,18 +653,13 @@ static unsigned int pci20xxx_di(struct comedi_device *dev,
}
#endif
-static int __init driver_pci20xxx_init_module(void)
-{
- return comedi_driver_register(&driver_pci20xxx);
-}
-
-static void __exit driver_pci20xxx_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pci20xxx);
-}
-
-module_init(driver_pci20xxx_init_module);
-module_exit(driver_pci20xxx_cleanup_module);
+static struct comedi_driver pci20xxx_driver = {
+ .driver_name = "ii_pci20kc",
+ .module = THIS_MODULE,
+ .attach = pci20xxx_attach,
+ .detach = pci20xxx_detach,
+};
+module_comedi_driver(pci20xxx_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 6a79ba1..d536a11 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -59,28 +59,6 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
-static int jr3_pci_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int jr3_pci_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_jr3_pci = {
- .driver_name = "jr3_pci",
- .module = THIS_MODULE,
- .attach = jr3_pci_attach,
- .detach = jr3_pci_detach,
-};
-
-static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
-
struct jr3_pci_dev_private {
struct pci_dev *pci_dev;
@@ -948,9 +926,7 @@ out:
return result;
}
-MODULE_FIRMWARE("comedi/jr3pci.idm");
-
-static int jr3_pci_detach(struct comedi_device *dev)
+static void jr3_pci_detach(struct comedi_device *dev)
{
int i;
struct jr3_pci_dev_private *devpriv = dev->private;
@@ -962,56 +938,52 @@ static int jr3_pci_detach(struct comedi_device *dev)
for (i = 0; i < devpriv->n_channels; i++)
kfree(dev->subdevices[i].private);
}
-
if (devpriv->iobase)
iounmap((void *)devpriv->iobase);
if (devpriv->pci_enabled)
comedi_pci_disable(devpriv->pci_dev);
-
if (devpriv->pci_dev)
pci_dev_put(devpriv->pci_dev);
}
- return 0;
}
-static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver jr3_pci_driver = {
+ .driver_name = "jr3_pci",
+ .module = THIS_MODULE,
+ .attach = jr3_pci_attach,
+ .detach = jr3_pci_detach,
+};
+
+static int __devinit jr3_pci_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name);
+ return comedi_pci_auto_config(dev, &jr3_pci_driver);
}
-static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev)
+static void __devexit jr3_pci_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_jr3_pci_pci_driver = {
- .id_table = jr3_pci_pci_table,
- .probe = &driver_jr3_pci_pci_probe,
- .remove = __devexit_p(&driver_jr3_pci_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
-static int __init driver_jr3_pci_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_jr3_pci);
- if (retval < 0)
- return retval;
-
- driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name;
- return pci_register_driver(&driver_jr3_pci_pci_driver);
-}
-
-static void __exit driver_jr3_pci_cleanup_module(void)
-{
- pci_unregister_driver(&driver_jr3_pci_pci_driver);
- comedi_driver_unregister(&driver_jr3_pci);
-}
-
-module_init(driver_jr3_pci_init_module);
-module_exit(driver_jr3_pci_cleanup_module);
+static struct pci_driver jr3_pci_pci_driver = {
+ .name = "jr3_pci",
+ .id_table = jr3_pci_pci_table,
+ .probe = jr3_pci_pci_probe,
+ .remove = __devexit_p(jr3_pci_pci_remove),
+};
+module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("comedi/jr3pci.idm");
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 4e9e9a0..09d1918 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -46,18 +46,6 @@ Kolter Electronic PCI Counter Card.
#define PCI_VENDOR_ID_KOLTER 0x1001
#define CNT_CARD_DEVICE_ID 0x0014
-/*-- function prototypes ----------------------------------------------------*/
-
-static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int cnt_detach(struct comedi_device *dev);
-
-static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, cnt_pci_table);
-
/*-- board specification structure ------------------------------------------*/
struct cnt_board_struct {
@@ -87,51 +75,6 @@ struct cnt_device_private {
#define devpriv ((struct cnt_device_private *)dev->private)
-static struct comedi_driver cnt_driver = {
- .driver_name = CNT_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = cnt_attach,
- .detach = cnt_detach,
-};
-
-static int __devinit cnt_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, cnt_driver.driver_name);
-}
-
-static void __devexit cnt_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cnt_driver_pci_driver = {
- .id_table = cnt_pci_table,
- .probe = &cnt_driver_pci_probe,
- .remove = __devexit_p(&cnt_driver_pci_remove)
-};
-
-static int __init cnt_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&cnt_driver);
- if (retval < 0)
- return retval;
-
- cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name;
- return pci_register_driver(&cnt_driver_pci_driver);
-}
-
-static void __exit cnt_driver_cleanup_module(void)
-{
- pci_unregister_driver(&cnt_driver_pci_driver);
- comedi_driver_unregister(&cnt_driver);
-}
-
-module_init(cnt_driver_init_module);
-module_exit(cnt_driver_cleanup_module);
-
/*-- counter write ----------------------------------------------------------*/
/* This should be used only for resetting the counters; maybe it is better
@@ -181,8 +124,6 @@ static int cnt_rinsn(struct comedi_device *dev,
return 1;
}
-/*-- attach -----------------------------------------------------------------*/
-
static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *subdevice;
@@ -278,20 +219,47 @@ found:
return 0;
}
-/*-- detach -----------------------------------------------------------------*/
-
-static int cnt_detach(struct comedi_device *dev)
+static void cnt_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
pci_dev_put(devpriv->pcidev);
}
- printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
- dev->minor);
- return 0;
}
+static struct comedi_driver ke_counter_driver = {
+ .driver_name = "ke_counter",
+ .module = THIS_MODULE,
+ .attach = cnt_attach,
+ .detach = cnt_detach,
+};
+
+static int __devinit ke_counter_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &ke_counter_driver);
+}
+
+static void __devexit ke_counter_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
+
+static struct pci_driver ke_counter_pci_driver = {
+ .name = "ke_counter",
+ .id_table = ke_counter_pci_table,
+ .probe = ke_counter_pci_probe,
+ .remove = __devexit_p(ke_counter_pci_remove),
+};
+module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index b0bc6bb..8ca1b546 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -65,30 +65,6 @@ broken.
#include "me4000_fw.h"
#endif
-/*=============================================================================
- PCI device table.
- This is used by modprobe to translate PCI IDs to drivers.
- ===========================================================================*/
-
-static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, me4000_pci_table);
-
static const struct me4000_board me4000_boards[] = {
{"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} },
@@ -113,22 +89,8 @@ static const struct me4000_board me4000_boards[] = {
#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1)
/*-----------------------------------------------------------------------------
- Comedi function prototypes
- ---------------------------------------------------------------------------*/
-static int me4000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int me4000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_me4000 = {
- .driver_name = "me4000",
- .module = THIS_MODULE,
- .attach = me4000_attach,
- .detach = me4000_detach,
-};
-
-/*-----------------------------------------------------------------------------
Meilhaus function prototypes
---------------------------------------------------------------------------*/
-static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it);
static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p);
static int init_board_info(struct comedi_device *dev,
struct pci_dev *pci_dev_p);
@@ -139,76 +101,10 @@ static int init_cnt_context(struct comedi_device *dev);
static int xilinx_download(struct comedi_device *dev);
static int reset_board(struct comedi_device *dev);
-static int me4000_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int cnt_reset(struct comedi_device *dev, unsigned int channel);
-
-static int cnt_config(struct comedi_device *dev,
- unsigned int channel, unsigned int mode);
-
-static int me4000_cnt_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *subdevice,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int ai_check_chanlist(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-static int ai_round_cmd_args(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd,
- unsigned int *init_ticks,
- unsigned int *scan_ticks,
- unsigned int *chan_ticks);
-
-static int ai_prepare(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd,
- unsigned int init_ticks,
- unsigned int scan_ticks, unsigned int chan_ticks);
-
static int ai_write_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd);
-static irqreturn_t me4000_ai_isr(int irq, void *dev_id);
-
-static int me4000_ai_do_cmd_test(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-static int me4000_ai_do_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int me4000_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/*-----------------------------------------------------------------------------
Meilhaus inline functions
---------------------------------------------------------------------------*/
@@ -262,130 +158,6 @@ static const struct comedi_lrange me4000_ao_range = {
}
};
-static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int result;
-
- CALL_PDEBUG("In me4000_attach()\n");
-
- result = me4000_probe(dev, it);
- if (result)
- return result;
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h. It relies on
- * n_subdevices being set correctly.
- */
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- /*=========================================================================
- Analog input subdevice
- ========================================================================*/
-
- s = dev->subdevices + 0;
-
- if (thisboard->ai.count) {
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
- s->n_chan = thisboard->ai.count;
- s->maxdata = 0xFFFF; /* 16 bit ADC */
- s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
- s->range_table = &me4000_ai_range;
- s->insn_read = me4000_ai_insn_read;
-
- if (info->irq > 0) {
- if (request_irq(info->irq, me4000_ai_isr,
- IRQF_SHARED, "ME-4000", dev)) {
- printk
- ("comedi%d: me4000: me4000_attach(): "
- "Unable to allocate irq\n", dev->minor);
- } else {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = me4000_ai_cancel;
- s->do_cmdtest = me4000_ai_do_cmd_test;
- s->do_cmd = me4000_ai_do_cmd;
- }
- } else {
- printk(KERN_WARNING
- "comedi%d: me4000: me4000_attach(): "
- "No interrupt available\n", dev->minor);
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*=========================================================================
- Analog output subdevice
- ========================================================================*/
-
- s = dev->subdevices + 1;
-
- if (thisboard->ao.count) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
- s->n_chan = thisboard->ao.count;
- s->maxdata = 0xFFFF; /* 16 bit DAC */
- s->range_table = &me4000_ao_range;
- s->insn_write = me4000_ao_insn_write;
- s->insn_read = me4000_ao_insn_read;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*=========================================================================
- Digital I/O subdevice
- ========================================================================*/
-
- s = dev->subdevices + 2;
-
- if (thisboard->dio.count) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = thisboard->dio.count * 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = me4000_dio_insn_bits;
- s->insn_config = me4000_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*
- * Check for optoisolated ME-4000 version. If one the first
- * port is a fixed output port and the second is a fixed input port.
- */
- if (!me4000_inl(dev, info->dio_context.dir_reg)) {
- s->io_bits |= 0xFF;
- me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
- info->dio_context.dir_reg);
- }
-
- /*=========================================================================
- Counter subdevice
- ========================================================================*/
-
- s = dev->subdevices + 3;
-
- if (thisboard->cnt.count) {
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = thisboard->cnt.count;
- s->maxdata = 0xFFFF; /* 16 bit counters */
- s->insn_read = me4000_cnt_insn_read;
- s->insn_write = me4000_cnt_insn_write;
- s->insn_config = me4000_cnt_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- return 0;
-}
-
static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pci_device = NULL;
@@ -920,22 +692,6 @@ static int reset_board(struct comedi_device *dev)
return 0;
}
-static int me4000_detach(struct comedi_device *dev)
-{
- CALL_PDEBUG("In me4000_detach()\n");
-
- if (info) {
- if (info->pci_dev_p) {
- reset_board(dev);
- if (info->plx_regbase)
- comedi_pci_disable(info->pci_dev_p);
- pci_dev_put(info->pci_dev_p);
- }
- }
-
- return 0;
-}
-
/*=============================================================================
Analog input section
===========================================================================*/
@@ -2424,43 +2180,185 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
return 1;
}
-static int __devinit driver_me4000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_pci_auto_config(dev, driver_me4000.driver_name);
+ struct comedi_subdevice *s;
+ int result;
+
+ CALL_PDEBUG("In me4000_attach()\n");
+
+ result = me4000_probe(dev, it);
+ if (result)
+ return result;
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h. It relies on
+ * n_subdevices being set correctly.
+ */
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ /*=========================================================================
+ Analog input subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 0;
+
+ if (thisboard->ai.count) {
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags =
+ SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+ s->n_chan = thisboard->ai.count;
+ s->maxdata = 0xFFFF; /* 16 bit ADC */
+ s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
+ s->range_table = &me4000_ai_range;
+ s->insn_read = me4000_ai_insn_read;
+
+ if (info->irq > 0) {
+ if (request_irq(info->irq, me4000_ai_isr,
+ IRQF_SHARED, "ME-4000", dev)) {
+ printk
+ ("comedi%d: me4000: me4000_attach(): "
+ "Unable to allocate irq\n", dev->minor);
+ } else {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->cancel = me4000_ai_cancel;
+ s->do_cmdtest = me4000_ai_do_cmd_test;
+ s->do_cmd = me4000_ai_do_cmd;
+ }
+ } else {
+ printk(KERN_WARNING
+ "comedi%d: me4000: me4000_attach(): "
+ "No interrupt available\n", dev->minor);
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*=========================================================================
+ Analog output subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 1;
+
+ if (thisboard->ao.count) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
+ s->n_chan = thisboard->ao.count;
+ s->maxdata = 0xFFFF; /* 16 bit DAC */
+ s->range_table = &me4000_ao_range;
+ s->insn_write = me4000_ao_insn_write;
+ s->insn_read = me4000_ao_insn_read;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*=========================================================================
+ Digital I/O subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 2;
+
+ if (thisboard->dio.count) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = thisboard->dio.count * 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = me4000_dio_insn_bits;
+ s->insn_config = me4000_dio_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*
+ * Check for optoisolated ME-4000 version. If one the first
+ * port is a fixed output port and the second is a fixed input port.
+ */
+ if (!me4000_inl(dev, info->dio_context.dir_reg)) {
+ s->io_bits |= 0xFF;
+ me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
+ info->dio_context.dir_reg);
+ }
+
+ /*=========================================================================
+ Counter subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 3;
+
+ if (thisboard->cnt.count) {
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = thisboard->cnt.count;
+ s->maxdata = 0xFFFF; /* 16 bit counters */
+ s->insn_read = me4000_cnt_insn_read;
+ s->insn_write = me4000_cnt_insn_write;
+ s->insn_config = me4000_cnt_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ return 0;
}
-static void __devexit driver_me4000_pci_remove(struct pci_dev *dev)
+static void me4000_detach(struct comedi_device *dev)
{
- comedi_pci_auto_unconfig(dev);
+ if (info) {
+ if (info->pci_dev_p) {
+ reset_board(dev);
+ if (info->plx_regbase)
+ comedi_pci_disable(info->pci_dev_p);
+ pci_dev_put(info->pci_dev_p);
+ }
+ }
}
-static struct pci_driver driver_me4000_pci_driver = {
- .id_table = me4000_pci_table,
- .probe = &driver_me4000_pci_probe,
- .remove = __devexit_p(&driver_me4000_pci_remove)
+static struct comedi_driver me4000_driver = {
+ .driver_name = "me4000",
+ .module = THIS_MODULE,
+ .attach = me4000_attach,
+ .detach = me4000_detach,
};
-static int __init driver_me4000_init_module(void)
+static int __devinit me4000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int retval;
-
- retval = comedi_driver_register(&driver_me4000);
- if (retval < 0)
- return retval;
-
- driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name;
- return pci_register_driver(&driver_me4000_pci_driver);
+ return comedi_pci_auto_config(dev, &me4000_driver);
}
-static void __exit driver_me4000_cleanup_module(void)
+static void __devexit me4000_pci_remove(struct pci_dev *dev)
{
- pci_unregister_driver(&driver_me4000_pci_driver);
- comedi_driver_unregister(&driver_me4000);
+ comedi_pci_auto_unconfig(dev);
}
-module_init(driver_me4000_init_module);
-module_exit(driver_me4000_cleanup_module);
+static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, me4000_pci_table);
+
+static struct pci_driver me4000_pci_driver = {
+ .name = "me4000",
+ .id_table = me4000_pci_table,
+ .probe = me4000_pci_probe,
+ .remove = __devexit_p(me4000_pci_remove),
+};
+module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 8b812e4..ffe2512 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -146,10 +146,6 @@ from http://www.comedi.org
#define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */
#define ME_COUNTER_VALUE_B 0x0022 /* R | - */
-/* Function prototypes */
-static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int me_detach(struct comedi_device *dev);
-
static const struct comedi_lrange me2000_ai_range = {
8,
{
@@ -187,14 +183,6 @@ static const struct comedi_lrange me2600_ao_range = {
}
};
-static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, me_pci_table);
-
/* Board specification structure */
struct me_board {
const char *name; /* driver name */
@@ -247,51 +235,6 @@ static const struct me_board me_boards[] = {
#define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board))
-static struct comedi_driver me_driver = {
- .driver_name = ME_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = me_attach,
- .detach = me_detach,
-};
-
-static int __devinit me_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, me_driver.driver_name);
-}
-
-static void __devexit me_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver me_driver_pci_driver = {
- .id_table = me_pci_table,
- .probe = &me_driver_pci_probe,
- .remove = __devexit_p(&me_driver_pci_remove)
-};
-
-static int __init me_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&me_driver);
- if (retval < 0)
- return retval;
-
- me_driver_pci_driver.name = (char *)me_driver.driver_name;
- return pci_register_driver(&me_driver_pci_driver);
-}
-
-static void __exit me_driver_cleanup_module(void)
-{
- pci_unregister_driver(&me_driver_pci_driver);
- comedi_driver_unregister(&me_driver);
-}
-
-module_init(me_driver_init_module);
-module_exit(me_driver_cleanup_module);
-
/* Private data structure */
struct me_private_data {
struct pci_dev *pci_device;
@@ -669,12 +612,6 @@ static int me_reset(struct comedi_device *dev)
return 0;
}
-/*
- * Attach
- *
- * - Register PCI device
- * - Declare device driver capability
- */
static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pci_device = NULL;
@@ -869,8 +806,7 @@ found:
return 0;
}
-/* Detach */
-static int me_detach(struct comedi_device *dev)
+static void me_detach(struct comedi_device *dev)
{
if (dev_private) {
if (dev_private->me_regbase) {
@@ -882,13 +818,44 @@ static int me_detach(struct comedi_device *dev)
if (dev_private->pci_device) {
if (dev_private->plx_regbase_size)
comedi_pci_disable(dev_private->pci_device);
-
pci_dev_put(dev_private->pci_device);
}
}
- return 0;
}
+static struct comedi_driver me_daq_driver = {
+ .driver_name = "me_daq",
+ .module = THIS_MODULE,
+ .attach = me_attach,
+ .detach = me_detach,
+};
+
+static int __devinit me_daq_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &me_daq_driver);
+}
+
+static void __devexit me_daq_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, me_daq_pci_table);
+
+static struct pci_driver me_daq_pci_driver = {
+ .name = "me_daq",
+ .id_table = me_daq_pci_table,
+ .probe = me_daq_pci_probe,
+ .remove = __devexit_p(me_daq_pci_remove),
+};
+module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index 999551f..83f1b27 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -66,9 +66,9 @@ struct mite_struct {
struct pci_dev *pcidev;
resource_size_t mite_phys_addr;
- void *mite_io_addr;
+ void __iomem *mite_io_addr;
resource_size_t daq_phys_addr;
- void *daq_io_addr;
+ void __iomem *daq_io_addr;
struct mite_channel channels[MAX_MITE_DMA_CHANNELS];
short channel_allocated[MAX_MITE_DMA_CHANNELS];
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index dd09a6d..4304e86 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -148,131 +148,6 @@ static const struct comedi_lrange range_mpc624_bipolar10 = {
}
};
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int mpc624_detach(struct comedi_device *dev);
-/* -------------------------------------------------------------------------- */
-static struct comedi_driver driver_mpc624 = {
- .driver_name = "mpc624",
- .module = THIS_MODULE,
- .attach = mpc624_attach,
- .detach = mpc624_detach
-};
-
-/* -------------------------------------------------------------------------- */
-static int mpc624_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
-
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
- if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
- printk(KERN_ERR "I/O port(s) in use\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
- dev->board_name = "mpc624";
-
- /* Private structure initialization */
- if (alloc_private(dev, sizeof(struct skel_private)) < 0)
- return -ENOMEM;
-
- switch (it->options[1]) {
- case 0:
- devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
- printk(KERN_INFO "3.52 kHz, ");
- break;
- case 1:
- devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
- printk(KERN_INFO "1.76 kHz, ");
- break;
- case 2:
- devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
- printk(KERN_INFO "880 Hz, ");
- break;
- case 3:
- devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
- printk(KERN_INFO "440 Hz, ");
- break;
- case 4:
- devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
- printk(KERN_INFO "220 Hz, ");
- break;
- case 5:
- devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
- printk(KERN_INFO "110 Hz, ");
- break;
- case 6:
- devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
- printk(KERN_INFO "55 Hz, ");
- break;
- case 7:
- devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
- printk(KERN_INFO "27.5 Hz, ");
- break;
- case 8:
- devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
- printk(KERN_INFO "13.75 Hz, ");
- break;
- case 9:
- devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
- printk(KERN_INFO "6.875 Hz, ");
- break;
- default:
- printk
- (KERN_ERR "illegal conversion rate setting!"
- " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
- devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
- }
-
- /* Subdevices structures */
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_DIFF;
- s->n_chan = 8;
- switch (it->options[1]) {
- default:
- s->maxdata = 0x3FFFFFFF;
- printk(KERN_INFO "30 bit, ");
- }
-
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_mpc624_bipolar1;
- printk(KERN_INFO "1.01V]: ");
- break;
- default:
- s->range_table = &range_mpc624_bipolar10;
- printk(KERN_INFO "10.1V]: ");
- }
- s->len_chanlist = 1;
- s->insn_read = mpc624_ai_rinsn;
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-static int mpc624_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: mpc624: remove\n", dev->minor);
-
- if (dev->iobase)
- release_region(dev->iobase, MPC624_SIZE);
-
- return 0;
-}
-
/* Timeout 200ms */
#define TIMEOUT 200
@@ -406,18 +281,117 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
return n;
}
-static int __init driver_mpc624_init_module(void)
+static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_driver_register(&driver_mpc624);
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+
+ iobase = it->options[0];
+ printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
+ if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
+ printk(KERN_ERR "I/O port(s) in use\n");
+ return -EIO;
+ }
+
+ dev->iobase = iobase;
+ dev->board_name = "mpc624";
+
+ /* Private structure initialization */
+ if (alloc_private(dev, sizeof(struct skel_private)) < 0)
+ return -ENOMEM;
+
+ switch (it->options[1]) {
+ case 0:
+ devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+ printk(KERN_INFO "3.52 kHz, ");
+ break;
+ case 1:
+ devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
+ printk(KERN_INFO "1.76 kHz, ");
+ break;
+ case 2:
+ devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
+ printk(KERN_INFO "880 Hz, ");
+ break;
+ case 3:
+ devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
+ printk(KERN_INFO "440 Hz, ");
+ break;
+ case 4:
+ devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
+ printk(KERN_INFO "220 Hz, ");
+ break;
+ case 5:
+ devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
+ printk(KERN_INFO "110 Hz, ");
+ break;
+ case 6:
+ devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
+ printk(KERN_INFO "55 Hz, ");
+ break;
+ case 7:
+ devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
+ printk(KERN_INFO "27.5 Hz, ");
+ break;
+ case 8:
+ devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
+ printk(KERN_INFO "13.75 Hz, ");
+ break;
+ case 9:
+ devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
+ printk(KERN_INFO "6.875 Hz, ");
+ break;
+ default:
+ printk
+ (KERN_ERR "illegal conversion rate setting!"
+ " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
+ devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+ }
+
+ /* Subdevices structures */
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
+ s->n_chan = 8;
+ switch (it->options[1]) {
+ default:
+ s->maxdata = 0x3FFFFFFF;
+ printk(KERN_INFO "30 bit, ");
+ }
+
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_mpc624_bipolar1;
+ printk(KERN_INFO "1.01V]: ");
+ break;
+ default:
+ s->range_table = &range_mpc624_bipolar10;
+ printk(KERN_INFO "10.1V]: ");
+ }
+ s->len_chanlist = 1;
+ s->insn_read = mpc624_ai_rinsn;
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
}
-static void __exit driver_mpc624_cleanup_module(void)
+static void mpc624_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_mpc624);
+ if (dev->iobase)
+ release_region(dev->iobase, MPC624_SIZE);
}
-module_init(driver_mpc624_init_module);
-module_exit(driver_mpc624_cleanup_module);
+static struct comedi_driver mpc624_driver = {
+ .driver_name = "mpc624",
+ .module = THIS_MODULE,
+ .attach = mpc624_attach,
+ .detach = mpc624_detach
+};
+module_comedi_driver(mpc624_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index 5f6816a..364470e 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -46,75 +46,6 @@ struct mpc8260cpm_private {
#define devpriv ((struct mpc8260cpm_private *)dev->private)
-static int mpc8260cpm_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int mpc8260cpm_detach(struct comedi_device *dev);
-static struct comedi_driver driver_mpc8260cpm = {
- .driver_name = "mpc8260cpm",
- .module = THIS_MODULE,
- .attach = mpc8260cpm_attach,
- .detach = mpc8260cpm_detach,
-};
-
-static int __init driver_mpc8260cpm_init_module(void)
-{
- return comedi_driver_register(&driver_mpc8260cpm);
-}
-
-static void __exit driver_mpc8260cpm_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_mpc8260cpm);
-}
-
-module_init(driver_mpc8260cpm_init_module);
-module_exit(driver_mpc8260cpm_cleanup_module);
-
-static int mpc8260cpm_dio_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int mpc8260cpm_dio_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int mpc8260cpm_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int i;
-
- printk("comedi%d: mpc8260cpm: ", dev->minor);
-
- dev->board_ptr = mpc8260cpm_boards + dev->board;
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- for (i = 0; i < 4; i++) {
- s = dev->subdevices + i;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 32;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = mpc8260cpm_dio_config;
- s->insn_bits = mpc8260cpm_dio_bits;
- }
-
- return 1;
-}
-
-static int mpc8260cpm_detach(struct comedi_device *dev)
-{
- printk("comedi%d: mpc8260cpm: remove\n", dev->minor);
-
- return 0;
-}
-
static unsigned long *cpm_pdat(int port)
{
switch (port) {
@@ -184,3 +115,48 @@ static int mpc8260cpm_dio_bits(struct comedi_device *dev,
return 2;
}
+
+static int mpc8260cpm_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int i;
+
+ printk("comedi%d: mpc8260cpm: ", dev->minor);
+
+ dev->board_ptr = mpc8260cpm_boards + dev->board;
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ for (i = 0; i < 4; i++) {
+ s = dev->subdevices + i;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_config = mpc8260cpm_dio_config;
+ s->insn_bits = mpc8260cpm_dio_bits;
+ }
+
+ return 1;
+}
+
+static void mpc8260cpm_detach(struct comedi_device *dev)
+{
+ /* Nothing to cleanup */
+}
+
+static struct comedi_driver mpc8260cpm_driver = {
+ .driver_name = "mpc8260cpm",
+ .module = THIS_MODULE,
+ .attach = mpc8260cpm_attach,
+ .detach = mpc8260cpm_detach,
+};
+module_comedi_driver(mpc8260cpm_driver);
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index dace902..e951e73 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -83,29 +83,6 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3)
#define MULTIQ3_TIMEOUT 30
-static int multiq3_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int multiq3_detach(struct comedi_device *dev);
-static struct comedi_driver driver_multiq3 = {
- .driver_name = "multiq3",
- .module = THIS_MODULE,
- .attach = multiq3_attach,
- .detach = multiq3_detach,
-};
-
-static int __init driver_multiq3_init_module(void)
-{
- return comedi_driver_register(&driver_multiq3);
-}
-
-static void __exit driver_multiq3_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_multiq3);
-}
-
-module_init(driver_multiq3_init_module);
-module_exit(driver_multiq3_cleanup_module);
-
struct multiq3_private {
unsigned int ao_readback[2];
};
@@ -338,18 +315,22 @@ static int multiq3_attach(struct comedi_device *dev,
return 0;
}
-static int multiq3_detach(struct comedi_device *dev)
+static void multiq3_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, MULTIQ3_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static struct comedi_driver multiq3_driver = {
+ .driver_name = "multiq3",
+ .module = THIS_MODULE,
+ .attach = multiq3_attach,
+ .detach = multiq3_detach,
+};
+module_comedi_driver(multiq3_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 54741c9..b02aa0e 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -78,7 +78,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800
static int ni6527_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni6527_detach(struct comedi_device *dev);
+static void ni6527_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni6527 = {
.driver_name = "ni6527",
.module = THIS_MODULE,
@@ -449,19 +449,15 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int ni6527_detach(struct comedi_device *dev)
+static void ni6527_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
writeb(0x00,
devpriv->mite->daq_io_addr + Master_Interrupt_Control);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv && devpriv->mite)
mite_unsetup(devpriv->mite);
-
- return 0;
}
static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
@@ -493,7 +489,7 @@ static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni6527.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni6527);
}
static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 403fc09..0d27a93 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -111,7 +111,7 @@ static inline unsigned Filter_Enable(unsigned port)
static int ni_65xx_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_65xx_detach(struct comedi_device *dev);
+static void ni_65xx_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_65xx = {
.driver_name = "ni_65xx",
.module = THIS_MODULE,
@@ -784,7 +784,7 @@ static int ni_65xx_attach(struct comedi_device *dev,
return 0;
}
-static int ni_65xx_detach(struct comedi_device *dev)
+static void ni_65xx_detach(struct comedi_device *dev)
{
if (private(dev) && private(dev)->mite
&& private(dev)->mite->daq_io_addr) {
@@ -792,10 +792,8 @@ static int ni_65xx_detach(struct comedi_device *dev)
private(dev)->mite->daq_io_addr +
Master_Interrupt_Control);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (private(dev)) {
unsigned i;
for (i = 0; i < dev->n_subdevices; ++i) {
@@ -805,7 +803,6 @@ static int ni_65xx_detach(struct comedi_device *dev)
if (private(dev)->mite)
mite_unsetup(private(dev)->mite);
}
- return 0;
}
static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
@@ -837,7 +834,7 @@ static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_65xx);
}
static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 35f3a47..8c40730 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -458,7 +458,7 @@ static inline const struct ni_660x_board *board(struct comedi_device *dev)
static int ni_660x_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_660x_detach(struct comedi_device *dev);
+static void ni_660x_detach(struct comedi_device *dev);
static void init_tio_chip(struct comedi_device *dev, int chipset);
static void ni_660x_select_pfi_output(struct comedi_device *dev,
unsigned pfi_channel,
@@ -474,7 +474,7 @@ static struct comedi_driver driver_ni_660x = {
static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_660x.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_660x);
}
static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev)
@@ -761,7 +761,7 @@ static inline void ni_660x_write_register(struct comedi_device *dev,
unsigned chip_index, unsigned bits,
enum NI_660x_Register reg)
{
- void *const write_address =
+ void __iomem *write_address =
private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
registerData[reg].offset;
@@ -784,7 +784,7 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev,
unsigned chip_index,
enum NI_660x_Register reg)
{
- void *const read_address =
+ void __iomem *read_address =
private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
registerData[reg].offset;
@@ -1188,14 +1188,10 @@ static int ni_660x_attach(struct comedi_device *dev,
return 0;
}
-static int ni_660x_detach(struct comedi_device *dev)
+static void ni_660x_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor);
-
- /* Free irq */
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private) {
if (private(dev)->counter_dev)
ni_gpct_device_destroy(private(dev)->counter_dev);
@@ -1204,7 +1200,6 @@ static int ni_660x_detach(struct comedi_device *dev)
mite_unsetup(private(dev)->mite);
}
}
- return 0;
}
static int
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index d8d91f9..a9cf94f 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -111,7 +111,7 @@ struct ni_670x_private {
static int ni_670x_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_670x_detach(struct comedi_device *dev);
+static void ni_670x_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_670x = {
.driver_name = "ni_670x",
@@ -123,7 +123,7 @@ static struct comedi_driver driver_ni_670x = {
static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_670x.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_670x);
}
static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev)
@@ -249,19 +249,13 @@ static int ni_670x_attach(struct comedi_device *dev,
return 1;
}
-static int ni_670x_detach(struct comedi_device *dev)
+static void ni_670x_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor);
-
kfree(dev->subdevices[0].range_table_list);
-
if (dev->private && devpriv->mite)
mite_unsetup(devpriv->mite);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
static int ni_670x_ao_winsn(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index c25e44c..ae896a0 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -171,46 +171,13 @@ struct a2150_private {
#define devpriv ((struct a2150_private *)dev->private)
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int a2150_detach(struct comedi_device *dev);
static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static struct comedi_driver driver_a2150 = {
- .driver_name = "ni_at_a2150",
- .module = THIS_MODULE,
- .attach = a2150_attach,
- .detach = a2150_detach,
-};
-
-static irqreturn_t a2150_interrupt(int irq, void *d);
-static int a2150_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
int flags);
-static int a2150_probe(struct comedi_device *dev);
static int a2150_set_chanlist(struct comedi_device *dev,
unsigned int start_channel,
unsigned int num_channels);
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_a2150_init_module(void)
-{
- return comedi_driver_register(&driver_a2150);
-}
-
-static void __exit driver_a2150_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_a2150);
-}
-
-module_init(driver_a2150_init_module);
-module_exit(driver_a2150_cleanup_module);
-
#ifdef A2150_DEBUG
static void ni_dump_regs(struct comedi_device *dev)
@@ -331,161 +298,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
-/* probes board type, returns offset */
-static int a2150_probe(struct comedi_device *dev)
-{
- int status = inw(dev->iobase + STATUS_REG);
- return ID_BITS(status);
-}
-
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase = it->options[0];
- unsigned int irq = it->options[1];
- unsigned int dma = it->options[2];
- static const int timeout = 2000;
- int i;
-
- printk("comedi%d: %s: io 0x%lx", dev->minor, driver_a2150.driver_name,
- iobase);
- if (irq) {
- printk(", irq %u", irq);
- } else {
- printk(", no irq");
- }
- if (dma) {
- printk(", dma %u", dma);
- } else {
- printk(", no dma");
- }
- printk("\n");
-
- /* allocate and initialize dev->private */
- if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
- return -ENOMEM;
-
- if (iobase == 0) {
- printk(" io base address required\n");
- return -EINVAL;
- }
-
- /* check if io addresses are available */
- if (!request_region(iobase, A2150_SIZE, driver_a2150.driver_name)) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* grab our IRQ */
- if (irq) {
- /* check that irq is supported */
- if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
- printk(" invalid irq line %u\n", irq);
- return -EINVAL;
- }
- if (request_irq(irq, a2150_interrupt, 0,
- driver_a2150.driver_name, dev)) {
- printk("unable to allocate irq %u\n", irq);
- return -EINVAL;
- }
- devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
- dev->irq = irq;
- }
- /* initialize dma */
- if (dma) {
- if (dma == 4 || dma > 7) {
- printk(" invalid dma channel %u\n", dma);
- return -EINVAL;
- }
- if (request_dma(dma, driver_a2150.driver_name)) {
- printk(" failed to allocate dma channel %u\n", dma);
- return -EINVAL;
- }
- devpriv->dma = dma;
- devpriv->dma_buffer =
- kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
-
- disable_dma(dma);
- set_dma_mode(dma, DMA_MODE_READ);
-
- devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
- }
-
- dev->board_ptr = a2150_boards + a2150_probe(dev);
- dev->board_name = thisboard->name;
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- /* analog input subdevice */
- s = dev->subdevices + 0;
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
- s->n_chan = 4;
- s->len_chanlist = 4;
- s->maxdata = 0xffff;
- s->range_table = &range_a2150;
- s->do_cmd = a2150_ai_cmd;
- s->do_cmdtest = a2150_ai_cmdtest;
- s->insn_read = a2150_ai_rinsn;
- s->cancel = a2150_cancel;
-
- /* need to do this for software counting of completed conversions, to
- * prevent hardware count from stopping acquisition */
- outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
-
- /* set card's irq and dma levels */
- outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
-
- /* reset and sync adc clock circuitry */
- outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
- outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
- /* initialize configuration register */
- devpriv->config_bits = 0;
- outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
- /* wait until offset calibration is done, then enable analog inputs */
- for (i = 0; i < timeout; i++) {
- if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
- break;
- udelay(1000);
- }
- if (i == timeout) {
- printk
- (" timed out waiting for offset calibration to complete\n");
- return -ETIME;
- }
- devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
- outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
-
- return 0;
-};
-
-static int a2150_detach(struct comedi_device *dev)
-{
- printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name);
-
- /* only free stuff if it has been allocated by _attach */
- if (dev->iobase) {
- /* put board in power-down mode */
- outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
- release_region(dev->iobase, A2150_SIZE);
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv) {
- if (devpriv->dma)
- free_dma(devpriv->dma);
- kfree(devpriv->dma_buffer);
- }
-
- return 0;
-};
-
static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
/* disable dma on card */
@@ -539,7 +351,10 @@ static int a2150_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources are unique and mutually
+ * compatible
+ */
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
err++;
@@ -771,7 +586,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* start acquisition for soft trigger */
outw(0, dev->iobase + FIFO_START_REG);
- /* there is a 35.6 sample delay for data to get through the antialias filter */
+ /*
+ * there is a 35.6 sample delay for data to get through the
+ * antialias filter
+ */
for (n = 0; n < filter_delay; n++) {
for (i = 0; i < timeout; i++) {
if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
@@ -812,8 +630,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
-/* sets bits in devpriv->clock_bits to nearest approximation of requested period,
- * adjusts requested period to actual timing. */
+/*
+ * sets bits in devpriv->clock_bits to nearest approximation of requested
+ * period, adjusts requested period to actual timing.
+ */
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
int flags)
{
@@ -920,6 +740,162 @@ static int a2150_set_chanlist(struct comedi_device *dev,
return 0;
}
+/* probes board type, returns offset */
+static int a2150_probe(struct comedi_device *dev)
+{
+ int status = inw(dev->iobase + STATUS_REG);
+ return ID_BITS(status);
+}
+
+static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase = it->options[0];
+ unsigned int irq = it->options[1];
+ unsigned int dma = it->options[2];
+ static const int timeout = 2000;
+ int i;
+
+ printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
+ iobase);
+ if (irq) {
+ printk(", irq %u", irq);
+ } else {
+ printk(", no irq");
+ }
+ if (dma) {
+ printk(", dma %u", dma);
+ } else {
+ printk(", no dma");
+ }
+ printk("\n");
+
+ /* allocate and initialize dev->private */
+ if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
+ return -ENOMEM;
+
+ if (iobase == 0) {
+ printk(" io base address required\n");
+ return -EINVAL;
+ }
+
+ /* check if io addresses are available */
+ if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) {
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ /* grab our IRQ */
+ if (irq) {
+ /* check that irq is supported */
+ if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
+ printk(" invalid irq line %u\n", irq);
+ return -EINVAL;
+ }
+ if (request_irq(irq, a2150_interrupt, 0,
+ dev->driver->driver_name, dev)) {
+ printk("unable to allocate irq %u\n", irq);
+ return -EINVAL;
+ }
+ devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
+ dev->irq = irq;
+ }
+ /* initialize dma */
+ if (dma) {
+ if (dma == 4 || dma > 7) {
+ printk(" invalid dma channel %u\n", dma);
+ return -EINVAL;
+ }
+ if (request_dma(dma, dev->driver->driver_name)) {
+ printk(" failed to allocate dma channel %u\n", dma);
+ return -EINVAL;
+ }
+ devpriv->dma = dma;
+ devpriv->dma_buffer =
+ kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+ if (devpriv->dma_buffer == NULL)
+ return -ENOMEM;
+
+ disable_dma(dma);
+ set_dma_mode(dma, DMA_MODE_READ);
+
+ devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
+ }
+
+ dev->board_ptr = a2150_boards + a2150_probe(dev);
+ dev->board_name = thisboard->name;
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ /* analog input subdevice */
+ s = dev->subdevices + 0;
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
+ s->n_chan = 4;
+ s->len_chanlist = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &range_a2150;
+ s->do_cmd = a2150_ai_cmd;
+ s->do_cmdtest = a2150_ai_cmdtest;
+ s->insn_read = a2150_ai_rinsn;
+ s->cancel = a2150_cancel;
+
+ /* need to do this for software counting of completed conversions, to
+ * prevent hardware count from stopping acquisition */
+ outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
+
+ /* set card's irq and dma levels */
+ outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
+
+ /* reset and sync adc clock circuitry */
+ outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
+ outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
+ /* initialize configuration register */
+ devpriv->config_bits = 0;
+ outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+ /* wait until offset calibration is done, then enable analog inputs */
+ for (i = 0; i < timeout; i++) {
+ if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
+ break;
+ udelay(1000);
+ }
+ if (i == timeout) {
+ printk
+ (" timed out waiting for offset calibration to complete\n");
+ return -ETIME;
+ }
+ devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
+ outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+
+ return 0;
+};
+
+static void a2150_detach(struct comedi_device *dev)
+{
+ if (dev->iobase) {
+ outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
+ release_region(dev->iobase, A2150_SIZE);
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (devpriv) {
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ kfree(devpriv->dma_buffer);
+ }
+};
+
+static struct comedi_driver ni_at_a2150_driver = {
+ .driver_name = "ni_at_a2150",
+ .module = THIS_MODULE,
+ .attach = a2150_attach,
+ .detach = a2150_detach,
+};
+module_comedi_driver(ni_at_a2150_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 138dcc2..c43dd8a 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -157,17 +157,6 @@ struct atao_board {
int n_ao_chans;
};
-static const struct atao_board atao_boards[] = {
- {
- .name = "ai-ao-6",
- .n_ao_chans = 6,
- },
- {
- .name = "ai-ao-10",
- .n_ao_chans = 10,
- },
-};
-
#define thisboard ((struct atao_board *)dev->board_ptr)
struct atao_private {
@@ -182,133 +171,6 @@ struct atao_private {
#define devpriv ((struct atao_private *)dev->private)
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int atao_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atao = {
- .driver_name = "ni_at_ao",
- .module = THIS_MODULE,
- .attach = atao_attach,
- .detach = atao_detach,
- .board_name = &atao_boards[0].name,
- .offset = sizeof(struct atao_board),
- .num_names = ARRAY_SIZE(atao_boards),
-};
-
-static int __init driver_atao_init_module(void)
-{
- return comedi_driver_register(&driver_atao);
-}
-
-static void __exit driver_atao_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atao);
-}
-
-module_init(driver_atao_init_module);
-module_exit(driver_atao_cleanup_module);
-
-static void atao_reset(struct comedi_device *dev);
-
-static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
- int ao_unipolar;
-
- iobase = it->options[0];
- if (iobase == 0)
- iobase = 0x1c0;
- ao_unipolar = it->options[3];
-
- printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
-
- if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* dev->board_ptr = atao_probe(dev); */
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct atao_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = thisboard->n_ao_chans;
- s->maxdata = (1 << 12) - 1;
- if (ao_unipolar)
- s->range_table = &range_unipolar10;
- else
- s->range_table = &range_bipolar10;
- s->insn_write = &atao_ao_winsn;
- s->insn_read = &atao_ao_rinsn;
-
- s = dev->subdevices + 1;
- /* digital i/o subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = atao_dio_insn_bits;
- s->insn_config = atao_dio_insn_config;
-
- s = dev->subdevices + 2;
- /* caldac subdevice */
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 21;
- s->maxdata = 0xff;
- s->insn_read = atao_calib_insn_read;
- s->insn_write = atao_calib_insn_write;
-
- s = dev->subdevices + 3;
- /* eeprom subdevice */
- /* s->type=COMEDI_SUBD_EEPROM; */
- s->type = COMEDI_SUBD_UNUSED;
-
- atao_reset(dev);
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-static int atao_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: atao: remove\n", dev->minor);
-
- if (dev->iobase)
- release_region(dev->iobase, ATAO_SIZE);
-
- return 0;
-}
-
static void atao_reset(struct comedi_device *dev)
{
/* This is the reset sequence described in the manual */
@@ -471,6 +333,106 @@ static int atao_calib_insn_write(struct comedi_device *dev,
return insn->n;
}
+static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+ int ao_unipolar;
+
+ iobase = it->options[0];
+ if (iobase == 0)
+ iobase = 0x1c0;
+ ao_unipolar = it->options[3];
+
+ printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
+
+ if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ /* dev->board_ptr = atao_probe(dev); */
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct atao_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = thisboard->n_ao_chans;
+ s->maxdata = (1 << 12) - 1;
+ if (ao_unipolar)
+ s->range_table = &range_unipolar10;
+ else
+ s->range_table = &range_bipolar10;
+ s->insn_write = &atao_ao_winsn;
+ s->insn_read = &atao_ao_rinsn;
+
+ s = dev->subdevices + 1;
+ /* digital i/o subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = atao_dio_insn_bits;
+ s->insn_config = atao_dio_insn_config;
+
+ s = dev->subdevices + 2;
+ /* caldac subdevice */
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 21;
+ s->maxdata = 0xff;
+ s->insn_read = atao_calib_insn_read;
+ s->insn_write = atao_calib_insn_write;
+
+ s = dev->subdevices + 3;
+ /* eeprom subdevice */
+ /* s->type=COMEDI_SUBD_EEPROM; */
+ s->type = COMEDI_SUBD_UNUSED;
+
+ atao_reset(dev);
+
+ printk(KERN_INFO "\n");
+
+ return 0;
+}
+
+static void atao_detach(struct comedi_device *dev)
+{
+ if (dev->iobase)
+ release_region(dev->iobase, ATAO_SIZE);
+}
+
+static const struct atao_board atao_boards[] = {
+ {
+ .name = "ai-ao-6",
+ .n_ao_chans = 6,
+ }, {
+ .name = "ai-ao-10",
+ .n_ao_chans = 10,
+ },
+};
+
+static struct comedi_driver ni_at_ao_driver = {
+ .driver_name = "ni_at_ao",
+ .module = THIS_MODULE,
+ .attach = atao_attach,
+ .detach = atao_detach,
+ .board_name = &atao_boards[0].name,
+ .offset = sizeof(struct atao_board),
+ .num_names = ARRAY_SIZE(atao_boards),
+};
+module_comedi_driver(ni_at_ao_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 647c228..6448373 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -343,49 +343,8 @@ static struct pnp_device_id device_ids[] = {
MODULE_DEVICE_TABLE(pnp, device_ids);
-static int ni_atmio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int ni_atmio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atmio = {
- .driver_name = "ni_atmio",
- .module = THIS_MODULE,
- .attach = ni_atmio_attach,
- .detach = ni_atmio_detach,
-};
-
-static int __init driver_atmio_init_module(void)
-{
- return comedi_driver_register(&driver_atmio);
-}
-
-static void __exit driver_atmio_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atmio);
-}
-
-module_init(driver_atmio_init_module);
-module_exit(driver_atmio_cleanup_module);
-
#include "ni_mio_common.c"
-static int ni_getboardtype(struct comedi_device *dev);
-
-/* clean up allocated resources */
-static int ni_atmio_detach(struct comedi_device *dev)
-{
- mio_common_detach(dev);
-
- if (dev->iobase)
- release_region(dev->iobase, NI_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- if (devpriv->isapnp_dev)
- pnp_device_detach(devpriv->isapnp_dev);
-
- return 0;
-}
-
static int ni_isapnp_find_board(struct pnp_dev **dev)
{
struct pnp_dev *isapnp_dev = NULL;
@@ -424,6 +383,26 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
return 0;
}
+static int ni_getboardtype(struct comedi_device *dev)
+{
+ int device_id = ni_read_eeprom(dev, 511);
+ int i;
+
+ for (i = 0; i < n_ni_boards; i++) {
+ if (ni_boards[i].device_id == device_id)
+ return i;
+
+ }
+ if (device_id == 255)
+ printk(" can't find board\n");
+ else if (device_id == 0)
+ printk(" EEPROM read error (?) or device not found\n");
+ else
+ printk(" unknown device ID %d -- contact author\n", device_id);
+
+ return -1;
+}
+
static int ni_atmio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -518,22 +497,21 @@ static int ni_atmio_attach(struct comedi_device *dev,
return 0;
}
-static int ni_getboardtype(struct comedi_device *dev)
+static void ni_atmio_detach(struct comedi_device *dev)
{
- int device_id = ni_read_eeprom(dev, 511);
- int i;
-
- for (i = 0; i < n_ni_boards; i++) {
- if (ni_boards[i].device_id == device_id)
- return i;
-
- }
- if (device_id == 255)
- printk(" can't find board\n");
- else if (device_id == 0)
- printk(" EEPROM read error (?) or device not found\n");
- else
- printk(" unknown device ID %d -- contact author\n", device_id);
-
- return -1;
+ mio_common_detach(dev);
+ if (dev->iobase)
+ release_region(dev->iobase, NI_SIZE);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (devpriv->isapnp_dev)
+ pnp_device_detach(devpriv->isapnp_dev);
}
+
+static struct comedi_driver ni_atmio_driver = {
+ .driver_name = "ni_atmio",
+ .module = THIS_MODULE,
+ .attach = ni_atmio_attach,
+ .detach = ni_atmio_detach,
+};
+module_comedi_driver(ni_atmio_driver);
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 285b933..4f61453 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -110,60 +110,8 @@ struct atmio16_board_t {
int has_8255;
};
-static const struct atmio16_board_t atmio16_boards[] = {
- {
- .name = "atmio16",
- .has_8255 = 0,
- },
- {
- .name = "atmio16d",
- .has_8255 = 1,
- },
-};
-
-#define n_atmio16_boards ARRAY_SIZE(atmio16_boards)
-
#define boardtype ((const struct atmio16_board_t *)dev->board_ptr)
-/* function prototypes */
-static int atmio16d_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int atmio16d_detach(struct comedi_device *dev);
-static irqreturn_t atmio16d_interrupt(int irq, void *d);
-static int atmio16d_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int atmio16d_ai_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int atmio16d_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void reset_counters(struct comedi_device *dev);
-static void reset_atmio16d(struct comedi_device *dev);
-
-/* main driver struct */
-static struct comedi_driver driver_atmio16d = {
- .driver_name = "atmio16",
- .module = THIS_MODULE,
- .attach = atmio16d_attach,
- .detach = atmio16d_detach,
- .board_name = &atmio16_boards[0].name,
- .num_names = n_atmio16_boards,
- .offset = sizeof(struct atmio16_board_t),
-};
-
-static int __init driver_atmio16d_init_module(void)
-{
- return comedi_driver_register(&driver_atmio16d);
-}
-
-static void __exit driver_atmio16d_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atmio16d);
-}
-
-module_init(driver_atmio16d_init_module);
-module_exit(driver_atmio16d_cleanup_module);
-
/* range structs */
static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
BIP_RANGE
@@ -881,24 +829,38 @@ static int atmio16d_attach(struct comedi_device *dev,
return 0;
}
-static int atmio16d_detach(struct comedi_device *dev)
+static void atmio16d_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor);
-
if (dev->subdevices && boardtype->has_8255)
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
reset_atmio16d(dev);
-
if (dev->iobase)
release_region(dev->iobase, ATMIO16D_SIZE);
-
- return 0;
}
+static const struct atmio16_board_t atmio16_boards[] = {
+ {
+ .name = "atmio16",
+ .has_8255 = 0,
+ }, {
+ .name = "atmio16d",
+ .has_8255 = 1,
+ },
+};
+
+static struct comedi_driver atmio16d_driver = {
+ .driver_name = "atmio16",
+ .module = THIS_MODULE,
+ .attach = atmio16d_attach,
+ .detach = atmio16d_detach,
+ .board_name = &atmio16_boards[0].name,
+ .num_names = ARRAY_SIZE(atmio16_boards),
+ .offset = sizeof(struct atmio16_board_t),
+};
+module_comedi_driver(atmio16d_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e242012..75764e8 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev;
static int dio700_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dio700_detach(struct comedi_device *dev);
+static void dio700_detach(struct comedi_device *dev);
enum dio700_bustype { pcmcia_bustype };
@@ -419,19 +419,14 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int dio700_detach(struct comedi_device *dev)
+static void dio700_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: ni_daq_700: cs-remove\n", dev->minor);
-
if (dev->subdevices)
subdev_700_cleanup(dev, dev->subdevices + 0);
-
if (thisboard->bustype != pcmcia_bustype && dev->iobase)
release_region(dev->iobase, DIO700_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
};
static void dio700_config(struct pcmcia_device *link);
@@ -472,18 +467,12 @@ static int dio700_cs_attach(struct pcmcia_device *link)
static void dio700_cs_detach(struct pcmcia_device *link)
{
-
- printk(KERN_INFO "ni_daq_700: cs-detach!\n");
-
- dev_dbg(&link->dev, "dio700_cs_detach\n");
-
((struct local_info_t *)link->priv)->stop = 1;
dio700_release(link);
/* This points to the parent struct local_info_t struct */
kfree(link->priv);
-
-} /* dio700_cs_detach */
+}
static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index c0423a8..493a227 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev;
#define DIO24_SIZE 4 /* size of io region used by board */
static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dio24_detach(struct comedi_device *dev);
+static void dio24_detach(struct comedi_device *dev);
enum dio24_bustype { pcmcia_bustype };
@@ -168,19 +168,14 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int dio24_detach(struct comedi_device *dev)
+static void dio24_detach(struct comedi_device *dev)
{
- dev_info(dev->hw_dev, "comedi%d: ni_daq_dio24: remove\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 0);
-
if (thisboard->bustype != pcmcia_bustype && dev->iobase)
release_region(dev->iobase, DIO24_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
};
static void dio24_config(struct pcmcia_device *link);
@@ -221,18 +216,12 @@ static int dio24_cs_attach(struct pcmcia_device *link)
static void dio24_cs_detach(struct pcmcia_device *link)
{
-
- printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n");
-
- dev_dbg(&link->dev, "dio24_cs_detach\n");
-
((struct local_info_t *)link->priv)->stop = 1;
dio24_release(link);
/* This points to the parent local_info_t struct */
kfree(link->priv);
-
-} /* dio24_cs_detach */
+}
static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 721b2be..5334977 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -805,13 +805,10 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
}
#endif
-int labpc_common_detach(struct comedi_device *dev)
+void labpc_common_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
#ifdef CONFIG_ISA_DMA_API
/* only free stuff if it has been allocated by _attach */
kfree(devpriv->dma_buffer);
@@ -826,8 +823,6 @@ int labpc_common_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
#endif
-
- return 0;
};
EXPORT_SYMBOL_GPL(labpc_common_detach);
@@ -2141,7 +2136,7 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
static int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_labpc.driver_name);
+ return comedi_pci_auto_config(dev, &driver_labpc);
}
static void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index 422cee5..e052ed3 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -103,7 +103,7 @@ struct labpc_private {
int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
unsigned int irq, unsigned int dma);
-int labpc_common_detach(struct comedi_device *dev);
+void labpc_common_detach(struct comedi_device *dev);
extern const int labpc_1200_is_unipolar[];
extern const int labpc_1200_ai_gain_bits[];
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index ff38405..dbb61b6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -188,21 +188,13 @@ static int labpc_cs_attach(struct pcmcia_device *link)
static void labpc_cs_detach(struct pcmcia_device *link)
{
- dev_dbg(&link->dev, "labpc_cs_detach\n");
-
- /*
- If the device is currently configured and active, we won't
- actually delete it yet. Instead, it is marked so that when
- the release() function is called, that will trigger a proper
- detach().
- */
((struct local_info_t *)link->priv)->stop = 1;
labpc_release(link);
/* This points to the parent local_info_t struct (may be null) */
kfree(link->priv);
-} /* labpc_cs_detach */
+}
static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 53ec24bb..b85765d 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -227,7 +227,7 @@ static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr)
static int mio_cs_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int mio_cs_detach(struct comedi_device *dev);
+static void mio_cs_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_mio_cs = {
.driver_name = "ni_mio_cs",
.module = THIS_MODULE,
@@ -240,18 +240,11 @@ static struct comedi_driver driver_ni_mio_cs = {
static int ni_getboardtype(struct comedi_device *dev,
struct pcmcia_device *link);
-/* clean up allocated resources */
-/* called when driver is removed */
-static int mio_cs_detach(struct comedi_device *dev)
+static void mio_cs_detach(struct comedi_device *dev)
{
mio_common_detach(dev);
-
- /* PCMCIA layer frees the IO region */
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
static void mio_cs_config(struct pcmcia_device *link);
@@ -276,8 +269,6 @@ static void cs_release(struct pcmcia_device *link)
static void cs_detach(struct pcmcia_device *link)
{
- DPRINTK("cs_detach(link=%p)\n", link);
-
cs_release(link);
}
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 1df8fcb..37b7008 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -293,18 +293,9 @@ enum FPGA_Control_Bits {
#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
#endif
-static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int nidio_detach(struct comedi_device *dev);
static int ni_pcidio_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
-static struct comedi_driver driver_pcidio = {
- .driver_name = "ni_pcidio",
- .module = THIS_MODULE,
- .attach = nidio_attach,
- .detach = nidio_detach,
-};
-
struct nidio_board {
int dev_id;
@@ -381,22 +372,6 @@ static const struct nidio_board nidio_boards[] = {
#define n_nidio_boards ARRAY_SIZE(nidio_boards)
#define this_board ((const struct nidio_board *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
-
struct nidio96_private {
struct mite_struct *mite;
int boardtype;
@@ -414,7 +389,6 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int ni_pcidio_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int trignum);
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot);
static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);
static int setup_mite_dma(struct comedi_device *dev,
struct comedi_subdevice *s);
@@ -1205,6 +1179,33 @@ static int pci_6534_upload_firmware(struct comedi_device *dev, int options[])
return 0;
}
+static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
+{
+ struct mite_struct *mite;
+ int i;
+
+ for (mite = mite_devices; mite; mite = mite->next) {
+ if (mite->used)
+ continue;
+ if (bus || slot) {
+ if (bus != mite->pcidev->bus->number ||
+ slot != PCI_SLOT(mite->pcidev->devfn))
+ continue;
+ }
+ for (i = 0; i < n_nidio_boards; i++) {
+ if (mite_device_id(mite) == nidio_boards[i].dev_id) {
+ dev->board_ptr = nidio_boards + i;
+ devpriv->mite = mite;
+
+ return 0;
+ }
+ }
+ }
+ printk(KERN_WARNING "no device found\n");
+ mite_list_devices();
+ return -EIO;
+}
+
static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -1306,7 +1307,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int nidio_detach(struct comedi_device *dev)
+static void nidio_detach(struct comedi_device *dev)
{
int i;
@@ -1314,10 +1315,8 @@ static int nidio_detach(struct comedi_device *dev)
for (i = 0; i < this_board->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->di_mite_ring) {
mite_free_ring(devpriv->di_mite_ring);
@@ -1326,73 +1325,48 @@ static int nidio_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
}
- return 0;
}
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
-{
- struct mite_struct *mite;
- int i;
-
- for (mite = mite_devices; mite; mite = mite->next) {
- if (mite->used)
- continue;
- if (bus || slot) {
- if (bus != mite->pcidev->bus->number ||
- slot != PCI_SLOT(mite->pcidev->devfn))
- continue;
- }
- for (i = 0; i < n_nidio_boards; i++) {
- if (mite_device_id(mite) == nidio_boards[i].dev_id) {
- dev->board_ptr = nidio_boards + i;
- devpriv->mite = mite;
-
- return 0;
- }
- }
- }
- printk(KERN_WARNING "no device found\n");
- mite_list_devices();
- return -EIO;
-}
+static struct comedi_driver ni_pcidio_driver = {
+ .driver_name = "ni_pcidio",
+ .module = THIS_MODULE,
+ .attach = nidio_attach,
+ .detach = nidio_detach,
+};
-static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit ni_pcidio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pcidio.driver_name);
+ return comedi_pci_auto_config(dev, &ni_pcidio_driver);
}
-static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit ni_pcidio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pcidio_pci_driver = {
- .id_table = ni_pcidio_pci_table,
- .probe = &driver_pcidio_pci_probe,
- .remove = __devexit_p(&driver_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
-static int __init driver_pcidio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pcidio);
- if (retval < 0)
- return retval;
-
- driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name;
- return pci_register_driver(&driver_pcidio_pci_driver);
-}
-
-static void __exit driver_pcidio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pcidio_pci_driver);
- comedi_driver_unregister(&driver_pcidio);
-}
-
-module_init(driver_pcidio_init_module);
-module_exit(driver_pcidio_cleanup_module);
+static struct pci_driver ni_pcidio_pci_driver = {
+ .name = "ni_pcidio",
+ .id_table = ni_pcidio_pci_table,
+ .probe = ni_pcidio_pci_probe,
+ .remove = __devexit_p(ni_pcidio_pci_remove),
+};
+module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 27baefa..3974c0d 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -129,66 +129,6 @@ Bugs:
#define DRV_NAME "ni_pcimio"
-/* The following two tables must be in the same order */
-static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pci_table);
-
/* These are not all the possible ao ranges for 628x boards.
They can do OFFSET +- REFERENCE where OFFSET can be
0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can
@@ -1250,54 +1190,6 @@ static const struct ni_board_struct ni_boards[] = {
#define n_pcimio_boards ARRAY_SIZE(ni_boards)
-static int pcimio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcimio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcimio = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = pcimio_attach,
- .detach = pcimio_detach,
-};
-
-static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pcimio.driver_name);
-}
-
-static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pcimio_pci_driver = {
- .id_table = ni_pci_table,
- .probe = &driver_pcimio_pci_probe,
- .remove = __devexit_p(&driver_pcimio_pci_remove)
-};
-
-static int __init driver_pcimio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pcimio);
- if (retval < 0)
- return retval;
-
- driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name;
- return pci_register_driver(&driver_pcimio_pci_driver);
-}
-
-static void __exit driver_pcimio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pcimio_pci_driver);
- comedi_driver_unregister(&driver_pcimio);
-}
-
-module_init(driver_pcimio_init_module);
-module_exit(driver_pcimio_cleanup_module);
-
struct ni_private {
NI_PRIVATE_COMMON};
#define devpriv ((struct ni_private *)dev->private)
@@ -1681,13 +1573,11 @@ static void init_6143(struct comedi_device *dev)
ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
}
-/* cleans up allocated resources */
-static int pcimio_detach(struct comedi_device *dev)
+static void pcimio_detach(struct comedi_device *dev)
{
mio_common_detach(dev);
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private) {
mite_free_ring(devpriv->ai_mite_ring);
mite_free_ring(devpriv->ao_mite_ring);
@@ -1697,8 +1587,6 @@ static int pcimio_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
}
-
- return 0;
}
static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -1874,6 +1762,90 @@ static int pcimio_dio_change(struct comedi_device *dev,
return 0;
}
+static struct comedi_driver ni_pcimio_driver = {
+ .driver_name = "ni_pcimio",
+ .module = THIS_MODULE,
+ .attach = pcimio_attach,
+ .detach = pcimio_detach,
+};
+
+static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &ni_pcimio_driver);
+}
+
+static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table);
+
+static struct pci_driver ni_pcimio_pci_driver = {
+ .name = "ni_pcimio",
+ .id_table = ni_pcimio_pci_table,
+ .probe = ni_pcimio_pci_probe,
+ .remove = __devexit_p(ni_pcimio_pci_remove)
+};
+module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver)
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h
index c4ca537..5e00212 100644
--- a/drivers/staging/comedi/drivers/ni_tio_internal.h
+++ b/drivers/staging/comedi/drivers/ni_tio_internal.h
@@ -362,8 +362,8 @@ static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index)
return 0;
}
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int
- counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(
+ int counter_index)
{
switch (counter_index) {
case 0:
@@ -407,8 +407,8 @@ static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index)
return 0;
}
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int
- counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(
+ int counter_index)
{
switch (counter_index) {
case 0:
@@ -472,15 +472,22 @@ enum Gi_Counting_Mode_Reg_Bits {
Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift,
Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift,
Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift,
- Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */
- Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, /* from m-series example code, not documented in 660x register level manual */
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_HW_Arm_Enable_Bit = 0x80,
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift,
Gi_660x_Prescale_X8_Bit = 0x1000,
Gi_M_Series_Prescale_X8_Bit = 0x2000,
Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift,
- /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */
+ /* must be set for clocks over 40MHz, which includes synchronous
+ * counting and quadrature modes */
Gi_660x_Alternate_Sync_Bit = 0x2000,
Gi_M_Series_Alternate_Sync_Bit = 0x4000,
- Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_660x_Prescale_X2_Bit = 0x4000,
Gi_M_Series_Prescale_X2_Bit = 0x8000,
};
@@ -503,7 +510,8 @@ enum Gi_Mode_Bits {
Gi_Level_Gating_Bits = 0x1,
Gi_Rising_Edge_Gating_Bits = 0x2,
Gi_Falling_Edge_Gating_Bits = 0x3,
- Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */
+ Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with
+ * rising edge gating mode */
Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18,
Gi_Edge_Gate_Starts_Stops_Bits = 0x0,
Gi_Edge_Gate_Stops_Starts_Bits = 0x8,
@@ -686,11 +694,10 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
{
unsigned bit;
- if (counter_index % 2) {
+ if (counter_index % 2)
bit = G1_Gate_Interrupt_Enable_Bit;
- } else {
+ else
bit = G0_Gate_Interrupt_Enable_Bit;
- }
return bit;
}
@@ -748,8 +755,9 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter,
}
/* ni_tio_set_bits( ) is for safely writing to registers whose bits may be
-twiddled in interrupt context, or whose software copy may be read in interrupt context.
-*/
+ * twiddled in interrupt context, or whose software copy may be read in
+ * interrupt context.
+ */
static inline void ni_tio_set_bits(struct ni_gpct *counter,
enum ni_gpct_register register_index,
unsigned bit_mask, unsigned bit_values)
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index b44386a..2e7753f 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -148,42 +148,8 @@ struct pcl711_board {
const struct comedi_lrange *ai_range_type;
};
-static const struct pcl711_board boardtypes[] = {
- {"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5},
- {"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai},
- {"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai},
- {"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board))
#define this_board ((const struct pcl711_board *)dev->board_ptr)
-static int pcl711_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl711_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl711 = {
- .driver_name = "pcl711",
- .module = THIS_MODULE,
- .attach = pcl711_attach,
- .detach = pcl711_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl711_board),
-};
-
-static int __init driver_pcl711_init_module(void)
-{
- return comedi_driver_register(&driver_pcl711);
-}
-
-static void __exit driver_pcl711_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl711);
-}
-
-module_init(driver_pcl711_init_module);
-module_exit(driver_pcl711_cleanup_module);
-
struct pcl711_private {
int board;
@@ -513,21 +479,6 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
return 2;
}
-/* Free any resources that we have claimed */
-static int pcl711_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- if (dev->iobase)
- release_region(dev->iobase, PCL711_SIZE);
-
- return 0;
-}
-
-/* Initialization */
static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -640,6 +591,32 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
+static void pcl711_detach(struct comedi_device *dev)
+{
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, PCL711_SIZE);
+}
+
+static const struct pcl711_board boardtypes[] = {
+ { "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 },
+ { "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai },
+ { "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai },
+ { "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai },
+};
+
+static struct comedi_driver pcl711_driver = {
+ .driver_name = "pcl711",
+ .module = THIS_MODULE,
+ .attach = pcl711_attach,
+ .detach = pcl711_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl711_board),
+};
+module_comedi_driver(pcl711_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 61b075d..1f66fe1 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -56,10 +56,6 @@ See the source for configuration details.
/* #define PCL724_IRQ 1 no IRQ support now */
-static int pcl724_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl724_detach(struct comedi_device *dev);
-
struct pcl724_board {
const char *name; /* board name */
@@ -71,41 +67,8 @@ struct pcl724_board {
char is_pet48;
};
-static const struct pcl724_board boardtypes[] = {
- {"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
- {"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,},
- {"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,},
- {"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,},
- {"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
- {"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board))
#define this_board ((const struct pcl724_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl724 = {
- .driver_name = "pcl724",
- .module = THIS_MODULE,
- .attach = pcl724_attach,
- .detach = pcl724_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl724_board),
-};
-
-static int __init driver_pcl724_init_module(void)
-{
- return comedi_driver_register(&driver_pcl724);
-}
-
-static void __exit driver_pcl724_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl724);
-}
-
-module_init(driver_pcl724_init_module);
-module_exit(driver_pcl724_cleanup_module);
-
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
{
unsigned long iobase = arg;
@@ -214,25 +177,39 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl724_detach(struct comedi_device *dev)
+static void pcl724_detach(struct comedi_device *dev)
{
int i;
- /* printk("comedi%d: pcl724: remove\n",dev->minor); */
-
for (i = 0; i < dev->n_subdevices; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
-
#ifdef PCL724_IRQ
if (dev->irq)
free_irq(dev->irq, dev);
#endif
-
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcl724_board boardtypes[] = {
+ { "pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+ { "pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0, },
+ { "pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0, },
+ { "acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0, },
+ { "acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+ { "pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1, },
+};
+
+static struct comedi_driver pcl724_driver = {
+ .driver_name = "pcl724",
+ .module = THIS_MODULE,
+ .attach = pcl724_attach,
+ .detach = pcl724_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl724_board),
+};
+module_comedi_driver(pcl724_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 24b223c..83a6fa5 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -20,29 +20,6 @@ Devices: [Advantech] PCL-725 (pcl725)
#define PCL725_DO 0
#define PCL725_DI 1
-static int pcl725_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl725_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl725 = {
- .driver_name = "pcl725",
- .module = THIS_MODULE,
- .attach = pcl725_attach,
- .detach = pcl725_detach,
-};
-
-static int __init driver_pcl725_init_module(void)
-{
- return comedi_driver_register(&driver_pcl725);
-}
-
-static void __exit driver_pcl725_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl725);
-}
-
-module_init(driver_pcl725_init_module);
-module_exit(driver_pcl725_cleanup_module);
-
static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -112,16 +89,20 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl725_detach(struct comedi_device *dev)
+static void pcl725_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PCL725_SIZE);
-
- return 0;
}
+static struct comedi_driver pcl725_driver = {
+ .driver_name = "pcl725",
+ .module = THIS_MODULE,
+ .attach = pcl725_attach,
+ .detach = pcl725_detach,
+};
+module_comedi_driver(pcl725_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 897cd80..d25c30c 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -111,10 +111,6 @@ static const struct comedi_lrange *const rangelist_728[] = {
&range_4_20mA, &range_0_20mA
};
-static int pcl726_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl726_detach(struct comedi_device *dev);
-
struct pcl726_board {
const char *name; /* driver name */
@@ -149,32 +145,8 @@ static const struct pcl726_board boardtypes[] = {
&rangelist_728[0],},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl726_board))
#define this_board ((const struct pcl726_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl726 = {
- .driver_name = "pcl726",
- .module = THIS_MODULE,
- .attach = pcl726_attach,
- .detach = pcl726_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl726_board),
-};
-
-static int __init driver_pcl726_init_module(void)
-{
- return comedi_driver_register(&driver_pcl726);
-}
-
-static void __exit driver_pcl726_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl726);
-}
-
-module_init(driver_pcl726_init_module);
-module_exit(driver_pcl726_cleanup_module);
-
struct pcl726_private {
int bipolar[12];
@@ -378,21 +350,27 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl726_detach(struct comedi_device *dev)
+static void pcl726_detach(struct comedi_device *dev)
{
-/* printk("comedi%d: pcl726: remove\n",dev->minor); */
-
#ifdef ACL6126_IRQ
if (dev->irq)
free_irq(dev->irq, dev);
#endif
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static struct comedi_driver pcl726_driver = {
+ .driver_name = "pcl726",
+ .module = THIS_MODULE,
+ .attach = pcl726_attach,
+ .detach = pcl726_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl726_board),
+};
+module_comedi_driver(pcl726_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index c9682d6..e11704a 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -26,48 +26,14 @@ The ACL-7130 card have an 8254 timer/counter not supported by this driver.
#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */
#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */
-static int pcl730_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl730_detach(struct comedi_device *dev);
-
struct pcl730_board {
const char *name; /* board name */
unsigned int io_range; /* len of I/O space */
};
-static const struct pcl730_board boardtypes[] = {
- {"pcl730", PCL730_SIZE,},
- {"iso730", PCL730_SIZE,},
- {"acl7130", ACL7130_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board))
#define this_board ((const struct pcl730_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl730 = {
- .driver_name = "pcl730",
- .module = THIS_MODULE,
- .attach = pcl730_attach,
- .detach = pcl730_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl730_board),
-};
-
-static int __init driver_pcl730_init_module(void)
-{
- return comedi_driver_register(&driver_pcl730);
-}
-
-static void __exit driver_pcl730_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl730);
-}
-
-module_init(driver_pcl730_init_module);
-module_exit(driver_pcl730_cleanup_module);
-
static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -168,16 +134,29 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl730_detach(struct comedi_device *dev)
+static void pcl730_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcl730_board boardtypes[] = {
+ { "pcl730", PCL730_SIZE, },
+ { "iso730", PCL730_SIZE, },
+ { "acl7130", ACL7130_SIZE, },
+};
+
+static struct comedi_driver pcl730_driver = {
+ .driver_name = "pcl730",
+ .module = THIS_MODULE,
+ .attach = pcl730_attach,
+ .detach = pcl730_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl730_board),
+};
+module_comedi_driver(pcl730_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 6fc7464..51f4ca9 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -316,10 +316,6 @@ static const struct comedi_lrange range_a821pgh_ai = { 4, {
}
};
-static int pcl812_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl812_detach(struct comedi_device *dev);
-
struct pcl812_board {
const char *name; /* board name */
@@ -340,89 +336,8 @@ struct pcl812_board {
unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */
};
-static const struct pcl812_board boardtypes[] = {
- {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
- 33000, 500, &range_bipolar10, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, 500, &range_pcl813b_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
- 10000, 500, &range_pcl813b_ai, NULL,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, 500, &range_a821pgh_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_acl8113_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_iso813_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board))
#define this_board ((const struct pcl812_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl812 = {
- .driver_name = "pcl812",
- .module = THIS_MODULE,
- .attach = pcl812_attach,
- .detach = pcl812_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl812_board),
-};
-
-static int __init driver_pcl812_init_module(void)
-{
- return comedi_driver_register(&driver_pcl812);
-}
-
-static void __exit driver_pcl812_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl812);
-}
-
-module_init(driver_pcl812_init_module);
-module_exit(driver_pcl812_cleanup_module);
-
struct pcl812_private {
unsigned char valid; /* =1 device is OK */
@@ -1356,9 +1271,6 @@ static void pcl812_reset(struct comedi_device *dev)
#endif
}
-/*
-==============================================================================
-*/
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret, subdev;
@@ -1702,19 +1614,79 @@ no_dma:
return 0;
}
-/*
-==============================================================================
- */
-static int pcl812_detach(struct comedi_device *dev)
+static void pcl812_detach(struct comedi_device *dev)
{
-
-#ifdef PCL812_EXTDEBUG
- printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor);
-#endif
free_resources(dev);
- return 0;
}
+static const struct pcl812_board boardtypes[] = {
+ {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_bipolar10, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, NULL,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_a821pgh_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_acl8113_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_iso813_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+};
+
+static struct comedi_driver pcl812_driver = {
+ .driver_name = "pcl812",
+ .module = THIS_MODULE,
+ .attach = pcl812_attach,
+ .detach = pcl812_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl812_board),
+};
+module_comedi_driver(pcl812_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 96cd7ec..cc67b6d 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -125,63 +125,14 @@ struct pcl816_board {
int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
};
-static const struct pcl816_board boardtypes[] = {
- {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc, /* IRQ mask */
- 0x0a, /* DMA mask */
- 0xffff, /* 16-bit card */
- 0xffff, /* D/A maxdata */
- 1024,
- 1, /* ao chan list */
- 100},
- {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc,
- 0x0a,
- 0x3fff, /* 14 bit card */
- 0x3fff,
- 1024,
- 1,
- 100},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
#define devpriv ((struct pcl816_private *)dev->private)
#define this_board ((const struct pcl816_board *)dev->board_ptr)
-static int pcl816_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl816_detach(struct comedi_device *dev);
-
#ifdef unused
static int RTC_lock; /* RTC lock */
static int RTC_timer_lock; /* RTC int lock */
#endif
-static struct comedi_driver driver_pcl816 = {
- .driver_name = "pcl816",
- .module = THIS_MODULE,
- .attach = pcl816_attach,
- .detach = pcl816_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl816_board),
-};
-
-static int __init driver_pcl816_init_module(void)
-{
- return comedi_driver_register(&driver_pcl816);
-}
-
-static void __exit driver_pcl816_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl816);
-}
-
-module_init(driver_pcl816_init_module);
-module_exit(driver_pcl816_cleanup_module);
-
struct pcl816_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
@@ -1075,46 +1026,6 @@ static int set_rtc_irq_bit(unsigned char bit)
}
#endif
-/*
-==============================================================================
- Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
- /* printk("free_resource()\n"); */
- if (dev->private) {
- pcl816_ai_cancel(dev, devpriv->sub_ai);
- pcl816_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
-#endif
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, this_board->io_range);
- /* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
- Initialization
-
-*/
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -1340,21 +1251,69 @@ case COMEDI_SUBD_DO:
return 0;
}
-/*
-==============================================================================
- Removes device
- */
-static int pcl816_detach(struct comedi_device *dev)
+static void pcl816_detach(struct comedi_device *dev)
{
- DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
- free_resources(dev);
+ if (dev->private) {
+ pcl816_ai_cancel(dev, devpriv->sub_ai);
+ pcl816_reset(dev);
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ if (devpriv->dmabuf[0])
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ if (devpriv->dmabuf[1])
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+ if (devpriv->rtc_irq)
+ free_irq(devpriv->rtc_irq, dev);
+ if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+ if (devpriv->rtc_iobase)
+ release_region(devpriv->rtc_iobase,
+ devpriv->rtc_iosize);
+ }
+#endif
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, this_board->io_range);
#ifdef unused
if (devpriv->dma_rtc)
RTC_lock--;
#endif
- return 0;
}
+static const struct pcl816_board boardtypes[] = {
+ {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+ &range_pcl816, PCLx1x_RANGE,
+ 0x00fc, /* IRQ mask */
+ 0x0a, /* DMA mask */
+ 0xffff, /* 16-bit card */
+ 0xffff, /* D/A maxdata */
+ 1024,
+ 1, /* ao chan list */
+ 100},
+ {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+ &range_pcl816, PCLx1x_RANGE,
+ 0x00fc,
+ 0x0a,
+ 0x3fff, /* 14 bit card */
+ 0x3fff,
+ 1024,
+ 1,
+ 100},
+};
+
+static struct comedi_driver pcl816_driver = {
+ .driver_name = "pcl816",
+ .module = THIS_MODULE,
+ .attach = pcl816_attach,
+ .detach = pcl816_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl816_board),
+};
+module_comedi_driver(pcl816_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 7344a53..1406c97 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -247,10 +247,6 @@ static const struct comedi_lrange range718_bipolar0_5 =
static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
-static int pcl818_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl818_detach(struct comedi_device *dev);
-
#ifdef unused
static int RTC_lock; /* RTC lock */
static int RTC_timer_lock; /* RTC int lock */
@@ -277,56 +273,6 @@ struct pcl818_board {
int is_818;
};
-static const struct pcl818_board boardtypes[] = {
- {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 0},
- /* pcm3718 */
- {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
-
-static struct comedi_driver driver_pcl818 = {
- .driver_name = "pcl818",
- .module = THIS_MODULE,
- .attach = pcl818_attach,
- .detach = pcl818_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl818_board),
-};
-
-static int __init driver_pcl818_init_module(void)
-{
- return comedi_driver_register(&driver_pcl818);
-}
-
-static void __exit driver_pcl818_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl818);
-}
-
-module_init(driver_pcl818_init_module);
-module_exit(driver_pcl818_cleanup_module);
-
struct pcl818_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
@@ -1688,48 +1634,6 @@ static int rtc_setfreq_irq(int freq)
}
#endif
-/*
-==============================================================================
- Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
- /* printk("free_resource()\n"); */
- if (dev->private) {
- pcl818_ai_cancel(dev, devpriv->sub_ai);
- pcl818_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
- if (devpriv->dma_rtc)
- RTC_lock--;
-#endif
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, devpriv->io_range);
- /* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
- Initialization
-
-*/
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -2020,17 +1924,71 @@ no_dma:
return 0;
}
-/*
-==============================================================================
- Removes device
- */
-static int pcl818_detach(struct comedi_device *dev)
+static void pcl818_detach(struct comedi_device *dev)
{
- /* printk("comedi%d: pcl818: remove\n", dev->minor); */
- free_resources(dev);
- return 0;
+ if (dev->private) {
+ pcl818_ai_cancel(dev, devpriv->sub_ai);
+ pcl818_reset(dev);
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ if (devpriv->dmabuf[0])
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ if (devpriv->dmabuf[1])
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+ if (devpriv->rtc_irq)
+ free_irq(devpriv->rtc_irq, dev);
+ if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+ if (devpriv->rtc_iobase)
+ release_region(devpriv->rtc_iobase,
+ devpriv->rtc_iosize);
+ }
+ if (devpriv->dma_rtc)
+ RTC_lock--;
+#endif
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, devpriv->io_range);
}
+static const struct pcl818_board boardtypes[] = {
+ {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 1, 1},
+ {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 1, 1},
+ {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 0},
+ /* pcm3718 */
+ {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
+};
+
+static struct comedi_driver pcl818_driver = {
+ .driver_name = "pcl818",
+ .module = THIS_MODULE,
+ .attach = pcl818_attach,
+ .detach = pcl818_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl818_board),
+};
+module_comedi_driver(pcl818_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index f5c0bd1..7492b8f 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -62,10 +62,6 @@ Copy/pasted/hacked from pcm724.c
#define CR_A_MODE(a) ((a)<<5)
#define CR_CW 0x80
-static int pcm3724_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcm3724_detach(struct comedi_device *dev);
-
struct pcm3724_board {
const char *name; /* driver name */
int dio; /* num of DIO */
@@ -80,36 +76,8 @@ struct priv_pcm3724 {
int dio_2;
};
-static const struct pcm3724_board boardtypes[] = {
- {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board))
#define this_board ((const struct pcm3724_board *)dev->board_ptr)
-static struct comedi_driver driver_pcm3724 = {
- .driver_name = "pcm3724",
- .module = THIS_MODULE,
- .attach = pcm3724_attach,
- .detach = pcm3724_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcm3724_board),
-};
-
-static int __init driver_pcm3724_init_module(void)
-{
- return comedi_driver_register(&driver_pcm3724);
-}
-
-static void __exit driver_pcm3724_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcm3724);
-}
-
-module_init(driver_pcm3724_init_module);
-module_exit(driver_pcm3724_cleanup_module);
-
/* (setq c-basic-offset 8) */
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
@@ -305,7 +273,7 @@ static int pcm3724_attach(struct comedi_device *dev,
return 0;
}
-static int pcm3724_detach(struct comedi_device *dev)
+static void pcm3724_detach(struct comedi_device *dev)
{
int i;
@@ -315,10 +283,23 @@ static int pcm3724_detach(struct comedi_device *dev)
}
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcm3724_board boardtypes[] = {
+ { "pcm3724", 48, 2, 0x00fc, PCM3724_SIZE, },
+};
+
+static struct comedi_driver pcm3724_driver = {
+ .driver_name = "pcm3724",
+ .module = THIS_MODULE,
+ .attach = pcm3724_attach,
+ .detach = pcm3724_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcm3724_board),
+};
+module_comedi_driver(pcm3724_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index bada6b2..f8d1c64 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -28,29 +28,6 @@ Configuration options:
#define PCM3730_DIB 2
#define PCM3730_DIC 3
-static int pcm3730_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcm3730_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcm3730 = {
- .driver_name = "pcm3730",
- .module = THIS_MODULE,
- .attach = pcm3730_attach,
- .detach = pcm3730_detach,
-};
-
-static int __init driver_pcm3730_init_module(void)
-{
- return comedi_driver_register(&driver_pcm3730);
-}
-
-static void __exit driver_pcm3730_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcm3730);
-}
-
-module_init(driver_pcm3730_init_module);
-module_exit(driver_pcm3730_cleanup_module);
-
static int pcm3730_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -156,16 +133,20 @@ static int pcm3730_attach(struct comedi_device *dev,
return 0;
}
-static int pcm3730_detach(struct comedi_device *dev)
+static void pcm3730_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PCM3730_SIZE);
-
- return 0;
}
+static struct comedi_driver pcm3730_driver = {
+ .driver_name = "pcm3730",
+ .module = THIS_MODULE,
+ .attach = pcm3730_attach,
+ .detach = pcm3730_detach,
+};
+module_comedi_driver(pcm3730_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 23b3d77..1ec7d5c 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -57,19 +57,8 @@ struct pcmad_board_struct {
const char *name;
int n_ai_bits;
};
-static const struct pcmad_board_struct pcmad_boards[] = {
- {
- .name = "pcmad12",
- .n_ai_bits = 12,
- },
- {
- .name = "pcmad16",
- .n_ai_bits = 16,
- },
-};
#define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
-#define n_pcmad_boards ARRAY_SIZE(pcmad_boards)
struct pcmad_priv_struct {
int differential;
@@ -77,31 +66,6 @@ struct pcmad_priv_struct {
};
#define devpriv ((struct pcmad_priv_struct *)dev->private)
-static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pcmad_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcmad = {
- .driver_name = "pcmad",
- .module = THIS_MODULE,
- .attach = pcmad_attach,
- .detach = pcmad_detach,
- .board_name = &pcmad_boards[0].name,
- .num_names = n_pcmad_boards,
- .offset = sizeof(pcmad_boards[0]),
-};
-
-static int __init driver_pcmad_init_module(void)
-{
- return comedi_driver_register(&driver_pcmad);
-}
-
-static void __exit driver_pcmad_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcmad);
-}
-
-module_init(driver_pcmad_init_module);
-module_exit(driver_pcmad_cleanup_module);
-
#define TIMEOUT 100
static int pcmad_ai_insn_read(struct comedi_device *dev,
@@ -175,19 +139,34 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcmad_detach(struct comedi_device *dev)
+static void pcmad_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase)
release_region(dev->iobase, PCMAD_SIZE);
-
- return 0;
}
+static const struct pcmad_board_struct pcmad_boards[] = {
+ {
+ .name = "pcmad12",
+ .n_ai_bits = 12,
+ }, {
+ .name = "pcmad16",
+ .n_ai_bits = 16,
+ },
+};
+static struct comedi_driver pcmad_driver = {
+ .driver_name = "pcmad",
+ .module = THIS_MODULE,
+ .attach = pcmad_attach,
+ .detach = pcmad_detach,
+ .board_name = &pcmad_boards[0].name,
+ .num_names = ARRAY_SIZE(pcmad_boards),
+ .offset = sizeof(pcmad_boards[0]),
+};
+module_comedi_driver(pcmad_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 0e9ffa2..4786148 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -80,12 +80,6 @@ static const struct comedi_lrange pcmda12_ranges = {
}
};
-static const struct pcmda12_board pcmda12_boards[] = {
- {
- .name = "pcmda12",
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -99,137 +93,6 @@ struct pcmda12_private {
#define devpriv ((struct pcmda12_private *)(dev->private))
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmda12_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmda12_detach(struct comedi_device *dev);
-
-static void zero_chans(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmda12",
- .module = THIS_MODULE,
- .attach = pcmda12_attach,
- .detach = pcmda12_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmda12_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmda12_boards[0].name,
- .offset = sizeof(struct pcmda12_board),
- .num_names = ARRAY_SIZE(pcmda12_boards),
-};
-
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmda12_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
-
- iobase = it->options[0];
- printk(KERN_INFO
- "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
- iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
-
- if (!request_region(iobase, IOSIZE, driver.driver_name)) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
- printk(KERN_ERR "cannot allocate private data structure\n");
- return -ENOMEM;
- }
-
- devpriv->simultaneous_xfer_mode = it->options[1];
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
- * 96-channel version of the board.
- */
- if (alloc_subdevices(dev, 1) < 0) {
- printk(KERN_ERR "cannot allocate subdevice data structures\n");
- return -ENOMEM;
- }
-
- s = dev->subdevices;
- s->private = NULL;
- s->maxdata = (0x1 << BITS) - 1;
- s->range_table = &pcmda12_ranges;
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = CHANS;
- s->insn_write = &ao_winsn;
- s->insn_read = &ao_rinsn;
-
- zero_chans(dev); /* clear out all the registers, basically */
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmda12_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO
- "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, IOSIZE);
- return 0;
-}
-
static void zero_chans(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -301,22 +164,91 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
+static int pcmda12_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+
+ iobase = it->options[0];
+ printk(KERN_INFO
+ "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name,
+ iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
+
+ if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) {
+ printk("I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
+ printk(KERN_ERR "cannot allocate private data structure\n");
+ return -ENOMEM;
+ }
+
+ devpriv->simultaneous_xfer_mode = it->options[1];
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+ * 96-channel version of the board.
+ */
+ if (alloc_subdevices(dev, 1) < 0) {
+ printk(KERN_ERR "cannot allocate subdevice data structures\n");
+ return -ENOMEM;
+ }
+
+ s = dev->subdevices;
+ s->private = NULL;
+ s->maxdata = (0x1 << BITS) - 1;
+ s->range_table = &pcmda12_ranges;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = CHANS;
+ s->insn_write = &ao_winsn;
+ s->insn_read = &ao_rinsn;
+
+ zero_chans(dev); /* clear out all the registers, basically */
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmda12_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ if (dev->iobase)
+ release_region(dev->iobase, IOSIZE);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmda12_board pcmda12_boards[] = {
+ {
+ .name = "pcmda12",
+ },
+};
+
+static struct comedi_driver pcmda12_driver = {
+ .driver_name = "pcmda12",
+ .module = THIS_MODULE,
+ .attach = pcmda12_attach,
+ .detach = pcmda12_detach,
+ .board_name = &pcmda12_boards[0].name,
+ .offset = sizeof(struct pcmda12_board),
+ .num_names = ARRAY_SIZE(pcmda12_boards),
+};
+module_comedi_driver(pcmda12_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index eddac00..efed168 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -145,13 +145,6 @@ Configuration Options:
#define PAGE_ENAB 2
#define PAGE_INT_ID 3
-static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-
/*
* Board descriptions for two imaginary boards. Describing the
* boards in this way is optional, and completely driver-dependent.
@@ -190,23 +183,6 @@ static const struct comedi_lrange ranges_ao = {
RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
};
-static const struct pcmmio_board pcmmio_boards[] = {
- {
- .name = "pcmmio",
- .dio_num_asics = 1,
- .dio_num_ports = 6,
- .total_iosize = 32,
- .ai_bits = 16,
- .ao_bits = 16,
- .n_ai_chans = 16,
- .n_ao_chans = 8,
- .ai_range_table = &ranges_ai,
- .ao_range_table = &ranges_ao,
- .ai_rinsn = ai_rinsn,
- .ao_rinsn = ao_rinsn,
- .ao_winsn = ao_winsn},
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -293,312 +269,6 @@ struct pcmmio_private {
*/
#define devpriv ((struct pcmmio_private *)dev->private)
#define subpriv ((struct pcmmio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmmio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmmio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmmio",
- .module = THIS_MODULE,
- .attach = pcmmio_attach,
- .detach = pcmmio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmmio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmmio_boards[0].name,
- .offset = sizeof(struct pcmmio_board),
- .num_names = ARRAY_SIZE(pcmmio_boards),
-};
-
-static int pcmmio_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcmmio_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmmio(int irq, void *d);
-static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-/* sets up/clears ASIC chips to defaults */
-static void init_asics(struct comedi_device *dev);
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
- thisasic_chanct = 0;
- unsigned long iobase;
- unsigned int irq[MAX_ASICS];
-
- iobase = it->options[0];
- irq[0] = it->options[1];
-
- printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
- driver.driver_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase,
- thisboard->total_iosize,
- driver.driver_name)) {
- printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
- return -EIO;
- }
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
- printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
- dev->minor);
- return -ENOMEM;
- }
-
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- devpriv->asics[asic].num = asic;
- devpriv->asics[asic].iobase =
- dev->iobase + 16 + asic * ASIC_IOSIZE;
- /*
- * this gets actually set at the end of this function when we
- * request_irqs
- */
- devpriv->asics[asic].irq = 0;
- spin_lock_init(&devpriv->asics[asic].spinlock);
- }
-
- chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
- n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
- n_subdevs = n_dio_subdevs + 2;
- devpriv->sprivs =
- kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
- GFP_KERNEL);
- if (!devpriv->sprivs) {
- printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
- dev->minor);
- return -ENOMEM;
- }
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
- */
- if (alloc_subdevices(dev, n_subdevs) < 0) {
- printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
- dev->minor);
- return -ENOMEM;
- }
-
- /* First, AI */
- sdev_no = 0;
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = thisboard->ai_range_table;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
- s->type = COMEDI_SUBD_AI;
- s->n_chan = thisboard->n_ai_chans;
- s->len_chanlist = s->n_chan;
- s->insn_read = thisboard->ai_rinsn;
- subpriv->iobase = dev->iobase + 0;
- /* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
-
- /* Next, AO */
- ++sdev_no;
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = (1 << thisboard->ao_bits) - 1;
- s->range_table = thisboard->ao_range_table;
- s->subdev_flags = SDF_READABLE;
- s->type = COMEDI_SUBD_AO;
- s->n_chan = thisboard->n_ao_chans;
- s->len_chanlist = s->n_chan;
- s->insn_read = thisboard->ao_rinsn;
- s->insn_write = thisboard->ao_winsn;
- subpriv->iobase = dev->iobase + 8;
- /* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
-
- ++sdev_no;
- port = 0;
- asic = 0;
- for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
- int byte_no;
-
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmmio_dio_insn_bits;
- s->insn_config = pcmmio_dio_insn_config;
- s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
- subpriv->dio.intr.asic = -1;
- subpriv->dio.intr.first_chan = -1;
- subpriv->dio.intr.asic_chan = -1;
- subpriv->dio.intr.num_asic_chans = -1;
- subpriv->dio.intr.active = 0;
- s->len_chanlist = 1;
-
- /* save the ioport address for each 'port' of 8 channels in the
- subdevice */
- for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
- if (port >= PORTS_PER_ASIC) {
- port = 0;
- ++asic;
- thisasic_chanct = 0;
- }
- subpriv->iobases[byte_no] =
- devpriv->asics[asic].iobase + port;
-
- if (thisasic_chanct <
- CHANS_PER_PORT * INTR_PORTS_PER_ASIC
- && subpriv->dio.intr.asic < 0) {
- /*
- * this is an interrupt subdevice,
- * so setup the struct
- */
- subpriv->dio.intr.asic = asic;
- subpriv->dio.intr.active = 0;
- subpriv->dio.intr.stop_count = 0;
- subpriv->dio.intr.first_chan = byte_no * 8;
- subpriv->dio.intr.asic_chan = thisasic_chanct;
- subpriv->dio.intr.num_asic_chans =
- s->n_chan - subpriv->dio.intr.first_chan;
- s->cancel = pcmmio_cancel;
- s->do_cmd = pcmmio_cmd;
- s->do_cmdtest = pcmmio_cmdtest;
- s->len_chanlist =
- subpriv->dio.intr.num_asic_chans;
- }
- thisasic_chanct += CHANS_PER_PORT;
- }
- spin_lock_init(&subpriv->dio.intr.spinlock);
-
- chans_left -= s->n_chan;
-
- if (!chans_left) {
- /*
- * reset the asic to our first asic,
- * to do intr subdevs
- */
- asic = 0;
- port = 0;
- }
-
- }
-
- init_asics(dev); /* clear out all the registers, basically */
-
- for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], interrupt_pcmmio,
- IRQF_SHARED, thisboard->name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
- }
- devpriv->asics[asic].irq = irq[asic];
- }
-
- dev->irq = irq[0]; /*
- * grr.. wish comedi dev struct supported
- * multiple irqs..
- */
-
- if (irq[0]) {
- printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
- if (thisboard->dio_num_asics == 2 && irq[1])
- printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
- dev->minor, irq[1]);
- } else {
- printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
- }
-
- printk(KERN_INFO "comedi%d: attached\n", dev->minor);
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmmio_detach(struct comedi_device *dev)
-{
- int i;
-
- printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, thisboard->total_iosize);
-
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv && devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
-
- if (devpriv && devpriv->sprivs)
- kfree(devpriv->sprivs);
-
- return 0;
-}
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -667,7 +337,7 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev,
}
#ifdef DAMMIT_ITS_BROKEN
/* DEBUG */
- printk("data_out_byte %02x\n", (unsigned)byte);
+ printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
#endif
/* save the digital input lines for this byte.. */
s->state |= ((unsigned int)byte) << offset;
@@ -751,6 +421,21 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+ if (asic < 0 || asic >= thisboard->dio_num_asics)
+ return; /* paranoia */
+ if (page < 0 || page >= NUM_PAGES)
+ return; /* more paranoia */
+
+ devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+ devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+ /* now write out the shadow register */
+ outb(devpriv->asics[asic].pagelock,
+ devpriv->asics[asic].iobase + REG_PAGELOCK);
+}
+
static void init_asics(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -788,21 +473,6 @@ static void init_asics(struct comedi_device *dev)
}
}
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
- if (asic < 0 || asic >= thisboard->dio_num_asics)
- return; /* paranoia */
- if (page < 0 || page >= NUM_PAGES)
- return; /* more paranoia */
-
- devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
- devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- devpriv->asics[asic].iobase + REG_PAGELOCK);
-}
-
#ifdef notused
static void lock_port(struct comedi_device *dev, int asic, int port)
{
@@ -831,6 +501,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port)
}
#endif /* notused */
+static void pcmmio_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ int nports, firstport, asic, port;
+
+ asic = subpriv->dio.intr.asic;
+ if (asic < 0)
+ return; /* not an interrupt subdev */
+
+ subpriv->dio.intr.enabled_mask = 0;
+ subpriv->dio.intr.active = 0;
+ s->async->inttrig = 0;
+ nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
+ firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
+ switch_page(dev, asic, PAGE_ENAB);
+ for (port = firstport; port < firstport + nports; ++port) {
+ /* disable all intrs for this subdev.. */
+ outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ }
+}
+
static irqreturn_t interrupt_pcmmio(int irq, void *d)
{
int asic, got1 = 0;
@@ -991,27 +682,6 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d)
return IRQ_HANDLED;
}
-static void pcmmio_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- int nports, firstport, asic, port;
-
- asic = subpriv->dio.intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
-
- subpriv->dio.intr.enabled_mask = 0;
- subpriv->dio.intr.active = 0;
- s->async->inttrig = 0;
- nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- /* disable all intrs for this subdev.. */
- outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
- }
-}
-
static int pcmmio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1340,22 +1010,261 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
+static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
+ thisasic_chanct = 0;
+ unsigned long iobase;
+ unsigned int irq[MAX_ASICS];
+
+ iobase = it->options[0];
+ irq[0] = it->options[1];
+
+ printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
+ dev->driver->driver_name, iobase);
+
+ dev->iobase = iobase;
+
+ if (!iobase || !request_region(iobase,
+ thisboard->total_iosize,
+ dev->driver->driver_name)) {
+ printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
+ return -EIO;
+ }
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
+ printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+
+ for (asic = 0; asic < MAX_ASICS; ++asic) {
+ devpriv->asics[asic].num = asic;
+ devpriv->asics[asic].iobase =
+ dev->iobase + 16 + asic * ASIC_IOSIZE;
+ /*
+ * this gets actually set at the end of this function when we
+ * request_irqs
+ */
+ devpriv->asics[asic].irq = 0;
+ spin_lock_init(&devpriv->asics[asic].spinlock);
+ }
+
+ chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
+ n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
+ n_subdevs = n_dio_subdevs + 2;
+ devpriv->sprivs =
+ kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
+ GFP_KERNEL);
+ if (!devpriv->sprivs) {
+ printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
+ */
+ if (alloc_subdevices(dev, n_subdevs) < 0) {
+ printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+
+ /* First, AI */
+ sdev_no = 0;
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = thisboard->ai_range_table;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+ s->type = COMEDI_SUBD_AI;
+ s->n_chan = thisboard->n_ai_chans;
+ s->len_chanlist = s->n_chan;
+ s->insn_read = thisboard->ai_rinsn;
+ subpriv->iobase = dev->iobase + 0;
+ /* initialize the resource enable register by clearing it */
+ outb(0, subpriv->iobase + 3);
+ outb(0, subpriv->iobase + 4 + 3);
+
+ /* Next, AO */
+ ++sdev_no;
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = (1 << thisboard->ao_bits) - 1;
+ s->range_table = thisboard->ao_range_table;
+ s->subdev_flags = SDF_READABLE;
+ s->type = COMEDI_SUBD_AO;
+ s->n_chan = thisboard->n_ao_chans;
+ s->len_chanlist = s->n_chan;
+ s->insn_read = thisboard->ao_rinsn;
+ s->insn_write = thisboard->ao_winsn;
+ subpriv->iobase = dev->iobase + 8;
+ /* initialize the resource enable register by clearing it */
+ outb(0, subpriv->iobase + 3);
+ outb(0, subpriv->iobase + 4 + 3);
+
+ ++sdev_no;
+ port = 0;
+ asic = 0;
+ for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+ int byte_no;
+
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->type = COMEDI_SUBD_DIO;
+ s->insn_bits = pcmmio_dio_insn_bits;
+ s->insn_config = pcmmio_dio_insn_config;
+ s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+ subpriv->dio.intr.asic = -1;
+ subpriv->dio.intr.first_chan = -1;
+ subpriv->dio.intr.asic_chan = -1;
+ subpriv->dio.intr.num_asic_chans = -1;
+ subpriv->dio.intr.active = 0;
+ s->len_chanlist = 1;
+
+ /* save the ioport address for each 'port' of 8 channels in the
+ subdevice */
+ for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+ if (port >= PORTS_PER_ASIC) {
+ port = 0;
+ ++asic;
+ thisasic_chanct = 0;
+ }
+ subpriv->iobases[byte_no] =
+ devpriv->asics[asic].iobase + port;
+
+ if (thisasic_chanct <
+ CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+ && subpriv->dio.intr.asic < 0) {
+ /*
+ * this is an interrupt subdevice,
+ * so setup the struct
+ */
+ subpriv->dio.intr.asic = asic;
+ subpriv->dio.intr.active = 0;
+ subpriv->dio.intr.stop_count = 0;
+ subpriv->dio.intr.first_chan = byte_no * 8;
+ subpriv->dio.intr.asic_chan = thisasic_chanct;
+ subpriv->dio.intr.num_asic_chans =
+ s->n_chan - subpriv->dio.intr.first_chan;
+ s->cancel = pcmmio_cancel;
+ s->do_cmd = pcmmio_cmd;
+ s->do_cmdtest = pcmmio_cmdtest;
+ s->len_chanlist =
+ subpriv->dio.intr.num_asic_chans;
+ }
+ thisasic_chanct += CHANS_PER_PORT;
+ }
+ spin_lock_init(&subpriv->dio.intr.spinlock);
+
+ chans_left -= s->n_chan;
+
+ if (!chans_left) {
+ /*
+ * reset the asic to our first asic,
+ * to do intr subdevs
+ */
+ asic = 0;
+ port = 0;
+ }
+
+ }
+
+ init_asics(dev); /* clear out all the registers, basically */
+
+ for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+ if (irq[asic]
+ && request_irq(irq[asic], interrupt_pcmmio,
+ IRQF_SHARED, thisboard->name, dev)) {
+ int i;
+ /* unroll the allocated irqs.. */
+ for (i = asic - 1; i >= 0; --i) {
+ free_irq(irq[i], dev);
+ devpriv->asics[i].irq = irq[i] = 0;
+ }
+ irq[asic] = 0;
+ }
+ devpriv->asics[asic].irq = irq[asic];
+ }
+
+ dev->irq = irq[0]; /*
+ * grr.. wish comedi dev struct supported
+ * multiple irqs..
+ */
+
+ if (irq[0]) {
+ printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
+ if (thisboard->dio_num_asics == 2 && irq[1])
+ printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
+ dev->minor, irq[1]);
+ } else {
+ printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
+ }
+
+ printk(KERN_INFO "comedi%d: attached\n", dev->minor);
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmmio_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ int i;
+
+ if (dev->iobase)
+ release_region(dev->iobase, thisboard->total_iosize);
+ for (i = 0; i < MAX_ASICS; ++i) {
+ if (devpriv && devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
+ if (devpriv && devpriv->sprivs)
+ kfree(devpriv->sprivs);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmmio_board pcmmio_boards[] = {
+ {
+ .name = "pcmmio",
+ .dio_num_asics = 1,
+ .dio_num_ports = 6,
+ .total_iosize = 32,
+ .ai_bits = 16,
+ .ao_bits = 16,
+ .n_ai_chans = 16,
+ .n_ao_chans = 8,
+ .ai_range_table = &ranges_ai,
+ .ao_range_table = &ranges_ao,
+ .ai_rinsn = ai_rinsn,
+ .ao_rinsn = ao_rinsn,
+ .ao_winsn = ao_winsn
+ },
+};
+
+static struct comedi_driver pcmmio_driver = {
+ .driver_name = "pcmmio",
+ .module = THIS_MODULE,
+ .attach = pcmmio_attach,
+ .detach = pcmmio_detach,
+ .board_name = &pcmmio_boards[0].name,
+ .offset = sizeof(struct pcmmio_board),
+ .num_names = ARRAY_SIZE(pcmmio_boards),
+};
+module_comedi_driver(pcmmio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 661ba2e..623381d5 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -155,19 +155,6 @@ struct pcmuio_board {
const int num_ports;
};
-static const struct pcmuio_board pcmuio_boards[] = {
- {
- .name = "pcmuio48",
- .num_asics = 1,
- .num_ports = 6,
- },
- {
- .name = "pcmuio96",
- .num_asics = 2,
- .num_ports = 12,
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -218,262 +205,6 @@ struct pcmuio_private {
*/
#define devpriv ((struct pcmuio_private *)dev->private)
#define subpriv ((struct pcmuio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmuio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmuio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmuio",
- .module = THIS_MODULE,
- .attach = pcmuio_attach,
- .detach = pcmuio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmuio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmuio_boards[0].name,
- .offset = sizeof(struct pcmuio_board),
- .num_names = ARRAY_SIZE(pcmuio_boards),
-};
-
-static int pcmuio_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcmuio_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmuio(int irq, void *d);
-static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
- unsigned long iobase;
- unsigned int irq[MAX_ASICS];
-
- iobase = it->options[0];
- irq[0] = it->options[1];
- irq[1] = it->options[2];
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
- driver.driver_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase,
- thisboard->num_asics * ASIC_IOSIZE,
- driver.driver_name)) {
- dev_err(dev->hw_dev, "I/O port conflict\n");
- return -EIO;
- }
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
- dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
- return -ENOMEM;
- }
-
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- devpriv->asics[asic].num = asic;
- devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
- devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
- this function when we
- request_irqs */
- spin_lock_init(&devpriv->asics[asic].spinlock);
- }
-
- chans_left = CHANS_PER_ASIC * thisboard->num_asics;
- n_subdevs = CALC_N_SUBDEVS(chans_left);
- devpriv->sprivs =
- kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
- GFP_KERNEL);
- if (!devpriv->sprivs) {
- dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
- return -ENOMEM;
- }
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
- * 96-channel version of the board.
- */
- if (alloc_subdevices(dev, n_subdevs) < 0) {
- dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
- return -ENOMEM;
- }
-
- port = 0;
- asic = 0;
- for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
- int byte_no;
-
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmuio_dio_insn_bits;
- s->insn_config = pcmuio_dio_insn_config;
- s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
- subpriv->intr.asic = -1;
- subpriv->intr.first_chan = -1;
- subpriv->intr.asic_chan = -1;
- subpriv->intr.num_asic_chans = -1;
- subpriv->intr.active = 0;
- s->len_chanlist = 1;
-
- /* save the ioport address for each 'port' of 8 channels in the
- subdevice */
- for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
- if (port >= PORTS_PER_ASIC) {
- port = 0;
- ++asic;
- thisasic_chanct = 0;
- }
- subpriv->iobases[byte_no] =
- devpriv->asics[asic].iobase + port;
-
- if (thisasic_chanct <
- CHANS_PER_PORT * INTR_PORTS_PER_ASIC
- && subpriv->intr.asic < 0) {
- /* this is an interrupt subdevice, so setup the struct */
- subpriv->intr.asic = asic;
- subpriv->intr.active = 0;
- subpriv->intr.stop_count = 0;
- subpriv->intr.first_chan = byte_no * 8;
- subpriv->intr.asic_chan = thisasic_chanct;
- subpriv->intr.num_asic_chans =
- s->n_chan - subpriv->intr.first_chan;
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = pcmuio_cancel;
- s->do_cmd = pcmuio_cmd;
- s->do_cmdtest = pcmuio_cmdtest;
- s->len_chanlist = subpriv->intr.num_asic_chans;
- }
- thisasic_chanct += CHANS_PER_PORT;
- }
- spin_lock_init(&subpriv->intr.spinlock);
-
- chans_left -= s->n_chan;
-
- if (!chans_left) {
- asic = 0; /* reset the asic to our first asic, to do intr subdevs */
- port = 0;
- }
-
- }
-
- init_asics(dev); /* clear out all the registers, basically */
-
- for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], interrupt_pcmuio,
- IRQF_SHARED, thisboard->name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
- }
- devpriv->asics[asic].irq = irq[asic];
- }
-
- dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
- irqs.. */
-
- if (irq[0]) {
- dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
- if (irq[1] && thisboard->num_asics == 2)
- dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
- } else {
- dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
- }
-
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmuio_detach(struct comedi_device *dev)
-{
- int i;
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
- driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
-
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
-
- if (devpriv && devpriv->sprivs)
- kfree(devpriv->sprivs);
-
- return 0;
-}
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -621,6 +352,21 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+ if (asic < 0 || asic >= thisboard->num_asics)
+ return; /* paranoia */
+ if (page < 0 || page >= NUM_PAGES)
+ return; /* more paranoia */
+
+ devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+ devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+ /* now write out the shadow register */
+ outb(devpriv->asics[asic].pagelock,
+ dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
+}
+
static void init_asics(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -658,21 +404,6 @@ static void init_asics(struct comedi_device *dev)
}
}
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
- if (asic < 0 || asic >= thisboard->num_asics)
- return; /* paranoia */
- if (page < 0 || page >= NUM_PAGES)
- return; /* more paranoia */
-
- devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
- devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
-}
-
#ifdef notused
static void lock_port(struct comedi_device *dev, int asic, int port)
{
@@ -700,6 +431,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port)
}
#endif /* notused */
+static void pcmuio_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ int nports, firstport, asic, port;
+
+ asic = subpriv->intr.asic;
+ if (asic < 0)
+ return; /* not an interrupt subdev */
+
+ subpriv->intr.enabled_mask = 0;
+ subpriv->intr.active = 0;
+ s->async->inttrig = 0;
+ nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
+ firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
+ switch_page(dev, asic, PAGE_ENAB);
+ for (port = firstport; port < firstport + nports; ++port) {
+ /* disable all intrs for this subdev.. */
+ outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ }
+}
+
static irqreturn_t interrupt_pcmuio(int irq, void *d)
{
int asic, got1 = 0;
@@ -852,27 +604,6 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d)
return IRQ_HANDLED;
}
-static void pcmuio_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- int nports, firstport, asic, port;
-
- asic = subpriv->intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
-
- subpriv->intr.enabled_mask = 0;
- subpriv->intr.active = 0;
- s->async->inttrig = 0;
- nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- /* disable all intrs for this subdev.. */
- outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
- }
-}
-
static int pcmuio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1014,22 +745,205 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
return comedi_pcm_cmdtest(dev, s, cmd);
}
+static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
+ unsigned long iobase;
+ unsigned int irq[MAX_ASICS];
+
+ iobase = it->options[0];
+ irq[0] = it->options[1];
+ irq[1] = it->options[2];
+
+ dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
+ dev->driver->driver_name, iobase);
+
+ dev->iobase = iobase;
+
+ if (!iobase || !request_region(iobase,
+ thisboard->num_asics * ASIC_IOSIZE,
+ dev->driver->driver_name)) {
+ dev_err(dev->hw_dev, "I/O port conflict\n");
+ return -EIO;
+ }
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
+ dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
+ return -ENOMEM;
+ }
+
+ for (asic = 0; asic < MAX_ASICS; ++asic) {
+ devpriv->asics[asic].num = asic;
+ devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
+ devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
+ this function when we
+ request_irqs */
+ spin_lock_init(&devpriv->asics[asic].spinlock);
+ }
+
+ chans_left = CHANS_PER_ASIC * thisboard->num_asics;
+ n_subdevs = CALC_N_SUBDEVS(chans_left);
+ devpriv->sprivs =
+ kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
+ GFP_KERNEL);
+ if (!devpriv->sprivs) {
+ dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
+ return -ENOMEM;
+ }
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+ * 96-channel version of the board.
+ */
+ if (alloc_subdevices(dev, n_subdevs) < 0) {
+ dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
+ return -ENOMEM;
+ }
+
+ port = 0;
+ asic = 0;
+ for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+ int byte_no;
+
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->type = COMEDI_SUBD_DIO;
+ s->insn_bits = pcmuio_dio_insn_bits;
+ s->insn_config = pcmuio_dio_insn_config;
+ s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+ subpriv->intr.asic = -1;
+ subpriv->intr.first_chan = -1;
+ subpriv->intr.asic_chan = -1;
+ subpriv->intr.num_asic_chans = -1;
+ subpriv->intr.active = 0;
+ s->len_chanlist = 1;
+
+ /* save the ioport address for each 'port' of 8 channels in the
+ subdevice */
+ for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+ if (port >= PORTS_PER_ASIC) {
+ port = 0;
+ ++asic;
+ thisasic_chanct = 0;
+ }
+ subpriv->iobases[byte_no] =
+ devpriv->asics[asic].iobase + port;
+
+ if (thisasic_chanct <
+ CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+ && subpriv->intr.asic < 0) {
+ /* this is an interrupt subdevice, so setup the struct */
+ subpriv->intr.asic = asic;
+ subpriv->intr.active = 0;
+ subpriv->intr.stop_count = 0;
+ subpriv->intr.first_chan = byte_no * 8;
+ subpriv->intr.asic_chan = thisasic_chanct;
+ subpriv->intr.num_asic_chans =
+ s->n_chan - subpriv->intr.first_chan;
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->cancel = pcmuio_cancel;
+ s->do_cmd = pcmuio_cmd;
+ s->do_cmdtest = pcmuio_cmdtest;
+ s->len_chanlist = subpriv->intr.num_asic_chans;
+ }
+ thisasic_chanct += CHANS_PER_PORT;
+ }
+ spin_lock_init(&subpriv->intr.spinlock);
+
+ chans_left -= s->n_chan;
+
+ if (!chans_left) {
+ asic = 0; /* reset the asic to our first asic, to do intr subdevs */
+ port = 0;
+ }
+
+ }
+
+ init_asics(dev); /* clear out all the registers, basically */
+
+ for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+ if (irq[asic]
+ && request_irq(irq[asic], interrupt_pcmuio,
+ IRQF_SHARED, thisboard->name, dev)) {
+ int i;
+ /* unroll the allocated irqs.. */
+ for (i = asic - 1; i >= 0; --i) {
+ free_irq(irq[i], dev);
+ devpriv->asics[i].irq = irq[i] = 0;
+ }
+ irq[asic] = 0;
+ }
+ devpriv->asics[asic].irq = irq[asic];
+ }
+
+ dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
+ irqs.. */
+
+ if (irq[0]) {
+ dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
+ if (irq[1] && thisboard->num_asics == 2)
+ dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
+ } else {
+ dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
+ }
+
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmuio_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ int i;
+
+ if (dev->iobase)
+ release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
+ for (i = 0; i < MAX_ASICS; ++i) {
+ if (devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
+ if (devpriv && devpriv->sprivs)
+ kfree(devpriv->sprivs);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmuio_board pcmuio_boards[] = {
+ {
+ .name = "pcmuio48",
+ .num_asics = 1,
+ .num_ports = 6,
+ }, {
+ .name = "pcmuio96",
+ .num_asics = 2,
+ .num_ports = 12,
+ },
+};
+
+static struct comedi_driver pcmuio_driver = {
+ .driver_name = "pcmuio",
+ .module = THIS_MODULE,
+ .attach = pcmuio_attach,
+ .detach = pcmuio_detach,
+ .board_name = &pcmuio_boards[0].name,
+ .offset = sizeof(struct pcmuio_board),
+ .num_names = ARRAY_SIZE(pcmuio_boards),
+};
+module_comedi_driver(pcmuio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 831a576..e712048 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -41,20 +41,6 @@ Configuration options:
#include <linux/ioport.h>
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int poc_detach(struct comedi_device *dev);
-static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcl733_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcl734_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
struct boarddef_struct {
const char *name;
unsigned int iosize;
@@ -70,108 +56,9 @@ struct boarddef_struct {
struct comedi_insn *, unsigned int *);
const struct comedi_lrange *range;
};
-static const struct boarddef_struct boards[] = {
- {
- .name = "dac02",
- .iosize = 8,
- /* .setup = dac02_setup, */
- .type = COMEDI_SUBD_AO,
- .n_chan = 2,
- .n_bits = 12,
- .winsn = dac02_ao_winsn,
- .rinsn = readback_insn,
- .range = &range_unknown,
- },
- {
- .name = "pcl733",
- .iosize = 4,
- .type = COMEDI_SUBD_DI,
- .n_chan = 32,
- .n_bits = 1,
- .insnbits = pcl733_insn_bits,
- .range = &range_digital,
- },
- {
- .name = "pcl734",
- .iosize = 4,
- .type = COMEDI_SUBD_DO,
- .n_chan = 32,
- .n_bits = 1,
- .insnbits = pcl734_insn_bits,
- .range = &range_digital,
- },
-};
-#define n_boards ARRAY_SIZE(boards)
#define this_board ((const struct boarddef_struct *)dev->board_ptr)
-static struct comedi_driver driver_poc = {
- .driver_name = "poc",
- .module = THIS_MODULE,
- .attach = poc_attach,
- .detach = poc_detach,
- .board_name = &boards[0].name,
- .num_names = n_boards,
- .offset = sizeof(boards[0]),
-};
-
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iosize;
-
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
- this_board->name, iobase);
-
- dev->board_name = this_board->name;
-
- if (iobase == 0) {
- printk(KERN_ERR "io base address required\n");
- return -EINVAL;
- }
-
- iosize = this_board->iosize;
- /* check if io addresses are available */
- if (!request_region(iobase, iosize, "dac02")) {
- printk(KERN_ERR "I/O port conflict: failed to allocate ports "
- "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
- return -EIO;
- }
- dev->iobase = iobase;
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
- if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
- return -ENOMEM;
-
- /* analog output subdevice */
- s = dev->subdevices + 0;
- s->type = this_board->type;
- s->n_chan = this_board->n_chan;
- s->maxdata = (1 << this_board->n_bits) - 1;
- s->range_table = this_board->range;
- s->insn_write = this_board->winsn;
- s->insn_read = this_board->rinsn;
- s->insn_bits = this_board->insnbits;
- if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
- s->subdev_flags = SDF_WRITABLE;
-
- return 0;
-}
-
-static int poc_detach(struct comedi_device *dev)
-{
- /* only free stuff if it has been allocated by _attach */
- if (dev->iobase)
- release_region(dev->iobase, this_board->iosize);
-
- printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor);
-
- return 0;
-}
-
static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -248,18 +135,98 @@ static int pcl734_insn_bits(struct comedi_device *dev,
return 2;
}
-static int __init driver_poc_init_module(void)
+static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_driver_register(&driver_poc);
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+ unsigned int iosize;
+
+ iobase = it->options[0];
+ printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
+ this_board->name, iobase);
+
+ dev->board_name = this_board->name;
+
+ if (iobase == 0) {
+ printk(KERN_ERR "io base address required\n");
+ return -EINVAL;
+ }
+
+ iosize = this_board->iosize;
+ /* check if io addresses are available */
+ if (!request_region(iobase, iosize, "dac02")) {
+ printk(KERN_ERR "I/O port conflict: failed to allocate ports "
+ "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+ if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
+ return -ENOMEM;
+
+ /* analog output subdevice */
+ s = dev->subdevices + 0;
+ s->type = this_board->type;
+ s->n_chan = this_board->n_chan;
+ s->maxdata = (1 << this_board->n_bits) - 1;
+ s->range_table = this_board->range;
+ s->insn_write = this_board->winsn;
+ s->insn_read = this_board->rinsn;
+ s->insn_bits = this_board->insnbits;
+ if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
+ s->subdev_flags = SDF_WRITABLE;
+
+ return 0;
}
-static void __exit driver_poc_cleanup_module(void)
+static void poc_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_poc);
+ if (dev->iobase)
+ release_region(dev->iobase, this_board->iosize);
}
-module_init(driver_poc_init_module);
-module_exit(driver_poc_cleanup_module);
+static const struct boarddef_struct boards[] = {
+ {
+ .name = "dac02",
+ .iosize = 8,
+ /* .setup = dac02_setup, */
+ .type = COMEDI_SUBD_AO,
+ .n_chan = 2,
+ .n_bits = 12,
+ .winsn = dac02_ao_winsn,
+ .rinsn = readback_insn,
+ .range = &range_unknown,
+ }, {
+ .name = "pcl733",
+ .iosize = 4,
+ .type = COMEDI_SUBD_DI,
+ .n_chan = 32,
+ .n_bits = 1,
+ .insnbits = pcl733_insn_bits,
+ .range = &range_digital,
+ }, {
+ .name = "pcl734",
+ .iosize = 4,
+ .type = COMEDI_SUBD_DO,
+ .n_chan = 32,
+ .n_bits = 1,
+ .insnbits = pcl734_insn_bits,
+ .range = &range_digital,
+ },
+};
+
+static struct comedi_driver poc_driver = {
+ .driver_name = "poc",
+ .module = THIS_MODULE,
+ .attach = poc_attach,
+ .detach = poc_detach,
+ .board_name = &boards[0].name,
+ .num_names = ARRAY_SIZE(boards),
+ .offset = sizeof(boards[0]),
+};
+module_comedi_driver(poc_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index e0bb734..2f130b3 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -181,7 +181,7 @@ static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} };
/* comedi interface code */
static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int daqp_detach(struct comedi_device *dev);
+static void daqp_detach(struct comedi_device *dev);
static struct comedi_driver driver_daqp = {
.driver_name = "quatech_daqp_cs",
.module = THIS_MODULE,
@@ -922,15 +922,9 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/* daqp_detach (called from comedi_comdig) does nothing. If the PCMCIA
- * card is removed, daqp_cs_detach() is called by the pcmcia subsystem.
- */
-
-static int daqp_detach(struct comedi_device *dev)
+static void daqp_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor);
-
- return 0;
+ /* Nothing to cleanup */
}
/*====================================================================
@@ -1010,8 +1004,6 @@ static void daqp_cs_detach(struct pcmcia_device *link)
{
struct local_info_t *dev = link->priv;
- dev_dbg(&link->dev, "daqp_cs_detach\n");
-
dev->stop = 1;
daqp_cs_release(link);
@@ -1019,7 +1011,7 @@ static void daqp_cs_detach(struct pcmcia_device *link)
dev_table[dev->table_index] = NULL;
kfree(dev);
-} /* daqp_cs_detach */
+}
static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
{
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 1384419..1678a0c 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -328,14 +328,6 @@ static const struct rtdBoard rtd520Boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -347,13 +339,13 @@ MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
*/
struct rtdPrivate {
/* memory mapped board structures */
- void *las0;
- void *las1;
- void *lcfg;
+ void __iomem *las0;
+ void __iomem *las1;
+ void __iomem *lcfg;
unsigned long intCount; /* interrupt count */
long aiCount; /* total transfer size (samples) */
- int transCount; /* # to tranfer data. 0->1/2FIFO */
+ int transCount; /* # to transfer data. 0->1/2FIFO */
int flags; /* flag event modes */
/* PCI device info */
@@ -377,8 +369,11 @@ struct rtdPrivate {
u8 utcCtrl[4]; /* crtl mode for 3 utc + read back */
u8 dioStatus; /* could be read back (dio0Ctrl) */
#ifdef USE_DMA
- /* Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that size.
- After transferring, interrupt processes 1/2 FIFO and passes to comedi */
+ /*
+ * Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that
+ * size. After transferring, interrupt processes 1/2 FIFO and
+ * passes to comedi
+ */
s16 dma0Offset; /* current processing offset (0, 1/2) */
uint16_t *dma0Buff[DMA_CHAIN_COUNT]; /* DMA buffers (for ADC) */
dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT]; /* physical addresses */
@@ -581,7 +576,8 @@ struct rtdPrivate {
/* User output N source select (write only) */
#define RtdUsrOutSource(dev, n, v) \
- writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT))
+ writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : \
+ LAS0_UOUT1_SELECT))
/* Digital IO */
#define RtdDio0Read(dev) \
@@ -608,7 +604,8 @@ struct rtdPrivate {
/* Write one data value (sign + 12bit + marker bits) */
/* Note: matches what DMA would put. Actual value << 3 */
#define RtdDacFifoPut(dev, n, v) \
- writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO))
+ writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : \
+ LAS1_DAC2_FIFO))
/* Start single DAC conversion */
#define RtdDacUpdate(dev, n) \
@@ -625,7 +622,8 @@ struct rtdPrivate {
/* Reset DAC FIFO */
#define RtdDacClearFifo(dev, n) \
- writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET))
+ writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : \
+ LAS0_DAC2_RESET))
/* Set source for DMA 0 (write only, shadow?) */
#define RtdDma0Source(dev, n) \
@@ -705,22 +703,6 @@ struct rtdPrivate {
#define RtdDma1Status(dev) \
readb(devpriv->lcfg+LCFG_DMACSR1)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attac/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int rtd_detach(struct comedi_device *dev);
-
-static struct comedi_driver rtd520Driver = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = rtd_attach,
- .detach = rtd_detach,
-};
-
static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -737,7 +719,10 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd);
static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-/* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */
+/*
+ * static int rtd_ai_poll(struct comedi_device *dev,
+ * struct comedi_subdevice *s);
+ */
static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
static irqreturn_t rtd_interrupt(int irq, void *d);
static int rtd520_probe_fifo_depth(struct comedi_device *dev);
@@ -857,7 +842,9 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
}
- /* Undocumented EPLD version (doesn't match RTD driver results) */
+ /*
+ * Undocumented EPLD version (doesn't match RTD driver results)
+ */
/*DPRINTK ("rtd520: Reading epld from %p\n",
devpriv->las0+0);
epld_version = readl (devpriv->las0+0);
@@ -970,9 +957,11 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#ifdef USE_DMA
if (dev->irq > 0) {
printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
- /* The PLX9080 has 2 DMA controllers, but there could be 4 sources:
- ADC, digital, DAC1, and DAC2. Since only the ADC supports cmd mode
- right now, this isn't an issue (yet) */
+ /*
+ * The PLX9080 has 2 DMA controllers, but there could be
+ * 4 sources: ADC, digital, DAC1, and DAC2. Since only the
+ * ADC supports cmd mode right now, this isn't an issue (yet)
+ */
devpriv->dma0Offset = 0;
for (index = 0; index < DMA_CHAIN_COUNT; index++) {
@@ -988,10 +977,14 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
/*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
index,
- devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]); */
+ devpriv->dma0Buff[index],
+ devpriv->dma0BuffPhysAddr[index]); */
}
- /* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */
+ /*
+ * setup DMA descriptor ring (use cpu_to_le32 for byte
+ * ordering?)
+ */
devpriv->dma0Chain =
pci_alloc_consistent(devpriv->pci_dev,
sizeof(struct plx_dma_desc) *
@@ -1088,30 +1081,12 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int rtd_detach(struct comedi_device *dev)
+static void rtd_detach(struct comedi_device *dev)
{
#ifdef USE_DMA
int index;
#endif
- DPRINTK("comedi%d: rtd520: removing (%ld ints)\n",
- dev->minor, (devpriv ? devpriv->intCount : 0L));
- if (devpriv && devpriv->lcfg) {
- DPRINTK
- ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n",
- 0xffff & RtdInterruptStatus(dev),
- 0xffff & RtdInterruptOverrunStatus(dev),
- (0xffff & RtdFifoStatus(dev)) ^ 0x6666);
- }
-
if (devpriv) {
/* Shut down any board ops by resetting it */
#ifdef USE_DMA
@@ -1148,37 +1123,24 @@ static int rtd_detach(struct comedi_device *dev)
devpriv->dma0Chain = NULL;
}
#endif /* USE_DMA */
-
- /* release IRQ */
if (dev->irq) {
- /* disable interrupt controller */
RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
& ~(ICS_PLIE | ICS_DMA0_E |
ICS_DMA1_E));
free_irq(dev->irq, dev);
}
-
- /* release all regions that were allocated */
if (devpriv->las0)
iounmap(devpriv->las0);
-
if (devpriv->las1)
iounmap(devpriv->las1);
-
if (devpriv->lcfg)
iounmap(devpriv->lcfg);
-
if (devpriv->pci_dev) {
if (devpriv->got_regions)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
-
- printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor);
-
- return 0;
}
/*
@@ -1278,7 +1240,8 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev)
}
}
if (i == limit) {
- printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME);
+ printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n",
+ DRV_NAME);
return -EIO;
}
RtdAdcClearFifo(dev);
@@ -1378,9 +1341,10 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
d = RtdAdcFifoGet(dev); /* get 2s comp value */
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
- sample = d + 2048; /* convert to comedi unsigned data */
- else
+ if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ /* convert to comedi unsigned data */
+ sample = d + 2048;
+ } else
sample = d;
if (!comedi_buf_put(s->async, sample))
@@ -1406,9 +1370,10 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
}
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
- sample = d + 2048; /* convert to comedi unsigned data */
- else
+ if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ /* convert to comedi unsigned data */
+ sample = d + 2048;
+ } else
sample = d;
if (!comedi_buf_put(s->async, sample))
@@ -1525,7 +1490,9 @@ static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s)
comedi_buf_memcpy_to(s->async, 0, dp, n);
comedi_buf_write_free(s->async, n);
- /* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */
+ /*
+ * always at least 1 scan -- 1/2 FIFO is larger than our max scan list
+ */
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) { /* next buffer */
@@ -1989,7 +1956,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
(TRANS_TARGET_PERIOD * cmd->chanlist_len) /
cmd->scan_begin_arg;
if (devpriv->transCount < cmd->chanlist_len) {
- /* tranfer after each scan (and avoid 0) */
+ /* transfer after each scan (and avoid 0) */
devpriv->transCount = cmd->chanlist_len;
} else { /* make a multiple of scan length */
devpriv->transCount =
@@ -2005,12 +1972,12 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->transCount = 0;
devpriv->flags &= ~SEND_EOS;
} else {
- /* interrupt for each tranfer */
+ /* interrupt for each transfer */
RtdAboutCounter(dev, devpriv->transCount - 1);
}
DPRINTK
- ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n",
+ ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n",
cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
cmd->scan_begin_arg, devpriv->flags);
} else { /* unknown timing, just use 1/2 FIFO */
@@ -2348,47 +2315,38 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
return 1;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver rtd520_driver = {
+ .driver_name = "rtd520",
+ .module = THIS_MODULE,
+ .attach = rtd_attach,
+ .detach = rtd_detach,
+};
+
+static int __devinit rtd520_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, rtd520Driver.driver_name);
+ return comedi_pci_auto_config(dev, &rtd520_driver);
}
-static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev)
+static void __devexit rtd520_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver rtd520Driver_pci_driver = {
- .id_table = rtd520_pci_table,
- .probe = &rtd520Driver_pci_probe,
- .remove = __devexit_p(&rtd520Driver_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
+ { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
-static int __init rtd520Driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&rtd520Driver);
- if (retval < 0)
- return retval;
-
- rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name;
- return pci_register_driver(&rtd520Driver_pci_driver);
-}
-
-static void __exit rtd520Driver_cleanup_module(void)
-{
- pci_unregister_driver(&rtd520Driver_pci_driver);
- comedi_driver_unregister(&rtd520Driver);
-}
-
-module_init(rtd520Driver_init_module);
-module_exit(rtd520Driver_cleanup_module);
+static struct pci_driver rtd520_pci_driver = {
+ .name = "rtd520",
+ .id_table = rtd520_pci_table,
+ .probe = rtd520_pci_probe,
+ .remove = __devexit_p(rtd520_pci_remove),
+};
+module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 72042b8..f0eb52a 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -138,39 +138,8 @@ struct rti800_board {
int has_ao;
};
-static const struct rti800_board boardtypes[] = {
- {"rti800", 0},
- {"rti815", 1},
-};
-
#define this_board ((const struct rti800_board *)dev->board_ptr)
-static int rti800_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int rti800_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti800 = {
- .driver_name = "rti800",
- .module = THIS_MODULE,
- .attach = rti800_attach,
- .detach = rti800_detach,
- .num_names = ARRAY_SIZE(boardtypes),
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct rti800_board),
-};
-
-static int __init driver_rti800_init_module(void)
-{
- return comedi_driver_register(&driver_rti800);
-}
-
-static void __exit driver_rti800_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_rti800);
-}
-
-module_init(driver_rti800_init_module);
-module_exit(driver_rti800_cleanup_module);
-
static irqreturn_t rti800_interrupt(int irq, void *dev);
struct rti800_private {
@@ -474,19 +443,30 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int rti800_detach(struct comedi_device *dev)
+static void rti800_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, RTI800_SIZE);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static const struct rti800_board boardtypes[] = {
+ { "rti800", 0 },
+ { "rti815", 1 },
+};
+
+static struct comedi_driver rti800_driver = {
+ .driver_name = "rti800",
+ .module = THIS_MODULE,
+ .attach = rti800_attach,
+ .detach = rti800_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct rti800_board),
+};
+module_comedi_driver(rti800_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index f59cb11..09da5c2 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -47,29 +47,6 @@ Configuration Options:
#define RTI802_DATALOW 1
#define RTI802_DATAHIGH 2
-static int rti802_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int rti802_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti802 = {
- .driver_name = "rti802",
- .module = THIS_MODULE,
- .attach = rti802_attach,
- .detach = rti802_detach,
-};
-
-static int __init driver_rti802_init_module(void)
-{
- return comedi_driver_register(&driver_rti802);
-}
-
-static void __exit driver_rti802_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_rti802);
-}
-
-module_init(driver_rti802_init_module);
-module_exit(driver_rti802_cleanup_module);
-
struct rti802_private {
enum {
dac_2comp, dac_straight
@@ -152,16 +129,20 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int rti802_detach(struct comedi_device *dev)
+static void rti802_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, RTI802_SIZE);
-
- return 0;
}
+static struct comedi_driver rti802_driver = {
+ .driver_name = "rti802",
+ .module = THIS_MODULE,
+ .attach = rti802_attach,
+ .detach = rti802_detach,
+};
+module_comedi_driver(rti802_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 2b34dae..7a56434 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -230,287 +230,6 @@ struct s526_private {
*/
#define devpriv ((struct s526_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s526_detach(struct comedi_device *dev);
-static struct comedi_driver driver_s526 = {
- .driver_name = "s526",
- .module = THIS_MODULE,
- .attach = s526_attach,
- .detach = s526_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in s526_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &s526_boards[0].name,
- .offset = sizeof(struct s526_board),
- .num_names = ARRAY_SIZE(s526_boards),
-};
-
-static int s526_gpct_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int s526_gpct_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_gpct_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int s526_ai_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int iobase;
- int i, n;
-/* short value; */
-/* int subdev_channel = 0; */
- union cmReg cmReg;
-
- printk(KERN_INFO "comedi%d: s526: ", dev->minor);
-
- iobase = it->options[0];
- if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
- comedi_error(dev, "I/O port conflict");
- return -EIO;
- }
- dev->iobase = iobase;
-
- printk("iobase=0x%lx\n", dev->iobase);
-
- /*** make it a little quieter, exw, 8/29/06
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
- inw(ADDR_REG(s526_ports[i])));
- }
- ***/
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_ptr = &s526_boards[0];
-
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct s526_private)) < 0)
- return -ENOMEM;
-
-/*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- dev->n_subdevices = 4;
- if (alloc_subdevices(dev, dev->n_subdevices) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
- /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
- s->n_chan = thisboard->gpct_chans;
- s->maxdata = 0x00ffffff; /* 24 bit counter */
- s->insn_read = s526_gpct_rinsn;
- s->insn_config = s526_gpct_insn_config;
- s->insn_write = s526_gpct_winsn;
-
- /* Command are not implemented yet, however they are necessary to
- allocate the necessary memory for the comedi_async struct (used
- to trigger the GPCT in case of pulsegenerator function */
- /* s->do_cmd = s526_gpct_cmd; */
- /* s->do_cmdtest = s526_gpct_cmdtest; */
- /* s->cancel = s526_gpct_cancel; */
-
- s = dev->subdevices + 1;
- /* dev->read_subdev=s; */
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- /* we support differential */
- s->subdev_flags = SDF_READABLE | SDF_DIFF;
- /* channels 0 to 7 are the regular differential inputs */
- /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
- s->n_chan = 10;
- s->maxdata = 0xffff;
- s->range_table = &range_bipolar10;
- s->len_chanlist = 16; /* This is the maximum chanlist length that
- the board can handle */
- s->insn_read = s526_ai_rinsn;
- s->insn_config = s526_ai_insn_config;
-
- s = dev->subdevices + 2;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->range_table = &range_bipolar10;
- s->insn_write = s526_ao_winsn;
- s->insn_read = s526_ao_rinsn;
-
- s = dev->subdevices + 3;
- /* digital i/o subdevice */
- if (thisboard->have_dio) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = s526_dio_insn_bits;
- s->insn_config = s526_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-
-#if 0
- /* Example of Counter Application */
- /* One-shot (software trigger) */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 1; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
- cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 2; /* Hardware */
- cmReg.reg.clockSource = 2; /* Internal */
- cmReg.reg.countDir = 1; /* Down */
- cmReg.reg.countDirCtrl = 1; /* Software */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
-
- outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
-
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Reset RCAP (fires one-shot) */
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-
-#else
-
- /* Set Counter Mode Register */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 0; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
- cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
- cmReg.reg.clockSource = 3; /* x4 */
- cmReg.reg.countDir = 0; /* up */
- cmReg.reg.countDirCtrl = 0; /* quadrature */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- n = 0;
- printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
- cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
-
- /* Load the pre-load register high word */
-/* value = (short) (0x55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
-
- /* Load the pre-load register low word */
-/* value = (short)(0xaa55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
-
- /* Write the Counter Control Register */
-/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
-
- /* Reset the counter if it is software preload */
- if (cmReg.reg.autoLoadResetRcap == 0) {
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
- }
-
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-#endif
- printk(KERN_INFO "Current registres:\n");
-
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk(KERN_INFO "0x%02lx: 0x%04x\n",
- ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
- }
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int s526_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor);
-
- if (dev->iobase > 0)
- release_region(dev->iobase, S526_IOSIZE);
-
- return 0;
-}
-
static int s526_gpct_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -1023,22 +742,218 @@ static int s526_dio_insn_config(struct comedi_device *dev,
return 1;
}
+static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int iobase;
+ int i, n;
+/* short value; */
+/* int subdev_channel = 0; */
+ union cmReg cmReg;
+
+ printk(KERN_INFO "comedi%d: s526: ", dev->minor);
+
+ iobase = it->options[0];
+ if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
+ comedi_error(dev, "I/O port conflict");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ printk("iobase=0x%lx\n", dev->iobase);
+
+ /*** make it a little quieter, exw, 8/29/06
+ for (i = 0; i < S526_NUM_PORTS; i++) {
+ printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
+ inw(ADDR_REG(s526_ports[i])));
+ }
+ ***/
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_s526_init_module(void)
-{
- return comedi_driver_register(&driver_s526);
+ dev->board_ptr = &s526_boards[0];
+
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct s526_private)) < 0)
+ return -ENOMEM;
+
+/*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ */
+ dev->n_subdevices = 4;
+ if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
+ /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
+ s->n_chan = thisboard->gpct_chans;
+ s->maxdata = 0x00ffffff; /* 24 bit counter */
+ s->insn_read = s526_gpct_rinsn;
+ s->insn_config = s526_gpct_insn_config;
+ s->insn_write = s526_gpct_winsn;
+
+ /* Command are not implemented yet, however they are necessary to
+ allocate the necessary memory for the comedi_async struct (used
+ to trigger the GPCT in case of pulsegenerator function */
+ /* s->do_cmd = s526_gpct_cmd; */
+ /* s->do_cmdtest = s526_gpct_cmdtest; */
+ /* s->cancel = s526_gpct_cancel; */
+
+ s = dev->subdevices + 1;
+ /* dev->read_subdev=s; */
+ /* analog input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ /* we support differential */
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
+ /* channels 0 to 7 are the regular differential inputs */
+ /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
+ s->n_chan = 10;
+ s->maxdata = 0xffff;
+ s->range_table = &range_bipolar10;
+ s->len_chanlist = 16; /* This is the maximum chanlist length that
+ the board can handle */
+ s->insn_read = s526_ai_rinsn;
+ s->insn_config = s526_ai_insn_config;
+
+ s = dev->subdevices + 2;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = s526_ao_winsn;
+ s->insn_read = s526_ao_rinsn;
+
+ s = dev->subdevices + 3;
+ /* digital i/o subdevice */
+ if (thisboard->have_dio) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = s526_dio_insn_bits;
+ s->insn_config = s526_dio_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
+
+#if 0
+ /* Example of Counter Application */
+ /* One-shot (software trigger) */
+ cmReg.reg.coutSource = 0; /* out RCAP */
+ cmReg.reg.coutPolarity = 1; /* Polarity inverted */
+ cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
+ cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
+ cmReg.reg.ctEnableCtrl = 2; /* Hardware */
+ cmReg.reg.clockSource = 2; /* Internal */
+ cmReg.reg.countDir = 1; /* Down */
+ cmReg.reg.countDirCtrl = 1; /* Software */
+ cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
+ cmReg.reg.preloadRegSel = 0; /* PR0 */
+ cmReg.reg.reserved = 0;
+
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+
+ outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Reset RCAP (fires one-shot) */
+ outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+
+#else
+
+ /* Set Counter Mode Register */
+ cmReg.reg.coutSource = 0; /* out RCAP */
+ cmReg.reg.coutPolarity = 0; /* Polarity inverted */
+ cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
+ cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
+ cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
+ cmReg.reg.clockSource = 3; /* x4 */
+ cmReg.reg.countDir = 0; /* up */
+ cmReg.reg.countDirCtrl = 0; /* quadrature */
+ cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
+ cmReg.reg.preloadRegSel = 0; /* PR0 */
+ cmReg.reg.reserved = 0;
+
+ n = 0;
+ printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
+ cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ udelay(1000);
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+ /* Load the pre-load register high word */
+/* value = (short) (0x55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
+
+ /* Load the pre-load register low word */
+/* value = (short)(0xaa55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
+
+ /* Write the Counter Control Register */
+/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
+
+ /* Reset the counter if it is software preload */
+ if (cmReg.reg.autoLoadResetRcap == 0) {
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
+ }
+
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ udelay(1000);
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+#endif
+ printk(KERN_INFO "Current registres:\n");
+
+ for (i = 0; i < S526_NUM_PORTS; i++) {
+ printk(KERN_INFO "0x%02lx: 0x%04x\n",
+ ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
+ }
+ return 1;
}
-static void __exit driver_s526_cleanup_module(void)
+static void s526_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_s526);
+ if (dev->iobase > 0)
+ release_region(dev->iobase, S526_IOSIZE);
}
-module_init(driver_s526_init_module);
-module_exit(driver_s526_cleanup_module);
+static struct comedi_driver s526_driver = {
+ .driver_name = "s526",
+ .module = THIS_MODULE,
+ .attach = s526_attach,
+ .detach = s526_detach,
+ .board_name = &s526_boards[0].name,
+ .offset = sizeof(struct s526_board),
+ .num_names = ARRAY_SIZE(s526_boards),
+};
+module_comedi_driver(s526_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 23fc64b..7beb8f6 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -79,12 +79,17 @@ INSN_CONFIG instructions:
#include "comedi_fc.h"
#include "s626.h"
-MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
-MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
-MODULE_LICENSE("GPL");
+#define PCI_VENDOR_ID_S626 0x1131
+#define PCI_DEVICE_ID_S626 0x7146
+#define PCI_SUBVENDOR_ID_S626 0x6000
+#define PCI_SUBDEVICE_ID_S626 0x0272
struct s626_board {
const char *name;
+ int vendor_id;
+ int device_id;
+ int subvendor_id;
+ int subdevice_id;
int ai_chans;
int ai_bits;
int ao_chans;
@@ -97,6 +102,10 @@ struct s626_board {
static const struct s626_board s626_boards[] = {
{
.name = "s626",
+ .vendor_id = PCI_VENDOR_ID_S626,
+ .device_id = PCI_DEVICE_ID_S626,
+ .subvendor_id = PCI_SUBVENDOR_ID_S626,
+ .subdevice_id = PCI_SUBDEVICE_ID_S626,
.ai_chans = S626_ADC_CHANNELS,
.ai_bits = 14,
.ao_chans = S626_DAC_CHANNELS,
@@ -108,30 +117,6 @@ static const struct s626_board s626_boards[] = {
};
#define thisboard ((const struct s626_board *)dev->board_ptr)
-#define PCI_VENDOR_ID_S626 0x1131
-#define PCI_DEVICE_ID_S626 0x7146
-
-/*
- * For devices with vendor:device id == 0x1131:0x7146 you must specify
- * also subvendor:subdevice ids, because otherwise it will conflict with
- * Philips SAA7146 media/dvb based cards.
- */
-static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
- {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, s626_pci_table);
-
-static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s626_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_s626 = {
- .driver_name = "s626",
- .module = THIS_MODULE,
- .attach = s626_attach,
- .detach = s626_detach,
-};
struct s626_private {
struct pci_dev *pdev;
@@ -224,44 +209,6 @@ static struct dio_private *dio_private_word[]={
#define devpriv ((struct s626_private *)dev->private)
#define diopriv ((struct dio_private *)s->private)
-static int __devinit driver_s626_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_s626.driver_name);
-}
-
-static void __devexit driver_s626_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_s626_pci_driver = {
- .id_table = s626_pci_table,
- .probe = &driver_s626_pci_probe,
- .remove = __devexit_p(&driver_s626_pci_remove)
-};
-
-static int __init driver_s626_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_s626);
- if (retval < 0)
- return retval;
-
- driver_s626_pci_driver.name = (char *)driver_s626.driver_name;
- return pci_register_driver(&driver_s626_pci_driver);
-}
-
-static void __exit driver_s626_cleanup_module(void)
-{
- pci_unregister_driver(&driver_s626_pci_driver);
- comedi_driver_unregister(&driver_s626);
-}
-
-module_init(driver_s626_init_module);
-module_exit(driver_s626_cleanup_module);
-
/* ioctl routines */
static int s626_ai_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -554,17 +501,17 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
resource_size_t resourceStart;
dma_addr_t appdma;
struct comedi_subdevice *s;
- const struct pci_device_id *ids;
struct pci_dev *pdev = NULL;
if (alloc_private(dev, sizeof(struct s626_private)) < 0)
return -ENOMEM;
- for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) {
- ids = &s626_pci_table[i];
+ for (i = 0; i < ARRAY_SIZE(s626_boards) && !pdev; i++) {
do {
- pdev = pci_get_subsys(ids->vendor, ids->device,
- ids->subvendor, ids->subdevice,
+ pdev = pci_get_subsys(s626_boards[i].vendor_id,
+ s626_boards[i].device_id,
+ s626_boards[i].subvendor_id,
+ s626_boards[i].subdevice_id,
pdev);
if ((it->options[0] || it->options[1]) && pdev) {
@@ -1365,7 +1312,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
return IRQ_HANDLED;
}
-static int s626_detach(struct comedi_device *dev)
+static void s626_detach(struct comedi_device *dev)
{
if (devpriv) {
/* stop ai_command */
@@ -1389,20 +1336,14 @@ static int s626_detach(struct comedi_device *dev)
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv->base_addr)
iounmap(devpriv->base_addr);
-
if (devpriv->pdev) {
if (devpriv->got_regions)
comedi_pci_disable(devpriv->pdev);
pci_dev_put(devpriv->pdev);
}
}
-
- DEBUG("s626_detach: S626 detached!\n");
-
- return 0;
}
/*
@@ -3367,3 +3308,45 @@ static void CountersInit(struct comedi_device *dev)
DEBUG("CountersInit: counters initialized\n");
}
+
+static struct comedi_driver s626_driver = {
+ .driver_name = "s626",
+ .module = THIS_MODULE,
+ .attach = s626_attach,
+ .detach = s626_detach,
+};
+
+static int __devinit s626_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &s626_driver);
+}
+
+static void __devexit s626_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+/*
+ * For devices with vendor:device id == 0x1131:0x7146 you must specify
+ * also subvendor:subdevice ids, because otherwise it will conflict with
+ * Philips SAA7146 media/dvb based cards.
+ */
+static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
+ { PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
+ PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, s626_pci_table);
+
+static struct pci_driver s626_pci_driver = {
+ .name = "s626",
+ .id_table = s626_pci_table,
+ .probe = s626_pci_probe,
+ .remove = __devexit_p(s626_pci_remove),
+};
+module_comedi_pci_driver(s626_driver, s626_pci_driver);
+
+MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
+MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index d880c2f..6342bc5 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -43,20 +43,10 @@ Status: in development
#include <linux/serial.h>
#include <linux/poll.h>
-/*
- * Board descriptions for two imaginary boards. Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
struct serial2002_board {
const char *name;
};
-static const struct serial2002_board serial2002_boards[] = {
- {
- .name = "serial2002"}
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -89,35 +79,6 @@ struct serial2002_private {
*/
#define devpriv ((struct serial2002_private *)dev->private)
-static int serial2002_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int serial2002_detach(struct comedi_device *dev);
-struct comedi_driver driver_serial2002 = {
- .driver_name = "serial2002",
- .module = THIS_MODULE,
- .attach = serial2002_attach,
- .detach = serial2002_detach,
- .board_name = &serial2002_boards[0].name,
- .offset = sizeof(struct serial2002_board),
- .num_names = ARRAY_SIZE(serial2002_boards),
-};
-
-static int serial2002_di_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_do_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
struct serial_data {
enum { is_invalid, is_digital, is_channel } kind;
int index;
@@ -887,32 +848,34 @@ static int serial2002_attach(struct comedi_device *dev,
return 1;
}
-static int serial2002_detach(struct comedi_device *dev)
+static void serial2002_detach(struct comedi_device *dev)
{
struct comedi_subdevice *s;
int i;
- dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor);
for (i = 0; i < 5; i++) {
s = &dev->subdevices[i];
kfree(s->maxdata_list);
kfree(s->range_table_list);
}
- return 0;
-}
-
-static int __init driver_serial2002_init_module(void)
-{
- return comedi_driver_register(&driver_serial2002);
}
-static void __exit driver_serial2002_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_serial2002);
-}
+static const struct serial2002_board serial2002_boards[] = {
+ {
+ .name = "serial2002"
+ },
+};
-module_init(driver_serial2002_init_module);
-module_exit(driver_serial2002_cleanup_module);
+static struct comedi_driver serial2002_driver = {
+ .driver_name = "serial2002",
+ .module = THIS_MODULE,
+ .attach = serial2002_attach,
+ .detach = serial2002_detach,
+ .board_name = &serial2002_boards[0].name,
+ .offset = sizeof(struct serial2002_board),
+ .num_names = ARRAY_SIZE(serial2002_boards),
+};
+module_comedi_driver(serial2002_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index ed69008..7d13ffa 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -156,7 +156,7 @@ struct skel_private {
* the device code.
*/
static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int skel_detach(struct comedi_device *dev);
+static void skel_detach(struct comedi_device *dev);
static struct comedi_driver driver_skel = {
.driver_name = "dummy",
.module = THIS_MODULE,
@@ -295,11 +295,8 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* allocated by _attach(). dev->private and dev->subdevices are
* deallocated automatically by the core.
*/
-static int skel_detach(struct comedi_device *dev)
+static void skel_detach(struct comedi_device *dev)
{
- pr_info("comedi%d: skel: remove\n", dev->minor);
-
- return 0;
}
/*
@@ -623,7 +620,7 @@ static int skel_dio_insn_config(struct comedi_device *dev,
static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_skel.driver_name);
+ return comedi_pci_auto_config(dev, &driver_skel);
}
static void __devexit driver_skel_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 526de2e..16c4f5a 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -59,16 +59,6 @@ struct dnp_board {
int have_dio;
};
-/* We only support one DNP 'board' variant at the moment */
-static const struct dnp_board dnp_boards[] = {
-{
- .name = "dnp-1486",
- .ai_chans = 16,
- .ai_bits = 12,
- .have_dio = 1,
- },
-};
-
/* Useful for shorthand access to the particular board structure ----------- */
#define thisboard ((const struct dnp_board *)dev->board_ptr)
@@ -81,136 +71,6 @@ struct dnp_private_data {
#define devpriv ((dnp_private *)dev->private)
/* ------------------------------------------------------------------------- */
-/* The struct comedi_driver structure tells the Comedi core module which */
-/* functions to call to configure/deconfigure (attach/detach) the board, and */
-/* also about the kernel module that contains the device code. */
-/* */
-/* In the following section we define the API of this driver. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dnp_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_dnp = {
- .driver_name = "ssv_dnp",
- .module = THIS_MODULE,
- .attach = dnp_attach,
- .detach = dnp_detach,
- .board_name = &dnp_boards[0].name,
- /* only necessary for non-PnP devs */
- .offset = sizeof(struct dnp_board), /* like ISA-PnP, PCI or PCMCIA */
- .num_names = ARRAY_SIZE(dnp_boards),
-};
-
-static int __init driver_dnp_init_module(void)
-{
- return comedi_driver_register(&driver_dnp);
-}
-
-static void __exit driver_dnp_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dnp);
-}
-
-module_init(driver_dnp_init_module);
-module_exit(driver_dnp_cleanup_module);
-
-static int dnp_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int dnp_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/* ------------------------------------------------------------------------- */
-/* Attach is called by comedi core to configure the driver for a particular */
-/* board. If you specified a board_name array in the driver structure, */
-/* dev->board_ptr contains that address. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-
- struct comedi_subdevice *s;
-
- printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
-
- /* Autoprobing: this should find out which board we have. Currently */
- /* only the 1486 board is supported and autoprobing is not */
- /* implemented :-) */
- /* dev->board_ptr = dnp_probe(dev); */
-
- /* Initialize the name of the board. */
- /* We can use the "thisboard" macro now. */
- dev->board_name = thisboard->name;
-
- /* Allocate the private structure area. alloc_private() is a */
- /* convenient macro defined in comedidev.h. */
- if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
- return -ENOMEM;
-
- /* Allocate the subdevice structures. alloc_subdevice() is a */
- /* convenient macro defined in comedidev.h. */
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* digital i/o subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 20;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = dnp_dio_insn_bits;
- s->insn_config = dnp_dio_insn_config;
-
- printk("attached\n");
-
- /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
- * allocated for the primary 8259, so we don't need to allocate them
- * ourselves. */
-
- /* configure all ports as input (default) */
- outb(PAMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PBMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PCMR, CSCIR);
- outb((inb(CSCDR) & 0xAA), CSCDR);
-
- return 1;
-
-}
-
-/* ------------------------------------------------------------------------- */
-/* detach is called to deconfigure a device. It should deallocate the */
-/* resources. This function is also called when _attach() fails, so it */
-/* should be careful not to release resources that were not necessarily */
-/* allocated by _attach(). dev->private and dev->subdevices are */
-/* deallocated automatically by the core. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_detach(struct comedi_device *dev)
-{
-
- /* configure all ports as input (default) */
- outb(PAMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PBMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PCMR, CSCIR);
- outb((inb(CSCDR) & 0xAA), CSCDR);
-
- /* announce that we are finished */
- printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor);
-
- return 0;
-
-}
-
-/* ------------------------------------------------------------------------- */
/* The insn_bits interface allows packed reading/writing of DIO channels. */
/* The comedi core can convert between insn_bits and insn_read/write, so you */
/* are able to use these instructions as well. */
@@ -326,6 +186,89 @@ static int dnp_dio_insn_config(struct comedi_device *dev,
}
+static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+
+ printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
+
+ /* Autoprobing: this should find out which board we have. Currently */
+ /* only the 1486 board is supported and autoprobing is not */
+ /* implemented :-) */
+ /* dev->board_ptr = dnp_probe(dev); */
+
+ /* Initialize the name of the board. */
+ /* We can use the "thisboard" macro now. */
+ dev->board_name = thisboard->name;
+
+ /* Allocate the private structure area. alloc_private() is a */
+ /* convenient macro defined in comedidev.h. */
+ if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
+ return -ENOMEM;
+
+ /* Allocate the subdevice structures. alloc_subdevice() is a */
+ /* convenient macro defined in comedidev.h. */
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* digital i/o subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 20;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = dnp_dio_insn_bits;
+ s->insn_config = dnp_dio_insn_config;
+
+ printk("attached\n");
+
+ /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
+ * allocated for the primary 8259, so we don't need to allocate them
+ * ourselves. */
+
+ /* configure all ports as input (default) */
+ outb(PAMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PBMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PCMR, CSCIR);
+ outb((inb(CSCDR) & 0xAA), CSCDR);
+
+ return 1;
+}
+
+static void dnp_detach(struct comedi_device *dev)
+{
+ outb(PAMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PBMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PCMR, CSCIR);
+ outb((inb(CSCDR) & 0xAA), CSCDR);
+}
+
+static const struct dnp_board dnp_boards[] = {
+ {
+ .name = "dnp-1486",
+ .ai_chans = 16,
+ .ai_bits = 12,
+ .have_dio = 1,
+ },
+};
+
+static struct comedi_driver dnp_driver = {
+ .driver_name = "ssv_dnp",
+ .module = THIS_MODULE,
+ .attach = dnp_attach,
+ .detach = dnp_detach,
+ .board_name = &dnp_boards[0].name,
+ .offset = sizeof(struct dnp_board),
+ .num_names = ARRAY_SIZE(dnp_boards),
+};
+module_comedi_driver(dnp_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index f45824f..d5f1f22 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -83,96 +83,188 @@ struct unioxx5_subd_priv {
unsigned char usp_prev_cn_val[3]; /* previous channel value */
};
-static int unioxx5_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int unioxx5_subdev_write(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_subdev_read(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_detach(struct comedi_device *dev);
-static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
- int subdev_iobase, int minor);
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_define_chan_offset(int chan_num);
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel);
+static int __unioxx5_define_chan_offset(int chan_num)
+{
-static struct comedi_driver unioxx5_driver = {
- .driver_name = DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = unioxx5_attach,
- .detach = unioxx5_detach
-};
+ if (chan_num < 0 || chan_num > 23)
+ return -1;
-static int __init unioxx5_driver_init_module(void)
+ return (chan_num >> 3) + 1;
+}
+
+#if 0 /* not used? */
+static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
{
- return comedi_driver_register(&unioxx5_driver);
+ int i, mask;
+
+ mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
+ printk("COMEDI: mode = %d\n", mask);
+
+ outb(1, usp->usp_iobase + 0);
+
+ for (i = 0; i < 3; i++)
+ outb(mask, usp->usp_iobase + i);
+
+ outb(0, usp->usp_iobase + 0);
}
+#endif
-static void __exit unioxx5_driver_cleanup_module(void)
+/* configure channels for analog i/o (even to output, odd to input) */
+static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
{
- comedi_driver_unregister(&unioxx5_driver);
+ int chan_a, chan_b, conf, channel_offset;
+
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ conf = usp->usp_prev_cn_val[channel_offset - 1];
+ chan_a = chan_b = 1;
+
+ /* setting channel A and channel B mask */
+ if (channel % 2 == 0) {
+ chan_a <<= channel & 0x07;
+ chan_b <<= (channel + 1) & 0x07;
+ } else {
+ chan_a <<= (channel - 1) & 0x07;
+ chan_b <<= channel & 0x07;
+ }
+
+ conf |= chan_a; /* even channel ot output */
+ conf &= ~chan_b; /* odd channel to input */
+
+ outb(1, usp->usp_iobase + 0);
+ outb(conf, usp->usp_iobase + channel_offset);
+ outb(0, usp->usp_iobase + 0);
+
+ usp->usp_prev_cn_val[channel_offset - 1] = conf;
}
-module_init(unioxx5_driver_init_module);
-module_exit(unioxx5_driver_cleanup_module);
+static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int channel_offset, mask = 1 << (channel & 0x07);
-static int unioxx5_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ if (channel_offset < 0) {
+ printk(KERN_ERR
+ "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+ minor, channel);
+ return 0;
+ }
+
+ *data = inb(usp->usp_iobase + channel_offset);
+ *data &= mask;
+
+ /* correct the read value to 0 or 1 */
+ if (channel_offset > 1)
+ channel -= 2 << channel_offset;
+ *data >>= channel;
+ return 1;
+}
+
+static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
{
- int iobase, i, n_subd;
- int id, num, ba;
+ int module_no, read_ch;
+ char control;
- iobase = it->options[0];
+ module_no = channel / 2;
+ read_ch = channel % 2; /* depend on type of channel (A or B) */
- dev->board_name = DRIVER_NAME;
- dev->iobase = iobase;
- iobase += UNIOXX5_SUBDEV_BASE;
+ /* defining if given module can work on input */
+ if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
+ printk(KERN_ERR
+ "comedi%d: module in position %d with id 0x%02x is for output only",
+ minor, module_no, usp->usp_module_type[module_no]);
+ return 0;
+ }
- /* defining number of subdevices and getting they types (it must be 'g01') */
- for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
- id = inb(ba + 0xE);
- num = inb(ba + 0xF);
+ __unioxx5_analog_config(usp, channel);
+ /* sends module number to card(1 .. 12) */
+ outb(module_no + 1, usp->usp_iobase + 5);
+ outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */
+ control = inb(usp->usp_iobase); /* get control register byte */
- if (id != 'g' || num != 1)
- continue;
+ /* waits while reading four bytes will be allowed */
+ while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
+ ;
- n_subd++;
+ /* if four bytes readding error occurs - return 0(false) */
+ if ((control & Rx4CA_ERR_MASK)) {
+ printk("COMEDI: 4 bytes error\n");
+ return 0;
}
- /* unioxx5 can has from two to four subdevices */
- if (n_subd < 2) {
+ if (read_ch)
+ *data = inw(usp->usp_iobase + 6); /* channel B */
+ else
+ *data = inw(usp->usp_iobase + 4); /* channel A */
+
+ return 1;
+}
+
+static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int channel_offset, val;
+ int mask = 1 << (channel & 0x07);
+
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ if (channel_offset < 0) {
printk(KERN_ERR
- "your card must has at least 2 'g01' subdevices\n");
- return -1;
+ "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+ minor, channel);
+ return 0;
}
- if (alloc_subdevices(dev, n_subd) < 0) {
- printk(KERN_ERR "out of memory\n");
- return -ENOMEM;
+ /* getting previous written value */
+ val = usp->usp_prev_wr_val[channel_offset - 1];
+
+ if (*data)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ outb(val, usp->usp_iobase + channel_offset);
+ /* saving new written value */
+ usp->usp_prev_wr_val[channel_offset - 1] = val;
+
+ return 1;
+}
+
+static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int module, i;
+
+ module = channel / 2; /* definig module number(0 .. 11) */
+ i = (channel % 2) << 1; /* depends on type of channel (A or B) */
+
+ /* defining if given module can work on output */
+ if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
+ printk(KERN_ERR
+ "comedi%d: module in position %d with id 0x%0x is for input only!\n",
+ minor, module, usp->usp_module_type[module]);
+ return 0;
}
- /* initializing each of for same subdevices */
- for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
- if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
- dev->minor) < 0)
- return -1;
+ __unioxx5_analog_config(usp, channel);
+ /* saving minor byte */
+ usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
+ /* saving major byte */
+ usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
+
+ /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
+ /* sending module number to card(1 .. 12) */
+ outb(module + 1, usp->usp_iobase + 5);
+ outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */
+
+ /* sending for bytes to module(one byte per cycle iteration) */
+ for (i = 0; i < 4; i++) {
+ while (!((inb(usp->usp_iobase + 0)) & TxBE))
+ ; /* waits while writting will be allowed */
+ outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
}
- printk(KERN_INFO "attached\n");
- return 0;
+ return 1;
}
static int unioxx5_subdev_read(struct comedi_device *dev,
@@ -275,22 +367,6 @@ static int unioxx5_insn_config(struct comedi_device *dev,
return 0;
}
-static int unioxx5_detach(struct comedi_device *dev)
-{
- int i;
- struct comedi_subdevice *subdev;
- struct unioxx5_subd_priv *usp;
-
- for (i = 0; i < dev->n_subdevices; i++) {
- subdev = &dev->subdevices[i];
- usp = subdev->private;
- release_region(usp->usp_iobase, UNIOXX5_SIZE);
- kfree(subdev->private);
- }
-
- return 0;
-}
-
/* initializing subdevice with given address */
static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
int subdev_iobase, int minor)
@@ -362,196 +438,73 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
return 0;
}
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
+static int unioxx5_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
- int channel_offset, val;
- int mask = 1 << (channel & 0x07);
-
- channel_offset = __unioxx5_define_chan_offset(channel);
- if (channel_offset < 0) {
- printk(KERN_ERR
- "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
- return 0;
- }
-
- /* getting previous written value */
- val = usp->usp_prev_wr_val[channel_offset - 1];
+ int iobase, i, n_subd;
+ int id, num, ba;
- if (*data)
- val |= mask;
- else
- val &= ~mask;
+ iobase = it->options[0];
- outb(val, usp->usp_iobase + channel_offset);
- /* saving new written value */
- usp->usp_prev_wr_val[channel_offset - 1] = val;
+ dev->board_name = DRIVER_NAME;
+ dev->iobase = iobase;
+ iobase += UNIOXX5_SUBDEV_BASE;
- return 1;
-}
+ /* defining number of subdevices and getting they types (it must be 'g01') */
+ for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
+ id = inb(ba + 0xE);
+ num = inb(ba + 0xF);
-/* function for digital reading */
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int channel_offset, mask = 1 << (channel & 0x07);
+ if (id != 'g' || num != 1)
+ continue;
- channel_offset = __unioxx5_define_chan_offset(channel);
- if (channel_offset < 0) {
- printk(KERN_ERR
- "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
- return 0;
+ n_subd++;
}
- *data = inb(usp->usp_iobase + channel_offset);
- *data &= mask;
-
- if (channel_offset > 1)
- channel -= 2 << channel_offset; /* this operation is created for correct readed value to 0 or 1 */
- *data >>= channel;
- return 1;
-}
-
-#if 0 /* not used? */
-static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
-{
- int i, mask;
-
- mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
- printk("COMEDI: mode = %d\n", mask);
-
- outb(1, usp->usp_iobase + 0);
-
- for (i = 0; i < 3; i++)
- outb(mask, usp->usp_iobase + i);
-
- outb(0, usp->usp_iobase + 0);
-}
-#endif
-
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int module, i;
-
- module = channel / 2; /* definig module number(0 .. 11) */
- i = (channel % 2) << 1; /* depends on type of channel (A or B) */
-
- /* defining if given module can work on output */
- if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
+ /* unioxx5 can has from two to four subdevices */
+ if (n_subd < 2) {
printk(KERN_ERR
- "comedi%d: module in position %d with id 0x%0x is for input only!\n",
- minor, module, usp->usp_module_type[module]);
- return 0;
- }
-
- __unioxx5_analog_config(usp, channel);
- /* saving minor byte */
- usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
- /* saving major byte */
- usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
-
- /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
- /* sending module number to card(1 .. 12) */
- outb(module + 1, usp->usp_iobase + 5);
- outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */
-
- /* sending for bytes to module(one byte per cycle iteration) */
- for (i = 0; i < 4; i++) {
- while (!((inb(usp->usp_iobase + 0)) & TxBE))
- ; /* waits while writting will be allowed */
- outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
+ "your card must has at least 2 'g01' subdevices\n");
+ return -1;
}
- return 1;
-}
-
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int module_no, read_ch;
- char control;
-
- module_no = channel / 2;
- read_ch = channel % 2; /* depend on type of channel (A or B) */
-
- /* defining if given module can work on input */
- if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
- printk(KERN_ERR
- "comedi%d: module in position %d with id 0x%02x is for output only",
- minor, module_no, usp->usp_module_type[module_no]);
- return 0;
+ if (alloc_subdevices(dev, n_subd) < 0) {
+ printk(KERN_ERR "out of memory\n");
+ return -ENOMEM;
}
- __unioxx5_analog_config(usp, channel);
- /* sends module number to card(1 .. 12) */
- outb(module_no + 1, usp->usp_iobase + 5);
- outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */
- control = inb(usp->usp_iobase); /* get control register byte */
-
- /* waits while reading four bytes will be allowed */
- while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
- ;
-
- /* if four bytes readding error occurs - return 0(false) */
- if ((control & Rx4CA_ERR_MASK)) {
- printk("COMEDI: 4 bytes error\n");
- return 0;
+ /* initializing each of for same subdevices */
+ for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
+ if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
+ dev->minor) < 0)
+ return -1;
}
- if (read_ch)
- *data = inw(usp->usp_iobase + 6); /* channel B */
- else
- *data = inw(usp->usp_iobase + 4); /* channel A */
-
- return 1;
+ printk(KERN_INFO "attached\n");
+ return 0;
}
-/* configure channels for analog i/o (even to output, odd to input) */
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
+static void unioxx5_detach(struct comedi_device *dev)
{
- int chan_a, chan_b, conf, channel_offset;
-
- channel_offset = __unioxx5_define_chan_offset(channel);
- conf = usp->usp_prev_cn_val[channel_offset - 1];
- chan_a = chan_b = 1;
+ int i;
+ struct comedi_subdevice *subdev;
+ struct unioxx5_subd_priv *usp;
- /* setting channel A and channel B mask */
- if (channel % 2 == 0) {
- chan_a <<= channel & 0x07;
- chan_b <<= (channel + 1) & 0x07;
- } else {
- chan_a <<= (channel - 1) & 0x07;
- chan_b <<= channel & 0x07;
+ for (i = 0; i < dev->n_subdevices; i++) {
+ subdev = &dev->subdevices[i];
+ usp = subdev->private;
+ release_region(usp->usp_iobase, UNIOXX5_SIZE);
+ kfree(subdev->private);
}
-
- conf |= chan_a; /* even channel ot output */
- conf &= ~chan_b; /* odd channel to input */
-
- outb(1, usp->usp_iobase + 0);
- outb(conf, usp->usp_iobase + channel_offset);
- outb(0, usp->usp_iobase + 0);
-
- usp->usp_prev_cn_val[channel_offset - 1] = conf;
}
-/* *\
- * this function defines if the given channel number *
- * enters in default numeric interspace(from 0 to 23) *
- * and it returns address offset for usage needed *
- * channel. *
-\* */
-
-static int __unioxx5_define_chan_offset(int chan_num)
-{
-
- if (chan_num < 0 || chan_num > 23)
- return -1;
-
- return (chan_num >> 3) + 1;
-}
+static struct comedi_driver unioxx5_driver = {
+ .driver_name = DRIVER_NAME,
+ .module = THIS_MODULE,
+ .attach = unioxx5_attach,
+ .detach = unioxx5_detach,
+};
+module_comedi_driver(unioxx5_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index bf62e0d..13d9fd3 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -317,6 +317,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbdux; /* see below for initializer */
+
/*
* Stops the data acquision
* It should be safe to call this function from any context
@@ -2304,11 +2306,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
void *context)
{
struct usbduxsub *usbduxsub_tmp = context;
- struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxsub_tmp->interface;
int ret;
if (fw == NULL) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Firmware complete handler without firmware!\n");
return;
}
@@ -2320,11 +2322,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbdux);
out:
release_firmware(fw);
}
@@ -2606,7 +2608,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
return;
}
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&usbduxsub_tmp->sem);
tidy_up(usbduxsub_tmp);
@@ -2615,46 +2617,21 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
}
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+/* common part of attach and attach_usb */
+static int usbdux_attach_common(struct comedi_device *dev,
+ struct usbduxsub *udev,
+ void *aux_data, int aux_len)
{
int ret;
- int index;
- int i;
- struct usbduxsub *udev;
-
struct comedi_subdevice *s = NULL;
- dev->private = NULL;
-
- down(&start_stop_sem);
- /* find a valid device which has been detected by the probe function of
- * the usb */
- index = -1;
- for (i = 0; i < NUMUSBDUX; i++) {
- if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
- index = i;
- break;
- }
- }
- if (index < 0) {
- printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no "
- "usbdux devs connected to the usb bus.\n", dev->minor);
- up(&start_stop_sem);
- return -ENODEV;
- }
-
- udev = &usbduxsub[index];
down(&udev->sem);
/* pointer back to the corresponding comedi device */
udev->comedidev = dev;
/* trying to upload the firmware into the chip */
- if (comedi_aux_data(it->options, 0) &&
- it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
- firmwareUpload(udev, comedi_aux_data(it->options, 0),
- it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
- }
+ if (aux_data)
+ firmwareUpload(udev, aux_data, aux_len);
dev->board_name = BOARDNAME;
@@ -2673,13 +2650,9 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev_err(&udev->interface->dev,
"comedi%d: error alloc space for subdev\n", dev->minor);
up(&udev->sem);
- up(&start_stop_sem);
return ret;
}
- dev_info(&udev->interface->dev,
- "comedi%d: usb-device %d is attached to comedi.\n",
- dev->minor, index);
/* private structure is also simply the usb-structure */
dev->private = udev;
@@ -2776,44 +2749,91 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
up(&udev->sem);
- up(&start_stop_sem);
-
dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
dev->minor);
return 0;
}
-static int usbdux_detach(struct comedi_device *dev)
+/* is called when comedi-config is called */
+static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct usbduxsub *usbduxsub_tmp;
+ int ret;
+ int index;
+ int i;
+ void *aux_data;
+ int aux_len;
- if (!dev) {
- printk(KERN_ERR
- "comedi?: usbdux: detach without dev variable...\n");
- return -EFAULT;
+ dev->private = NULL;
+
+ aux_data = comedi_aux_data(it->options, 0);
+ aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+ if (aux_data == NULL)
+ aux_len = 0;
+ else if (aux_len == 0)
+ aux_data = NULL;
+
+ down(&start_stop_sem);
+ /* find a valid device which has been detected by the probe function of
+ * the usb */
+ index = -1;
+ for (i = 0; i < NUMUSBDUX; i++) {
+ if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
+ index = i;
+ break;
+ }
}
- usbduxsub_tmp = dev->private;
- if (!usbduxsub_tmp) {
+ if (index < 0) {
printk(KERN_ERR
- "comedi?: usbdux: detach without ptr to usbduxsub[]\n");
- return -EFAULT;
- }
+ "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else
+ ret = usbdux_attach_common(dev, &usbduxsub[index],
+ aux_data, aux_len);
+ up(&start_stop_sem);
+ return ret;
+}
- dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n",
- dev->minor);
+/* is called from comedi_usb_auto_config() */
+static int usbdux_attach_usb(struct comedi_device *dev,
+ struct usb_interface *uinterf)
+{
+ int ret;
+ struct usbduxsub *this_usbduxsub;
- down(&usbduxsub_tmp->sem);
- /* Don't allow detach to free the private structure */
- /* It's one entry of of usbduxsub[] */
dev->private = NULL;
- usbduxsub_tmp->attached = 0;
- usbduxsub_tmp->comedidev = NULL;
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi%d: detach: successfully removed\n", dev->minor);
- up(&usbduxsub_tmp->sem);
- return 0;
+
+ down(&start_stop_sem);
+ this_usbduxsub = usb_get_intfdata(uinterf);
+ if (!this_usbduxsub || !this_usbduxsub->probed) {
+ printk(KERN_ERR
+ "comedi%d: usbdux: error: attach_usb failed, not connected\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else if (this_usbduxsub->attached) {
+ printk(KERN_ERR
+ "comedi%d: usbdux: error: attach_usb failed, already attached\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else
+ ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+ up(&start_stop_sem);
+ return ret;
+}
+
+static void usbdux_detach(struct comedi_device *dev)
+{
+ struct usbduxsub *usb = dev->private;
+
+ if (usb) {
+ down(&usb->sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&usb->sem);
+ }
}
/* main driver struct */
@@ -2822,6 +2842,7 @@ static struct comedi_driver driver_usbdux = {
.module = THIS_MODULE,
.attach = usbdux_attach,
.detach = usbdux_detach,
+ .attach_usb = usbdux_attach_usb,
};
/* Table with the USB-devices: just now only testing IDs */
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 2a8e725..7b1d21a 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -201,6 +201,8 @@ static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbduxfast; /* see below for initializer */
+
/*
* bulk transfers to usbduxfast
*/
@@ -453,14 +455,15 @@ static int usbduxfastsub_start(struct usbduxfastsub_s *udfs)
/* 7f92 to zero */
local_transfer_buffer[0] = 0;
/* bRequest, "Firmware" */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
- VENDOR_DIR_OUT, /* bmRequestType */
- USBDUXFASTSUB_CPUCS, /* Value */
- 0x0000, /* Index */
- /* address of the transfer buffer */
- local_transfer_buffer,
- 1, /* Length */
- EZTIMEOUT); /* Timeout */
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
+ VENDOR_DIR_OUT, /* bmRequestType */
+ USBDUXFASTSUB_CPUCS, /* Value */
+ 0x0000, /* Index */
+ /* address of the transfer buffer */
+ local_transfer_buffer,
+ 1, /* Length */
+ EZTIMEOUT); /* Timeout */
if (ret < 0) {
printk("comedi_: usbduxfast_: control msg failed (start)\n");
return ret;
@@ -477,7 +480,8 @@ static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs)
/* 7f92 to one */
local_transfer_buffer[0] = 1;
/* bRequest, "Firmware" */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
VENDOR_DIR_OUT, /* bmRequestType */
USBDUXFASTSUB_CPUCS, /* Value */
0x0000, /* Index */
@@ -504,14 +508,15 @@ static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs,
startAddr, local_transfer_buffer[0]);
#endif
/* brequest, firmware */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
- VENDOR_DIR_OUT, /* bmRequestType */
- startAddr, /* value */
- 0x0000, /* index */
- /* our local safe buffer */
- local_transfer_buffer,
- len, /* length */
- EZTIMEOUT); /* timeout */
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
+ VENDOR_DIR_OUT, /* bmRequestType */
+ startAddr, /* value */
+ 0x0000, /* index */
+ /* our local safe buffer */
+ local_transfer_buffer,
+ len, /* length */
+ EZTIMEOUT); /* timeout */
#ifdef CONFIG_COMEDI_DEBUG
printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret);
@@ -1440,7 +1445,7 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
*fw, void *context)
{
struct usbduxfastsub_s *usbduxfastsub_tmp = context;
- struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxfastsub_tmp->interface;
int ret;
if (fw == NULL)
@@ -1453,12 +1458,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbduxfast);
out:
release_firmware(fw);
}
@@ -1606,7 +1611,7 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf)
return;
}
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&udfs->sem);
@@ -1721,43 +1726,19 @@ static int usbduxfast_attach(struct comedi_device *dev,
return 0;
}
-static int usbduxfast_detach(struct comedi_device *dev)
+static void usbduxfast_detach(struct comedi_device *dev)
{
- struct usbduxfastsub_s *udfs;
-
- if (!dev) {
- printk(KERN_ERR "comedi?: usbduxfast: detach without dev "
- "variable...\n");
- return -EFAULT;
- }
-#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n",
- dev->minor);
-#endif
-
- udfs = dev->private;
- if (!udfs) {
- printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to "
- "usbduxfastsub[]\n");
- return -EFAULT;
+ struct usbduxfastsub_s *usb = dev->private;
+
+ if (usb) {
+ down(&usb->sem);
+ down(&start_stop_sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&start_stop_sem);
+ up(&usb->sem);
}
-
- down(&udfs->sem);
- down(&start_stop_sem);
- /*
- * Don't allow detach to free the private structure
- * It's one entry of of usbduxfastsub[]
- */
- dev->private = NULL;
- udfs->attached = 0;
- udfs->comedidev = NULL;
-#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully "
- "removed\n", dev->minor);
-#endif
- up(&start_stop_sem);
- up(&udfs->sem);
- return 0;
}
/*
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 63c9b6d..465afbd 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -267,6 +267,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbduxsigma; /* see below for initializer */
+
/*
* Stops the data acquision
* It should be safe to call this function from any context
@@ -2312,11 +2314,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
void *context)
{
struct usbduxsub *usbduxsub_tmp = context;
- struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxsub_tmp->interface;
int ret;
if (fw == NULL) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Firmware complete handler without firmware!\n");
return;
}
@@ -2328,11 +2330,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbduxsigma);
out:
release_firmware(fw);
}
@@ -2623,7 +2625,7 @@ static void usbduxsigma_disconnect(struct usb_interface *intf)
if (usbduxsub_tmp->ao_cmd_running)
/* we are still running a command */
usbdux_ao_stop(usbduxsub_tmp, 1);
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&usbduxsub_tmp->sem);
tidy_up(usbduxsub_tmp);
@@ -2799,37 +2801,17 @@ static int usbduxsigma_attach(struct comedi_device *dev,
return 0;
}
-static int usbduxsigma_detach(struct comedi_device *dev)
+static void usbduxsigma_detach(struct comedi_device *dev)
{
- struct usbduxsub *usbduxsub_tmp;
+ struct usbduxsub *usb = dev->private;
- if (!dev) {
- printk(KERN_ERR
- "comedi? usbduxsigma detach: dev=NULL\n");
- return -EFAULT;
+ if (usb) {
+ down(&usb->sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&usb->sem);
}
-
- usbduxsub_tmp = dev->private;
- if (!usbduxsub_tmp) {
- printk(KERN_ERR
- "comedi?: usbduxsigma detach: private=NULL\n");
- return -EFAULT;
- }
-
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi%d: detach usb device\n",
- dev->minor);
-
- down(&usbduxsub_tmp->sem);
- /* Don't allow detach to free the private structure */
- /* It's one entry of of usbduxsub[] */
- dev->private = NULL;
- usbduxsub_tmp->attached = 0;
- usbduxsub_tmp->comedidev = NULL;
- dev_info(&usbduxsub_tmp->interface->dev,
- "comedi%d: successfully detached.\n", dev->minor);
- up(&usbduxsub_tmp->sem);
- return 0;
}
/* main driver struct */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 3d13ca6e1..baee8d7 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -151,27 +151,12 @@ MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
#define URB_RCV_FLAG (1 << 0)
#define URB_SND_FLAG (1 << 1)
-#define CONFIG_VMK80XX_DEBUG
-#undef CONFIG_VMK80XX_DEBUG
-
-#ifdef CONFIG_VMK80XX_DEBUG
-static int dbgvm = 1;
-#else
-static int dbgvm;
-#endif
-
#ifdef CONFIG_COMEDI_DEBUG
static int dbgcm = 1;
#else
static int dbgcm;
#endif
-#define dbgvm(fmt, arg...) \
-do { \
- if (dbgvm) \
- printk(KERN_DEBUG fmt, ##arg); \
-} while (0)
-
#define dbgcm(fmt, arg...) \
do { \
if (dbgcm) \
@@ -247,13 +232,13 @@ static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
static DEFINE_MUTEX(glb_mutex);
+static struct comedi_driver driver_vmk80xx; /* see below for initializer */
+
static void vmk80xx_tx_callback(struct urb *urb)
{
struct vmk80xx_usb *dev = urb->context;
int stat = urb->status;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (stat && !(stat == -ENOENT
|| stat == -ECONNRESET || stat == -ESHUTDOWN))
dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
@@ -272,8 +257,6 @@ static void vmk80xx_rx_callback(struct urb *urb)
struct vmk80xx_usb *dev = urb->context;
int stat = urb->status;
- dbgvm("vmk80xx: %s\n", __func__);
-
switch (stat) {
case 0:
break;
@@ -295,7 +278,9 @@ resubmit:
if (!usb_submit_urb(urb, GFP_KERNEL))
goto exit;
- err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
+ dev_err(&urb->dev->dev,
+ "comedi#: vmk80xx: %s - submit urb failed\n",
+ __func__);
usb_unanchor_urb(urb);
}
@@ -312,8 +297,6 @@ static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
unsigned char tx[1];
unsigned char rx[2];
- dbgvm("vmk80xx: %s\n", __func__);
-
tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
@@ -338,8 +321,6 @@ static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
unsigned char rx[64];
int cnt;
- dbgvm("vmk80xx: %s\n", __func__);
-
tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
@@ -367,8 +348,6 @@ static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
int ival;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
@@ -406,8 +385,6 @@ static void vmk80xx_build_int_urb(struct urb *urb, int flag)
void (*callback) (struct urb *);
int ival;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (flag & URB_RCV_FLAG) {
rx_addr = dev->ep_rx->bEndpointAddress;
pipe = usb_rcvintpipe(dev->udev, rx_addr);
@@ -435,8 +412,6 @@ static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
unsigned int rx_pipe;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
set_bit(TRANS_IN_BUSY, &dev->flags);
set_bit(TRANS_OUT_BUSY, &dev->flags);
@@ -464,8 +439,6 @@ static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
struct urb *urb;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev->intf)
return -ENODEV;
@@ -512,8 +485,6 @@ static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
struct urb *urb;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev->intf)
return -ENODEV;
@@ -588,8 +559,6 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -641,8 +610,6 @@ static int vmk80xx_ao_winsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -686,8 +653,6 @@ static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -720,8 +685,6 @@ static int vmk80xx_di_bits(struct comedi_device *cdev,
int reg;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
retval = rudimentary_check(dev, DIR_IN);
if (retval)
return retval;
@@ -766,8 +729,6 @@ static int vmk80xx_di_rinsn(struct comedi_device *cdev,
int inp;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -813,8 +774,6 @@ static int vmk80xx_do_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -861,8 +820,6 @@ static int vmk80xx_do_rinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -895,8 +852,6 @@ static int vmk80xx_do_bits(struct comedi_device *cdev,
int dir, reg, cmd;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
dir = 0;
if (data[0])
@@ -962,8 +917,6 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -1012,18 +965,16 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
- down(&dev->limit_sem);
-
insn_cmd = data[0];
if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
return -EINVAL;
+ down(&dev->limit_sem);
+
chan = CR_CHAN(insn->chanspec);
if (dev->board.model == VMK8055_MODEL) {
@@ -1060,8 +1011,6 @@ static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -1106,8 +1055,6 @@ static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -1141,8 +1088,6 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -1191,8 +1136,6 @@ static int vmk80xx_attach(struct comedi_device *cdev,
struct comedi_subdevice *s;
int minor;
- dbgvm("vmk80xx: %s\n", __func__);
-
mutex_lock(&glb_mutex);
for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1307,34 +1250,16 @@ static int vmk80xx_attach(struct comedi_device *cdev,
return 0;
}
-static int vmk80xx_detach(struct comedi_device *cdev)
+static void vmk80xx_detach(struct comedi_device *dev)
{
- struct vmk80xx_usb *dev;
- int minor;
-
- dbgvm("vmk80xx: %s\n", __func__);
-
- if (!cdev)
- return -EFAULT;
-
- dev = cdev->private;
- if (!dev)
- return -EFAULT;
+ struct vmk80xx_usb *usb = dev->private;
- down(&dev->limit_sem);
-
- cdev->private = NULL;
- dev->attached = 0;
-
- minor = cdev->minor;
-
- printk(KERN_INFO
- "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
- minor, dev->count, dev->board.name);
-
- up(&dev->limit_sem);
-
- return 0;
+ if (usb) {
+ down(&usb->limit_sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ up(&usb->limit_sem);
+ }
}
static int vmk80xx_probe(struct usb_interface *intf,
@@ -1346,8 +1271,6 @@ static int vmk80xx_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep_desc;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
mutex_lock(&glb_mutex);
for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1482,7 +1405,7 @@ static int vmk80xx_probe(struct usb_interface *intf,
mutex_unlock(&glb_mutex);
- comedi_usb_auto_config(dev->udev, BOARDNAME);
+ comedi_usb_auto_config(intf, &driver_vmk80xx);
return 0;
error:
@@ -1495,12 +1418,10 @@ static void vmk80xx_disconnect(struct usb_interface *intf)
{
struct vmk80xx_usb *dev = usb_get_intfdata(intf);
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev)
return;
- comedi_usb_auto_unconfig(dev->udev);
+ comedi_usb_auto_unconfig(intf);
mutex_lock(&glb_mutex);
down(&dev->limit_sem);
diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h
index 434ce34..7ed20a0 100644
--- a/drivers/staging/comedi/internal.h
+++ b/drivers/staging/comedi/internal.h
@@ -1,5 +1,5 @@
/*
- * various internal comedi functions
+ * various internal comedi stuff
*/
int do_rangeinfo_ioctl(struct comedi_device *dev,
struct comedi_rangeinfo __user *arg);
@@ -7,6 +7,10 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
int comedi_alloc_board_minor(struct device *hardware_device);
void comedi_free_board_minor(unsigned minor);
+int comedi_find_board_minor(struct device *hardware_device);
void comedi_reset_async_buf(struct comedi_async *async);
int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned long new_size);
+
+extern unsigned int comedi_default_buf_size_kb;
+extern unsigned int comedi_default_buf_maxsize_kb;
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 886f565..5b11c5e 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -1710,7 +1710,8 @@ static int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
return value;
}
-static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value)
+static int et131x_mdio_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 value)
{
struct net_device *netdev = bus->priv;
struct et131x_adapter *adapter = netdev_priv(netdev);
@@ -4013,7 +4014,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
dev_err(&pdev->dev, "Missing PCIe capabilities\n");
goto err_out;
}
-
+
/* Let's set up the PORT LOGIC Register. First we need to know what
* the max_payload_size is
*/
@@ -4060,7 +4061,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
goto err_out;
}
- ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | ( 0x04 << 12);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | (0x04 << 12);
if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) {
dev_err(&pdev->dev,
@@ -4824,7 +4825,8 @@ static int et131x_open(struct net_device *netdev)
adapter->error_timer.data = (unsigned long)adapter;
add_timer(&adapter->error_timer);
- result = request_irq(irq, et131x_isr, IRQF_SHARED, netdev->name, netdev);
+ result = request_irq(irq, et131x_isr,
+ IRQF_SHARED, netdev->name, netdev);
if (result) {
dev_err(&pdev->dev, "could not register IRQ %d\n", irq);
return result;
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 3bf0f40e..acbb2cc 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -333,8 +333,8 @@ static int usb_alphatrack_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&usb_alphatrack_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
}
@@ -494,7 +494,8 @@ static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -564,7 +565,8 @@ static ssize_t usb_alphatrack_write(struct file *file,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -599,7 +601,7 @@ static ssize_t usb_alphatrack_write(struct file *file,
}
if (dev->interrupt_out_endpoint == NULL) {
- err("Endpoint should not be be null!\n");
+ dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
goto unlock_exit;
}
@@ -619,7 +621,8 @@ static ssize_t usb_alphatrack_write(struct file *file,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
atomic_dec(&dev->writes_pending);
goto unlock_exit;
}
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 29e99bb..376706f 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -353,7 +353,7 @@ static int usb_tranzport_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&usb_tranzport_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
@@ -517,9 +517,11 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer,
goto exit;
}
- /* verify that the device wasn't unplugged */ if (dev->intf == NULL) {
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -691,7 +693,8 @@ static ssize_t usb_tranzport_write(struct file *file,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -726,7 +729,7 @@ static ssize_t usb_tranzport_write(struct file *file,
}
if (dev->interrupt_out_endpoint == NULL) {
- err("Endpoint should not be be null!\n");
+ dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
goto unlock_exit;
}
@@ -746,7 +749,8 @@ static ssize_t usb_tranzport_write(struct file *file,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
diff --git a/drivers/staging/gdm72xx/Kconfig b/drivers/staging/gdm72xx/Kconfig
new file mode 100644
index 0000000..3c18efe
--- /dev/null
+++ b/drivers/staging/gdm72xx/Kconfig
@@ -0,0 +1,46 @@
+#
+# GCT GDM72xx WiMAX driver configuration
+#
+
+menuconfig WIMAX_GDM72XX
+ tristate "GCT GDM72xx WiMAX support"
+ depends on NET
+ help
+ Support for the GCT GDM72xx WiMAX chip
+
+if WIMAX_GDM72XX
+
+config WIMAX_GDM72XX_QOS
+ bool "Enable QoS support"
+ default n
+
+config WIMAX_GDM72XX_K_MODE
+ bool "Enable K mode"
+ default n
+
+config WIMAX_GDM72XX_WIMAX2
+ bool "Enable WIMAX2 support"
+ default n
+
+choice
+ prompt "Select interface"
+
+config WIMAX_GDM72XX_USB
+ bool "USB interface"
+ depends on USB
+
+config WIMAX_GDM72XX_SDIO
+ bool "SDIO interface"
+ depends on MMC
+
+endchoice
+
+if WIMAX_GDM72XX_USB
+
+config WIMAX_GDM72XX_USB_PM
+ bool "Enable power managerment support"
+ depends on USB_SUSPEND
+
+endif # WIMAX_GDM72XX_USB
+
+endif # WIMAX_GDM72XX
diff --git a/drivers/staging/gdm72xx/Makefile b/drivers/staging/gdm72xx/Makefile
new file mode 100644
index 0000000..35da7b9
--- /dev/null
+++ b/drivers/staging/gdm72xx/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_WIMAX_GDM72XX) := gdmwm.o
+
+gdmwm-y += gdm_wimax.o netlink_k.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_QOS) += gdm_qos.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_SDIO) += gdm_sdio.o sdio_boot.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_USB) += gdm_usb.o usb_boot.o
diff --git a/drivers/staging/gdm72xx/TODO b/drivers/staging/gdm72xx/TODO
new file mode 100644
index 0000000..30ac01a
--- /dev/null
+++ b/drivers/staging/gdm72xx/TODO
@@ -0,0 +1,5 @@
+TODO:
+- Replace kernel_thread with kthread in gdm_usb.c
+- Replace hard-coded firmware paths with request_firmware in
+ sdio_boot.c and usb_boot.c
+- Clean up coding style to meet kernel standard.
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
new file mode 100644
index 0000000..0217680
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_ether.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "gdm_qos.h"
+
+#define B2H(x) __be16_to_cpu(x)
+
+#undef dprintk
+#define dprintk(fmt, args ...) printk(KERN_DEBUG "[QoS] " fmt, ## args)
+#undef wprintk
+#define wprintk(fmt, args ...) \
+ printk(KERN_WARNING "[QoS WARNING] " fmt, ## args)
+#undef eprintk
+#define eprintk(fmt, args ...) printk(KERN_ERR "[QoS ERROR] " fmt, ## args)
+
+
+#define MAX_FREE_LIST_CNT 32
+static struct {
+ struct list_head head;
+ int cnt;
+ spinlock_t lock;
+} qos_free_list;
+
+static void init_qos_entry_list(void)
+{
+ qos_free_list.cnt = 0;
+ INIT_LIST_HEAD(&qos_free_list.head);
+ spin_lock_init(&qos_free_list.lock);
+}
+
+static void *alloc_qos_entry(void)
+{
+ struct qos_entry_s *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qos_free_list.lock, flags);
+ if (qos_free_list.cnt) {
+ entry = list_entry(qos_free_list.head.prev, struct qos_entry_s,
+ list);
+ list_del(&entry->list);
+ qos_free_list.cnt--;
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+ return entry;
+ }
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+ entry = kmalloc(sizeof(struct qos_entry_s), GFP_ATOMIC);
+ return entry;
+}
+
+static void free_qos_entry(void *entry)
+{
+ struct qos_entry_s *qentry = (struct qos_entry_s *) entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qos_free_list.lock, flags);
+ if (qos_free_list.cnt < MAX_FREE_LIST_CNT) {
+ list_add(&qentry->list, &qos_free_list.head);
+ qos_free_list.cnt++;
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+ kfree(entry);
+}
+
+static void free_qos_entry_list(struct list_head *free_list)
+{
+ struct qos_entry_s *entry, *n;
+ int total_free = 0;
+
+ list_for_each_entry_safe(entry, n, free_list, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ total_free++;
+ }
+
+ dprintk("%s: total_free_cnt=%d\n", __func__, total_free);
+}
+
+void gdm_qos_init(void *nic_ptr)
+{
+ struct nic *nic = nic_ptr;
+ struct qos_cb_s *qcb = &nic->qos;
+ int i;
+
+ for (i = 0 ; i < QOS_MAX; i++) {
+ INIT_LIST_HEAD(&qcb->qos_list[i]);
+ qcb->csr[i].QoSBufCount = 0;
+ qcb->csr[i].Enabled = 0;
+ }
+
+ qcb->qos_list_cnt = 0;
+ qcb->qos_null_idx = QOS_MAX-1;
+ qcb->qos_limit_size = 255;
+
+ spin_lock_init(&qcb->qos_lock);
+
+ init_qos_entry_list();
+}
+
+void gdm_qos_release_list(void *nic_ptr)
+{
+ struct nic *nic = nic_ptr;
+ struct qos_cb_s *qcb = &nic->qos;
+ unsigned long flags;
+ struct qos_entry_s *entry, *n;
+ struct list_head free_list;
+ int i;
+
+ INIT_LIST_HEAD(&free_list);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+
+ for (i = 0; i < QOS_MAX; i++) {
+ qcb->csr[i].QoSBufCount = 0;
+ qcb->csr[i].Enabled = 0;
+ }
+
+ qcb->qos_list_cnt = 0;
+ qcb->qos_null_idx = QOS_MAX-1;
+
+ for (i = 0; i < QOS_MAX; i++) {
+ list_for_each_entry_safe(entry, n, &qcb->qos_list[i], list) {
+ list_move_tail(&entry->list, &free_list);
+ }
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ free_qos_entry_list(&free_list);
+}
+
+static u32 chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *Stream, u8 *port)
+{
+ int i;
+
+ if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) {
+ if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) ||
+ ((Stream[1] & csr->IPToSMask) > csr->IPToSHigh))
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOL) {
+ if (Stream[9] != csr->Protocol)
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) {
+ for (i = 0; i < 4; i++) {
+ if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) !=
+ (csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i]))
+ return 1;
+ }
+ }
+
+ if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) {
+ for (i = 0; i < 4; i++) {
+ if ((Stream[16 + i] & csr->IPDstAddrMask[i]) !=
+ (csr->IPDstAddr[i] & csr->IPDstAddrMask[i]))
+ return 1;
+ }
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) {
+ i = ((port[0]<<8)&0xff00)+port[1];
+ if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh))
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) {
+ i = ((port[2]<<8)&0xff00)+port[3];
+ if ((i < csr->DstPortLow) || (i > csr->DstPortHigh))
+ return 1;
+ }
+
+ return 0;
+}
+
+static u32 get_qos_index(struct nic *nic, u8* iph, u8* tcpudph)
+{
+ u32 IP_Ver, Header_Len, i;
+ struct qos_cb_s *qcb = &nic->qos;
+
+ if (iph == NULL || tcpudph == NULL)
+ return -1;
+
+ IP_Ver = (iph[0]>>4)&0xf;
+ Header_Len = iph[0]&0xf;
+
+ if (IP_Ver == 4) {
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled) {
+ if (qcb->csr[i].ClassifierRuleEnable) {
+ if (chk_ipv4_rule(&qcb->csr[i], iph,
+ tcpudph) == 0)
+ return i;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static u32 extract_qos_list(struct nic *nic, struct list_head *head)
+{
+ struct qos_cb_s *qcb = &nic->qos;
+ struct qos_entry_s *entry;
+ int i;
+
+ INIT_LIST_HEAD(head);
+
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled) {
+ if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) {
+ if (!list_empty(&qcb->qos_list[i])) {
+ entry = list_entry(
+ qcb->qos_list[i].prev,
+ struct qos_entry_s, list);
+ list_move_tail(&entry->list, head);
+ qcb->csr[i].QoSBufCount++;
+
+ if (!list_empty(&qcb->qos_list[i]))
+ wprintk("QoS Index(%d) "
+ "is piled!!\n", i);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void send_qos_list(struct nic *nic, struct list_head *head)
+{
+ struct qos_entry_s *entry, *n;
+
+ list_for_each_entry_safe(entry, n, head, list) {
+ list_del(&entry->list);
+ free_qos_entry(entry);
+ gdm_wimax_send_tx(entry->skb, entry->dev);
+ }
+}
+
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ int index;
+ struct qos_cb_s *qcb = &nic->qos;
+ unsigned long flags;
+ struct ethhdr *ethh = (struct ethhdr *) (skb->data + HCI_HEADER_SIZE);
+ struct iphdr *iph = (struct iphdr *) ((char *) ethh + ETH_HLEN);
+ struct tcphdr *tcph;
+ struct qos_entry_s *entry = NULL;
+ struct list_head send_list;
+ int ret = 0;
+
+ tcph = (struct tcphdr *) iph + iph->ihl*4;
+
+ if (B2H(ethh->h_proto) == ETH_P_IP) {
+ if (qcb->qos_list_cnt && !qos_free_list.cnt) {
+ entry = alloc_qos_entry();
+ entry->skb = skb;
+ entry->dev = dev;
+ dprintk("qcb->qos_list_cnt=%d\n", qcb->qos_list_cnt);
+ }
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ if (qcb->qos_list_cnt) {
+ index = get_qos_index(nic, (u8 *)iph, (u8 *) tcph);
+ if (index == -1)
+ index = qcb->qos_null_idx;
+
+ if (!entry) {
+ entry = alloc_qos_entry();
+ entry->skb = skb;
+ entry->dev = dev;
+ }
+
+ list_add_tail(&entry->list, &qcb->qos_list[index]);
+ extract_qos_list(nic, &send_list);
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ send_qos_list(nic, &send_list);
+ goto out;
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ if (entry)
+ free_qos_entry(entry);
+ }
+
+ ret = gdm_wimax_send_tx(skb, dev);
+out:
+ return ret;
+}
+
+static u32 get_csr(struct qos_cb_s *qcb, u32 SFID, int mode)
+{
+ int i;
+
+ for (i = 0; i < qcb->qos_list_cnt; i++) {
+ if (qcb->csr[i].SFID == SFID)
+ return i;
+ }
+
+ if (mode) {
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled == 0) {
+ qcb->csr[i].Enabled = 1;
+ qcb->qos_list_cnt++;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+#define QOS_CHANGE_DEL 0xFC
+#define QOS_ADD 0xFD
+#define QOS_REPORT 0xFE
+
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
+{
+ struct nic *nic = nic_ptr;
+ u32 i, SFID, index, pos;
+ u8 subCmdEvt;
+ u8 len;
+ struct qos_cb_s *qcb = &nic->qos;
+ struct qos_entry_s *entry, *n;
+ struct list_head send_list;
+ struct list_head free_list;
+ unsigned long flags;
+
+ subCmdEvt = (u8)buf[4];
+
+ if (subCmdEvt == QOS_REPORT) {
+ len = (u8)buf[5];
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ for (i = 0; i < qcb->qos_list_cnt; i++) {
+ SFID = ((buf[(i*5)+6]<<24)&0xff000000);
+ SFID += ((buf[(i*5)+7]<<16)&0xff0000);
+ SFID += ((buf[(i*5)+8]<<8)&0xff00);
+ SFID += (buf[(i*5)+9]);
+ index = get_csr(qcb, SFID, 0);
+ if (index == -1) {
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ eprintk("QoS ERROR: No SF\n");
+ return;
+ }
+ qcb->csr[index].QoSBufCount = buf[(i*5)+10];
+ }
+
+ extract_qos_list(nic, &send_list);
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ send_qos_list(nic, &send_list);
+ return;
+ } else if (subCmdEvt == QOS_ADD) {
+ pos = 5;
+ len = (u8)buf[pos++];
+
+ SFID = ((buf[pos++]<<24)&0xff000000);
+ SFID += ((buf[pos++]<<16)&0xff0000);
+ SFID += ((buf[pos++]<<8)&0xff00);
+ SFID += (buf[pos++]);
+
+ index = get_csr(qcb, SFID, 1);
+ if (index == -1) {
+ eprintk("QoS ERROR: csr Update Error\n");
+ return;
+ }
+
+ dprintk("QOS_ADD SFID = 0x%x, index=%d\n", SFID, index);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ qcb->csr[index].SFID = SFID;
+ qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].ClassifierRuleEnable += buf[pos++];
+ if (qcb->csr[index].ClassifierRuleEnable == 0)
+ qcb->qos_null_idx = index;
+ qcb->csr[index].IPToSMask = buf[pos++];
+ qcb->csr[index].IPToSLow = buf[pos++];
+ qcb->csr[index].IPToSHigh = buf[pos++];
+ qcb->csr[index].Protocol = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[0] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[1] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[2] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[3] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[0] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[1] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[2] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[3] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[0] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[1] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[2] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[3] = buf[pos++];
+ qcb->csr[index].IPDstAddr[0] = buf[pos++];
+ qcb->csr[index].IPDstAddr[1] = buf[pos++];
+ qcb->csr[index].IPDstAddr[2] = buf[pos++];
+ qcb->csr[index].IPDstAddr[3] = buf[pos++];
+ qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].SrcPortLow += buf[pos++];
+ qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].SrcPortHigh += buf[pos++];
+ qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].DstPortLow += buf[pos++];
+ qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].DstPortHigh += buf[pos++];
+
+ qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ } else if (subCmdEvt == QOS_CHANGE_DEL) {
+ pos = 5;
+ len = (u8)buf[pos++];
+ SFID = ((buf[pos++]<<24)&0xff000000);
+ SFID += ((buf[pos++]<<16)&0xff0000);
+ SFID += ((buf[pos++]<<8)&0xff00);
+ SFID += (buf[pos++]);
+ index = get_csr(qcb, SFID, 1);
+ if (index == -1) {
+ eprintk("QoS ERROR: Wrong index(%d)\n", index);
+ return;
+ }
+
+ dprintk("QOS_CHANGE_DEL SFID = 0x%x, index=%d\n", SFID, index);
+
+ INIT_LIST_HEAD(&free_list);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ qcb->csr[index].Enabled = 0;
+ qcb->qos_list_cnt--;
+ qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+
+ list_for_each_entry_safe(entry, n, &qcb->qos_list[index],
+ list) {
+ list_move_tail(&entry->list, &free_list);
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ free_qos_entry_list(&free_list);
+ }
+}
diff --git a/drivers/staging/gdm72xx/gdm_qos.h b/drivers/staging/gdm72xx/gdm_qos.h
new file mode 100644
index 0000000..33f2bd4
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(GDM_QOS_H_20090403)
+#define GDM_QOS_H_20090403
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define BOOLEAN u8
+
+#define QOS_MAX 16
+#define IPTYPEOFSERVICE 0x8000
+#define PROTOCOL 0x4000
+#define IPMASKEDSRCADDRESS 0x2000
+#define IPMASKEDDSTADDRESS 0x1000
+#define PROTOCOLSRCPORTRANGE 0x800
+#define PROTOCOLDSTPORTRANGE 0x400
+#define DSTMACADDR 0x200
+#define SRCMACADDR 0x100
+#define ETHERTYPE 0x80
+#define IEEE802_1DUSERPRIORITY 0x40
+#define IEEE802_1QVLANID 0x10
+
+struct gdm_wimax_csr_s {
+ /* union{
+ U16 all;
+ struct _CS_CLASSIFIER_RULE_ENABLE{
+ IPTypeOfService:1,
+ Protocol:1,
+ IPMaskedSrcAddress:1,
+ IPMaskedDstAddress:1,
+ ProtocolSrcPortRange:1,
+ ProtocolDstPortRange:1,
+ DstMacAddr:1,
+ SrcMacAddr:1,
+ Ethertype:1,
+ IEEE802_1DUserPriority:1,
+ IEEE802_1QVLANID:1,
+ Reserved:5;
+ } fields;
+ } */
+ BOOLEAN Enabled;
+ u32 SFID;
+ u8 QoSBufCount;
+ u16 ClassifierRuleEnable;
+ u8 IPToSLow;
+ u8 IPToSHigh;
+ u8 IPToSMask;
+ u8 Protocol;
+ u8 IPSrcAddr[16];
+ u8 IPSrcAddrMask[16];
+ u8 IPDstAddr[16];
+ u8 IPDstAddrMask[16];
+ u16 SrcPortLow;
+ u16 SrcPortHigh;
+ u16 DstPortLow;
+ u16 DstPortHigh;
+};
+
+struct qos_entry_s {
+ struct list_head list;
+ struct sk_buff *skb;
+ struct net_device *dev;
+
+};
+
+struct qos_cb_s {
+ struct list_head qos_list[QOS_MAX];
+ u32 qos_list_cnt;
+ u32 qos_null_idx;
+ struct gdm_wimax_csr_s csr[QOS_MAX];
+ spinlock_t qos_lock;
+ u32 qos_limit_size;
+};
+
+void gdm_qos_init(void *nic_ptr);
+void gdm_qos_release_list(void *nic_ptr);
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev);
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size);
+
+#endif
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
new file mode 100644
index 0000000..e1a3dd2
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "gdm_sdio.h"
+#include "gdm_wimax.h"
+#include "sdio_boot.h"
+#include "hci.h"
+
+#define TYPE_A_HEADER_SIZE 4
+#define TYPE_A_LOOKAHEAD_SIZE 16
+
+#define MAX_NR_RX_BUF 4
+
+#define SDU_TX_BUF_SIZE 2048
+#define TX_BUF_SIZE 2048
+#define TX_CHUNK_SIZE (2048 - TYPE_A_HEADER_SIZE)
+#define RX_BUF_SIZE (25*1024)
+
+#define TX_HZ 2000
+#define TX_INTERVAL (1000000/TX_HZ)
+
+/*#define DEBUG*/
+
+static int init_sdio(struct sdiowm_dev *sdev);
+static void release_sdio(struct sdiowm_dev *sdev);
+
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: length = %d\n", title, len);
+ for (i = 0; i < len; i++) {
+ printk(KERN_DEBUG "%02x ", data[i]);
+ if ((i & 0xf) == 0xf)
+ printk(KERN_DEBUG "\n");
+ }
+ printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+ struct sdio_tx *t = NULL;
+
+ t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ if (t == NULL)
+ goto out;
+
+ memset(t, 0, sizeof(*t));
+
+ t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+ if (t->buf == NULL)
+ goto out;
+
+ t->tx_cxt = tx;
+
+ return t;
+out:
+ if (t) {
+ kfree(t->buf);
+ kfree(t);
+ }
+ return NULL;
+}
+
+static void free_tx_struct(struct sdio_tx *t)
+{
+ if (t) {
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+ struct sdio_rx *r = NULL;
+
+ r = kmalloc(sizeof(*r), GFP_ATOMIC);
+ if (r == NULL)
+ goto out;
+
+ memset(r, 0, sizeof(*r));
+
+ r->rx_cxt = rx;
+
+ return r;
+out:
+ kfree(r);
+ return NULL;
+}
+
+static void free_rx_struct(struct sdio_rx *r)
+{
+ kfree(r);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+ struct sdio_tx *t;
+
+ if (list_empty(&tx->free_list))
+ return NULL;
+
+ t = list_entry(tx->free_list.prev, struct sdio_tx, list);
+ list_del(&t->list);
+
+ *no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+ return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct sdio_tx *t)
+{
+ list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_rx *get_rx_struct(struct rx_cxt *rx)
+{
+ struct sdio_rx *r;
+
+ if (list_empty(&rx->free_list))
+ return NULL;
+
+ r = list_entry(rx->free_list.prev, struct sdio_rx, list);
+ list_del(&r->list);
+
+ return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct sdio_rx *r)
+{
+ list_add_tail(&r->list, &rx->free_list);
+}
+
+static int init_sdio(struct sdiowm_dev *sdev)
+{
+ int ret = 0, i;
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_tx *t;
+ struct sdio_rx *r;
+
+ INIT_LIST_HEAD(&tx->free_list);
+ INIT_LIST_HEAD(&tx->sdu_list);
+ INIT_LIST_HEAD(&tx->hci_list);
+
+ spin_lock_init(&tx->lock);
+
+ tx->sdu_buf = kmalloc(SDU_TX_BUF_SIZE, GFP_KERNEL);
+ if (tx->sdu_buf == NULL) {
+ printk(KERN_ERR "Failed to allocate SDU tx buffer.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&t->list, &tx->free_list);
+ }
+
+ INIT_LIST_HEAD(&rx->free_list);
+ INIT_LIST_HEAD(&rx->req_list);
+
+ spin_lock_init(&rx->lock);
+
+ for (i = 0; i < MAX_NR_RX_BUF; i++) {
+ r = alloc_rx_struct(rx);
+ if (r == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&r->list, &rx->free_list);
+ }
+
+ rx->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+ if (rx->rx_buf == NULL) {
+ printk(KERN_ERR "Failed to allocate rx buffer.\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ release_sdio(sdev);
+ return ret;
+}
+
+static void release_sdio(struct sdiowm_dev *sdev)
+{
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_tx *t, *t_next;
+ struct sdio_rx *r, *r_next;
+
+ kfree(tx->sdu_buf);
+
+ list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ kfree(rx->rx_buf);
+
+ list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->req_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+}
+
+static void send_sdio_pkt(struct sdio_func *func, u8 *data, int len)
+{
+ int n, blocks, ret, remain;
+
+ sdio_claim_host(func);
+
+ blocks = len / func->cur_blksize;
+ n = blocks * func->cur_blksize;
+ if (blocks) {
+ ret = sdio_memcpy_toio(func, 0, data, n);
+ if (ret < 0) {
+ if (ret != -ENOMEDIUM)
+ printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+ __func__, ret);
+ goto end_io;
+ }
+ }
+
+ remain = len - n;
+ remain = (remain + 3) & ~3;
+
+ if (remain) {
+ ret = sdio_memcpy_toio(func, 0, data + n, remain);
+ if (ret < 0) {
+ if (ret != -ENOMEDIUM)
+ printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+ __func__, ret);
+ goto end_io;
+ }
+ }
+
+end_io:
+ sdio_release_host(func);
+}
+
+static void send_sdu(struct sdio_func *func, struct tx_cxt *tx)
+{
+ struct list_head *l, *next;
+ struct hci_s *hci;
+ struct sdio_tx *t;
+ int pos, len, i, estlen, aggr_num = 0, aggr_len;
+ u8 *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ pos = TYPE_A_HEADER_SIZE + HCI_HEADER_SIZE;
+ list_for_each_entry(t, &tx->sdu_list, list) {
+ estlen = ((t->len + 3) & ~3) + 4;
+ if ((pos + estlen) > SDU_TX_BUF_SIZE)
+ break;
+
+ aggr_num++;
+ memcpy(tx->sdu_buf + pos, t->buf, t->len);
+ memset(tx->sdu_buf + pos + t->len, 0, estlen - t->len);
+ pos += estlen;
+ }
+ aggr_len = pos;
+
+ hci = (struct hci_s *)(tx->sdu_buf + TYPE_A_HEADER_SIZE);
+ hci->cmd_evt = H2B(WIMAX_TX_SDU_AGGR);
+ hci->length = H2B(aggr_len - TYPE_A_HEADER_SIZE - HCI_HEADER_SIZE);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef DEBUG
+ hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE,
+ aggr_len - TYPE_A_HEADER_SIZE);
+#endif
+
+ for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) {
+ len = aggr_len - pos;
+ len = len > TX_CHUNK_SIZE ? TX_CHUNK_SIZE : len;
+ buf = tx->sdu_buf + pos - TYPE_A_HEADER_SIZE;
+
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ buf[2] = (len >> 16) & 0xff;
+ buf[3] = (pos + len) >= aggr_len ? 0 : 1;
+ send_sdio_pkt(func, buf, len + TYPE_A_HEADER_SIZE);
+ }
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ for (l = tx->sdu_list.next, i = 0; i < aggr_num; i++, l = next) {
+ next = l->next;
+ t = list_entry(l, struct sdio_tx, list);
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ list_del(l);
+ put_tx_struct(t->tx_cxt, t);
+ }
+
+ do_gettimeofday(&tx->sdu_stamp);
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void send_hci(struct sdio_func *func, struct tx_cxt *tx,
+ struct sdio_tx *t)
+{
+ unsigned long flags;
+
+#ifdef DEBUG
+ hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE,
+ t->len - TYPE_A_HEADER_SIZE);
+#endif
+ send_sdio_pkt(func, t->buf, t->len);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (t->callback)
+ t->callback(t->cb_data);
+ free_tx_struct(t);
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void do_tx(struct work_struct *work)
+{
+ struct sdiowm_dev *sdev = container_of(work, struct sdiowm_dev, ws);
+ struct sdio_func *func = sdev->func;
+ struct tx_cxt *tx = &sdev->tx;
+ struct sdio_tx *t = NULL;
+ struct timeval now, *before;
+ int is_sdu = 0;
+ long diff;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (!tx->can_send) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+
+ if (!list_empty(&tx->hci_list)) {
+ t = list_entry(tx->hci_list.next, struct sdio_tx, list);
+ list_del(&t->list);
+ is_sdu = 0;
+ } else if (!tx->stop_sdu_tx && !list_empty(&tx->sdu_list)) {
+ do_gettimeofday(&now);
+ before = &tx->sdu_stamp;
+
+ diff = (now.tv_sec - before->tv_sec) * 1000000 +
+ (now.tv_usec - before->tv_usec);
+ if (diff >= 0 && diff < TX_INTERVAL) {
+ schedule_work(&sdev->ws);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+ is_sdu = 1;
+ }
+
+ if (!is_sdu && t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+
+ tx->can_send = 0;
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (is_sdu)
+ send_sdu(func, tx);
+ else
+ send_hci(func, tx, t);
+}
+
+static int gdm_sdio_send(void *priv_dev, void *data, int len,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct sdiowm_dev *sdev = priv_dev;
+ struct tx_cxt *tx = &sdev->tx;
+ struct sdio_tx *t;
+ u8 *pkt = data;
+ int no_spc = 0;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ BUG_ON(len > TX_BUF_SIZE - TYPE_A_HEADER_SIZE);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU) {
+ t = get_tx_struct(tx, &no_spc);
+ if (t == NULL) {
+ /* This case must not happen. */
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOSPC;
+ }
+ list_add_tail(&t->list, &tx->sdu_list);
+
+ memcpy(t->buf, data, len);
+
+ t->len = len;
+ t->callback = cb;
+ t->cb_data = cb_data;
+ } else {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOMEM;
+ }
+ list_add_tail(&t->list, &tx->hci_list);
+
+ t->buf[0] = len & 0xff;
+ t->buf[1] = (len >> 8) & 0xff;
+ t->buf[2] = (len >> 16) & 0xff;
+ t->buf[3] = 2;
+ memcpy(t->buf + TYPE_A_HEADER_SIZE, data, len);
+
+ t->len = len + TYPE_A_HEADER_SIZE;
+ t->callback = cb;
+ t->cb_data = cb_data;
+ }
+
+ if (tx->can_send)
+ schedule_work(&sdev->ws);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (no_spc)
+ return -ENOSPC;
+
+ return 0;
+}
+
+/*
+ * Handle the HCI, WIMAX_SDU_TX_FLOW.
+ */
+static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len)
+{
+ struct tx_cxt *tx = &sdev->tx;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (hci_data[0] << 8) | (hci_data[1]);
+ if (cmd_evt != WIMAX_SDU_TX_FLOW)
+ goto out;
+
+ if (hci_data[4] == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+ tx->stop_sdu_tx = 1;
+ } else if (hci_data[4] == 1) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+ tx->stop_sdu_tx = 0;
+ if (tx->can_send)
+ schedule_work(&sdev->ws);
+ /*
+ * If free buffer for sdu tx doesn't exist, then tx queue
+ * should not be woken. For this reason, don't pass the command,
+ * START_SDU_TX.
+ */
+ if (list_empty(&tx->free_list))
+ len = 0;
+ }
+
+out:
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return len;
+}
+
+static void gdm_sdio_irq(struct sdio_func *func)
+{
+ struct phy_dev *phy_dev = sdio_get_drvdata(func);
+ struct sdiowm_dev *sdev = phy_dev->priv_dev;
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_rx *r;
+ unsigned long flags;
+ u8 val, hdr[TYPE_A_LOOKAHEAD_SIZE], *buf;
+ u32 len, blocks, n;
+ int ret, remain;
+
+ /* Check interrupt */
+ val = sdio_readb(func, 0x13, &ret);
+ if (val & 0x01)
+ sdio_writeb(func, 0x01, 0x13, &ret); /* clear interrupt */
+ else
+ return;
+
+ ret = sdio_memcpy_fromio(func, hdr, 0x0, TYPE_A_LOOKAHEAD_SIZE);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n", func->num);
+ goto done;
+ }
+
+ len = (hdr[2] << 16) | (hdr[1] << 8) | hdr[0];
+ if (len > (RX_BUF_SIZE - TYPE_A_HEADER_SIZE)) {
+ printk(KERN_ERR "Too big Type-A size: %d\n", len);
+ goto done;
+ }
+
+ if (hdr[3] == 1) { /* Ack */
+#ifdef DEBUG
+ u32 *ack_seq = (u32 *)&hdr[4];
+#endif
+ spin_lock_irqsave(&tx->lock, flags);
+ tx->can_send = 1;
+
+ if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list))
+ schedule_work(&sdev->ws);
+ spin_unlock_irqrestore(&tx->lock, flags);
+#ifdef DEBUG
+ printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq));
+#endif
+ goto done;
+ }
+
+ memcpy(rx->rx_buf, hdr + TYPE_A_HEADER_SIZE,
+ TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE);
+
+ buf = rx->rx_buf + TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE;
+ remain = len - TYPE_A_LOOKAHEAD_SIZE + TYPE_A_HEADER_SIZE;
+ if (remain <= 0)
+ goto end_io;
+
+ blocks = remain / func->cur_blksize;
+
+ if (blocks) {
+ n = blocks * func->cur_blksize;
+ ret = sdio_memcpy_fromio(func, buf, 0x0, n);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n",
+ func->num);
+ goto done;
+ }
+ buf += n;
+ remain -= n;
+ }
+
+ if (remain) {
+ ret = sdio_memcpy_fromio(func, buf, 0x0, remain);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n",
+ func->num);
+ goto done;
+ }
+ }
+
+end_io:
+#ifdef DEBUG
+ hexdump("sdio_receive", rx->rx_buf, len);
+#endif
+ len = control_sdu_tx_flow(sdev, rx->rx_buf, len);
+
+ spin_lock_irqsave(&rx->lock, flags);
+
+ if (!list_empty(&rx->req_list)) {
+ r = list_entry(rx->req_list.next, struct sdio_rx, list);
+ spin_unlock_irqrestore(&rx->lock, flags);
+ if (r->callback)
+ r->callback(r->cb_data, rx->rx_buf, len);
+ spin_lock_irqsave(&rx->lock, flags);
+ list_del(&r->list);
+ put_rx_struct(rx, r);
+ }
+
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+done:
+ sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */
+ if (!phy_dev->netdev)
+ register_wimax_device(phy_dev, &func->dev);
+}
+
+static int gdm_sdio_receive(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data)
+{
+ struct sdiowm_dev *sdev = priv_dev;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->lock, flags);
+ r = get_rx_struct(rx);
+ if (r == NULL) {
+ spin_unlock_irqrestore(&rx->lock, flags);
+ return -ENOMEM;
+ }
+
+ r->callback = cb;
+ r->cb_data = cb_data;
+
+ list_add_tail(&r->list, &rx->req_list);
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+ return 0;
+}
+
+static int sdio_wimax_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret;
+ struct phy_dev *phy_dev = NULL;
+ struct sdiowm_dev *sdev = NULL;
+
+ printk(KERN_INFO "Found GDM SDIO VID = 0x%04x PID = 0x%04x...\n",
+ func->vendor, func->device);
+ printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+ sdio_claim_host(func);
+ sdio_enable_func(func);
+ sdio_claim_irq(func, gdm_sdio_irq);
+
+ ret = sdio_boot(func);
+ if (ret)
+ return ret;
+
+ phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+ if (phy_dev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+ if (sdev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(phy_dev, 0, sizeof(*phy_dev));
+ memset(sdev, 0, sizeof(*sdev));
+
+ phy_dev->priv_dev = (void *)sdev;
+ phy_dev->send_func = gdm_sdio_send;
+ phy_dev->rcv_func = gdm_sdio_receive;
+
+ ret = init_sdio(sdev);
+ if (sdev < 0)
+ goto out;
+
+ sdev->func = func;
+
+ sdio_writeb(func, 1, 0x14, &ret); /* Enable interrupt */
+ sdio_release_host(func);
+
+ INIT_WORK(&sdev->ws, do_tx);
+
+ sdio_set_drvdata(func, phy_dev);
+out:
+ if (ret) {
+ kfree(phy_dev);
+ kfree(sdev);
+ }
+
+ return ret;
+}
+
+static void sdio_wimax_remove(struct sdio_func *func)
+{
+ struct phy_dev *phy_dev = sdio_get_drvdata(func);
+ struct sdiowm_dev *sdev = phy_dev->priv_dev;
+
+ if (phy_dev->netdev)
+ unregister_wimax_device(phy_dev);
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ release_sdio(sdev);
+
+ kfree(sdev);
+ kfree(phy_dev);
+}
+
+static const struct sdio_device_id sdio_wimax_ids[] = {
+ { SDIO_DEVICE(0x0296, 0x5347) },
+ {0}
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_wimax_ids);
+
+static struct sdio_driver sdio_wimax_driver = {
+ .probe = sdio_wimax_probe,
+ .remove = sdio_wimax_remove,
+ .name = "sdio_wimax",
+ .id_table = sdio_wimax_ids,
+};
+
+static int __init sdio_gdm_wimax_init(void)
+{
+ return sdio_register_driver(&sdio_wimax_driver);
+}
+
+static void __exit sdio_gdm_wimax_exit(void)
+{
+ sdio_unregister_driver(&sdio_wimax_driver);
+}
+
+module_init(sdio_gdm_wimax_init);
+module_exit(sdio_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax SDIO Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_sdio.h b/drivers/staging/gdm72xx/gdm_sdio.h
new file mode 100644
index 0000000..216e98f
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_SDIO_H__
+#define __GDM_SDIO_H__
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+#define MAX_NR_SDU_BUF 64
+
+struct sdio_tx {
+ struct list_head list;
+ struct tx_cxt *tx_cxt;
+
+ u8 *buf;
+ int len;
+
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct tx_cxt {
+ struct list_head free_list;
+ struct list_head sdu_list;
+ struct list_head hci_list;
+ struct timeval sdu_stamp;
+
+ u8 *sdu_buf;
+
+ spinlock_t lock;
+ int can_send;
+ int stop_sdu_tx;
+};
+
+struct sdio_rx {
+ struct list_head list;
+ struct rx_cxt *rx_cxt;
+
+ void (*callback)(void *cb_data, void *data, int len);
+ void *cb_data;
+};
+
+struct rx_cxt {
+ struct list_head free_list;
+ struct list_head req_list;
+
+ u8 *rx_buf;
+
+ spinlock_t lock;
+};
+
+struct sdiowm_dev {
+ struct sdio_func *func;
+
+ struct tx_cxt tx;
+ struct rx_cxt rx;
+
+ struct work_struct ws;
+};
+
+#endif /* __GDM_SDIO_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
new file mode 100644
index 0000000..1e9dc0d
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <asm/byteorder.h>
+
+#include "gdm_usb.h"
+#include "gdm_wimax.h"
+#include "usb_boot.h"
+#include "hci.h"
+
+#include "usb_ids.h"
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+#define TX_BUF_SIZE 2048
+#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+#define RX_BUF_SIZE (128*1024) /* For packet aggregation */
+#else
+#define RX_BUF_SIZE 2048
+#endif
+
+#define GDM7205_PADDING 256
+
+#define H2B(x) __cpu_to_be16(x)
+#define B2H(x) __be16_to_cpu(x)
+#define DB2H(x) __be32_to_cpu(x)
+
+#define DOWNLOAD_CONF_VALUE 0x21
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+
+static DECLARE_WAIT_QUEUE_HEAD(k_wait);
+static LIST_HEAD(k_list);
+static DEFINE_SPINLOCK(k_lock);
+static int k_mode_stop;
+
+#define K_WAIT_TIME (2 * HZ / 100)
+
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static int init_usb(struct usbwm_dev *udev);
+static void release_usb(struct usbwm_dev *udev);
+
+/*#define DEBUG */
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: length = %d\n", title, len);
+ for (i = 0; i < len; i++) {
+ printk(KERN_DEBUG "%02x ", data[i]);
+ if ((i & 0xf) == 0xf)
+ printk(KERN_DEBUG "\n");
+ }
+ printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+ struct usb_tx *t = NULL;
+
+ t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ if (t == NULL)
+ goto out;
+
+ memset(t, 0, sizeof(*t));
+
+ t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+ if (t->urb == NULL || t->buf == NULL)
+ goto out;
+
+ t->tx_cxt = tx;
+
+ return t;
+out:
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+ return NULL;
+}
+
+static void free_tx_struct(struct usb_tx *t)
+{
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+ struct usb_rx *r = NULL;
+
+ r = kmalloc(sizeof(*r), GFP_ATOMIC);
+ if (r == NULL)
+ goto out;
+
+ memset(r, 0, sizeof(*r));
+
+ r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
+ if (r->urb == NULL || r->buf == NULL)
+ goto out;
+
+ r->rx_cxt = rx;
+ return r;
+out:
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+ return NULL;
+}
+
+static void free_rx_struct(struct usb_rx *r)
+{
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+ struct usb_tx *t;
+
+ if (list_empty(&tx->free_list)) {
+ *no_spc = 1;
+ return NULL;
+ }
+
+ t = list_entry(tx->free_list.next, struct usb_tx, list);
+ list_del(&t->list);
+
+ *no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+ return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct usb_tx *t)
+{
+ list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_rx *get_rx_struct(struct rx_cxt *rx)
+{
+ struct usb_rx *r;
+
+ if (list_empty(&rx->free_list)) {
+ r = alloc_rx_struct(rx);
+ if (r == NULL)
+ return NULL;
+
+ list_add(&r->list, &rx->free_list);
+ }
+
+ r = list_entry(rx->free_list.next, struct usb_rx, list);
+ list_del(&r->list);
+ list_add_tail(&r->list, &rx->used_list);
+
+ return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
+{
+ list_del(&r->list);
+ list_add(&r->list, &rx->free_list);
+}
+
+static int init_usb(struct usbwm_dev *udev)
+{
+ int ret = 0, i;
+ struct tx_cxt *tx = &udev->tx;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_tx *t;
+ struct usb_rx *r;
+
+ INIT_LIST_HEAD(&tx->free_list);
+ INIT_LIST_HEAD(&tx->sdu_list);
+ INIT_LIST_HEAD(&tx->hci_list);
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ INIT_LIST_HEAD(&tx->pending_list);
+#endif
+
+ INIT_LIST_HEAD(&rx->free_list);
+ INIT_LIST_HEAD(&rx->used_list);
+
+ spin_lock_init(&tx->lock);
+ spin_lock_init(&rx->lock);
+
+ for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&t->list, &tx->free_list);
+ }
+
+ r = alloc_rx_struct(rx);
+ if (r == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ list_add(&r->list, &rx->free_list);
+ return ret;
+
+fail:
+ release_usb(udev);
+ return ret;
+}
+
+static void release_usb(struct usbwm_dev *udev)
+{
+ struct tx_cxt *tx = &udev->tx;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_tx *t, *t_next;
+ struct usb_rx *r, *r_next;
+
+ list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->used_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+ struct usb_tx *t = urb->context;
+ struct tx_cxt *tx = t->tx_cxt;
+ u8 *pkt = t->buf;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ /* Completion by usb_unlink_urb */
+ if (urb->status == -ECONNRESET)
+ return;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ /* Delete from sdu list or hci list. */
+ list_del(&t->list);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU)
+ put_tx_struct(tx, t);
+ else
+ free_tx_struct(t);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static int gdm_usb_send(void *priv_dev, void *data, int len,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct usbwm_dev *udev = priv_dev;
+ struct usb_device *usbdev = udev->usbdev;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t;
+ int padding = udev->padding;
+ int no_spc = 0, ret;
+ u8 *pkt = data;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ printk(KERN_ERR "%s: No such device\n", __func__);
+ return -ENODEV;
+ }
+
+ BUG_ON(len > TX_BUF_SIZE - padding - 1);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU) {
+ t = get_tx_struct(tx, &no_spc);
+ if (t == NULL) {
+ /* This case must not happen. */
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOSPC;
+ }
+ list_add_tail(&t->list, &tx->sdu_list);
+ } else {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOMEM;
+ }
+ list_add_tail(&t->list, &tx->hci_list);
+ }
+
+ memcpy(t->buf + padding, data, len);
+ t->callback = cb;
+ t->cb_data = cb_data;
+
+ /*
+ * In some cases, USB Module of WiMax is blocked when data size is
+ * the multiple of 512. So, increment length by one in that case.
+ */
+ if ((len % 512) == 0)
+ len++;
+
+ usb_fill_bulk_urb(t->urb,
+ usbdev,
+ usb_sndbulkpipe(usbdev, 1),
+ t->buf,
+ len + padding,
+ gdm_usb_send_complete,
+ t);
+
+#ifdef DEBUG
+ hexdump("usb_send", t->buf, len + padding);
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ if (usbdev->state & USB_STATE_SUSPENDED) {
+ list_add_tail(&t->p_list, &tx->pending_list);
+ schedule_work(&udev->pm_ws);
+ goto out;
+ }
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ if (udev->bw_switch) {
+ list_add_tail(&t->p_list, &tx->pending_list);
+ goto out;
+ } else if (cmd_evt == WIMAX_SCAN) {
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_unlink_urb(r->urb);
+ udev->bw_switch = 1;
+
+ spin_lock(&k_lock);
+ list_add_tail(&udev->list, &k_list);
+ spin_unlock(&k_lock);
+
+ wake_up(&k_wait);
+ }
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+ if (ret)
+ goto send_fail;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ usb_mark_last_busy(usbdev);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+out:
+#endif
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (no_spc)
+ return -ENOSPC;
+
+ return 0;
+
+send_fail:
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return ret;
+}
+
+static void gdm_usb_rcv_complete(struct urb *urb)
+{
+ struct usb_rx *r = urb->context;
+ struct rx_cxt *rx = r->rx_cxt;
+ struct usbwm_dev *udev = container_of(r->rx_cxt, struct usbwm_dev, rx);
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t;
+ u16 cmd_evt;
+ unsigned long flags;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ struct usb_device *dev = urb->dev;
+#endif
+
+ /* Completion by usb_unlink_urb */
+ if (urb->status == -ECONNRESET)
+ return;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (!urb->status) {
+ cmd_evt = (r->buf[0] << 8) | (r->buf[1]);
+#ifdef DEBUG
+ hexdump("usb_receive", r->buf, urb->actual_length);
+#endif
+ if (cmd_evt == WIMAX_SDU_TX_FLOW) {
+ if (r->buf[4] == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+ list_for_each_entry(t, &tx->sdu_list, list)
+ usb_unlink_urb(t->urb);
+ } else if (r->buf[4] == 1) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+ list_for_each_entry(t, &tx->sdu_list, list) {
+ usb_submit_urb(t->urb, GFP_ATOMIC);
+ }
+ /*
+ * If free buffer for sdu tx doesn't
+ * exist, then tx queue should not be
+ * woken. For this reason, don't pass
+ * the command, START_SDU_TX.
+ */
+ if (list_empty(&tx->free_list))
+ urb->actual_length = 0;
+ }
+ }
+ }
+
+ if (!urb->status && r->callback)
+ r->callback(r->cb_data, r->buf, urb->actual_length);
+
+ spin_lock(&rx->lock);
+ put_rx_struct(rx, r);
+ spin_unlock(&rx->lock);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ usb_mark_last_busy(dev);
+#endif
+}
+
+static int gdm_usb_receive(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data)
+{
+ struct usbwm_dev *udev = priv_dev;
+ struct usb_device *usbdev = udev->usbdev;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_rx *r;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ printk(KERN_ERR "%s: No such device\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&rx->lock, flags);
+ r = get_rx_struct(rx);
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+ if (r == NULL)
+ return -ENOMEM;
+
+ r->callback = cb;
+ r->cb_data = cb_data;
+
+ usb_fill_bulk_urb(r->urb,
+ usbdev,
+ usb_rcvbulkpipe(usbdev, 0x82),
+ r->buf,
+ RX_BUF_SIZE,
+ gdm_usb_rcv_complete,
+ r);
+
+ return usb_submit_urb(r->urb, GFP_ATOMIC);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static void do_pm_control(struct work_struct *work)
+{
+ struct usbwm_dev *udev = container_of(work, struct usbwm_dev, pm_ws);
+ struct tx_cxt *tx = &udev->tx;
+ int ret;
+ unsigned long flags;
+
+ ret = usb_autopm_get_interface(udev->intf);
+ if (!ret)
+ usb_autopm_put_interface(udev->intf);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (!(udev->usbdev->state & USB_STATE_SUSPENDED)
+ && (!list_empty(&tx->hci_list) || !list_empty(&tx->sdu_list))) {
+ struct usb_tx *t, *temp;
+
+ list_for_each_entry_safe(t, temp, &tx->pending_list, p_list) {
+ list_del(&t->p_list);
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ if (ret) {
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+static int gdm_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret = 0;
+ u8 bConfigurationValue;
+ struct phy_dev *phy_dev = NULL;
+ struct usbwm_dev *udev = NULL;
+ u16 idVendor, idProduct, bcdDevice;
+
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ usb_get_dev(usbdev);
+ bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+
+ /*USB description is set up with Little-Endian*/
+ idVendor = L2H(usbdev->descriptor.idVendor);
+ idProduct = L2H(usbdev->descriptor.idProduct);
+ bcdDevice = L2H(usbdev->descriptor.bcdDevice);
+
+ printk(KERN_INFO "Found GDM USB VID = 0x%04x PID = 0x%04x...\n",
+ idVendor, idProduct);
+ printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+
+ if (idProduct == EMERGENCY_PID) {
+ ret = usb_emergency(usbdev);
+ goto out;
+ }
+
+ /* Support for EEPROM bootloader */
+ if (bConfigurationValue == DOWNLOAD_CONF_VALUE ||
+ idProduct & B_DOWNLOAD) {
+ ret = usb_boot(usbdev, bcdDevice);
+ goto out;
+ }
+
+ phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+ if (phy_dev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ udev = kmalloc(sizeof(*udev), GFP_KERNEL);
+ if (udev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(phy_dev, 0, sizeof(*phy_dev));
+ memset(udev, 0, sizeof(*udev));
+
+ if (idProduct == 0x7205 || idProduct == 0x7206)
+ udev->padding = GDM7205_PADDING;
+ else
+ udev->padding = 0;
+
+ phy_dev->priv_dev = (void *)udev;
+ phy_dev->send_func = gdm_usb_send;
+ phy_dev->rcv_func = gdm_usb_receive;
+
+ ret = init_usb(udev);
+ if (ret < 0)
+ goto out;
+
+ udev->usbdev = usbdev;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ udev->intf = intf;
+
+ intf->needs_remote_wakeup = 1;
+ device_init_wakeup(&intf->dev, 1);
+
+ pm_runtime_set_autosuspend_delay(&usbdev->dev, 10 * 1000); /* msec */
+
+ INIT_WORK(&udev->pm_ws, do_pm_control);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+ ret = register_wimax_device(phy_dev, &intf->dev);
+
+out:
+ if (ret) {
+ kfree(phy_dev);
+ kfree(udev);
+ }
+ usb_set_intfdata(intf, phy_dev);
+ return ret;
+}
+
+static void gdm_usb_disconnect(struct usb_interface *intf)
+{
+ u8 bConfigurationValue;
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ u16 idProduct;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+ phy_dev = usb_get_intfdata(intf);
+
+ /*USB description is set up with Little-Endian*/
+ idProduct = L2H(usbdev->descriptor.idProduct);
+
+ if (idProduct != EMERGENCY_PID &&
+ bConfigurationValue != DOWNLOAD_CONF_VALUE &&
+ (idProduct & B_DOWNLOAD) == 0) {
+ udev = phy_dev->priv_dev;
+ udev->usbdev = NULL;
+
+ unregister_wimax_device(phy_dev);
+ release_usb(udev);
+ kfree(udev);
+ kfree(phy_dev);
+ }
+
+ usb_put_dev(usbdev);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static int gdm_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_unlink_urb(r->urb);
+
+ return 0;
+}
+
+static int gdm_resume(struct usb_interface *intf)
+{
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_submit_urb(r->urb, GFP_ATOMIC);
+
+ return 0;
+}
+
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+static int k_mode_thread(void *arg)
+{
+ struct usbwm_dev *udev;
+ struct tx_cxt *tx;
+ struct rx_cxt *rx;
+ struct usb_tx *t, *temp;
+ struct usb_rx *r;
+ unsigned long flags, flags2, expire;
+ int ret;
+
+ daemonize("k_mode_wimax");
+
+ while (!k_mode_stop) {
+
+ spin_lock_irqsave(&k_lock, flags2);
+ while (!list_empty(&k_list)) {
+
+ udev = list_entry(k_list.next, struct usbwm_dev, list);
+ tx = &udev->tx;
+ rx = &udev->rx;
+
+ list_del(&udev->list);
+ spin_unlock_irqrestore(&k_lock, flags2);
+
+ expire = jiffies + K_WAIT_TIME;
+ while (jiffies < expire)
+ schedule_timeout(K_WAIT_TIME);
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_submit_urb(r->urb, GFP_ATOMIC);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ list_for_each_entry_safe(t, temp, &tx->pending_list,
+ p_list) {
+ list_del(&t->p_list);
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ if (ret) {
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ }
+ }
+
+ udev->bw_switch = 0;
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ spin_lock_irqsave(&k_lock, flags2);
+ }
+ spin_unlock_irqrestore(&k_lock, flags2);
+
+ interruptible_sleep_on(&k_wait);
+ }
+ return 0;
+}
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static struct usb_driver gdm_usb_driver = {
+ .name = "gdm_wimax",
+ .probe = gdm_usb_probe,
+ .disconnect = gdm_usb_disconnect,
+ .id_table = id_table,
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ .supports_autosuspend = 1,
+ .suspend = gdm_suspend,
+ .resume = gdm_resume,
+ .reset_resume = gdm_resume,
+#endif
+};
+
+static int __init usb_gdm_wimax_init(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ kernel_thread(k_mode_thread, NULL, CLONE_KERNEL);
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+ return usb_register(&gdm_usb_driver);
+}
+
+static void __exit usb_gdm_wimax_exit(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ k_mode_stop = 1;
+ wake_up(&k_wait);
+#endif
+ usb_deregister(&gdm_usb_driver);
+}
+
+module_init(usb_gdm_wimax_init);
+module_exit(usb_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_usb.h b/drivers/staging/gdm72xx/gdm_usb.h
new file mode 100644
index 0000000..ecb891f
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_USB_H__
+#define __GDM_USB_H__
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define B_DIFF_DL_DRV (1<<4)
+#define B_DOWNLOAD (1 << 5)
+#define MAX_NR_SDU_BUF 64
+
+struct usb_tx {
+ struct list_head list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ struct list_head p_list;
+#endif
+ struct tx_cxt *tx_cxt;
+
+ struct urb *urb;
+ u8 *buf;
+
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct tx_cxt {
+ struct list_head free_list;
+ struct list_head sdu_list;
+ struct list_head hci_list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ struct list_head pending_list;
+#endif
+
+ spinlock_t lock;
+};
+
+struct usb_rx {
+ struct list_head list;
+ struct rx_cxt *rx_cxt;
+
+ struct urb *urb;
+ u8 *buf;
+
+ void (*callback)(void *cb_data, void *data, int len);
+ void *cb_data;
+};
+
+struct rx_cxt {
+ struct list_head free_list;
+ struct list_head used_list;
+ spinlock_t lock;
+};
+
+struct usbwm_dev {
+ struct usb_device *usbdev;
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ struct work_struct pm_ws;
+
+ struct usb_interface *intf;
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ int bw_switch;
+ struct list_head list;
+#endif
+
+ struct tx_cxt tx;
+ struct rx_cxt rx;
+
+ int padding;
+};
+
+#endif /* __GDM_USB_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
new file mode 100644
index 0000000..f1936b9
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "wm_ioctl.h"
+#include "netlink_k.h"
+
+#define gdm_wimax_send(n, d, l) \
+ (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, NULL, NULL)
+#define gdm_wimax_send_with_cb(n, d, l, c, b) \
+ (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, c, b)
+#define gdm_wimax_rcv_with_cb(n, c, b) \
+ (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
+
+#define EVT_MAX_SIZE 2048
+
+struct evt_entry {
+ struct list_head list;
+ struct net_device *dev;
+ char evt_data[EVT_MAX_SIZE];
+ int size;
+};
+
+static void __gdm_wimax_event_send(struct work_struct *work);
+static inline struct evt_entry *alloc_event_entry(void);
+static inline void free_event_entry(struct evt_entry *e);
+static struct evt_entry *get_event_entry(void);
+static void put_event_entry(struct evt_entry *e);
+
+static struct {
+ int ref_cnt;
+ struct sock *sock;
+ struct list_head evtq;
+ spinlock_t evt_lock;
+
+ struct list_head freeq;
+ struct work_struct ws;
+} wm_event;
+
+static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30};
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm);
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up);
+
+#if defined(DEBUG_SDU)
+static void printk_hex(u8 *buf, u32 size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (i && i % 16 == 0)
+ printk(KERN_DEBUG "\n%02x ", *buf++);
+ else
+ printk(KERN_DEBUG "%02x ", *buf++);
+ }
+
+ printk(KERN_DEBUG "\n");
+}
+
+static const char *get_protocol_name(u16 protocol)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (protocol) {
+ case ETH_P_ARP:
+ name = "ARP";
+ break;
+ case ETH_P_IP:
+ name = "IP";
+ break;
+ case ETH_P_IPV6:
+ name = "IPv6";
+ break;
+ }
+
+ sprintf(buf, "0x%04x(%s)", protocol, name);
+ return buf;
+}
+
+static const char *get_ip_protocol_name(u8 ip_protocol)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (ip_protocol) {
+ case IPPROTO_TCP:
+ name = "TCP";
+ break;
+ case IPPROTO_UDP:
+ name = "UDP";
+ break;
+ case IPPROTO_ICMP:
+ name = "ICMP";
+ break;
+ }
+
+ sprintf(buf, "%u(%s)", ip_protocol, name);
+ return buf;
+}
+
+static const char *get_port_name(u16 port)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (port) {
+ case 67:
+ name = "DHCP-Server";
+ break;
+ case 68:
+ name = "DHCP-Client";
+ break;
+ case 69:
+ name = "TFTP";
+ break;
+ }
+
+ sprintf(buf, "%u(%s)", port, name);
+ return buf;
+}
+
+static void dump_eth_packet(const char *title, u8 *data, int len)
+{
+ struct iphdr *ih = NULL;
+ struct udphdr *uh = NULL;
+ u16 protocol = 0;
+ u8 ip_protocol = 0;
+ u16 port = 0;
+
+ protocol = (data[12]<<8) | data[13];
+ ih = (struct iphdr *) (data+ETH_HLEN);
+
+ if (protocol == ETH_P_IP) {
+ uh = (struct udphdr *) ((char *)ih + sizeof(struct iphdr));
+ ip_protocol = ih->protocol;
+ port = ntohs(uh->dest);
+ } else if (protocol == ETH_P_IPV6) {
+ struct ipv6hdr *i6h = (struct ipv6hdr *) data;
+ uh = (struct udphdr *) ((char *)i6h + sizeof(struct ipv6hdr));
+ ip_protocol = i6h->nexthdr;
+ port = ntohs(uh->dest);
+ }
+
+ printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n",
+ title, len,
+ get_protocol_name(protocol),
+ get_ip_protocol_name(ip_protocol),
+ get_port_name(port));
+
+ #if 1
+ if (!(data[0] == 0xff && data[1] == 0xff)) {
+ if (protocol == ETH_P_IP) {
+ printk(KERN_DEBUG " src=%u.%u.%u.%u\n",
+ NIPQUAD(ih->saddr));
+ } else if (protocol == ETH_P_IPV6) {
+ #ifdef NIP6
+ printk(KERN_DEBUG " src=%x:%x:%x:%x:%x:%x:%x:%x\n",
+ NIP6(ih->saddr));
+ #else
+ printk(KERN_DEBUG " src=%pI6\n", &ih->saddr);
+ #endif
+ }
+ }
+ #endif
+
+ #if (DUMP_PACKET & DUMP_SDU_ALL)
+ printk_hex(data, len);
+ #else
+ #if (DUMP_PACKET & DUMP_SDU_ARP)
+ if (protocol == ETH_P_ARP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP)
+ if (protocol == ETH_P_IP || protocol == ETH_P_IPV6)
+ printk_hex(data, len);
+ #else
+ #if (DUMP_PACKET & DUMP_SDU_IP_TCP)
+ if (ip_protocol == IPPROTO_TCP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP_UDP)
+ if (ip_protocol == IPPROTO_UDP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP_ICMP)
+ if (ip_protocol == IPPROTO_ICMP)
+ printk_hex(data, len);
+ #endif
+ #endif
+ #endif
+}
+#endif
+
+
+static inline int gdm_wimax_header(struct sk_buff **pskb)
+{
+ u16 buf[HCI_HEADER_SIZE / sizeof(u16)];
+ struct sk_buff *skb = *pskb;
+ int ret = 0;
+
+ if (unlikely(skb_headroom(skb) < HCI_HEADER_SIZE)) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_realloc_headroom(skb, HCI_HEADER_SIZE);
+ if (skb2 == NULL)
+ return -ENOMEM;
+ if (skb->sk)
+ skb_set_owner_w(skb2, skb->sk);
+ kfree_skb(skb);
+ skb = skb2;
+ }
+
+ skb_push(skb, HCI_HEADER_SIZE);
+ buf[0] = H2B(WIMAX_TX_SDU);
+ buf[1] = H2B(skb->len - HCI_HEADER_SIZE);
+ memcpy(skb->data, buf, HCI_HEADER_SIZE);
+
+ *pskb = skb;
+ return ret;
+}
+
+static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg,
+ int len)
+{
+ struct nic *nic = netdev_priv(dev);
+
+ #if defined(DEBUG_HCI)
+ u8 *buf = (u8 *) msg;
+ u16 hci_cmd = (buf[0]<<8) | buf[1];
+ u16 hci_len = (buf[2]<<8) | buf[3];
+ printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
+ #endif
+
+ gdm_wimax_send(nic, msg, len);
+}
+
+static int gdm_wimax_event_init(void)
+{
+ if (wm_event.ref_cnt == 0) {
+ wm_event.sock = netlink_init(NETLINK_WIMAX,
+ gdm_wimax_event_rcv);
+ INIT_LIST_HEAD(&wm_event.evtq);
+ INIT_LIST_HEAD(&wm_event.freeq);
+ INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
+ spin_lock_init(&wm_event.evt_lock);
+ }
+
+ if (wm_event.sock) {
+ wm_event.ref_cnt++;
+ return 0;
+ }
+
+ printk(KERN_ERR "Creating WiMax Event netlink is failed\n");
+ return -1;
+}
+
+static void gdm_wimax_event_exit(void)
+{
+ if (wm_event.sock && --wm_event.ref_cnt == 0) {
+ struct evt_entry *e, *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ list_for_each_entry_safe(e, temp, &wm_event.evtq, list) {
+ list_del(&e->list);
+ free_event_entry(e);
+ }
+ list_for_each_entry_safe(e, temp, &wm_event.freeq, list) {
+ list_del(&e->list);
+ free_event_entry(e);
+ }
+
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+ netlink_exit(wm_event.sock);
+ wm_event.sock = NULL;
+ }
+}
+
+static inline struct evt_entry *alloc_event_entry(void)
+{
+ return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC);
+}
+
+static inline void free_event_entry(struct evt_entry *e)
+{
+ kfree(e);
+}
+
+static struct evt_entry *get_event_entry(void)
+{
+ struct evt_entry *e;
+
+ if (list_empty(&wm_event.freeq))
+ e = alloc_event_entry();
+ else {
+ e = list_entry(wm_event.freeq.next, struct evt_entry, list);
+ list_del(&e->list);
+ }
+
+ return e;
+}
+
+static void put_event_entry(struct evt_entry *e)
+{
+ BUG_ON(!e);
+
+ list_add_tail(&e->list, &wm_event.freeq);
+}
+
+static void __gdm_wimax_event_send(struct work_struct *work)
+{
+ int idx;
+ unsigned long flags;
+ struct evt_entry *e;
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ while (!list_empty(&wm_event.evtq)) {
+ e = list_entry(wm_event.evtq.next, struct evt_entry, list);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+ sscanf(e->dev->name, "wm%d", &idx);
+ netlink_send(wm_event.sock, idx, 0, e->evt_data, e->size);
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+ list_del(&e->list);
+ put_event_entry(e);
+ }
+
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+}
+
+static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size)
+{
+ struct evt_entry *e;
+ unsigned long flags;
+
+ #if defined(DEBUG_HCI)
+ u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1];
+ u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3];
+ printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
+ #endif
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ e = get_event_entry();
+ if (!e) {
+ printk(KERN_ERR "%s: No memory for event\n", __func__);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+ return -ENOMEM;
+ }
+
+ e->dev = dev;
+ e->size = size;
+ memcpy(e->evt_data, buf, size);
+
+ list_add_tail(&e->list, &wm_event.evtq);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+ schedule_work(&wm_event.ws);
+
+ return 0;
+}
+
+static void tx_complete(void *arg)
+{
+ struct nic *nic = arg;
+
+ if (netif_queue_stopped(nic->netdev))
+ netif_wake_queue(nic->netdev);
+}
+
+int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ struct nic *nic = netdev_priv(dev);
+
+ ret = gdm_wimax_send_with_cb(nic, skb->data, skb->len, tx_complete,
+ nic);
+ if (ret == -ENOSPC) {
+ netif_stop_queue(dev);
+ ret = 0;
+ }
+
+ if (ret) {
+ skb_pull(skb, HCI_HEADER_SIZE);
+ return ret;
+ }
+
+ nic->stats.tx_packets++;
+ nic->stats.tx_bytes += skb->len - HCI_HEADER_SIZE;
+ kfree_skb(skb);
+ return ret;
+}
+
+static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ #if defined(DEBUG_SDU)
+ dump_eth_packet("TX", skb->data, skb->len);
+ #endif
+
+ ret = gdm_wimax_header(&skb);
+ if (ret < 0) {
+ skb_pull(skb, HCI_HEADER_SIZE);
+ return ret;
+ }
+
+ #if !defined(LOOPBACK_TEST)
+ if (!fsm)
+ printk(KERN_ERR "ASSERTION ERROR: fsm is NULL!!\n");
+ else if (fsm->m_status != M_CONNECTED) {
+ printk(KERN_EMERG "ASSERTION ERROR: Device is NOT ready. status=%d\n",
+ fsm->m_status);
+ kfree_skb(skb);
+ return 0;
+ }
+ #endif
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ ret = gdm_qos_send_hci_pkt(skb, dev);
+#else
+ ret = gdm_wimax_send_tx(skb, dev);
+#endif
+ return ret;
+}
+
+static int gdm_wimax_set_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void __gdm_wimax_set_mac_addr(struct net_device *dev, char *mac_addr)
+{
+ u16 hci_pkt_buf[32 / sizeof(u16)];
+ u8 *pkt = (u8 *) &hci_pkt_buf[0];
+ struct nic *nic = netdev_priv(dev);
+
+ /* Since dev is registered as a ethernet device,
+ * ether_setup has made dev->addr_len to be ETH_ALEN
+ */
+ memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+
+ /* Let lower layer know of this change by sending
+ * SetInformation(MAC Address)
+ */
+ hci_pkt_buf[0] = H2B(WIMAX_SET_INFO); /* cmd_evt */
+ hci_pkt_buf[1] = H2B(8); /* size */
+ pkt[4] = 0; /* T */
+ pkt[5] = 6; /* L */
+ memcpy(pkt + 6, mac_addr, dev->addr_len); /* V */
+
+ gdm_wimax_send(nic, pkt, HCI_HEADER_SIZE + 8);
+}
+
+/* A driver function */
+static int gdm_wimax_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ __gdm_wimax_set_mac_addr(dev, addr->sa_data);
+
+ return 0;
+}
+
+static struct net_device_stats *gdm_wimax_stats(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+
+ return &nic->stats;
+}
+
+static int gdm_wimax_open(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ netif_start_queue(dev);
+
+ if (fsm && fsm->m_status != M_INIT)
+ gdm_wimax_ind_if_updown(dev, 1);
+ return 0;
+}
+
+static int gdm_wimax_close(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ netif_stop_queue(dev);
+
+ if (fsm && fsm->m_status != M_INIT)
+ gdm_wimax_ind_if_updown(dev, 0);
+ return 0;
+}
+
+static void kdelete(void **buf)
+{
+ if (buf && *buf) {
+ kfree(*buf);
+ *buf = NULL;
+ }
+}
+
+static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
+{
+ int size;
+
+ size = dst->size < src->size ? dst->size : src->size;
+
+ dst->size = size;
+ if (src->size) {
+ if (!dst->buf)
+ return -EINVAL;
+ if (copy_to_user(dst->buf, src->buf, size))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
+{
+ if (!src->size) {
+ dst->size = 0;
+ return 0;
+ }
+
+ if (!src->buf)
+ return -EINVAL;
+
+ if (!(dst->buf && dst->size == src->size)) {
+ kdelete(&dst->buf);
+ dst->buf = kmalloc(src->size, GFP_KERNEL);
+ if (dst->buf == NULL)
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(dst->buf, src->buf, src->size)) {
+ kdelete(&dst->buf);
+ return -EFAULT;
+ }
+ dst->size = src->size;
+ return 0;
+}
+
+static void gdm_wimax_cleanup_ioctl(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < SIOC_DATA_MAX; i++)
+ kdelete(&nic->sdk_data[i].buf);
+}
+
+static void gdm_update_fsm(struct net_device *dev, struct fsm_s *new_fsm)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *cur_fsm =
+ (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ if (!cur_fsm)
+ return;
+
+ if (cur_fsm->m_status != new_fsm->m_status ||
+ cur_fsm->c_status != new_fsm->c_status) {
+ if (new_fsm->m_status == M_CONNECTED)
+ netif_carrier_on(dev);
+ else if (cur_fsm->m_status == M_CONNECTED) {
+ netif_carrier_off(dev);
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ gdm_qos_release_list(nic);
+ #endif
+ }
+ gdm_wimax_ind_fsm_update(dev, new_fsm);
+ }
+}
+
+static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct wm_req_s *req = (struct wm_req_s *) ifr;
+ struct nic *nic = netdev_priv(dev);
+ int ret;
+
+ if (cmd != SIOCWMIOCTL)
+ return -EOPNOTSUPP;
+
+ switch (req->cmd) {
+ case SIOCG_DATA:
+ case SIOCS_DATA:
+ if (req->data_id >= SIOC_DATA_MAX) {
+ printk(KERN_ERR
+ "%s error: data-index(%d) is invalid!!\n",
+ __func__, req->data_id);
+ return -EOPNOTSUPP;
+ }
+ if (req->cmd == SIOCG_DATA) {
+ ret = gdm_wimax_ioctl_get_data(&req->data,
+ &nic->sdk_data[req->data_id]);
+ if (ret < 0)
+ return ret;
+ } else if (req->cmd == SIOCS_DATA) {
+ if (req->data_id == SIOC_DATA_FSM) {
+ /*NOTE: gdm_update_fsm should be called
+ before gdm_wimax_ioctl_set_data is called*/
+ gdm_update_fsm(dev,
+ (struct fsm_s *) req->data.buf);
+ }
+ ret = gdm_wimax_ioctl_set_data(
+ &nic->sdk_data[req->data_id], &req->data);
+ if (ret < 0)
+ return ret;
+ }
+ break;
+ default:
+ printk(KERN_ERR "%s: %x unknown ioctl\n", __func__, cmd);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void gdm_wimax_prepare_device(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ u16 buf[32 / sizeof(u16)];
+ struct hci_s *hci = (struct hci_s *) buf;
+ u16 len = 0;
+ u32 val = 0;
+
+ #define BIT_MULTI_CS 0
+ #define BIT_WIMAX 1
+ #define BIT_QOS 2
+ #define BIT_AGGREGATION 3
+
+ /* GetInformation mac address */
+ len = 0;
+ hci->cmd_evt = H2B(WIMAX_GET_INFO);
+ hci->data[len++] = TLV_T(T_MAC_ADDRESS);
+ hci->length = H2B(len);
+ gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+ val = (1<<BIT_WIMAX) | (1<<BIT_MULTI_CS);
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ val |= (1<<BIT_QOS);
+ #endif
+ #if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+ val |= (1<<BIT_AGGREGATION);
+ #endif
+
+ /* Set capability */
+ len = 0;
+ hci->cmd_evt = H2B(WIMAX_SET_INFO);
+ hci->data[len++] = TLV_T(T_CAPABILITY);
+ hci->data[len++] = TLV_L(T_CAPABILITY);
+ val = DH2B(val);
+ memcpy(&hci->data[len], &val, TLV_L(T_CAPABILITY));
+ len += TLV_L(T_CAPABILITY);
+ hci->length = H2B(len);
+ gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+ printk(KERN_INFO "GDM WiMax Set CAPABILITY: 0x%08X\n", DB2H(val));
+}
+
+static int gdm_wimax_hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V)
+{
+ #define __U82U16(b) ((u16)((u8 *)(b))[0] | ((u16)((u8 *)(b))[1] << 8))
+ int next_pos;
+
+ *T = buf[0];
+ if (buf[1] == 0x82) {
+ *L = B2H(__U82U16(&buf[2]));
+ next_pos = 1/*type*/+3/*len*/;
+ } else {
+ *L = buf[1];
+ next_pos = 1/*type*/+1/*len*/;
+ }
+ *V = &buf[next_pos];
+
+ next_pos += *L/*length of val*/;
+ return next_pos;
+}
+
+static int gdm_wimax_get_prepared_info(struct net_device *dev, char *buf,
+ int len)
+{
+ u8 T, *V;
+ u16 L;
+ u16 cmd_evt, cmd_len;
+ int pos = HCI_HEADER_SIZE;
+
+ cmd_evt = B2H(*(u16 *)&buf[0]);
+ cmd_len = B2H(*(u16 *)&buf[2]);
+
+ if (len < cmd_len + HCI_HEADER_SIZE) {
+ printk(KERN_ERR "%s: invalid length [%d/%d]\n", __func__,
+ cmd_len + HCI_HEADER_SIZE, len);
+ return -1;
+ }
+
+ if (cmd_evt == WIMAX_GET_INFO_RESULT) {
+ if (cmd_len < 2) {
+ printk(KERN_ERR "%s: len is too short [%x/%d]\n",
+ __func__, cmd_evt, len);
+ return -1;
+ }
+
+ pos += gdm_wimax_hci_get_tlv(&buf[pos], &T, &L, &V);
+ if (T == TLV_T(T_MAC_ADDRESS)) {
+ if (L != dev->addr_len) {
+ printk(KERN_ERR
+ "%s Invalid inofrmation result T/L "
+ "[%x/%d]\n", __func__, T, L);
+ return -1;
+ }
+ printk(KERN_INFO
+ "MAC change [%02x:%02x:%02x:%02x:%02x:%02x]"
+ "->[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ V[0], V[1], V[2], V[3], V[4], V[5]);
+ memcpy(dev->dev_addr, V, dev->addr_len);
+ return 1;
+ }
+ }
+
+ gdm_wimax_event_send(dev, buf, len);
+ return 0;
+}
+
+static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct sk_buff *skb;
+ int ret;
+
+ #if defined(DEBUG_SDU)
+ dump_eth_packet("RX", buf, len);
+ #endif
+
+ skb = dev_alloc_skb(len + 2);
+ if (!skb) {
+ printk(KERN_ERR "%s: dev_alloc_skb failed!\n", __func__);
+ return;
+ }
+ skb_reserve(skb, 2);
+
+ nic->stats.rx_packets++;
+ nic->stats.rx_bytes += len;
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev); /* what will happen? */
+
+ ret = in_interrupt() ? netif_rx(skb) : netif_rx_ni(skb);
+ if (ret == NET_RX_DROP)
+ printk(KERN_ERR "%s skb dropped\n", __func__);
+}
+
+static void gdm_wimax_transmit_aggr_pkt(struct net_device *dev, char *buf,
+ int len)
+{
+ #define HCI_PADDING_BYTE 4
+ #define HCI_RESERVED_BYTE 4
+ struct hci_s *hci;
+ int length;
+
+ while (len > 0) {
+ hci = (struct hci_s *) buf;
+
+ if (B2H(hci->cmd_evt) != WIMAX_RX_SDU) {
+ printk(KERN_ERR "Wrong cmd_evt(0x%04X)\n",
+ B2H(hci->cmd_evt));
+ break;
+ }
+
+ length = B2H(hci->length);
+ gdm_wimax_netif_rx(dev, hci->data, length);
+
+ if (length & 0x3) {
+ /* Add padding size */
+ length += HCI_PADDING_BYTE - (length & 0x3);
+ }
+
+ length += HCI_HEADER_SIZE + HCI_RESERVED_BYTE;
+ len -= length;
+ buf += length;
+ }
+}
+
+static void gdm_wimax_transmit_pkt(struct net_device *dev, char *buf, int len)
+{
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ struct nic *nic = netdev_priv(dev);
+ #endif
+ u16 cmd_evt, cmd_len;
+
+ /* This code is added for certain rx packet to be ignored. */
+ if (len == 0)
+ return;
+
+ cmd_evt = B2H(*(u16 *)&buf[0]);
+ cmd_len = B2H(*(u16 *)&buf[2]);
+
+ if (len < cmd_len + HCI_HEADER_SIZE) {
+ if (len)
+ printk(KERN_ERR "%s: invalid length [%d/%d]\n",
+ __func__, cmd_len + HCI_HEADER_SIZE, len);
+ return;
+ }
+
+ switch (cmd_evt) {
+ case WIMAX_RX_SDU_AGGR:
+ gdm_wimax_transmit_aggr_pkt(dev, &buf[HCI_HEADER_SIZE],
+ cmd_len);
+ break;
+ case WIMAX_RX_SDU:
+ gdm_wimax_netif_rx(dev, &buf[HCI_HEADER_SIZE], cmd_len);
+ break;
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ case WIMAX_EVT_MODEM_REPORT:
+ gdm_recv_qos_hci_packet(nic, buf, len);
+ break;
+ #endif
+ case WIMAX_SDU_TX_FLOW:
+ if (buf[4] == 0) {
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+ } else if (buf[4] == 1) {
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ }
+ break;
+ default:
+ gdm_wimax_event_send(dev, buf, len);
+ break;
+ }
+}
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm)
+{
+ u16 buf[32 / sizeof(u16)];
+ u8 *hci_pkt_buf = (u8 *)&buf[0];
+
+ /* Indicate updating fsm */
+ buf[0] = H2B(WIMAX_FSM_UPDATE);
+ buf[1] = H2B(sizeof(struct fsm_s));
+ memcpy(&hci_pkt_buf[HCI_HEADER_SIZE], fsm, sizeof(struct fsm_s));
+
+ gdm_wimax_event_send(dev, hci_pkt_buf,
+ HCI_HEADER_SIZE + sizeof(struct fsm_s));
+}
+
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up)
+{
+ u16 buf[32 / sizeof(u16)];
+ struct hci_s *hci = (struct hci_s *) buf;
+ unsigned char up_down;
+
+ up_down = if_up ? WIMAX_IF_UP : WIMAX_IF_DOWN;
+
+ /* Indicate updating fsm */
+ hci->cmd_evt = H2B(WIMAX_IF_UPDOWN);
+ hci->length = H2B(sizeof(up_down));
+ hci->data[0] = up_down;
+
+ gdm_wimax_event_send(dev, (char *)hci, HCI_HEADER_SIZE+sizeof(up_down));
+}
+
+static void rx_complete(void *arg, void *data, int len)
+{
+ struct nic *nic = arg;
+
+ gdm_wimax_transmit_pkt(nic->netdev, data, len);
+ gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+}
+
+static void prepare_rx_complete(void *arg, void *data, int len)
+{
+ struct nic *nic = arg;
+ int ret;
+
+ ret = gdm_wimax_get_prepared_info(nic->netdev, data, len);
+ if (ret == 1)
+ gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+ else {
+ if (ret < 0)
+ printk(KERN_ERR "get_prepared_info failed(%d)\n", ret);
+ gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+ #if 0
+ /* Re-prepare WiMax device */
+ gdm_wimax_prepare_device(nic->netdev);
+ #endif
+ }
+}
+
+static void start_rx_proc(struct nic *nic)
+{
+ gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+}
+
+static struct net_device_ops gdm_netdev_ops = {
+ .ndo_open = gdm_wimax_open,
+ .ndo_stop = gdm_wimax_close,
+ .ndo_set_config = gdm_wimax_set_config,
+ .ndo_start_xmit = gdm_wimax_tx,
+ .ndo_get_stats = gdm_wimax_stats,
+ .ndo_set_mac_address = gdm_wimax_set_mac_addr,
+ .ndo_do_ioctl = gdm_wimax_ioctl,
+};
+
+int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev)
+{
+ struct nic *nic = NULL;
+ struct net_device *dev;
+ int ret;
+
+ dev = (struct net_device *)alloc_netdev(sizeof(*nic),
+ "wm%d", ether_setup);
+
+ if (dev == NULL) {
+ printk(KERN_ERR "alloc_etherdev failed\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(dev, pdev);
+ dev->mtu = 1400;
+ dev->netdev_ops = &gdm_netdev_ops;
+ dev->flags &= ~IFF_MULTICAST;
+ memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr));
+
+ nic = netdev_priv(dev);
+ memset(nic, 0, sizeof(*nic));
+
+ nic->netdev = dev;
+ nic->phy_dev = phy_dev;
+ phy_dev->netdev = dev;
+
+ /* event socket init */
+ ret = gdm_wimax_event_init();
+ if (ret < 0) {
+ printk(KERN_ERR "Cannot create event.\n");
+ goto cleanup;
+ }
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto cleanup;
+
+ #if defined(LOOPBACK_TEST)
+ netif_start_queue(dev);
+ netif_carrier_on(dev);
+ #else
+ netif_carrier_off(dev);
+ #endif
+
+#ifdef CONFIG_WIMAX_GDM72XX_QOS
+ gdm_qos_init(nic);
+#endif
+
+ start_rx_proc(nic);
+
+ /* Prepare WiMax device */
+ gdm_wimax_prepare_device(dev);
+
+ return 0;
+
+cleanup:
+ printk(KERN_ERR "register_netdev failed\n");
+ free_netdev(dev);
+ return ret;
+}
+
+void unregister_wimax_device(struct phy_dev *phy_dev)
+{
+ struct nic *nic = netdev_priv(phy_dev->netdev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ if (fsm)
+ fsm->m_status = M_INIT;
+ unregister_netdev(nic->netdev);
+
+ gdm_wimax_event_exit();
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ gdm_qos_release_list(nic);
+#endif
+
+ gdm_wimax_cleanup_ioctl(phy_dev->netdev);
+
+ free_netdev(nic->netdev);
+}
diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h
new file mode 100644
index 0000000..023e649
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GDM_WIMAX_H__
+#define __GDM_WIMAX_H__
+
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include "wm_ioctl.h"
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+#include "gdm_qos.h"
+#endif
+
+#define DRIVER_VERSION "3.2.3"
+
+/*#define ETH_P_IP 0x0800 */
+/*#define ETH_P_ARP 0x0806 */
+/*#define ETH_P_IPV6 0x86DD */
+
+#define H2L(x) __cpu_to_le16(x)
+#define L2H(x) __le16_to_cpu(x)
+#define DH2L(x) __cpu_to_le32(x)
+#define DL2H(x) __le32_to_cpu(x)
+
+#define H2B(x) __cpu_to_be16(x)
+#define B2H(x) __be16_to_cpu(x)
+#define DH2B(x) __cpu_to_be32(x)
+#define DB2H(x) __be32_to_cpu(x)
+
+struct phy_dev {
+ void *priv_dev;
+ struct net_device *netdev;
+
+ int (*send_func)(void *priv_dev, void *data, int len,
+ void (*cb)(void *cb_data), void *cb_data);
+ int (*rcv_func)(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data);
+};
+
+struct nic {
+ struct net_device *netdev;
+ struct phy_dev *phy_dev;
+
+ struct net_device_stats stats;
+
+ struct data_s sdk_data[SIOC_DATA_MAX];
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ struct qos_cb_s qos;
+#endif
+
+};
+
+
+#if 0
+#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args)
+#else
+#define dprintk(...)
+#endif
+
+/*#define DEBUG_SDU */
+#if defined(DEBUG_SDU)
+#define DUMP_SDU_ALL (1<<0)
+#define DUMP_SDU_ARP (1<<1)
+#define DUMP_SDU_IP (1<<2)
+#define DUMP_SDU_IP_TCP (1<<8)
+#define DUMP_SDU_IP_UDP (1<<9)
+#define DUMP_SDU_IP_ICMP (1<<10)
+#define DUMP_PACKET (DUMP_SDU_ALL)
+#endif
+
+/*#define DEBUG_HCI */
+
+/*#define LOOPBACK_TEST */
+
+extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev);
+extern int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev);
+extern void unregister_wimax_device(struct phy_dev *phy_dev);
+
+#endif
diff --git a/drivers/staging/gdm72xx/hci.h b/drivers/staging/gdm72xx/hci.h
new file mode 100644
index 0000000..0e06766
--- /dev/null
+++ b/drivers/staging/gdm72xx/hci.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef HCI_H_20080801
+#define HCI_H_20080801
+
+#define HCI_HEADER_SIZE 4
+#define HCI_VALUE_OFFS (HCI_HEADER_SIZE)
+#define HCI_MAX_PACKET 2048
+#define HCI_MAX_PARAM (HCI_MAX_PACKET-HCI_HEADER_SIZE)
+#define HCI_MAX_TLV 32
+
+/* CMD-EVT */
+
+/* Category 0 */
+#define WIMAX_RESET 0x0000
+#define WIMAX_SET_INFO 0x0001
+#define WIMAX_GET_INFO 0x0002
+#define WIMAX_GET_INFO_RESULT 0x8003
+#define WIMAX_RADIO_OFF 0x0004
+#define WIMAX_RADIO_ON 0x0006
+#define WIMAX_WIMAX_RESET 0x0007 /* Is this still here */
+
+/* Category 1 */
+#define WIMAX_NET_ENTRY 0x0100
+#define WIMAX_NET_DISCONN 0x0102
+#define WIMAX_ENTER_SLEEP 0x0103
+#define WIMAX_EXIT_SLEEP 0x0104
+#define WIMAX_ENTER_IDLE 0x0105
+#define WIMAX_EXIT_IDLE 0x0106
+#define WIMAX_MODE_CHANGE 0x8108
+#define WIMAX_HANDOVER 0x8109 /* obsolete */
+
+#define WIMAX_SCAN 0x010d
+#define WIMAX_SCAN_COMPLETE 0x810e
+#define WIMAX_SCAN_RESULT 0x810f
+
+#define WIMAX_CONNECT 0x0110
+#define WIMAX_CONNECT_START 0x8111
+#define WIMAX_CONNECT_COMPLETE 0x8112
+#define WIMAX_ASSOC_START 0x8113
+#define WIMAX_ASSOC_COMPLETE 0x8114
+#define WIMAX_DISCONN_IND 0x8115
+#define WIMAX_ENTRY_IND 0x8116
+#define WIMAX_HO_START 0x8117
+#define WIMAX_HO_COMPLETE 0x8118
+#define WIMAX_RADIO_STATE_IND 0x8119
+#define WIMAX_IP_RENEW_IND 0x811a
+
+#define WIMAX_DISCOVER_NSP 0x011d
+#define WIMAX_DISCOVER_NSP_RESULT 0x811e
+
+#define WIMAX_SDU_TX_FLOW 0x8125
+
+/* Category 2 */
+#define WIMAX_TX_EAP 0x0200
+#define WIMAX_RX_EAP 0x8201
+#define WIMAX_TX_SDU 0x0202
+#define WIMAX_RX_SDU 0x8203
+#define WIMAX_RX_SDU_AGGR 0x8204
+#define WIMAX_TX_SDU_AGGR 0x0205
+
+/* Category 3 */
+#define WIMAX_DM_CMD 0x030a
+#define WIMAX_DM_RSP 0x830b
+
+#define WIMAX_CLI_CMD 0x030c
+#define WIMAX_CLI_RSP 0x830d
+
+#define WIMAX_DL_IMAGE 0x0310
+#define WIMAX_DL_IMAGE_STATUS 0x8311
+#define WIMAX_UL_IMAGE 0x0312
+#define WIMAX_UL_IMAGE_RESULT 0x8313
+#define WIMAX_UL_IMAGE_STATUS 0x0314
+
+#define WIMAX_EVT_MODEM_REPORT 0x8325
+
+/* Category 0xF */
+#define WIMAX_FSM_UPDATE 0x8F01
+#define WIMAX_IF_UPDOWN 0x8F02
+ #define WIMAX_IF_UP 1
+ #define WIMAX_IF_DOWN 2
+
+/* WIMAX mode */
+#define W_NULL 0
+#define W_STANDBY 1
+#define W_OOZ 2
+#define W_AWAKE 3
+#define W_IDLE 4
+#define W_SLEEP 5
+#define W_WAIT 6
+
+#define W_NET_ENTRY_RNG 0x80
+#define W_NET_ENTRY_SBC 0x81
+#define W_NET_ENTRY_PKM 0x82
+#define W_NET_ENTRY_REG 0x83
+#define W_NET_ENTRY_DSX 0x84
+
+#define W_NET_ENTRY_RNG_FAIL 0x1100100
+#define W_NET_ENTRY_SBC_FAIL 0x1100200
+#define W_NET_ENTRY_PKM_FAIL 0x1102000
+#define W_NET_ENTRY_REG_FAIL 0x1103000
+#define W_NET_ENTRY_DSX_FAIL 0x1104000
+
+/* Scan Type */
+#define W_SCAN_ALL_CHANNEL 0
+#define W_SCAN_ALL_SUBSCRIPTION 1
+#define W_SCAN_SPECIFIED_SUBSCRIPTION 2
+
+/*
+ * TLV
+ *
+ * [31:31] indicates the type is composite.
+ * [30:16] is the length of the type. 0 length means length is variable.
+ * [15:0] is the actual type.
+ *
+ */
+#define TLV_L(x) (((x) >> 16) & 0xff)
+#define TLV_T(x) ((x) & 0xff)
+#define TLV_COMPOSITE(x) ((x) >> 31)
+
+/* GENERAL */
+#define T_MAC_ADDRESS (0x00 | (6 << 16))
+#define T_BSID (0x01 | (6 << 16))
+#define T_MSK (0x02 | (64 << 16))
+#define T_RSSI_THRSHLD (0x03 | (1 << 16))
+#define T_FREQUENCY (0x04 | (4 << 16))
+#define T_CONN_CS_TYPE (0x05 | (1 << 16))
+#define T_HOST_IP_VER (0x06 | (1 << 16))
+#define T_STBY_SCAN_INTERVAL (0x07 | (4 << 16))
+#define T_OOZ_SCAN_INTERVAL (0x08 | (4 << 16))
+#define T_IMEI (0x09 | (8 << 16))
+#define T_PID (0x0a | (12 << 16))
+
+#define T_CAPABILITY (0x1a | (4 << 16))
+#define T_RELEASE_NUMBER (0x1b | (4 << 16))
+#define T_DRIVER_REVISION (0x1c | (4 << 16))
+#define T_FW_REVISION (0x1d | (4 << 16))
+#define T_MAC_HW_REVISION (0x1e | (4 << 16))
+#define T_PHY_HW_REVISION (0x1f | (4 << 16))
+
+/* HANDOVER */
+#define T_SCAN_INTERVAL (0x20 | (1 << 16))
+
+#define T_RSC_RETAIN_TIME (0x2f | (2 << 16))
+
+/* SLEEP */
+#define T_TYPE1_ISW (0x40 | (1 << 16))
+
+#define T_SLP_START_TO (0x4a | (2 << 16))
+
+/* IDLE */
+#define T_IDLE_MODE_TO (0x50 | (2 << 16))
+
+#define T_IDLE_START_TO (0x54 | (2 << 16))
+
+/* MONITOR */
+#define T_RSSI (0x60 | (1 << 16))
+#define T_CINR (0x61 | (1 << 16))
+#define T_TX_POWER (0x6a | (1 << 16))
+#define T_CUR_FREQ (0x7f | (4 << 16))
+
+
+/* WIMAX */
+#define T_MAX_SUBSCRIPTION (0xa1 | (1 << 16))
+#define T_MAX_SF (0xa2 | (1 << 16))
+#define T_PHY_TYPE (0xa3 | (1 << 16))
+#define T_PKM (0xa4 | (1 << 16))
+#define T_AUTH_POLICY (0xa5 | (1 << 16))
+#define T_CS_TYPE (0xa6 | (2 << 16))
+#define T_VENDOR_NAME (0xa7 | (0 << 16))
+#define T_MOD_NAME (0xa8 | (0 << 16))
+#define T_PACKET_FILTER (0xa9 | (1 << 16))
+#define T_NSP_CHANGE_COUNT (0xaa | (4 << 16))
+#define T_RADIO_STATE (0xab | (1 << 16))
+#define T_URI_CONTACT_TYPE (0xac | (1 << 16))
+#define T_URI_TEXT (0xad | (0 << 16))
+#define T_URI (0xae | (0 << 16))
+#define T_ENABLE_AUTH (0xaf | (1 << 16))
+#define T_TIMEOUT (0xb0 | (2 << 16))
+#define T_RUN_MODE (0xb1 | (1 << 16))
+#define T_OMADMT_VER (0xb2 | (4 << 16))
+/* This is measured in seconds from 00:00:00 GMT January 1, 1970. */
+#define T_RTC_TIME (0xb3 | (4 << 16))
+#define T_CERT_STATUS (0xb4 | (4 << 16))
+#define T_CERT_MASK (0xb5 | (4 << 16))
+#define T_EMSK (0xb6 | (64 << 16))
+
+/* Subscription TLV */
+#define T_SUBSCRIPTION_LIST (0xd1 | (0 << 16) | (1 << 31))
+#define T_H_NSPID (0xd2 | (3 << 16))
+#define T_NSP_NAME (0xd3 | (0 << 16))
+#define T_SUBSCRIPTION_NAME (0xd4 | (0 << 16))
+#define T_SUBSCRIPTION_FLAG (0xd5 | (2 << 16))
+#define T_V_NSPID (0xd6 | (3 << 16))
+#define T_NAP_ID (0xd7 | (3 << 16))
+#define T_PREAMBLES (0xd8 | (15 << 16))
+#define T_BW (0xd9 | (4 << 16))
+#define T_FFTSIZE (0xda | (4 << 16))
+#define T_DUPLEX_MODE (0xdb | (4 << 16))
+
+struct hci_s {
+ unsigned short cmd_evt;
+ unsigned short length;
+ unsigned char data[0];
+} __packed;
+
+#endif
diff --git a/drivers/staging/gdm72xx/netlink_k.c b/drivers/staging/gdm72xx/netlink_k.c
new file mode 100644
index 0000000..292af0f
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/netlink.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+#if !defined(NLMSG_HDRLEN)
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#endif
+
+#define ND_MAX_GROUP 30
+#define ND_IFINDEX_LEN sizeof(int)
+#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh) \
+ ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN 8096
+
+#if defined(DEFINE_MUTEX)
+static DEFINE_MUTEX(netlink_mutex);
+#else
+static struct semaphore netlink_mutex;
+#define mutex_lock(x) down(x)
+#define mutex_unlock(x) up(x)
+#endif
+
+static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
+
+static void netlink_rcv_cb(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct net_device *dev;
+ u32 mlen;
+ void *msg;
+ int ifindex;
+
+ if (skb->len >= NLMSG_SPACE(0)) {
+ nlh = (struct nlmsghdr *)skb->data;
+
+ if (skb->len < nlh->nlmsg_len ||
+ nlh->nlmsg_len > ND_MAX_MSG_LEN) {
+ printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len,
+ nlh->nlmsg_len);
+ return;
+ }
+
+ memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
+ msg = ND_NLMSG_DATA(nlh);
+ mlen = ND_NLMSG_R_LEN(nlh);
+
+ if (rcv_cb) {
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (dev) {
+ rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
+ dev_put(dev);
+ } else
+ printk(KERN_ERR "dev_get_by_index(%d) "
+ "is not found.\n", ifindex);
+ } else
+ printk(KERN_ERR "Unregistered Callback\n");
+ }
+}
+
+static void netlink_rcv(struct sk_buff *skb)
+{
+ mutex_lock(&netlink_mutex);
+ netlink_rcv_cb(skb);
+ mutex_unlock(&netlink_mutex);
+}
+
+struct sock *netlink_init(int unit, void (*cb)(struct net_device *dev, u16 type,
+ void *msg, int len))
+{
+ struct sock *sock;
+
+#if !defined(DEFINE_MUTEX)
+ init_MUTEX(&netlink_mutex);
+#endif
+
+ sock = netlink_kernel_create(&init_net, unit, 0, netlink_rcv, NULL,
+ THIS_MODULE);
+
+ if (sock)
+ rcv_cb = cb;
+
+ return sock;
+}
+
+void netlink_exit(struct sock *sock)
+{
+ sock_release(sock->sk_socket);
+}
+
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+{
+ static u32 seq;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh;
+ int ret = 0;
+
+ if (group > ND_MAX_GROUP) {
+ printk(KERN_ERR "Group %d is invalied.\n", group);
+ printk(KERN_ERR "Valid group is 0 ~ %d.\n", ND_MAX_GROUP);
+ return -EINVAL;
+ }
+
+ skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "netlink_broadcast ret=%d\n", ret);
+ return -ENOMEM;
+ }
+
+ seq++;
+ nlh = NLMSG_PUT(skb, 0, seq, type, len);
+ memcpy(NLMSG_DATA(nlh), msg, len);
+
+ NETLINK_CB(skb).pid = 0;
+ NETLINK_CB(skb).dst_group = 0;
+
+ ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
+
+ if (!ret)
+ return len;
+ else {
+ if (ret != -ESRCH) {
+ printk(KERN_ERR "netlink_broadcast g=%d, t=%d, l=%d, r=%d\n",
+ group, type, len, ret);
+ }
+ ret = 0;
+ }
+
+nlmsg_failure:
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/netlink_k.h b/drivers/staging/gdm72xx/netlink_k.h
new file mode 100644
index 0000000..1dffaa6
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(NETLINK_H_20081202)
+#define NETLINK_H_20081202
+#include <linux/netdevice.h>
+#include <net/sock.h>
+
+struct sock *netlink_init(int unit,
+ void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
+void netlink_exit(struct sock *sock);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+
+#endif
diff --git a/drivers/staging/gdm72xx/sdio_boot.c b/drivers/staging/gdm72xx/sdio_boot.c
new file mode 100644
index 0000000..6ff4dc3
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "gdm_sdio.h"
+
+#define TYPE_A_HEADER_SIZE 4
+#define TYPE_A_LOOKAHEAD_SIZE 16
+#define YMEM0_SIZE 0x8000 /* 32kbytes */
+#define DOWNLOAD_SIZE (YMEM0_SIZE - TYPE_A_HEADER_SIZE)
+
+#define KRN_PATH "/lib/firmware/gdm72xx/gdmskrn.bin"
+#define RFS_PATH "/lib/firmware/gdm72xx/gdmsrfs.bin"
+
+static u8 *tx_buf;
+
+static int ack_ready(struct sdio_func *func)
+{
+ unsigned long start = jiffies;
+ u8 val;
+ int ret;
+
+ while ((jiffies - start) < HZ) {
+ val = sdio_readb(func, 0x13, &ret);
+ if (val & 0x01)
+ return 1;
+ schedule();
+ }
+
+ return 0;
+}
+
+static int download_image(struct sdio_func *func, char *img_name)
+{
+ int ret = 0, len, size, pno;
+ struct file *filp = NULL;
+ struct inode *inode = NULL;
+ u8 *buf = tx_buf;
+ loff_t pos = 0;
+
+ filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", img_name);
+ return -ENOENT;
+ }
+
+ if (filp->f_dentry)
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", img_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ size = i_size_read(inode->i_mapping->host);
+ if (size <= 0) {
+ printk(KERN_ERR "Unable to find file size: %s\n", img_name);
+ ret = size;
+ goto out;
+ }
+
+ pno = 0;
+ while ((len = filp->f_op->read(filp, buf + TYPE_A_HEADER_SIZE,
+ DOWNLOAD_SIZE, &pos))) {
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ buf[2] = (len >> 16) & 0xff;
+
+ if (pos >= size) /* The last packet */
+ buf[3] = 2;
+ else
+ buf[3] = 0;
+
+ ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE);
+ if (ret < 0) {
+ printk(KERN_ERR "gdmwm: send image error: "
+ "packet number = %d ret = %d\n", pno, ret);
+ goto out;
+ }
+ if (buf[3] == 2) /* The last packet */
+ break;
+ if (!ack_ready(func)) {
+ ret = -EIO;
+ printk(KERN_ERR "gdmwm: Ack is not ready.\n");
+ goto out;
+ }
+ ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE);
+ if (ret < 0) {
+ printk(KERN_ERR "gdmwm: receive ack error: "
+ "packet number = %d ret = %d\n", pno, ret);
+ goto out;
+ }
+ sdio_writeb(func, 0x01, 0x13, &ret);
+ sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */
+
+ pno++;
+ }
+out:
+ filp_close(filp, current->files);
+ return ret;
+}
+
+int sdio_boot(struct sdio_func *func)
+{
+ static mm_segment_t fs;
+ int ret;
+
+ tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL);
+ if (tx_buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc: %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ ret = download_image(func, KRN_PATH);
+ if (ret)
+ goto restore_fs;
+ printk(KERN_INFO "GCT: Kernel download success.\n");
+
+ ret = download_image(func, RFS_PATH);
+ if (ret)
+ goto restore_fs;
+ printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+restore_fs:
+ set_fs(fs);
+ kfree(tx_buf);
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/sdio_boot.h b/drivers/staging/gdm72xx/sdio_boot.h
new file mode 100644
index 0000000..373ac28
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SDIO_BOOT_H__
+#define __SDIO_BOOT_H__
+
+struct sdio_func;
+
+extern int sdio_boot(struct sdio_func *func);
+
+#endif /* __SDIO_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c
new file mode 100644
index 0000000..5a0e030
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include "gdm_usb.h"
+#include "usb_boot.h"
+
+#define DN_KERNEL_MAGIC_NUMBER 0x10760001
+#define DN_ROOTFS_MAGIC_NUMBER 0x10760002
+
+#define DOWNLOAD_SIZE 1024
+
+#define DH2B(x) __cpu_to_be32(x)
+#define DL2H(x) __le32_to_cpu(x)
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+#define MAX_IMG_CNT 16
+#define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin"
+#define KERN_PATH "/lib/firmware/gdm72xx/zImage"
+#define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2"
+
+struct dn_header {
+ u32 magic_num;
+ u32 file_size;
+};
+
+struct img_header {
+ u32 magic_code;
+ u32 count;
+ u32 len;
+ u32 offset[MAX_IMG_CNT];
+ char hostname[32];
+ char date[32];
+};
+
+struct fw_info {
+ u32 id;
+ u32 len;
+ u32 kernel_len;
+ u32 rootfs_len;
+ u32 kernel_offset;
+ u32 rootfs_offset;
+ u32 fw_ver;
+ u32 mac_ver;
+ char hostname[32];
+ char userid[16];
+ char date[32];
+ char user_desc[128];
+};
+
+static void array_le32_to_cpu(u32 *arr, int num)
+{
+ int i;
+ for (i = 0; i < num; i++, arr++)
+ *arr = DL2H(*arr);
+}
+
+static u8 *tx_buf;
+
+static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
+{
+ int ret;
+ int actual;
+
+ ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
+ &actual, 1000);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
+{
+ int ret;
+ int actual;
+
+ ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
+ &actual, 5000);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n",
+ ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int download_image(struct usb_device *usbdev, struct file *filp,
+ loff_t *pos, u32 img_len, u32 magic_num)
+{
+ struct dn_header h;
+ int ret = 0;
+ u32 size;
+ int len, readn;
+
+ size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
+ h.magic_num = DH2B(magic_num);
+ h.file_size = DH2B(size);
+
+ ret = gdm_wibro_send(usbdev, &h, sizeof(h));
+ if (ret < 0)
+ goto out;
+
+ readn = 0;
+ while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
+
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+ readn += len;
+
+ ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
+ if (ret < 0)
+ goto out;
+ if (readn >= img_len)
+ break;
+ }
+
+ if (readn < img_len) {
+ printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
+ "Read = %d Requested = %d\n", readn, img_len);
+ ret = -EIO;
+ }
+out:
+
+ return ret;
+}
+
+int usb_boot(struct usb_device *usbdev, u16 pid)
+{
+ int i, ret = 0;
+ struct file *filp = NULL;
+ struct inode *inode = NULL;
+ static mm_segment_t fs;
+ struct img_header hdr;
+ struct fw_info fw_info;
+ loff_t pos = 0;
+ char *img_name = UIMG_PATH;
+ int len;
+
+ tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
+ if (tx_buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc\n");
+ return -ENOMEM;
+ }
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", img_name);
+ set_fs(fs);
+ ret = -ENOENT;
+ goto restore_fs;
+ }
+
+ if (filp->f_dentry)
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", img_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
+ if (len != sizeof(hdr)) {
+ printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ array_le32_to_cpu((u32 *)&hdr, 19);
+#if 0
+ if (hdr.magic_code != 0x10767fff) {
+ printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n",
+ hdr.magic_code);
+ ret = -EINVAL;
+ goto out;
+ }
+#endif
+ if (hdr.count > MAX_IMG_CNT) {
+ printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < hdr.count; i++) {
+ if (hdr.offset[i] > hdr.len) {
+ printk(KERN_ERR "gdmwm: Invalid offset. "
+ "Entry = %d Offset = 0x%08x "
+ "Image length = 0x%08x\n",
+ i, hdr.offset[i], hdr.len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pos = hdr.offset[i];
+ len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
+ &pos);
+ if (len != sizeof(fw_info)) {
+ printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ array_le32_to_cpu((u32 *)&fw_info, 8);
+#if 0
+ if ((fw_info.id & 0xfffff000) != 0x10767000) {
+ printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n",
+ fw_info.id);
+ ret = -EIO;
+ goto out;
+ }
+#endif
+
+ if ((fw_info.id & 0xffff) != pid)
+ continue;
+
+ pos = hdr.offset[i] + fw_info.kernel_offset;
+ ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
+ DN_KERNEL_MAGIC_NUMBER);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT: Kernel download success.\n");
+
+ pos = hdr.offset[i] + fw_info.rootfs_offset;
+ ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
+ DN_ROOTFS_MAGIC_NUMBER);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+ break;
+ }
+
+ if (i == hdr.count) {
+ printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid);
+ ret = -EINVAL;
+ }
+out:
+ filp_close(filp, current->files);
+
+restore_fs:
+ set_fs(fs);
+ kfree(tx_buf);
+ return ret;
+}
+
+/*#define GDM7205_PADDING 256 */
+#define DOWNLOAD_CHUCK 2048
+#define KERNEL_TYPE_STRING "linux"
+#define FS_TYPE_STRING "rootfs"
+
+static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
+{
+ int ack;
+ int ret = -1;
+
+ if (send_zlp) {
+ /*Send ZLP*/
+ ret = gdm_wibro_send(usbdev, NULL, 0);
+ if (ret < 0)
+ goto out;
+ }
+
+ /*Wait for ACK*/
+ ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
+ if (ret < 0)
+ goto out;
+out:
+ return ret;
+}
+
+static int em_download_image(struct usb_device *usbdev, char *path,
+ char *type_string)
+{
+ struct file *filp;
+ struct inode *inode;
+ static mm_segment_t fs;
+ char *buf = NULL;
+ loff_t pos = 0;
+ int ret = 0;
+ int len, readn = 0;
+ #if defined(GDM7205_PADDING)
+ const int pad_size = GDM7205_PADDING;
+ #else
+ const int pad_size = 0;
+ #endif
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", path);
+ set_fs(fs);
+ ret = -ENOENT;
+ goto restore_fs;
+ }
+
+ if (filp->f_dentry) {
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", path);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc\n");
+ return -ENOMEM;
+ }
+
+ strcpy(buf+pad_size, type_string);
+ ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
+ if (ret < 0)
+ goto out;
+
+ while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
+ &pos))) {
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+ readn += len;
+
+ ret = gdm_wibro_send(usbdev, buf, len+pad_size);
+ if (ret < 0)
+ goto out;
+
+ ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = em_wait_ack(usbdev, 1);
+ if (ret < 0)
+ goto out;
+
+out:
+ filp_close(filp, current->files);
+
+restore_fs:
+ set_fs(fs);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int em_fw_reset(struct usb_device *usbdev)
+{
+ int ret;
+
+ /*Send ZLP*/
+ ret = gdm_wibro_send(usbdev, NULL, 0);
+ return ret;
+}
+
+int usb_emergency(struct usb_device *usbdev)
+{
+ int ret;
+
+ ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
+
+ ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
+
+ ret = em_fw_reset(usbdev);
+out:
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/usb_boot.h b/drivers/staging/gdm72xx/usb_boot.h
new file mode 100644
index 0000000..c715cd3
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __USB_BOOT_H__
+#define __USB_BOOT_H__
+
+struct usb_device;
+
+extern int usb_boot(struct usb_device *usbdev, u16 pid);
+extern int usb_emergency(struct usb_device *usbdev);
+
+#endif /* __USB_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_ids.h b/drivers/staging/gdm72xx/usb_ids.h
new file mode 100644
index 0000000..b34616b
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_ids.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __USB_IDS_H__
+#define __USB_IDS_H__
+
+/*You can replace vendor-ID as yours.*/
+#define GCT_VID 0x1076
+
+/*You can replace product-ID as yours.*/
+#define GCT_PID1 0x7e00
+#define GCT_PID2 0x7f00
+
+#define USB_DEVICE_ID_MATCH_DEVICE_INTERFACE \
+ (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS)
+
+#define USB_DEVICE_INTF(vend, prod, intf) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_INTERFACE, \
+ .idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (intf)
+
+#define EMERGENCY_PID 0x720f
+#define BL_PID_MASK 0xffc0
+
+#define USB_DEVICE_BOOTLOADER(vid, pid) \
+ {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD)}, \
+ {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD|B_DIFF_DL_DRV)}
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+ {USB_DEVICE_INTF((vid), (pid), USB_CLASS_CDC_DATA)}
+
+static const struct usb_device_id id_table[] = {
+ USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x3),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x4),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x5),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x6),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x7),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x8),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x9),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xa),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xb),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xc),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xd),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xe),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xf),
+
+ USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x3),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x4),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x5),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x6),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x7),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x8),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x9),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xa),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xb),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xc),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xd),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xe),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xf),
+
+ {USB_DEVICE(GCT_VID, EMERGENCY_PID)},
+ { }
+};
+
+#endif /* __USB_IDS_H__ */
diff --git a/drivers/staging/gdm72xx/wm_ioctl.h b/drivers/staging/gdm72xx/wm_ioctl.h
new file mode 100644
index 0000000..9f46e06
--- /dev/null
+++ b/drivers/staging/gdm72xx/wm_ioctl.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(WM_IOCTL_H_20080714)
+#define WM_IOCTL_H_20080714
+#if !defined(__KERNEL__)
+#include <net/if.h>
+#endif
+
+#define NETLINK_WIMAX 31
+
+#define SIOCWMIOCTL SIOCDEVPRIVATE
+
+#define SIOCG_DATA 0x8D10
+#define SIOCS_DATA 0x8D11
+
+enum {
+ SIOC_DATA_FSM,
+ SIOC_DATA_NETLIST,
+ SIOC_DATA_CONNNSP,
+ SIOC_DATA_CONNCOMP,
+ SIOC_DATA_PROFILEID,
+
+ SIOC_DATA_END
+};
+
+#define SIOC_DATA_MAX 16
+
+/* FSM */
+enum {
+ M_INIT = 0,
+ M_OPEN_OFF,
+ M_OPEN_ON,
+ M_SCAN,
+ M_CONNECTING,
+ M_CONNECTED,
+ M_FSM_END,
+
+ C_INIT = 0,
+ C_CONNSTART,
+ C_ASSOCSTART,
+ C_RNG,
+ C_SBC,
+ C_AUTH,
+ C_REG,
+ C_DSX,
+ C_ASSOCCOMPLETE,
+ C_CONNCOMPLETE,
+ C_FSM_END,
+
+ D_INIT = 0,
+ D_READY,
+ D_LISTEN,
+ D_IPACQUISITION,
+
+ END_FSM
+};
+
+struct fsm_s {
+ int m_status; /*main status*/
+ int c_status; /*connection status*/
+ int d_status; /*oma-dm status*/
+};
+
+struct data_s {
+ int size;
+ void *buf;
+};
+
+struct wm_req_s {
+ union {
+ char ifrn_name[IFNAMSIZ];
+ } ifr_ifrn;
+
+ unsigned short cmd;
+
+ unsigned short data_id;
+ struct data_s data;
+
+/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */
+};
+
+#ifndef ifr_name
+#define ifr_name ifr_ifrn.ifrn_name
+#endif
+
+#endif
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index 8926f24..0338c7c 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -8,7 +8,7 @@ The crucial structure for device drivers in iio is iio_dev.
First allocate one using:
-struct iio_dev *indio_dev = iio_allocate_device(sizeof(struct chip_state));
+struct iio_dev *indio_dev = iio_device_alloc(sizeof(struct chip_state));
where chip_state is a structure of local state data for this instance of
the chip.
@@ -78,4 +78,4 @@ be registered afterwards (otherwise the whole parentage of devices
gets confused)
On remove, iio_device_unregister(indio_dev) will remove the device from
-the core, and iio_free_device will clean up.
+the core, and iio_device_free will clean up.
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index 69a05b9..bf55335 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -60,9 +60,9 @@ void print2byte(int input, struct iio_channel_info *info)
/* First swap if incorrect endian */
if (info->be)
- input = be16toh((uint_16t)input);
+ input = be16toh((uint16_t)input);
else
- input = le16toh((uint_16t)input);
+ input = le16toh((uint16_t)input);
/* shift before conversion to avoid sign extension
of left aligned data */
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 0d21a27..2227584 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -27,7 +27,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include "iio_utils.h"
-#include "../events.h"
+#include <linux/iio/events.h>
static const char * const iio_chan_type_name_spec[] = {
[IIO_VOLTAGE] = "voltage",
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
new file mode 100755
index 0000000..470f7ad
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
@@ -0,0 +1,6 @@
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ This property causes an internal calibration of the als gain trim
+ value which is later used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
new file mode 100755
index 0000000..b2798b2
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
@@ -0,0 +1,13 @@
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion: 3.3-rc1
+Contact: linux-iio@vger.kernel.org
+Description:
+ Causes an internal calibration of the als gain trim
+ value which is later used in calculating illuminance in lux.
+
+What: /sys/bus/iio/devices/device[n]/in_proximity0_calibrate
+KernelVersion: 3.3-rc1
+Contact: linux-iio@vger.kernel.org
+Description:
+ Causes a recalculation and adjustment to the
+ proximity_thresh_rising_value.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio
deleted file mode 100644
index 46a995d..0000000
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ /dev/null
@@ -1,741 +0,0 @@
-What: /sys/bus/iio/devices/iio:deviceX
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Hardware chip or device accessed by one communication port.
- Corresponds to a grouping of sensor channels. X is the IIO
- index of the device.
-
-What: /sys/bus/iio/devices/triggerX
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- An event driven driver of data capture to an in kernel buffer.
- May be provided by a device driver that also has an IIO device
- based on hardware generated events (e.g. data ready) or
- provided by a separate driver for other hardware (e.g.
- periodic timer, GPIO or high resolution timer).
- Contains trigger type specific elements. These do not
- generalize well and hence are not documented in this file.
- X is the IIO index of the trigger.
-
-What: /sys/bus/iio/devices/iio:deviceX/buffer
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Directory of attributes relating to the buffer for the device.
-
-What: /sys/bus/iio/devices/iio:deviceX/name
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Description of the physical chip / device for device X.
- Typically a part number.
-
-What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency
-What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
-What: /sys/bus/iio/devices/triggerX/sampling_frequency
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Some devices have internal clocks. This parameter sets the
- resulting sampling frequency. In many devices this
- parameter has an effect on input filters etc rather than
- simply controlling when the input is sampled. As this
- effects datardy triggers, hardware buffers and the sysfs
- direct access interfaces, it may be found in any of the
- relevant directories. If it effects all of the above
- then it is to be found in the base device directory.
-
-What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency_available
-What: /sys/.../iio:deviceX/buffer/sampling_frequency_available
-What: /sys/bus/iio/devices/triggerX/sampling_frequency_available
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- When the internal sampling clock can only take a small
- discrete set of values, this file lists those available.
-
-What: /sys/bus/iio/devices/iio:deviceX/oversampling_ratio
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Hardware dependent ADC oversampling. Controls the sampling ratio
- of the digital filter if available.
-
-What: /sys/bus/iio/devices/iio:deviceX/oversampling_ratio_available
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Hardware dependent values supported by the oversampling filter.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw (unscaled no bias removal etc) voltage measurement from
- channel Y. In special cases where the channel does not
- correspond to externally available input one of the named
- versions may be used. The number must always be specified and
- unique to allow association with event codes. Units after
- application of scale and offset are microvolts.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw (unscaled) differential voltage measurement equivalent to
- channel Y - channel Z where these channel numbers apply to the
- physically equivalent inputs when non differential readings are
- separately available. In differential only parts, then all that
- is required is a consistent labeling. Units after application
- of scale and offset are microvolts.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
-KernelVersion: 3.2
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw capacitance measurement from channel Y. Units after
- application of scale and offset are nanofarads.
-
-What: /sys/.../iio:deviceX/in_capacitanceY-in_capacitanceZ_raw
-KernelVersion: 3.2
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw differential capacitance measurement equivalent to
- channel Y - channel Z where these channel numbers apply to the
- physically equivalent inputs when non differential readings are
- separately available. In differential only parts, then all that
- is required is a consistent labeling. Units after application
- of scale and offset are nanofarads..
-
-What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_temp_z_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw (unscaled no bias removal etc) temperature measurement.
- It an axis is specified it generally means that the temperature
- sensor is associated with one part of a compound device (e.g.
- a gyroscope axis). Units after application of scale and offset
- are milli degrees Celsuis.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_tempX_input
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Scaled temperature measurement in milli degrees Celsius.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Acceleration in direction x, y or z (may be arbitrarily assigned
- but should match other such assignments on device).
- Has all of the equivalent parameters as per voltageY. Units
- after application of scale and offset are m/s^2.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Angular velocity about axis x, y or z (may be arbitrarily
- assigned) Data converted by application of offset then scale to
- radians per second. Has all the equivalent parameters as
- per voltageY. Units after application of scale and offset are
- radians per second.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_incli_x_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_incli_y_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_incli_z_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Inclination raw reading about axis x, y or z (may be
- arbitrarily assigned). Data converted by application of offset
- and scale to Degrees.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_raw
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Magnetic field along axis x, y or z (may be arbitrarily
- assigned). Data converted by application of offset
- then scale to Gauss.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw
-KernelVersion: 2.6.36
-Contact: linux-iio@vger.kernel.org
-Description:
- Highest value since some reset condition. These
- attributes allow access to this and are otherwise
- the direct equivalent of the <type>Y[_name]_raw attributes.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_xyz_squared_peak_raw
-KernelVersion: 2.6.36
-Contact: linux-iio@vger.kernel.org
-Description:
- A computed peak value based on the sum squared magnitude of
- the underlying value in the specified directions.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
-What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- If known for a device, offset to be added to <type>[Y]_raw prior
- to scaling by <type>[Y]_scale in order to obtain value in the
- <type> units as specified in <type>[y]_raw documentation.
- Not present if the offset is always 0 or unknown. If Y or
- axis <x|y|z> is not present, then the offset applies to all
- in channels of <type>.
- May be writable if a variable offset can be applied on the
- device. Note that this is different to calibbias which
- is for devices (or drivers) that apply offsets to compensate
- for variation between different instances of the part, typically
- adjusted by using some hardware supported calibration procedure.
- Calibbias is applied internally, offset is applied in userspace
- to the _raw output.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
-What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
-What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- If known for a device, scale to be applied to <type>Y[_name]_raw
- post addition of <type>[Y][_name]_offset in order to obtain the
- measured value in <type> units as specified in
- <type>[Y][_name]_raw documentation.. If shared across all in
- channels then Y and <x|y|z> are not present and the value is
- called <type>[Y][_name]_scale. The peak modifier means this
- value is applied to <type>Y[_name]_peak_raw values.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
-What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Hardware applied calibration offset. (assumed to fix production
- inaccuracies).
-
-What /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
-What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Hardware applied calibration scale factor. (assumed to fix
- production inaccuracies). If shared across all channels,
- <type>_calibscale is used.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
-What: /sys/.../iio:deviceX/in_voltageX_scale_available
-What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
-What: /sys/.../iio:deviceX/out_voltageX_scale_available
-What: /sys/.../iio:deviceX/in_capacitance_scale_available
-KernelVersion: 2.635
-Contact: linux-iio@vger.kernel.org
-Description:
- If a discrete set of scale values are available, they
- are listed in this attribute.
-
-What: /sys/.../in_accel_filter_low_pass_3db_frequency
-What: /sys/.../in_magn_filter_low_pass_3db_frequency
-What: /sys/.../in_anglvel_filter_low_pass_3db_frequency
-KernelVersion: 3.2
-Contact: linux-iio@vger.kernel.org
-Description:
- If a known or controllable low pass filter is applied
- to the underlying data channel, then this parameter
- gives the 3dB frequency of the filter in Hz.
-
-What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw (unscaled, no bias etc.) output voltage for
- channel Y. The number must always be specified and
- unique if the output corresponds to a single channel.
-
-What: /sys/bus/iio/devices/iio:deviceX/out_voltageY&Z_raw
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Raw (unscaled, no bias etc.) output voltage for an aggregate of
- channel Y, channel Z, etc. This interface is available in cases
- where a single output sets the value for multiple channels
- simultaneously.
-
-What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown_mode
-What: /sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown_mode
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Specifies the output powerdown mode.
- DAC output stage is disconnected from the amplifier and
- 1kohm_to_gnd: connected to ground via an 1kOhm resistor
- 100kohm_to_gnd: connected to ground via an 100kOhm resistor
- three_state: left floating
- For a list of available output power down options read
- outX_powerdown_mode_available. If Y is not present the
- mode is shared across all outputs.
-
-What: /sys/.../iio:deviceX/out_votlageY_powerdown_mode_available
-What: /sys/.../iio:deviceX/out_voltage_powerdown_mode_available
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Lists all available output power down modes.
- If Y is not present the mode is shared across all outputs.
-
-What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown
-What: /sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- Writing 1 causes output Y to enter the power down mode specified
- by the corresponding outY_powerdown_mode. Clearing returns to
- normal operation. Y may be suppressed if all outputs are
- controlled together.
-
-What: /sys/bus/iio/devices/iio:deviceX/events
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Configuration of which hardware generated events are passed up
- to user-space.
-
-What: /sys/.../iio:deviceX/events/in_accel_x_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_x_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_y_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_y_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_z_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_z_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_x_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_x_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_y_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_y_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_z_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_z_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_x_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_x_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
-What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
-What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Event generated when channel passes a threshold in the specified
- (_rising|_falling) direction. If the direction is not specified,
- then either the device will report an event which ever direction
- a single threshold value is passed in (e.g.
- <type>[Y][_name]_<raw|input>_thresh_value) or
- <type>[Y][_name]_<raw|input>_thresh_rising_value and
- <type>[Y][_name]_<raw|input>_thresh_falling_value may take
- different values, but the device can only enable both thresholds
- or neither.
- Note the driver will assume the last p events requested are
- to be enabled where p is however many it supports (which may
- vary depending on the exact set requested. So if you want to be
- sure you have set what you think you have, check the contents of
- these attributes after everything is configured. Drivers may
- have to buffer any parameters so that they are consistent when
- a given event type is enabled a future point (and not those for
- whatever event was previously enabled).
-
-What: /sys/.../iio:deviceX/events/in_accel_x_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_x_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_y_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_y_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_z_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_z_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_x_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_x_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_y_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_y_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_anglvel_z_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_anglvel_z_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_x_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_x_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_voltageY_roc_falling_en
-What: /sys/.../iio:deviceX/events/in_tempY_roc_rising_en
-What: /sys/.../iio:deviceX/events/in_tempY_roc_falling_en
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Event generated when channel passes a threshold on the rate of
- change (1st differential) in the specified (_rising|_falling)
- direction. If the direction is not specified, then either the
- device will report an event which ever direction a single
- threshold value is passed in (e.g.
- <type>[Y][_name]_<raw|input>_roc_value) or
- <type>[Y][_name]_<raw|input>_roc_rising_value and
- <type>[Y][_name]_<raw|input>_roc_falling_value may take
- different values, but the device can only enable both rate of
- change thresholds or neither.
- Note the driver will assume the last p events requested are
- to be enabled where p is however many it supports (which may
- vary depending on the exact set requested. So if you want to be
- sure you have set what you think you have, check the contents of
- these attributes after everything is configured. Drivers may
- have to buffer any parameters so that they are consistent when
- a given event type is enabled a future point (and not those for
- whatever event was previously enabled).
-
-What: /sys/.../events/in_accel_x_raw_thresh_rising_value
-What: /sys/.../events/in_accel_x_raw_thresh_falling_value
-What: /sys/.../events/in_accel_y_raw_thresh_rising_value
-What: /sys/.../events/in_accel_y_raw_thresh_falling_value
-What: /sys/.../events/in_accel_z_raw_thresh_rising_value
-What: /sys/.../events/in_accel_z_raw_thresh_falling_value
-What: /sys/.../events/in_anglvel_x_raw_thresh_rising_value
-What: /sys/.../events/in_anglvel_x_raw_thresh_falling_value
-What: /sys/.../events/in_anglvel_y_raw_thresh_rising_value
-What: /sys/.../events/in_anglvel_y_raw_thresh_falling_value
-What: /sys/.../events/in_anglvel_z_raw_thresh_rising_value
-What: /sys/.../events/in_anglvel_z_raw_thresh_falling_value
-What: /sys/.../events/in_magn_x_raw_thresh_rising_value
-What: /sys/.../events/in_magn_x_raw_thresh_falling_value
-What: /sys/.../events/in_magn_y_raw_thresh_rising_value
-What: /sys/.../events/in_magn_y_raw_thresh_falling_value
-What: /sys/.../events/in_magn_z_raw_thresh_rising_value
-What: /sys/.../events/in_magn_z_raw_thresh_falling_value
-What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value
-What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value
-What: /sys/.../events/in_voltageY_raw_thresh_falling_value
-What: /sys/.../events/in_voltageY_raw_thresh_falling_value
-What: /sys/.../events/in_tempY_raw_thresh_falling_value
-What: /sys/.../events/in_tempY_raw_thresh_falling_value
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Specifies the value of threshold that the device is comparing
- against for the events enabled by
- <type>Y[_name]_thresh[_rising|falling]_en.
- If separate attributes exist for the two directions, but
- direction is not specified for this attribute, then a single
- threshold value applies to both directions.
- The raw or input element of the name indicates whether the
- value is in raw device units or in processed units (as _raw
- and _input do on sysfs direct channel read attributes).
-
-What: /sys/.../events/in_accel_x_raw_roc_rising_value
-What: /sys/.../events/in_accel_x_raw_roc_falling_value
-What: /sys/.../events/in_accel_y_raw_roc_rising_value
-What: /sys/.../events/in_accel_y_raw_roc_falling_value
-What: /sys/.../events/in_accel_z_raw_roc_rising_value
-What: /sys/.../events/in_accel_z_raw_roc_falling_value
-What: /sys/.../events/in_anglvel_x_raw_roc_rising_value
-What: /sys/.../events/in_anglvel_x_raw_roc_falling_value
-What: /sys/.../events/in_anglvel_y_raw_roc_rising_value
-What: /sys/.../events/in_anglvel_y_raw_roc_falling_value
-What: /sys/.../events/in_anglvel_z_raw_roc_rising_value
-What: /sys/.../events/in_anglvel_z_raw_roc_falling_value
-What: /sys/.../events/in_magn_x_raw_roc_rising_value
-What: /sys/.../events/in_magn_x_raw_roc_falling_value
-What: /sys/.../events/in_magn_y_raw_roc_rising_value
-What: /sys/.../events/in_magn_y_raw_roc_falling_value
-What: /sys/.../events/in_magn_z_raw_roc_rising_value
-What: /sys/.../events/in_magn_z_raw_roc_falling_value
-What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value
-What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value
-What: /sys/.../events/in_voltageY_raw_roc_falling_value
-What: /sys/.../events/in_voltageY_raw_roc_falling_value
-What: /sys/.../events/in_tempY_raw_roc_falling_value
-What: /sys/.../events/in_tempY_raw_roc_falling_value
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Specifies the value of rate of change threshold that the
- device is comparing against for the events enabled by
- <type>[Y][_name]_roc[_rising|falling]_en.
- If separate attributes exist for the two directions,
- but direction is not specified for this attribute,
- then a single threshold value applies to both directions.
- The raw or input element of the name indicates whether the
- value is in raw device units or in processed units (as _raw
- and _input do on sysfs direct channel read attributes).
-
-What: /sys/.../events/in_accel_x_thresh_rising_period
-What: /sys/.../events/in_accel_x_thresh_falling_period
-hat: /sys/.../events/in_accel_x_roc_rising_period
-What: /sys/.../events/in_accel_x_roc_falling_period
-What: /sys/.../events/in_accel_y_thresh_rising_period
-What: /sys/.../events/in_accel_y_thresh_falling_period
-What: /sys/.../events/in_accel_y_roc_rising_period
-What: /sys/.../events/in_accel_y_roc_falling_period
-What: /sys/.../events/in_accel_z_thresh_rising_period
-What: /sys/.../events/in_accel_z_thresh_falling_period
-What: /sys/.../events/in_accel_z_roc_rising_period
-What: /sys/.../events/in_accel_z_roc_falling_period
-What: /sys/.../events/in_anglvel_x_thresh_rising_period
-What: /sys/.../events/in_anglvel_x_thresh_falling_period
-What: /sys/.../events/in_anglvel_x_roc_rising_period
-What: /sys/.../events/in_anglvel_x_roc_falling_period
-What: /sys/.../events/in_anglvel_y_thresh_rising_period
-What: /sys/.../events/in_anglvel_y_thresh_falling_period
-What: /sys/.../events/in_anglvel_y_roc_rising_period
-What: /sys/.../events/in_anglvel_y_roc_falling_period
-What: /sys/.../events/in_anglvel_z_thresh_rising_period
-What: /sys/.../events/in_anglvel_z_thresh_falling_period
-What: /sys/.../events/in_anglvel_z_roc_rising_period
-What: /sys/.../events/in_anglvel_z_roc_falling_period
-What: /sys/.../events/in_magn_x_thresh_rising_period
-What: /sys/.../events/in_magn_x_thresh_falling_period
-What: /sys/.../events/in_magn_x_roc_rising_period
-What: /sys/.../events/in_magn_x_roc_falling_period
-What: /sys/.../events/in_magn_y_thresh_rising_period
-What: /sys/.../events/in_magn_y_thresh_falling_period
-What: /sys/.../events/in_magn_y_roc_rising_period
-What: /sys/.../events/in_magn_y_roc_falling_period
-What: /sys/.../events/in_magn_z_thresh_rising_period
-What: /sys/.../events/in_magn_z_thresh_falling_period
-What: /sys/.../events/in_magn_z_roc_rising_period
-What: /sys/.../events/in_magn_z_roc_falling_period
-What: /sys/.../events/in_voltageY_supply_thresh_rising_period
-What: /sys/.../events/in_voltageY_supply_thresh_falling_period
-What: /sys/.../events/in_voltageY_supply_roc_rising_period
-What: /sys/.../events/in_voltageY_supply_roc_falling_period
-What: /sys/.../events/in_voltageY_thresh_rising_period
-What: /sys/.../events/in_voltageY_thresh_falling_period
-What: /sys/.../events/in_voltageY_roc_rising_period
-What: /sys/.../events/in_voltageY_roc_falling_period
-What: /sys/.../events/in_tempY_thresh_rising_period
-What: /sys/.../events/in_tempY_thresh_falling_period
-What: /sys/.../events/in_tempY_roc_rising_period
-What: /sys/.../events/in_tempY_roc_falling_period
-What: /sys/.../events/in_accel_x&y&z_mag_falling_period
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Period of time (in seconds) for which the condition must be
- met before an event is generated. If direction is not
- specified then this period applies to both directions.
-
-What: /sys/.../iio:deviceX/events/in_accel_mag_en
-What: /sys/.../iio:deviceX/events/in_accel_mag_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_mag_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_x_mag_en
-What: /sys/.../iio:deviceX/events/in_accel_x_mag_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_x_mag_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_y_mag_en
-What: /sys/.../iio:deviceX/events/in_accel_y_mag_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_y_mag_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_z_mag_en
-What: /sys/.../iio:deviceX/events/in_accel_z_mag_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_z_mag_falling_en
-What: /sys/.../iio:deviceX/events/in_accel_x&y&z_mag_rising_en
-What: /sys/.../iio:deviceX/events/in_accel_x&y&z_mag_falling_en
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Similar to in_accel_x_thresh[_rising|_falling]_en, but here the
- magnitude of the channel is compared to the threshold, not its
- signed value.
-
-What: /sys/.../events/in_accel_raw_mag_value
-What: /sys/.../events/in_accel_x_raw_mag_rising_value
-What: /sys/.../events/in_accel_y_raw_mag_rising_value
-What: /sys/.../events/in_accel_z_raw_mag_rising_value
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- The value to which the magnitude of the channel is compared. If
- number or direction is not specified, applies to all channels of
- this type.
-
-What: /sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- The name of the trigger source being used, as per string given
- in /sys/class/iio/triggerY/name.
-
-What: /sys/bus/iio/devices/iio:deviceX/buffer/length
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Number of scans contained by the buffer.
-
-What: /sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Bytes per scan. Due to alignment fun, the scan may be larger
- than implied directly by the scan_element parameters.
-
-What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Actually start the buffer capture up. Will start trigger
- if first device and appropriate.
-
-What: /sys/bus/iio/devices/iio:deviceX/buffer/scan_elements
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Directory containing interfaces for elements that will be
- captured for a single triggered sample set in the buffer.
-
-What: /sys/.../buffer/scan_elements/in_accel_x_en
-What: /sys/.../buffer/scan_elements/in_accel_y_en
-What: /sys/.../buffer/scan_elements/in_accel_z_en
-What: /sys/.../buffer/scan_elements/in_anglvel_x_en
-What: /sys/.../buffer/scan_elements/in_anglvel_y_en
-What: /sys/.../buffer/scan_elements/in_anglvel_z_en
-What: /sys/.../buffer/scan_elements/in_magn_x_en
-What: /sys/.../buffer/scan_elements/in_magn_y_en
-What: /sys/.../buffer/scan_elements/in_magn_z_en
-What: /sys/.../buffer/scan_elements/in_timestamp_en
-What: /sys/.../buffer/scan_elements/in_voltageY_supply_en
-What: /sys/.../buffer/scan_elements/in_voltageY_en
-What: /sys/.../buffer/scan_elements/in_voltageY-voltageZ_en
-What: /sys/.../buffer/scan_elements/in_incli_x_en
-What: /sys/.../buffer/scan_elements/in_incli_y_en
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Scan element control for triggered data capture.
-
-What: /sys/.../buffer/scan_elements/in_accel_type
-What: /sys/.../buffer/scan_elements/in_anglvel_type
-What: /sys/.../buffer/scan_elements/in_magn_type
-What: /sys/.../buffer/scan_elements/in_incli_type
-What: /sys/.../buffer/scan_elements/in_voltageY_type
-What: /sys/.../buffer/scan_elements/in_voltage-in_type
-What: /sys/.../buffer/scan_elements/in_voltageY_supply_type
-What: /sys/.../buffer/scan_elements/in_timestamp_type
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Description of the scan element data storage within the buffer
- and hence the form in which it is read from user-space.
- Form is [be|le]:[s|u]bits/storagebits[>>shift].
- be or le specifies big or little endian. s or u specifies if
- signed (2's complement) or unsigned. bits is the number of bits
- of data and storagebits is the space (after padding) that it
- occupies in the buffer. shift if specified, is the shift that
- needs to be applied prior to masking out unused bits. Some
- devices put their data in the middle of the transferred elements
- with additional information on both sides. Note that some
- devices will have additional information in the unused bits
- so to get a clean value, the bits value must be used to mask
- the buffer output value appropriately. The storagebits value
- also specifies the data alignment. So s48/64>>2 will be a
- signed 48 bit integer stored in a 64 bit location aligned to
- a a64 bit boundary. To obtain the clean value, shift right 2
- and apply a mask to zero the top 16 bits of the result.
- For other storage combinations this attribute will be extended
- appropriately.
-
-What: /sys/.../buffer/scan_elements/in_accel_type_available
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- If the type parameter can take one of a small set of values,
- this attribute lists them.
-
-What: /sys/.../buffer/scan_elements/in_voltageY_index
-What: /sys/.../buffer/scan_elements/in_voltageY_supply_index
-What: /sys/.../buffer/scan_elements/in_accel_x_index
-What: /sys/.../buffer/scan_elements/in_accel_y_index
-What: /sys/.../buffer/scan_elements/in_accel_z_index
-What: /sys/.../buffer/scan_elements/in_anglvel_x_index
-What: /sys/.../buffer/scan_elements/in_anglvel_y_index
-What: /sys/.../buffer/scan_elements/in_anglvel_z_index
-What: /sys/.../buffer/scan_elements/in_magn_x_index
-What: /sys/.../buffer/scan_elements/in_magn_y_index
-What: /sys/.../buffer/scan_elements/in_magn_z_index
-What: /sys/.../buffer/scan_elements/in_incli_x_index
-What: /sys/.../buffer/scan_elements/in_incli_y_index
-What: /sys/.../buffer/scan_elements/in_timestamp_index
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- A single positive integer specifying the position of this
- scan element in the buffer. Note these are not dependent on
- what is enabled and may not be contiguous. Thus for user-space
- to establish the full layout these must be used in conjunction
- with all _en attributes to establish which channels are present,
- and the relevant _type attributes to establish the data storage
- format.
-
-What: /sys/.../iio:deviceX/in_anglvel_z_quadrature_correction_raw
-KernelVersion: 2.6.38
-Contact: linux-iio@vger.kernel.org
-Description:
- This attribute is used to read the amount of quadrature error
- present in the device at a given time.
-
-What: /sys/.../iio:deviceX/ac_excitation_en
-KernelVersion: 3.1.0
-Contact: linux-iio@vger.kernel.org
-Description:
- This attribute, if available, is used to enable the AC
- excitation mode found on some converters. In ac excitation mode,
- the polarity of the excitation voltage is reversed on
- alternate cycles, to eliminate DC errors.
-
-What: /sys/.../iio:deviceX/bridge_switch_en
-KernelVersion: 3.1.0
-Contact: linux-iio@vger.kernel.org
-Description:
- This attribute, if available, is used to close or open the
- bridge power down switch found on some converters.
- In bridge applications, such as strain gauges and load cells,
- the bridge itself consumes the majority of the current in the
- system. To minimize the current consumption of the system,
- the bridge can be disconnected (when it is not being used
- using the bridge_switch_en attribute.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
new file mode 100644
index 0000000..1c35c50
--- /dev/null
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
@@ -0,0 +1,20 @@
+What: /sys/.../iio:deviceX/ac_excitation_en
+KernelVersion: 3.1.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ This attribute, if available, is used to enable the AC
+ excitation mode found on some converters. In ac excitation mode,
+ the polarity of the excitation voltage is reversed on
+ alternate cycles, to eliminate DC errors.
+
+What: /sys/.../iio:deviceX/bridge_switch_en
+KernelVersion: 3.1.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ This attribute, if available, is used to close or open the
+ bridge power down switch found on some converters.
+ In bridge applications, such as strain gauges and load cells,
+ the bridge itself consumes the majority of the current in the
+ system. To minimize the current consumption of the system,
+ the bridge can be disconnected (when it is not being used
+ using the bridge_switch_en attribute.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
index ffdd547..ee8c509 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
@@ -1,83 +1,86 @@
-What: /sys/bus/iio/devices/.../ddsX_freqY
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Stores frequency into tuning word Y.
- There will be more than one ddsX_freqY file, which allows for
- pin controlled FSK Frequency Shift Keying
- (ddsX_pincontrol_freq_en is active) or the user can control
- the desired active tuning word by writing Y to the
- ddsX_freqsymbol file.
+ There will be more than one out_altvoltageX_frequencyY file,
+ which allows for pin controlled FSK Frequency Shift Keying
+ (out_altvoltageX_pincontrol_frequency_en is active) or the user
+ can control the desired active tuning word by writing Y to the
+ out_altvoltageX_frequencysymbol file.
-What: /sys/bus/iio/devices/.../ddsX_freqY_scale
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Scale to be applied to ddsX_freqY in order to obtain the
- desired value in Hz. If shared across all frequency registers
- Y is not present. It is also possible X is not present if
- shared across all channels.
+ Scale to be applied to out_altvoltageX_frequencyY in order to
+ obtain the desired value in Hz. If shared across all frequency
+ registers Y is not present. It is also possible X is not present
+ if shared across all channels.
-What: /sys/bus/iio/devices/.../ddsX_freqsymbol
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Specifies the active output frequency tuning word. The value
- corresponds to the Y in ddsX_freqY. To exit this mode the user
- can write ddsX_pincontrol_freq_en or ddsX_out_enable file.
+ corresponds to the Y in out_altvoltageX_frequencyY.
+ To exit this mode the user can write
+ out_altvoltageX_pincontrol_frequency_en or
+ out_altvoltageX_out_enable file.
-What: /sys/bus/iio/devices/.../ddsX_phaseY
+What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Stores phase into Y.
- There will be more than one ddsX_phaseY file, which allows for
- pin controlled PSK Phase Shift Keying
- (ddsX_pincontrol_phase_en is active) or the user can
+ There will be more than one out_altvoltageX_phaseY file, which
+ allows for pin controlled PSK Phase Shift Keying
+ (out_altvoltageX_pincontrol_phase_en is active) or the user can
control the desired phase Y which is added to the phase
- accumulator output by writing Y to the en_phase file.
+ accumulator output by writing Y to the phase_en file.
-What: /sys/bus/iio/devices/.../ddsX_phaseY_scale
+What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Scale to be applied to ddsX_phaseY in order to obtain the
- desired value in rad. If shared across all phase registers
+ Scale to be applied to out_altvoltageX_phaseY in order to obtain
+ the desired value in rad. If shared across all phase registers
Y is not present. It is also possible X is not present if
shared across all channels.
-What: /sys/bus/iio/devices/.../ddsX_phasesymbol
+What: /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Specifies the active phase Y which is added to the phase
accumulator output. The value corresponds to the Y in
- ddsX_phaseY. To exit this mode the user can write
- ddsX_pincontrol_phase_en or disable file.
+ out_altvoltageX_phaseY. To exit this mode the user can write
+ out_altvoltageX_pincontrol_phase_en or disable file.
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_en
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- ddsX_pincontrol_en: Both, the active frequency and phase is
- controlled by the respective phase and frequency control inputs.
- In case the device in question allows to independent controls,
- then there are dedicated files (ddsX_pincontrol_freq_en,
- ddsX_pincontrol_phase_en).
+ out_altvoltageX_pincontrol_en: Both, the active frequency and
+ phase is controlled by the respective phase and frequency
+ control inputs. In case the device in features independent
+ controls, then there are dedicated files
+ (out_altvoltageX_pincontrol_frequency_en,
+ out_altvoltageX_pincontrol_phase_en).
-What: /sys/bus/iio/devices/.../ddsX_out_enable
-What: /sys/bus/iio/devices/.../ddsX_outY_enable
+What: /sys/bus/iio/devices/.../out_altvoltageX_out_enable
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- ddsX_outY_enable controls signal generation on output Y of
- channel X. Y may be suppressed if all channels are
+ out_altvoltageX_outY_enable controls signal generation on
+ output Y of channel X. Y may be suppressed if all channels are
controlled together.
-What: /sys/bus/iio/devices/.../ddsX_outY_wavetype
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -86,7 +89,7 @@ Description:
For a list of available output waveform options read
available_output_modes.
-What: /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
index edbf470..715c74d 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
@@ -26,7 +26,7 @@ Description:
Hardware dependent list of possible values supported for the
adc_resolution of the given sensor.
-What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw]
+What: /sys/bus/iio/devices/device[n]/in_illuminance0[_input|_raw]
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -45,7 +45,7 @@ Description:
do this calculation manually by reading the infrared sensor
value and doing the negation in sw.
-What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw]
+What: /sys/bus/iio/devices/device[n]/in_proximity[_input|_raw]
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -63,23 +63,22 @@ Description:
and if expressed in SI units, should include _input. If this
value is not in SI units, then it should include _raw.
-What: /sys/bus/iio/devices/device[n]/illuminance0_target
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_target
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
This property gets/sets the last known external
lux measurement used in/for calibration.
-What: /sys/bus/iio/devices/device[n]/illuminance0_integration_time
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_integration_time
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
This property gets/sets the sensors ADC analog integration time.
-What: /sys/bus/iio/devices/device[n]/illuminance0_calibscale
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_lux_table
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Hardware or software applied calibration scale factor assumed
- to account for attenuation due to industrial design (glass
- filters or aperture holes).
+ This property gets/sets the table of coefficients
+ used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/trigger.txt b/drivers/staging/iio/Documentation/trigger.txt
index fc2012e..75cc37f 100644
--- a/drivers/staging/iio/Documentation/trigger.txt
+++ b/drivers/staging/iio/Documentation/trigger.txt
@@ -5,7 +5,7 @@ an IIO device. Whilst this can create device specific complexities
such triggers are registered with the core in the same way as
stand-alone triggers.
-struct iio_trig *trig = iio_allocate_trigger("<trigger format string>", ...);
+struct iio_trig *trig = iio_trigger_alloc("<trigger format string>", ...);
allocates a trigger structure. The key elements to then fill in within
a driver are:
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index fe1586718..3c8e5ec 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -1,16 +1,9 @@
#
# Industrial I/O subsytem configuration
#
+menu "IIO staging drivers"
+ depends on IIO
-menuconfig IIO
- tristate "Industrial I/O support"
- depends on GENERIC_HARDIRQS
- help
- The industrial I/O subsystem provides a unified framework for
- drivers for many different types of embedded sensors using a
- number of different physical interfaces (i2c, spi, etc). See
- drivers/staging/iio/Documentation for more information.
-if IIO
config IIO_ST_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on HWMON
@@ -19,12 +12,6 @@ config IIO_ST_HWMON
map allows IIO devices to provide basic hwmon functionality
for those channels specified in the map.
-config IIO_BUFFER
- bool "Enable buffer support within IIO"
- help
- Provide core support for various buffer based data
- acquisition methods.
-
if IIO_BUFFER
config IIO_SW_RING
@@ -36,39 +23,14 @@ config IIO_SW_RING
with the intention that some devices would be able to write
in interrupt context.
-config IIO_KFIFO_BUF
- select IIO_TRIGGER
- tristate "Industrial I/O buffering based on kfifo"
- help
- A simple fifo based on kfifo. Use this if you want a fifo
- rather than a ring buffer. Note that this currently provides
- no buffer events so it is up to userspace to work out how
- often to read from the buffer.
-
endif # IIO_BUFFER
-config IIO_TRIGGER
- boolean "Enable triggered sampling support"
- help
- Provides IIO core support for triggers. Currently these
- are used to initialize capture of samples to push into
- ring buffers. The triggers are effectively a 'capture
- data now' interrupt.
-
-config IIO_CONSUMERS_PER_TRIGGER
- int "Maximum number of consumers per trigger"
- depends on IIO_TRIGGER
- default "2"
- help
- This value controls the maximum number of consumers that a
- given trigger may handle. Default is 2.
-
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/cdc/Kconfig"
source "drivers/staging/iio/dac/Kconfig"
-source "drivers/staging/iio/dds/Kconfig"
+source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
source "drivers/staging/iio/imu/Kconfig"
@@ -104,4 +66,4 @@ config IIO_SIMPLE_DUMMY_BUFFER
endif # IIO_SIMPLE_DUMMY
-endif # IIO
+endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 5075291..6a46d5a 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -2,13 +2,7 @@
# Makefile for the industrial I/O core.
#
-obj-$(CONFIG_IIO) += industrialio.o
-industrialio-y := industrialio-core.o industrialio-event.o inkern.o
-industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
-industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-
obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
iio_dummy-y := iio_simple_dummy.o
@@ -24,7 +18,7 @@ obj-y += adc/
obj-y += addac/
obj-y += cdc/
obj-y += dac/
-obj-y += dds/
+obj-y += frequency/
obj-y += gyro/
obj-y += impedance-analyzer/
obj-y += imu/
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index d1ad35e..cf3f948 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -67,7 +67,7 @@ e-mailing the normal IIO list (see below).
Documentation
1) Lots of cleanup and expansion.
-2) Some device require indvidual docs.
+2) Some device require individual docs.
Contact: Jonathan Cameron <jic23@cam.ac.uk>.
Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index d439e45..02b3409 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -15,9 +15,9 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16201.h"
@@ -171,7 +171,7 @@ static ssize_t adis16201_write_reset(struct device *dev,
ret = strtobool(buf, &res);
if (ret || !res)
return ret;
- return adis16201_reset(dev_get_drvdata(dev));
+ return adis16201_reset(dev_to_iio_dev(dev));
}
int adis16201_set_irq(struct iio_dev *indio_dev, bool enable)
@@ -298,7 +298,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16201_addresses[chan->address][0];
ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16);
@@ -406,39 +406,104 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16201_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16201_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
+ .address = in_supply,
+ .scan_index = ADIS16201_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16201_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
+ .address = temp,
+ .scan_index = ADIS16201_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16201_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+ .address = accel_x,
+ .scan_index = ADIS16201_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16201_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
+ .address = accel_y,
+ .scan_index = ADIS16201_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16201_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
+ .address = in_aux,
+ .scan_index = ADIS16201_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_x, ADIS16201_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+ .address = incli_x,
+ .scan_index = ADIS16201_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_y, ADIS16201_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
+ .address = incli_y,
+ .scan_index = ADIS16201_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(7)
};
@@ -467,7 +532,7 @@ static int __devinit adis16201_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -522,7 +587,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16201_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -535,7 +600,7 @@ static int adis16201_remove(struct spi_device *spi)
adis16201_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16201_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 97f9e6b..247602a 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -5,9 +5,9 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16201.h"
@@ -66,9 +66,8 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
@@ -81,7 +80,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c
index bce505e..96fdabb 100644
--- a/drivers/staging/iio/accel/adis16201_trigger.c
+++ b/drivers/staging/iio/accel/adis16201_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16201.h"
/**
@@ -29,7 +29,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16201_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16201-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16201-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -56,7 +56,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -67,5 +67,5 @@ void adis16201_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
- iio_free_trigger(state->trig);
+ iio_trigger_free(state->trig);
}
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 1a5140f..15d46bf 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -15,9 +15,9 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16203.h"
@@ -182,7 +182,7 @@ static ssize_t adis16203_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
switch (buf[0]) {
@@ -305,7 +305,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
u8 addr;
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->address][0];
ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
@@ -372,29 +372,75 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16203_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16203_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16203_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_x, ADIS16203_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- /* Fixme: Not what it appears to be - see data sheet */
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_y, ADIS16203_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16203_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16203_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16203_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = incli_x,
+ .scan_index = ADIS16203_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, { /* Fixme: Not what it appears to be - see data sheet */
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_y,
+ .scan_index = ADIS16203_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16203_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(5),
};
@@ -423,7 +469,7 @@ static int __devinit adis16203_probe(struct spi_device *spi)
struct adis16203_state *st;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -477,7 +523,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16203_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -490,7 +536,7 @@ static int adis16203_remove(struct spi_device *spi)
adis16203_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16203_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 6a8963d..7bbd2c2 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16203.h"
/**
* adis16203_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16203_read_ring_data(struct device *dev, u8 *rx)
+static int adis16203_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16203_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
int ret;
@@ -66,22 +65,21 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16203_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring,
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c
index 24bcb8e..b8a0407 100644
--- a/drivers/staging/iio/accel/adis16203_trigger.c
+++ b/drivers/staging/iio/accel/adis16203_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16203.h"
/**
@@ -29,7 +29,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16203_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16203-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16203-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -58,7 +58,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -69,5 +69,5 @@ void adis16203_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index fa89364..ac9d95e 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16204.h"
@@ -173,7 +173,7 @@ static ssize_t adis16204_read_14bit_signed(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
s16 val = 0;
ssize_t ret;
@@ -211,7 +211,7 @@ static ssize_t adis16204_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -342,7 +342,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
int addrind;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16204_addresses[chan->address][0];
ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
@@ -444,31 +444,78 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16204_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16204_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16204_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16204_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
- accel_x, ADIS16204_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
- accel_y, ADIS16204_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1, /* Note was not previously indexed */
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16204_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16204_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16204_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16204_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16204_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(5),
};
@@ -498,7 +545,7 @@ static int __devinit adis16204_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -551,7 +598,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16204_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -564,7 +611,7 @@ static int adis16204_remove(struct spi_device *spi)
adis16204_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16204_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 5c8ab73..f73518b 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16204.h"
/**
* adis16204_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16204_read_ring_data(struct device *dev, u8 *rx)
+static int adis16204_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16204_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
int ret;
@@ -63,22 +62,21 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16204_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c
index 6e542af..408a168 100644
--- a/drivers/staging/iio/accel/adis16204_trigger.c
+++ b/drivers/staging/iio/accel/adis16204_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16204.h"
/**
@@ -29,7 +29,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16204_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16204-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16204-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -58,7 +58,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -69,5 +69,5 @@ void adis16204_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
- iio_free_trigger(state->trig);
+ iio_trigger_free(state->trig);
}
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index a98715f..f6fd0d3 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -16,9 +16,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16209.h"
@@ -157,7 +157,7 @@ static ssize_t adis16209_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -331,7 +331,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16209_addresses[chan->address][0];
ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
@@ -408,41 +408,114 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16209_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16209_SCAN_SUPPLY,
- IIO_ST('u', 14, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16209_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16209_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16209_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16209_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_x, ADIS16209_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_y, ADIS16209_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X,
- 0,
- rot, ADIS16209_SCAN_ROT,
- IIO_ST('s', 14, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16209_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 0,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16209_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16209_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16209_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16209_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_x,
+ .scan_index = ADIS16209_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_y,
+ .scan_index = ADIS16209_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ROT,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .address = rot,
+ .scan_index = ADIS16209_SCAN_ROT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(8)
};
@@ -471,7 +544,7 @@ static int __devinit adis16209_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -524,7 +597,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16209_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -539,7 +612,7 @@ static int adis16209_remove(struct spi_device *spi)
adis16209_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16209_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 57254b6b..0906075 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16209.h"
/**
* adis16209_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16209_read_ring_data(struct device *dev, u8 *rx)
+static int adis16209_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16209_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
int ret;
@@ -61,25 +60,23 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16209_state *st = iio_priv(indio_dev);
struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16209_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c
index c5d82c1..2ad93dc 100644
--- a/drivers/staging/iio/accel/adis16209_trigger.c
+++ b/drivers/staging/iio/accel/adis16209_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16209.h"
/**
@@ -38,7 +38,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16209_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16209-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16209-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -66,7 +66,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -77,5 +77,5 @@ void adis16209_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 51a852d..6a9ac89 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -15,8 +15,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "adis16220.h"
@@ -145,7 +145,7 @@ static ssize_t adis16220_read_16bit(struct device *dev,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
ssize_t ret;
s16 val = 0;
@@ -164,7 +164,7 @@ static ssize_t adis16220_write_16bit(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
@@ -208,7 +208,7 @@ static ssize_t adis16220_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool val;
int ret;
@@ -228,7 +228,7 @@ static ssize_t adis16220_write_capture(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool val;
int ret;
@@ -393,7 +393,7 @@ static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -415,7 +415,7 @@ static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -437,7 +437,7 @@ static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -507,7 +507,7 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
u8 bits;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
addrind = 0;
break;
case IIO_CHAN_INFO_OFFSET:
@@ -575,11 +575,13 @@ static const struct iio_chan_spec adis16220_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
}, {
.type = IIO_ACCEL,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel,
@@ -587,20 +589,23 @@ static const struct iio_chan_spec adis16220_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = in_2,
}
};
@@ -629,7 +634,7 @@ static int __devinit adis16220_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -680,7 +685,7 @@ error_rm_accel_bin:
error_unregister_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -695,7 +700,7 @@ static int adis16220_remove(struct spi_device *spi)
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 17f77fe..8b15eae 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -19,9 +19,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16240.h"
@@ -154,7 +154,7 @@ static ssize_t adis16240_spi_read_signed(struct device *dev,
char *buf,
unsigned bits)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret;
s16 val = 0;
unsigned shift = 16 - bits;
@@ -177,7 +177,7 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev,
char *buf)
{
ssize_t ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
@@ -203,7 +203,7 @@ static ssize_t adis16240_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -365,7 +365,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][0];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
@@ -468,33 +468,88 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16240_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16240_SCAN_SUPPLY,
- IIO_ST('u', 10, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- 0,
- in_aux, ADIS16240_SCAN_AUX_ADC,
- IIO_ST('u', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16240_SCAN_ACC_X,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16240_SCAN_ACC_Y,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_z, ADIS16240_SCAN_ACC_Z,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- temp, ADIS16240_SCAN_TEMP,
- IIO_ST('u', 10, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16240_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16240_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16240_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16240_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_z,
+ .scan_index = ADIS16240_SCAN_ACC_Z,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16240_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(6)
};
@@ -523,7 +578,7 @@ static int __devinit adis16240_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -576,7 +631,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16240_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -592,7 +647,7 @@ static int adis16240_remove(struct spi_device *spi)
adis16240_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16240_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 43ba84e..86a2a47 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16240.h"
/**
* adis16240_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16240_read_ring_data(struct device *dev, u8 *rx)
+static int adis16240_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16240_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16240_OUTPUTS + 1];
int ret;
@@ -61,22 +60,21 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16240_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c
index 8e0ce56..fa90a22 100644
--- a/drivers/staging/iio/accel/adis16240_trigger.c
+++ b/drivers/staging/iio/accel/adis16240_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16240.h"
/**
@@ -38,7 +38,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16240_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16240-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16240-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -67,7 +67,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -78,5 +78,5 @@ void adis16240_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c
index d13d721..8cf7cd9 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/staging/iio/accel/kxsd9.c
@@ -23,8 +23,8 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define KXSD9_REG_X 0x00
#define KXSD9_REG_Y 0x02
@@ -158,7 +158,7 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
struct kxsd9_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = kxsd9_read(indio_dev, chan->address);
if (ret < 0)
goto error_ret;
@@ -181,7 +181,8 @@ error_ret:
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = KXSD9_REG_##axis, \
}
@@ -189,6 +190,7 @@ static struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
{
.type = IIO_VOLTAGE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.indexed = 1,
.address = KXSD9_REG_AUX,
}
@@ -226,7 +228,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi)
struct kxsd9_state *st;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -254,7 +256,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -262,7 +264,7 @@ error_ret:
static int __devexit kxsd9_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 376da51..9d26348 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -23,10 +23,10 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "lis3l02dq.h"
@@ -257,7 +257,7 @@ static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
u8 reg;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
@@ -297,7 +297,7 @@ static ssize_t lis3l02dq_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret, len = 0;
s8 t;
ret = lis3l02dq_spi_read_reg_8(indio_dev,
@@ -328,7 +328,7 @@ static ssize_t lis3l02dq_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long val;
int ret;
u8 t;
@@ -513,7 +513,8 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
}
#define LIS3L02DQ_INFO_MASK \
- (IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT)
@@ -521,13 +522,26 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define LIS3L02DQ_CHAN(index, mod) \
+ { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = LIS3L02DQ_INFO_MASK, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ .event_mask = LIS3L02DQ_EVENT_MASK, \
+ }
+
static struct iio_chan_spec lis3l02dq_channels[] = {
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
- 0, 0, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
- 1, 1, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
- 2, 2, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
+ LIS3L02DQ_CHAN(0, IIO_MOD_X),
+ LIS3L02DQ_CHAN(1, IIO_MOD_Y),
+ LIS3L02DQ_CHAN(2, IIO_MOD_Z),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -666,7 +680,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
struct lis3l02dq_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof *st);
+ indio_dev = iio_device_alloc(sizeof *st);
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -724,7 +738,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)))
lis3l02dq_remove_trigger(indio_dev);
error_free_interrupt:
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
@@ -734,7 +748,7 @@ error_uninitialize_buffer:
error_unreg_buffer_funcs:
lis3l02dq_unconfigure_buffer(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -789,7 +803,7 @@ static int lis3l02dq_remove(struct spi_device *spi)
iio_buffer_unregister(indio_dev);
lis3l02dq_unconfigure_buffer(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 0fc3973..51b00df 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -6,11 +6,11 @@
#include <linux/slab.h>
#include <linux/export.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../kfifo_buf.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "lis3l02dq.h"
/**
@@ -137,9 +137,9 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
- size_t datasize = buffer->access->get_bytes_per_datum(buffer);
- char *data = kmalloc(datasize, GFP_KERNEL);
+ char *data;
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(indio_dev->dev.parent,
"memory alloc failed in buffer bh");
@@ -150,7 +150,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
len = lis3l02dq_get_buffer_element(indio_dev, data);
/* Guaranteed to be aligned with 8 byte boundary */
- if (buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= pf->timestamp;
@@ -163,12 +163,11 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
/* Caller responsible for locking as necessary. */
static int
-__lis3l02dq_write_data_ready_config(struct device *dev, bool state)
+__lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state)
{
int ret;
u8 valold;
bool currentlyset;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct lis3l02dq_state *st = iio_priv(indio_dev);
/* Get the current event mask register */
@@ -236,7 +235,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
int ret = 0;
u8 t;
- __lis3l02dq_write_data_ready_config(&indio_dev->dev, state);
+ __lis3l02dq_write_data_ready_config(indio_dev, state);
if (state == false) {
/*
* A possible quirk with the handler is currently worked around
@@ -286,7 +285,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct lis3l02dq_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("lis3l02dq-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("lis3l02dq-dev%d", indio_dev->id);
if (!st->trig) {
ret = -ENOMEM;
goto error_ret;
@@ -302,7 +301,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
return 0;
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -312,7 +311,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
struct lis3l02dq_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 49764fb..6ec5c20 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -18,10 +18,10 @@
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "sca3000.h"
@@ -241,7 +241,7 @@ error_ret:
static int sca3000_check_status(struct device *dev)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -268,7 +268,7 @@ static ssize_t sca3000_show_rev(struct device *dev,
char *buf)
{
int len = 0, ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -296,7 +296,7 @@ sca3000_show_available_measurement_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0;
@@ -328,7 +328,7 @@ sca3000_show_measurement_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0, ret;
@@ -379,7 +379,7 @@ sca3000_store_measurement_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret;
u8 mask = 0x03;
@@ -429,17 +429,31 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR,
static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
#define SCA3000_INFO_MASK \
- IIO_CHAN_INFO_SCALE_SHARED_BIT
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT
#define SCA3000_EVENT_MASK \
(IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING))
+#define SCA3000_CHAN(index, mod) \
+ { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = SCA3000_INFO_MASK, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 11, \
+ .storagebits = 16, \
+ .shift = 5, \
+ }, \
+ .event_mask = SCA3000_EVENT_MASK, \
+ }
+
static struct iio_chan_spec sca3000_channels[] = {
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, SCA3000_INFO_MASK,
- 0, 0, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, SCA3000_INFO_MASK,
- 1, 1, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, SCA3000_INFO_MASK,
- 2, 2, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
+ SCA3000_CHAN(0, IIO_MOD_X),
+ SCA3000_CHAN(1, IIO_MOD_Y),
+ SCA3000_CHAN(2, IIO_MOD_Z),
};
static u8 sca3000_addresses[3][3] = {
@@ -462,7 +476,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
u8 address;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
if (st->mo_det_use_count) {
mutex_unlock(&st->lock);
@@ -503,7 +517,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0, ret, val;
@@ -574,7 +588,7 @@ static ssize_t sca3000_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret, len = 0, base_freq = 0, val;
@@ -616,7 +630,7 @@ static ssize_t sca3000_set_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret, base_freq = 0;
int ctrlval;
@@ -676,7 +690,7 @@ static ssize_t sca3000_read_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret;
int val;
@@ -897,7 +911,7 @@ static ssize_t sca3000_query_free_fall_mode(struct device *dev,
char *buf)
{
int ret, len;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int val;
@@ -925,7 +939,7 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -1131,7 +1145,7 @@ static int __devinit sca3000_probe(struct spi_device *spi)
struct sca3000_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -1195,7 +1209,7 @@ error_unregister_ring:
error_unregister_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -1233,7 +1247,7 @@ static int sca3000_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
sca3000_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 6b824a1..b7e1a002 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -18,9 +18,9 @@
#include <linux/sched.h>
#include <linux/poll.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "../ring_hw.h"
#include "sca3000.h"
@@ -157,7 +157,7 @@ static ssize_t sca3000_query_ring_int(struct device *dev,
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -178,7 +178,7 @@ static ssize_t sca3000_set_ring_int(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -219,7 +219,7 @@ static ssize_t sca3000_show_buffer_scale(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
return sprintf(buf, "0.%06d\n", 4*st->info->scale);
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 592eabd..2490dd2 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -25,7 +25,7 @@ config AD7606
depends on GPIOLIB
select IIO_BUFFER
select IIO_TRIGGER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
help
Say yes here to build support for Analog Devices:
ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
@@ -63,7 +63,7 @@ config AD799X_RING_BUFFER
bool "Analog Devices AD799x: use ring buffer"
depends on AD799X
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
help
Say yes here to include ring buffer support in the AD799X
ADC driver.
@@ -72,7 +72,7 @@ config AD7476
tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -87,7 +87,7 @@ config AD7887
tristate "Analog Devices AD7887 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -113,7 +113,7 @@ config AD7793
tristate "Analog Devices AD7792 AD7793 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -135,7 +135,7 @@ config AD7192
tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices AD7190,
@@ -195,11 +195,20 @@ config MAX1363_RING_BUFFER
config LPC32XX_ADC
tristate "NXP LPC32XX ADC"
- depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX
+ depends on ARCH_LPC32XX
help
Say yes here to build support for the integrated ADC inside the
LPC32XX SoC. Note that this feature uses the same hardware as the
- touchscreen driver, so you can only select one of the two drivers
- (lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs.
+ touchscreen driver, so you should either select only one of the two
+ drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case,
+ activate only one via device tree selection. Provides direct access
+ via sysfs.
+
+config SPEAR_ADC
+ tristate "ST SPEAr ADC"
+ depends on PLAT_SPEAR
+ help
+ Say yes here to build support for the integrated ADC inside the
+ ST SPEAr SoC. Provides direct access via sysfs.
endmenu
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index f83ab95..14e98b6 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_ADT7310) += adt7310.o
obj-$(CONFIG_ADT7410) += adt7410.o
obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 9fd6d63..5eaeaf1 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -1,7 +1,7 @@
/*
* AD7190 AD7192 AD7195 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -17,12 +17,12 @@
#include <linux/sched.h>
#include <linux/delay.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7192.h"
@@ -456,31 +456,19 @@ out:
static int ad7192_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7192_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
+
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- indio_dev->channels[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) |
AD7192_MODE_SEL(AD7192_MODE_CONT);
st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) |
@@ -533,7 +521,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
indio_dev->channels[0].scan_type.realbits/8);
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -556,7 +544,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -569,7 +557,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -579,8 +567,8 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -588,7 +576,7 @@ error_ret:
static void ad7192_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
/**
@@ -616,7 +604,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev)
struct ad7192_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->spi)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -649,7 +637,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->spi->irq, indio_dev);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -660,14 +648,14 @@ static void ad7192_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->spi->irq, indio_dev);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
static ssize_t ad7192_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->mclk /
@@ -679,7 +667,7 @@ static ssize_t ad7192_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
unsigned long lval;
int div, ret;
@@ -718,7 +706,7 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static ssize_t ad7192_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
int i, len = 0;
@@ -742,7 +730,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
@@ -752,7 +740,7 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
@@ -763,7 +751,7 @@ static ssize_t ad7192_set(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -849,7 +837,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -981,7 +969,8 @@ static const struct iio_info ad7195_info = {
.extend_name = _name, \
.channel = _chan, \
.channel2 = _chan2, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -990,7 +979,8 @@ static const struct iio_info ad7195_info = {
{ .type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -999,7 +989,8 @@ static const struct iio_info ad7195_info = {
{ .type = IIO_TEMP, \
.indexed = 1, \
.channel = _chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -1033,7 +1024,7 @@ static int __devinit ad7192_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -1114,7 +1105,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 7dbd681..cfc39a7 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -16,9 +16,9 @@
#include <linux/interrupt.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "ad7280a.h"
@@ -384,7 +384,7 @@ static ssize_t ad7280_show_balance_sw(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -398,7 +398,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
bool readin;
@@ -429,7 +429,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -453,7 +453,7 @@ static ssize_t ad7280_store_balance_timer(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long val;
@@ -508,6 +508,7 @@ static int ad7280_channel_init(struct ad7280_state *st)
}
st->channels[cnt].indexed = 1;
st->channels[cnt].info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT;
st->channels[cnt].address =
AD7280A_DEVADDR(dev) << 8 | ch;
@@ -524,7 +525,9 @@ static int ad7280_channel_init(struct ad7280_state *st)
st->channels[cnt].channel2 = dev * 6;
st->channels[cnt].address = AD7280A_ALL_CELLS;
st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT;
+ st->channels[cnt].info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT;
st->channels[cnt].scan_index = cnt;
st->channels[cnt].scan_type.sign = 'u';
st->channels[cnt].scan_type.realbits = 32;
@@ -596,7 +599,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned val;
@@ -626,7 +629,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -788,7 +791,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (chan->address == AD7280A_ALL_CELLS)
ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
@@ -836,7 +839,7 @@ static int __devinit ad7280_probe(struct spi_device *spi)
int ret;
const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890};
const unsigned short nAVG[4] = {1, 2, 4, 8};
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -942,7 +945,7 @@ error_free_channels:
kfree(st->channels);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -961,7 +964,7 @@ static int __devexit ad7280_remove(struct spi_device *spi)
kfree(st->channels);
kfree(st->iio_attr);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
index 81d6b61..029b39c 100644
--- a/drivers/staging/iio/adc/ad7291.c
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -17,9 +17,9 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* Simplified handling
@@ -132,7 +132,7 @@ static ssize_t ad7291_store_reset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
return ad7291_i2c_write(chip, AD7291_COMMAND,
@@ -214,7 +214,7 @@ static inline ssize_t ad7291_show_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u16 data;
@@ -232,7 +232,7 @@ static inline ssize_t ad7291_set_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u16 data;
@@ -461,7 +461,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
s16 signval;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&chip->state_lock);
@@ -536,7 +536,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
#define AD7291_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.indexed = 1, \
.channel = _chan, \
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\
@@ -554,7 +555,8 @@ static const struct iio_chan_spec ad7291_channels[] = {
AD7291_VOLTAGE_CHAN(7),
{
.type = IIO_TEMP,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.indexed = 1,
.channel = 0,
@@ -585,7 +587,7 @@ static int __devinit ad7291_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret = 0, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -667,7 +669,7 @@ error_put_reg:
if (!IS_ERR(chip->reg))
regulator_put(chip->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -687,7 +689,7 @@ static int __devexit ad7291_remove(struct i2c_client *client)
regulator_put(chip->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
index a0e5dea..5051a7e 100644
--- a/drivers/staging/iio/adc/ad7298.h
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -38,7 +38,6 @@ struct ad7298_platform_data {
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
index 8dd6aa9..c90f2b3 100644
--- a/drivers/staging/iio/adc/ad7298_core.c
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -16,40 +16,51 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7298.h"
+#define AD7298_V_CHAN(index) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }
+
static struct iio_chan_spec ad7298_channels[] = {
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 1, 1, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 2, 2, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 3, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 3, 3, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 4, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 4, 4, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 5, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 5, 5, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 6, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 6, 6, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 7, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 7, 7, IIO_ST('u', 12, 16, 0), 0),
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = 9,
+ .scan_index = AD7298_CH_TEMP,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ },
+ },
+ AD7298_V_CHAN(0),
+ AD7298_V_CHAN(1),
+ AD7298_V_CHAN(2),
+ AD7298_V_CHAN(3),
+ AD7298_V_CHAN(4),
+ AD7298_V_CHAN(5),
+ AD7298_V_CHAN(6),
+ AD7298_V_CHAN(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
@@ -121,7 +132,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
@@ -168,7 +179,7 @@ static int __devinit ad7298_probe(struct spi_device *spi)
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
int ret;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -241,7 +252,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -258,7 +269,7 @@ static int __devexit ad7298_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index feeb0ee..908a3e5 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -1,7 +1,7 @@
/*
* AD7298 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -11,10 +11,10 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7298.h"
@@ -28,25 +28,17 @@
static int ad7298_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7298_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
int i, m;
unsigned short command;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
- d_size = scan_count * (AD7298_STORAGE_BITS / 8);
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
+ int scan_count, ret;
- if (ring->access->set_bytes_per_datum)
- ring->access->set_bytes_per_datum(ring, d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
- st->d_size = d_size;
+ /* Now compute overall size */
+ scan_count = bitmap_weight(indio_dev->active_scan_mask,
+ indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
@@ -100,9 +92,9 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
if (b_sent)
return b_sent;
- if (ring->scan_timestamp) {
+ if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
- memcpy((u8 *)buf + st->d_size - sizeof(s64),
+ memcpy((u8 *)buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
@@ -126,7 +118,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -140,7 +132,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -151,8 +143,8 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -160,5 +152,5 @@ error_ret:
void ad7298_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
index 27f696c..b1dd931 100644
--- a/drivers/staging/iio/adc/ad7476.h
+++ b/drivers/staging/iio/adc/ad7476.h
@@ -27,7 +27,6 @@ struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index 0c064d1..be1c260 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -15,9 +15,9 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7476.h"
@@ -43,7 +43,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -66,53 +66,51 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+#define AD7476_CHAN(bits) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = bits, \
+ .storagebits = 16, \
+ .shift = 12 - bits, \
+ }, \
+}
+
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7466] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7467] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 10, 16, 2), 0),
+ .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7468] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1 , 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 8, 16, 4), 0),
+ .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7475] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7476] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7477] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 10, 16, 2), 0),
+ .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7478] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 8, 16, 4), 0),
+ .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7495] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_mv = 2500,
},
@@ -130,7 +128,7 @@ static int __devinit ad7476_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -200,7 +198,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -218,7 +216,7 @@ static int ad7476_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index d6af6c0..383611b 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
* Copyright (C) 2008 Jonathan Cameron
*
* Licensed under the GPL-2 or later.
@@ -13,43 +13,13 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7476.h"
-/**
- * ad7476_ring_preenable() setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the number of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
- **/
-static int ad7476_ring_preenable(struct iio_dev *indio_dev)
-{
- struct ad7476_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- st->chip_info->channel[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
- return 0;
-}
-
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -59,7 +29,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
__u8 *rxbuf;
int b_sent;
- rxbuf = kzalloc(st->d_size, GFP_KERNEL);
+ rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (rxbuf == NULL)
return -ENOMEM;
@@ -70,8 +40,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (indio_dev->buffer->scan_timestamp)
- memcpy(rxbuf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -83,7 +53,7 @@ done:
}
static const struct iio_buffer_setup_ops ad7476_ring_setup_ops = {
- .preenable = &ad7476_ring_preenable,
+ .preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
@@ -93,7 +63,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
struct ad7476_state *st = iio_priv(indio_dev);
int ret = 0;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -108,7 +78,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -119,8 +89,8 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -128,5 +98,5 @@ error_ret:
void ad7476_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index 97e8d3d..10ab6dc 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -18,9 +18,9 @@
#include <linux/sched.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7606.h"
@@ -88,7 +88,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -113,7 +113,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
static ssize_t ad7606_show_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
return sprintf(buf, "%u\n", st->range);
@@ -122,7 +122,7 @@ static ssize_t ad7606_show_range(struct device *dev,
static ssize_t ad7606_store_range(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
unsigned long lval;
@@ -147,7 +147,7 @@ static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000");
static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
return sprintf(buf, "%u\n", st->oversampling);
@@ -168,7 +168,7 @@ static int ad7606_oversampling_get_index(unsigned val)
static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
unsigned long lval;
int ret;
@@ -229,14 +229,15 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
-#define AD7606_CHANNEL(num) \
- { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = num, \
- .address = num, \
- .scan_index = num, \
- .scan_type = IIO_ST('s', 16, 16, 0), \
+#define AD7606_CHANNEL(num) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = num, \
+ .address = num, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .scan_index = num, \
+ .scan_type = IIO_ST('s', 16, 16, 0), \
}
static struct iio_chan_spec ad7606_8_channels[] = {
@@ -460,7 +461,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq,
struct ad7606_platform_data *pdata = dev->platform_data;
struct ad7606_state *st;
int ret;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
@@ -559,7 +560,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ERR_PTR(ret);
}
@@ -579,7 +580,7 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq)
}
ad7606_free_gpios(st);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index bb152a8..a53faaf 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -12,7 +12,7 @@
#include <linux/err.h>
#include <linux/io.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ad7606.h"
static int ad7606_par16_read_block(struct device *dev,
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index 1ef9fbc..24ce8fc 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*
@@ -11,10 +11,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7606.h"
@@ -51,8 +51,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
__u8 *buf;
int ret;
- buf = kzalloc(ring->access->get_bytes_per_datum(ring),
- GFP_KERNEL);
+ buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (buf == NULL)
return;
@@ -82,9 +81,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
- if (ring->scan_timestamp)
- *((s64 *)(buf + ring->access->get_bytes_per_datum(ring) -
- sizeof(s64))) = time_ns;
+ if (indio_dev->scan_timestamp)
+ *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
ring->access->store_to(indio_dev->buffer, buf, time_ns);
done:
@@ -104,7 +102,7 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -119,13 +117,13 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad7606_ring_setup_ops;
- indio_dev->buffer->scan_timestamp = true ;
+ indio_dev->buffer->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
@@ -133,8 +131,8 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -142,5 +140,5 @@ error_ret:
void ad7606_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
index 237f1c4..099d347 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -11,7 +11,7 @@
#include <linux/types.h>
#include <linux/err.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ad7606.h"
#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index a13e58c..1ece2ac 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -18,8 +18,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad7780.h"
@@ -94,7 +94,7 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
unsigned long scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ad7780_read(st, &smpl);
mutex_unlock(&indio_dev->mlock);
@@ -126,14 +126,34 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
[ID_AD7780] = {
- .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('s', 24, 32, 8), 0),
+ .channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ },
+ },
},
[ID_AD7781] = {
- .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('s', 20, 32, 12), 0),
+ .channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 20,
+ .storagebits = 32,
+ .shift = 12,
+ },
+ },
},
};
@@ -167,7 +187,7 @@ static int __devinit ad7780_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -245,7 +265,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -262,7 +282,7 @@ static int ad7780_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index 84ecde1..b36556f 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -1,7 +1,7 @@
/*
* AD7792/AD7793 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -18,12 +18,12 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7793.h"
@@ -319,31 +319,18 @@ out:
static int ad7793_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7793_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- indio_dev->channels[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) |
AD7793_MODE_SEL(AD7793_MODE_CONT);
st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) |
@@ -399,7 +386,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
indio_dev->channels[0].scan_type.realbits/8);
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -422,7 +409,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -435,7 +422,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -445,8 +432,8 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -454,7 +441,7 @@ error_ret:
static void ad7793_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
/**
@@ -482,7 +469,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev)
struct ad7793_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->spi)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -516,7 +503,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->spi->irq, indio_dev);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -527,7 +514,7 @@ static void ad7793_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->spi->irq, indio_dev);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19,
@@ -537,7 +524,7 @@ static ssize_t ad7793_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
@@ -549,7 +536,7 @@ static ssize_t ad7793_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
long lval;
int i, ret;
@@ -591,7 +578,7 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
static ssize_t ad7793_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
int i, len = 0;
@@ -630,7 +617,7 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -760,7 +747,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 0,
.channel2 = 0,
.address = AD7793_CH_AIN1P_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 0,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -771,7 +759,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 1,
.channel2 = 1,
.address = AD7793_CH_AIN2P_AIN2M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 1,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -782,7 +771,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN3P_AIN3M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -794,7 +784,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN1M_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -803,7 +794,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 0,
.address = AD7793_CH_TEMP,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('s', 24, 32, 0),
},
@@ -813,7 +805,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 4,
.address = AD7793_CH_AVDD_MONITOR,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('s', 24, 32, 0),
},
@@ -827,7 +820,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 0,
.channel2 = 0,
.address = AD7793_CH_AIN1P_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 0,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -838,7 +832,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 1,
.channel2 = 1,
.address = AD7793_CH_AIN2P_AIN2M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 1,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -849,7 +844,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN3P_AIN3M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -861,7 +857,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN1M_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -870,7 +867,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 0,
.address = AD7793_CH_TEMP,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('s', 16, 32, 0),
},
@@ -880,7 +878,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 4,
.address = AD7793_CH_AVDD_MONITOR,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('s', 16, 32, 0),
},
@@ -905,7 +904,7 @@ static int __devinit ad7793_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -989,7 +988,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -1009,7 +1008,7 @@ static int ad7793_remove(struct spi_device *spi)
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 52b720e..5356b09 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -16,9 +16,9 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* AD7816 config masks
@@ -113,7 +113,7 @@ static ssize_t ad7816_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (chip->mode)
@@ -127,7 +127,7 @@ static ssize_t ad7816_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (strcmp(buf, "full")) {
@@ -159,7 +159,7 @@ static ssize_t ad7816_show_channel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->channel_id);
@@ -170,7 +170,7 @@ static ssize_t ad7816_store_channel(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
unsigned long data;
int ret;
@@ -208,7 +208,7 @@ static ssize_t ad7816_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
u16 data;
s8 value;
@@ -263,7 +263,7 @@ static ssize_t ad7816_show_oti(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
int value;
@@ -284,7 +284,7 @@ static inline ssize_t ad7816_set_oti(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
long value;
u8 data;
@@ -354,7 +354,7 @@ static int __devinit ad7816_probe(struct spi_device *spi_dev)
return -EINVAL;
}
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -426,7 +426,7 @@ error_free_gpio_convert:
error_free_gpio_rdwr:
gpio_free(chip->rdwr_pin);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -443,7 +443,7 @@ static int __devexit ad7816_remove(struct spi_device *spi_dev)
gpio_free(chip->busy_pin);
gpio_free(chip->convert_pin);
gpio_free(chip->rdwr_pin);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
index bc53b65..2e09e54 100644
--- a/drivers/staging/iio/adc/ad7887.h
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -63,7 +63,6 @@ struct ad7887_state {
struct spi_device *spi;
const struct ad7887_chip_info *chip_info;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer[4];
struct spi_message msg[3];
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
index e9bbc3e..7186074 100644
--- a/drivers/staging/iio/adc/ad7887_core.c
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -15,9 +15,9 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7887.h"
@@ -42,7 +42,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -75,7 +75,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = 1,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
@@ -84,7 +85,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = 0,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
@@ -104,7 +106,7 @@ static int __devinit ad7887_probe(struct spi_device *spi)
struct ad7887_platform_data *pdata = spi->dev.platform_data;
struct ad7887_state *st;
int ret, voltage_uv = 0;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -220,7 +222,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -237,7 +239,7 @@ static int ad7887_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index d180907..fd91384 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
* Copyright (C) 2008 Jonathan Cameron
*
* Licensed under the GPL-2.
@@ -12,10 +12,10 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7887.h"
@@ -29,22 +29,11 @@
static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- st->chip_info->channel[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
+ int ret;
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
/* We know this is a single long so can 'cheat' */
switch (*indio_dev->active_scan_mask) {
@@ -83,7 +72,6 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7887_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *buf;
int b_sent;
@@ -92,7 +80,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
indio_dev->masklength) *
st->chip_info->channel[0].scan_type.storagebits / 8;
- buf = kzalloc(st->d_size, GFP_KERNEL);
+ buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
@@ -103,8 +91,8 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
memcpy(buf, st->data, bytes);
- if (ring->scan_timestamp)
- memcpy(buf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
@@ -126,7 +114,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -139,7 +127,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad7887_ring_setup_ops;
@@ -148,8 +136,8 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -157,5 +145,5 @@ error_ret:
void ad7887_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 356f690..99f8abe 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -104,7 +104,6 @@ struct ad799x_chip_info {
struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
- size_t d_size;
struct iio_trigger *trig;
struct regulator *reg;
u16 int_vref_mv;
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index a845866..80e0c6e 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -33,10 +33,10 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "ad799x.h"
@@ -148,7 +148,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -182,7 +182,7 @@ static ssize_t ad799x_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
@@ -201,7 +201,7 @@ static ssize_t ad799x_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
long val;
@@ -294,7 +294,7 @@ static ssize_t ad799x_read_channel_config(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -312,7 +312,7 @@ static ssize_t ad799x_write_channel_config(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -454,6 +454,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -461,6 +462,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -468,6 +470,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -475,6 +478,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -490,6 +494,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -497,6 +502,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -504,6 +510,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -511,6 +518,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -526,6 +534,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -533,6 +542,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -540,6 +550,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -547,6 +558,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -562,6 +574,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -570,6 +583,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -587,6 +601,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -596,6 +611,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.indexed = 1,
.channel = 1,
.scan_index = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
},
@@ -603,6 +619,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -611,6 +628,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -628,6 +646,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -636,6 +655,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -644,6 +664,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -652,6 +673,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -669,6 +691,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -677,6 +700,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -685,6 +709,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -693,6 +718,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -701,6 +727,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 4,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -708,6 +735,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 5,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -715,6 +743,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 6,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 6,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -722,6 +751,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 7,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 7,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -738,6 +768,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -746,6 +777,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -754,6 +786,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -762,6 +795,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -770,6 +804,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 4,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -777,6 +812,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 5,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -784,6 +820,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 6,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 6,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -791,6 +828,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 7,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 7,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -809,7 +847,7 @@ static int __devinit ad799x_probe(struct i2c_client *client,
int ret;
struct ad799x_platform_data *pdata = client->dev.platform_data;
struct ad799x_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -882,7 +920,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -902,7 +940,7 @@ static __devexit int ad799x_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 069765c..1c7ff44 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc.
* Copyright (C) 2008-2010 Jonathan Cameron
*
* This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,10 @@
#include <linux/i2c.h>
#include <linux/bitops.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad799x.h"
@@ -32,9 +32,7 @@
**/
static int ad799x_ring_preenable(struct iio_dev *indio_dev)
{
- struct iio_buffer *ring = indio_dev->buffer;
struct ad799x_state *st = iio_priv(indio_dev);
-
/*
* Need to figure out the current mode based upon the requested
* scan mask in iio_dev
@@ -43,21 +41,7 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
if (st->id == ad7997 || st->id == ad7998)
ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask);
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) * 2;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
- return 0;
+ return iio_sw_buffer_preenable(indio_dev);
}
/**
@@ -78,7 +62,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
int b_sent;
u8 cmd;
- rxbuf = kmalloc(st->d_size, GFP_KERNEL);
+ rxbuf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (rxbuf == NULL)
goto out;
@@ -111,8 +95,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (ring->scan_timestamp)
- memcpy(rxbuf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -136,7 +120,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret = 0;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -150,7 +134,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -161,8 +145,8 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -170,5 +154,5 @@ error_ret:
void ad799x_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
index caf57c1..e5f1ed7 100644
--- a/drivers/staging/iio/adc/adt7310.c
+++ b/drivers/staging/iio/adc/adt7310.c
@@ -15,9 +15,9 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* ADT7310 registers definition
*/
@@ -175,7 +175,7 @@ static ssize_t adt7310_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 config;
@@ -198,7 +198,7 @@ static ssize_t adt7310_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -242,7 +242,7 @@ static ssize_t adt7310_show_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
int bits;
@@ -264,7 +264,7 @@ static ssize_t adt7310_store_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
unsigned long data;
u16 config;
@@ -300,7 +300,7 @@ static ssize_t adt7310_show_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -350,7 +350,7 @@ static ssize_t adt7310_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 status;
u16 data;
@@ -424,7 +424,7 @@ static ssize_t adt7310_show_event_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -443,7 +443,7 @@ static ssize_t adt7310_set_event_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -476,7 +476,7 @@ static ssize_t adt7310_show_fault_queue(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -492,7 +492,7 @@ static ssize_t adt7310_set_fault_queue(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -522,7 +522,7 @@ static inline ssize_t adt7310_show_t_bound(struct device *dev,
u8 bound_reg,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 data;
int ret;
@@ -540,7 +540,7 @@ static inline ssize_t adt7310_set_t_bound(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
long tmp1, tmp2;
u16 data;
@@ -660,7 +660,7 @@ static ssize_t adt7310_show_t_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
u8 t_hyst;
@@ -677,7 +677,7 @@ static inline ssize_t adt7310_set_t_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
unsigned long data;
@@ -753,7 +753,7 @@ static int __devinit adt7310_probe(struct spi_device *spi_dev)
unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
unsigned long irq_flags;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -833,7 +833,7 @@ error_unreg_int_irq:
error_unreg_ct_irq:
free_irq(spi_dev->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -849,7 +849,7 @@ static int __devexit adt7310_remove(struct spi_device *spi_dev)
free_irq(adt7310_platform_data[0], indio_dev);
if (spi_dev->irq)
free_irq(spi_dev->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
index dff3e8c..917b692 100644
--- a/drivers/staging/iio/adc/adt7410.c
+++ b/drivers/staging/iio/adc/adt7410.c
@@ -15,9 +15,9 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* ADT7410 registers definition
@@ -144,7 +144,7 @@ static ssize_t adt7410_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 config;
@@ -167,7 +167,7 @@ static ssize_t adt7410_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -211,7 +211,7 @@ static ssize_t adt7410_show_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
int bits;
@@ -233,7 +233,7 @@ static ssize_t adt7410_store_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
unsigned long data;
u16 config;
@@ -269,7 +269,7 @@ static ssize_t adt7410_show_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -319,7 +319,7 @@ static ssize_t adt7410_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 status;
u16 data;
@@ -392,7 +392,7 @@ static ssize_t adt7410_show_event_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -411,7 +411,7 @@ static ssize_t adt7410_set_event_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -444,7 +444,7 @@ static ssize_t adt7410_show_fault_queue(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -460,7 +460,7 @@ static ssize_t adt7410_set_fault_queue(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -490,7 +490,7 @@ static inline ssize_t adt7410_show_t_bound(struct device *dev,
u8 bound_reg,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 data;
int ret;
@@ -508,7 +508,7 @@ static inline ssize_t adt7410_set_t_bound(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
long tmp1, tmp2;
u16 data;
@@ -628,7 +628,7 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
u8 t_hyst;
@@ -645,7 +645,7 @@ static inline ssize_t adt7410_set_t_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
unsigned long data;
@@ -721,7 +721,7 @@ static int __devinit adt7410_probe(struct i2c_client *client,
int ret = 0;
unsigned long *adt7410_platform_data = client->dev.platform_data;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -797,7 +797,7 @@ error_unreg_int_irq:
error_unreg_ct_irq:
free_irq(client->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -812,7 +812,7 @@ static int __devexit adt7410_remove(struct i2c_client *client)
free_irq(adt7410_platform_data[0], indio_dev);
if (client->irq)
free_irq(client->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index dfc9033..9690306 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -30,9 +30,10 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h>
+#include <linux/of.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* LPC32XX registers definitions
@@ -73,7 +74,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
{
struct lpc32xx_adc_info *info = iio_priv(indio_dev);
- if (mask == 0) {
+ if (mask == IIO_CHAN_INFO_RAW) {
mutex_lock(&indio_dev->mlock);
clk_enable(info->clk);
/* Measurement setup */
@@ -98,12 +99,13 @@ static const struct iio_info lpc32xx_adc_iio_info = {
.driver_module = THIS_MODULE,
};
-#define LPC32XX_ADC_CHANNEL(_index) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = _index, \
- .address = AD_IN * _index, \
- .scan_index = _index, \
+#define LPC32XX_ADC_CHANNEL(_index) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .address = AD_IN * _index, \
+ .scan_index = _index, \
}
static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
@@ -139,7 +141,7 @@ static int __devinit lpc32xx_adc_probe(struct platform_device *pdev)
goto errout1;
}
- iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info));
+ iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info));
if (!iodev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
retval = -ENOMEM;
@@ -200,7 +202,7 @@ errout4:
errout3:
iounmap(info->adc_base);
errout2:
- iio_free_device(iodev);
+ iio_device_free(iodev);
errout1:
return retval;
}
@@ -216,17 +218,26 @@ static int __devexit lpc32xx_adc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
clk_put(info->clk);
iounmap(info->adc_base);
- iio_free_device(iodev);
+ iio_device_free(iodev);
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id lpc32xx_adc_match[] = {
+ { .compatible = "nxp,lpc3220-adc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
+#endif
+
static struct platform_driver lpc32xx_adc_driver = {
.probe = lpc32xx_adc_probe,
.remove = __devexit_p(lpc32xx_adc_remove),
.driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_adc_match),
},
};
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index cf3e2ca..6799ce2 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -32,10 +32,11 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/driver.h>
#include "max1363.h"
@@ -248,7 +249,7 @@ static int max1363_read_raw(struct iio_dev *indio_dev,
struct max1363_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = max1363_read_single_chan(indio_dev, chan, val, m);
if (ret < 0)
return ret;
@@ -281,7 +282,8 @@ static const enum max1363_modes max1363_mode_list[] = {
#define MAX1363_EV_M \
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
| IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
-#define MAX1363_INFO_MASK IIO_CHAN_INFO_SCALE_SHARED_BIT
+#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT)
#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
{ \
.type = IIO_VOLTAGE, \
@@ -497,7 +499,7 @@ static ssize_t max1363_monitor_show_freq(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
+ struct max1363_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]);
}
@@ -506,7 +508,7 @@ static ssize_t max1363_monitor_store_freq(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max1363_state *st = iio_priv(indio_dev);
int i, ret;
unsigned long val;
@@ -830,6 +832,7 @@ static struct attribute_group max1363_event_attribute_group = {
static const struct iio_info max1238_info = {
.read_raw = &max1363_read_raw,
.driver_module = THIS_MODULE,
+ .update_scan_mode = &max1363_update_scan_mode,
};
static const struct iio_info max1363_info = {
@@ -1284,11 +1287,14 @@ static int __devinit max1363_probe(struct i2c_client *client,
if (ret)
goto error_put_reg;
- indio_dev = iio_allocate_device(sizeof(struct max1363_state));
+ indio_dev = iio_device_alloc(sizeof(struct max1363_state));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
}
+ ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+ if (ret < 0)
+ goto error_free_device;
st = iio_priv(indio_dev);
st->reg = reg;
/* this is only used for device removal purposes */
@@ -1299,7 +1305,7 @@ static int __devinit max1363_probe(struct i2c_client *client,
ret = max1363_alloc_scan_masks(indio_dev);
if (ret)
- goto error_free_device;
+ goto error_unregister_map;
/* Estabilish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
@@ -1349,8 +1355,10 @@ error_cleanup_ring:
max1363_ring_cleanup(indio_dev);
error_free_available_scan_masks:
kfree(indio_dev->available_scan_masks);
+error_unregister_map:
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
regulator_disable(reg);
error_put_reg:
@@ -1375,7 +1383,8 @@ static int max1363_remove(struct i2c_client *client)
regulator_disable(reg);
regulator_put(reg);
}
- iio_free_device(indio_dev);
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index d0a60a3..b302013 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -14,10 +14,10 @@
#include <linux/i2c.h>
#include <linux/bitops.h>
-#include "../iio.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "max1363.h"
@@ -54,7 +54,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
d_size = numvals*2;
else
d_size = numvals;
- if (indio_dev->buffer->scan_timestamp) {
+ if (indio_dev->scan_timestamp) {
d_size += sizeof(s64);
if (d_size % sizeof(s64))
d_size += sizeof(s64) - (d_size % sizeof(s64));
@@ -78,7 +78,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (indio_dev->buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
new file mode 100644
index 0000000..64d630e
--- /dev/null
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -0,0 +1,448 @@
+/*
+ * ST SPEAr ADC driver
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/*
+ * SPEAR registers definitions
+ */
+
+#define SCAN_RATE_LO(x) ((x) & 0xFFFF)
+#define SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF)
+#define CLK_LOW(x) (((x) & 0xf) << 0)
+#define CLK_HIGH(x) (((x) & 0xf) << 4)
+
+/* Bit definitions for SPEAR_ADC_STATUS */
+#define START_CONVERSION (1 << 0)
+#define CHANNEL_NUM(x) ((x) << 1)
+#define ADC_ENABLE (1 << 4)
+#define AVG_SAMPLE(x) ((x) << 5)
+#define VREF_INTERNAL (1 << 9)
+
+#define DATA_MASK 0x03ff
+#define DATA_BITS 10
+
+#define MOD_NAME "spear-adc"
+
+#define ADC_CHANNEL_NUM 8
+
+#define CLK_MIN 2500000
+#define CLK_MAX 20000000
+
+struct adc_regs_spear3xx {
+ u32 status;
+ u32 average;
+ u32 scan_rate;
+ u32 clk; /* Not avail for 1340 & 1310 */
+ u32 ch_ctrl[ADC_CHANNEL_NUM];
+ u32 ch_data[ADC_CHANNEL_NUM];
+};
+
+struct chan_data {
+ u32 lsb;
+ u32 msb;
+};
+
+struct adc_regs_spear6xx {
+ u32 status;
+ u32 pad[2];
+ u32 clk;
+ u32 ch_ctrl[ADC_CHANNEL_NUM];
+ struct chan_data ch_data[ADC_CHANNEL_NUM];
+ u32 scan_rate_lo;
+ u32 scan_rate_hi;
+ struct chan_data average;
+};
+
+struct spear_adc_info {
+ struct device_node *np;
+ struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
+ struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
+ struct clk *clk;
+ struct completion completion;
+ u32 current_clk;
+ u32 sampling_freq;
+ u32 avg_samples;
+ u32 vref_external;
+ u32 value;
+};
+
+/*
+ * Functions to access some SPEAr ADC register. Abstracted into
+ * static inline functions, because of different register offsets
+ * on different SoC variants (SPEAr300 vs SPEAr600 etc).
+ */
+static void spear_adc_set_status(struct spear_adc_info *info, u32 val)
+{
+ __raw_writel(val, &info->adc_base_spear6xx->status);
+}
+
+static void spear_adc_set_clk(struct spear_adc_info *info, u32 val)
+{
+ u32 clk_high, clk_low, count;
+ u32 apb_clk = clk_get_rate(info->clk);
+
+ count = (apb_clk + val - 1) / val;
+ clk_low = count / 2;
+ clk_high = count - clk_low;
+ info->current_clk = apb_clk / count;
+
+ __raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high),
+ &info->adc_base_spear6xx->clk);
+}
+
+static void spear_adc_set_ctrl(struct spear_adc_info *info, int n,
+ u32 val)
+{
+ __raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]);
+}
+
+static u32 spear_adc_get_average(struct spear_adc_info *info)
+{
+ if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+ return __raw_readl(&info->adc_base_spear6xx->average.msb) &
+ DATA_MASK;
+ } else {
+ return __raw_readl(&info->adc_base_spear3xx->average) &
+ DATA_MASK;
+ }
+}
+
+static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate)
+{
+ if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+ __raw_writel(SCAN_RATE_LO(rate),
+ &info->adc_base_spear6xx->scan_rate_lo);
+ __raw_writel(SCAN_RATE_HI(rate),
+ &info->adc_base_spear6xx->scan_rate_hi);
+ } else {
+ __raw_writel(rate, &info->adc_base_spear3xx->scan_rate);
+ }
+}
+
+static int spear_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct spear_adc_info *info = iio_priv(indio_dev);
+ u32 scale_mv;
+ u32 status;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+
+ status = CHANNEL_NUM(chan->channel) |
+ AVG_SAMPLE(info->avg_samples) |
+ START_CONVERSION | ADC_ENABLE;
+ if (info->vref_external == 0)
+ status |= VREF_INTERNAL;
+
+ spear_adc_set_status(info, status);
+ wait_for_completion(&info->completion); /* set by ISR */
+ *val = info->value;
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ scale_mv = (info->vref_external * 1000) >> DATA_BITS;
+ *val = scale_mv / 1000;
+ *val2 = (scale_mv % 1000) * 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
+ return -EINVAL;
+}
+
+#define SPEAR_ADC_CHAN(idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .channel = idx, \
+ .scan_type = { \
+ .sign = 'u', \
+ .storagebits = 16, \
+ }, \
+}
+
+static struct iio_chan_spec spear_adc_iio_channels[] = {
+ SPEAR_ADC_CHAN(0),
+ SPEAR_ADC_CHAN(1),
+ SPEAR_ADC_CHAN(2),
+ SPEAR_ADC_CHAN(3),
+ SPEAR_ADC_CHAN(4),
+ SPEAR_ADC_CHAN(5),
+ SPEAR_ADC_CHAN(6),
+ SPEAR_ADC_CHAN(7),
+};
+
+static irqreturn_t spear_adc_isr(int irq, void *dev_id)
+{
+ struct spear_adc_info *info = (struct spear_adc_info *)dev_id;
+
+ /* Read value to clear IRQ */
+ info->value = spear_adc_get_average(info);
+ complete(&info->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int spear_adc_configure(struct spear_adc_info *info)
+{
+ int i;
+
+ /* Reset ADC core */
+ spear_adc_set_status(info, 0);
+ __raw_writel(0, &info->adc_base_spear6xx->clk);
+ for (i = 0; i < 8; i++)
+ spear_adc_set_ctrl(info, i, 0);
+ spear_adc_set_scanrate(info, 0);
+
+ spear_adc_set_clk(info, info->sampling_freq);
+
+ return 0;
+}
+
+static ssize_t spear_adc_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct spear_adc_info *info = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", info->current_clk);
+}
+
+static ssize_t spear_adc_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct spear_adc_info *info = iio_priv(indio_dev);
+ u32 clk_high, clk_low, count;
+ u32 apb_clk = clk_get_rate(info->clk);
+ unsigned long lval;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &lval);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ if ((lval < CLK_MIN) || (lval > CLK_MAX)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ count = (apb_clk + lval - 1) / lval;
+ clk_low = count / 2;
+ clk_high = count - clk_low;
+ info->current_clk = apb_clk / count;
+ spear_adc_set_clk(info, lval);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ spear_adc_read_frequency,
+ spear_adc_write_frequency);
+
+static struct attribute *spear_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group spear_attribute_group = {
+ .attrs = spear_attributes,
+};
+
+static const struct iio_info spear_adc_iio_info = {
+ .read_raw = &spear_read_raw,
+ .attrs = &spear_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int __devinit spear_adc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct spear_adc_info *info;
+ struct iio_dev *iodev = NULL;
+ int ret = -ENODEV;
+ int irq;
+
+ iodev = iio_device_alloc(sizeof(struct spear_adc_info));
+ if (!iodev) {
+ dev_err(dev, "failed allocating iio device\n");
+ ret = -ENOMEM;
+ goto errout1;
+ }
+
+ info = iio_priv(iodev);
+ info->np = np;
+
+ /*
+ * SPEAr600 has a different register layout than other SPEAr SoC's
+ * (e.g. SPEAr3xx). Let's provide two register base addresses
+ * to support multi-arch kernels.
+ */
+ info->adc_base_spear6xx = of_iomap(np, 0);
+ if (!info->adc_base_spear6xx) {
+ dev_err(dev, "failed mapping memory\n");
+ ret = -ENOMEM;
+ goto errout2;
+ }
+ info->adc_base_spear3xx =
+ (struct adc_regs_spear3xx *)info->adc_base_spear6xx;
+
+ info->clk = clk_get(dev, NULL);
+ if (IS_ERR(info->clk)) {
+ dev_err(dev, "failed getting clock\n");
+ goto errout3;
+ }
+
+ ret = clk_prepare(info->clk);
+ if (ret) {
+ dev_err(dev, "failed preparing clock\n");
+ goto errout4;
+ }
+
+ ret = clk_enable(info->clk);
+ if (ret) {
+ dev_err(dev, "failed enabling clock\n");
+ goto errout5;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if ((irq < 0) || (irq >= NR_IRQS)) {
+ dev_err(dev, "failed getting interrupt resource\n");
+ ret = -EINVAL;
+ goto errout6;
+ }
+
+ ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
+ if (ret < 0) {
+ dev_err(dev, "failed requesting interrupt\n");
+ goto errout6;
+ }
+
+ if (of_property_read_u32(np, "sampling-frequency",
+ &info->sampling_freq)) {
+ dev_err(dev, "sampling-frequency missing in DT\n");
+ ret = -EINVAL;
+ goto errout6;
+ }
+
+ /*
+ * Optional avg_samples defaults to 0, resulting in single data
+ * conversion
+ */
+ of_property_read_u32(np, "average-samples", &info->avg_samples);
+
+ /*
+ * Optional vref_external defaults to 0, resulting in internal vref
+ * selection
+ */
+ of_property_read_u32(np, "vref-external", &info->vref_external);
+
+ spear_adc_configure(info);
+
+ platform_set_drvdata(pdev, iodev);
+
+ init_completion(&info->completion);
+
+ iodev->name = MOD_NAME;
+ iodev->dev.parent = dev;
+ iodev->info = &spear_adc_iio_info;
+ iodev->modes = INDIO_DIRECT_MODE;
+ iodev->channels = spear_adc_iio_channels;
+ iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
+
+ ret = iio_device_register(iodev);
+ if (ret)
+ goto errout6;
+
+ dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
+
+ return 0;
+
+errout6:
+ clk_disable(info->clk);
+errout5:
+ clk_unprepare(info->clk);
+errout4:
+ clk_put(info->clk);
+errout3:
+ iounmap(info->adc_base_spear6xx);
+errout2:
+ iio_device_free(iodev);
+errout1:
+ return ret;
+}
+
+static int __devexit spear_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *iodev = platform_get_drvdata(pdev);
+ struct spear_adc_info *info = iio_priv(iodev);
+
+ iio_device_unregister(iodev);
+ platform_set_drvdata(pdev, NULL);
+ clk_disable(info->clk);
+ clk_unprepare(info->clk);
+ clk_put(info->clk);
+ iounmap(info->adc_base_spear6xx);
+ iio_device_free(iodev);
+
+ return 0;
+}
+
+static const struct of_device_id spear_adc_dt_ids[] = {
+ { .compatible = "st,spear600-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
+
+static struct platform_driver spear_adc_driver = {
+ .probe = spear_adc_probe,
+ .remove = __devexit_p(spear_adc_remove),
+ .driver = {
+ .name = MOD_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(spear_adc_dt_ids),
+ },
+};
+
+module_platform_driver(spear_adc_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("SPEAr ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index fd6a454..8fb014a 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -19,9 +19,9 @@
#include <linux/rtc.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../events.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
+#include <linux/iio/sysfs.h>
#include "adt7316.h"
/*
@@ -220,7 +220,7 @@ static ssize_t adt7316_show_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
@@ -252,7 +252,7 @@ static ssize_t adt7316_store_enabled(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
int enable;
@@ -276,7 +276,7 @@ static ssize_t adt7316_show_select_ex_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -290,7 +290,7 @@ static ssize_t adt7316_store_select_ex_temp(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -320,7 +320,7 @@ static ssize_t adt7316_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
@@ -334,7 +334,7 @@ static ssize_t adt7316_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -370,7 +370,7 @@ static ssize_t adt7316_show_ad_channel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -409,7 +409,7 @@ static ssize_t adt7316_store_ad_channel(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
unsigned long data = 0;
@@ -455,7 +455,7 @@ static ssize_t adt7316_show_all_ad_channels(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -477,7 +477,7 @@ static ssize_t adt7316_show_disable_averaging(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -489,7 +489,7 @@ static ssize_t adt7316_store_disable_averaging(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -516,7 +516,7 @@ static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -528,7 +528,7 @@ static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -557,7 +557,7 @@ static ssize_t adt7316_store_reset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -580,7 +580,7 @@ static ssize_t adt7316_show_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
@@ -591,7 +591,7 @@ static ssize_t adt7316_store_powerdown(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -618,7 +618,7 @@ static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
@@ -629,7 +629,7 @@ static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -656,7 +656,7 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
@@ -674,7 +674,7 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -708,7 +708,7 @@ static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -723,7 +723,7 @@ static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -755,7 +755,7 @@ static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -767,7 +767,7 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -794,7 +794,7 @@ static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -806,7 +806,7 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -833,7 +833,7 @@ static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%x\n",
@@ -845,7 +845,7 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
unsigned long data = 0;
@@ -876,7 +876,7 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
@@ -900,7 +900,7 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
unsigned long data;
@@ -934,7 +934,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
@@ -955,7 +955,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 ldac_config;
unsigned long data;
@@ -994,7 +994,7 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1009,7 +1009,7 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
int ret;
@@ -1039,7 +1039,7 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1054,7 +1054,7 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
int ret;
@@ -1084,7 +1084,7 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1101,7 +1101,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 ldac_config;
unsigned long data;
@@ -1220,7 +1220,7 @@ static ssize_t adt7316_show_VDD(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
@@ -1231,7 +1231,7 @@ static ssize_t adt7316_show_in_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
@@ -1243,7 +1243,7 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
@@ -1256,7 +1256,7 @@ static ssize_t adt7316_show_AIN2(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
@@ -1267,7 +1267,7 @@ static ssize_t adt7316_show_AIN3(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
@@ -1278,7 +1278,7 @@ static ssize_t adt7316_show_AIN4(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
@@ -1330,7 +1330,7 @@ static ssize_t adt7316_show_in_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
@@ -1341,7 +1341,7 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
@@ -1355,7 +1355,7 @@ static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
@@ -1366,7 +1366,7 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
@@ -1380,7 +1380,7 @@ static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip,
@@ -1392,7 +1392,7 @@ static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip,
@@ -1407,7 +1407,7 @@ static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip,
@@ -1419,7 +1419,7 @@ static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip,
@@ -1504,7 +1504,7 @@ static ssize_t adt7316_show_DAC_A(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 0, buf);
@@ -1515,7 +1515,7 @@ static ssize_t adt7316_store_DAC_A(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 0, buf, len);
@@ -1528,7 +1528,7 @@ static ssize_t adt7316_show_DAC_B(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 1, buf);
@@ -1539,7 +1539,7 @@ static ssize_t adt7316_store_DAC_B(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 1, buf, len);
@@ -1552,7 +1552,7 @@ static ssize_t adt7316_show_DAC_C(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 2, buf);
@@ -1563,7 +1563,7 @@ static ssize_t adt7316_store_DAC_C(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 2, buf, len);
@@ -1576,7 +1576,7 @@ static ssize_t adt7316_show_DAC_D(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 3, buf);
@@ -1587,7 +1587,7 @@ static ssize_t adt7316_store_DAC_D(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 3, buf, len);
@@ -1600,7 +1600,7 @@ static ssize_t adt7316_show_device_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -1618,7 +1618,7 @@ static ssize_t adt7316_show_manufactorer_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -1637,7 +1637,7 @@ static ssize_t adt7316_show_device_rev(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 rev;
int ret;
@@ -1655,7 +1655,7 @@ static ssize_t adt7316_show_bus_type(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 stat;
int ret;
@@ -1841,7 +1841,7 @@ static ssize_t adt7316_show_int_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%x\n", chip->int_mask);
@@ -1855,7 +1855,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -1895,7 +1895,7 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 val;
int data;
@@ -1926,7 +1926,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
long data;
u8 val;
@@ -1965,7 +1965,7 @@ static ssize_t adt7316_show_int_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
@@ -1976,7 +1976,7 @@ static ssize_t adt7316_set_int_enabled(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -2133,7 +2133,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
unsigned short *adt7316_platform_data = dev->platform_data;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -2210,7 +2210,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
error_unreg_irq:
free_irq(chip->bus.irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -2224,7 +2224,7 @@ int __devexit adt7316_remove(struct device *dev)
iio_device_unregister(indio_dev);
if (chip->bus.irq)
free_irq(chip->bus.irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
deleted file mode 100644
index df2046d..0000000
--- a/drivers/staging/iio/buffer.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* The industrial I/O core - generic buffer interfaces.
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- */
-
-#ifndef _IIO_BUFFER_GENERIC_H_
-#define _IIO_BUFFER_GENERIC_H_
-#include <linux/sysfs.h>
-#include "iio.h"
-
-#ifdef CONFIG_IIO_BUFFER
-
-struct iio_buffer;
-
-/**
- * struct iio_buffer_access_funcs - access functions for buffers.
- * @store_to: actually store stuff to the buffer
- * @read_first_n: try to get a specified number of bytes (must exist)
- * @request_update: if a parameter change has been marked, update underlying
- * storage.
- * @get_bytes_per_datum:get current bytes per datum
- * @set_bytes_per_datum:set number of bytes per datum
- * @get_length: get number of datums in buffer
- * @set_length: set number of datums in buffer
- *
- * The purpose of this structure is to make the buffer element
- * modular as event for a given driver, different usecases may require
- * different buffer designs (space efficiency vs speed for example).
- *
- * It is worth noting that a given buffer implementation may only support a
- * small proportion of these functions. The core code 'should' cope fine with
- * any of them not existing.
- **/
-struct iio_buffer_access_funcs {
- int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp);
- int (*read_first_n)(struct iio_buffer *buffer,
- size_t n,
- char __user *buf);
-
- int (*request_update)(struct iio_buffer *buffer);
-
- int (*get_bytes_per_datum)(struct iio_buffer *buffer);
- int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
- int (*get_length)(struct iio_buffer *buffer);
- int (*set_length)(struct iio_buffer *buffer, int length);
-};
-
-/**
- * struct iio_buffer - general buffer structure
- * @length: [DEVICE] number of datums in buffer
- * @bytes_per_datum: [DEVICE] size of individual datum including timestamp
- * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode
- * control method is used
- * @scan_mask: [INTERN] bitmask used in masking scan mode elements
- * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
- * @scan_timestamp: [INTERN] does the scan mode include a timestamp
- * @access: [DRIVER] buffer access functions associated with the
- * implementation.
- * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
- * @scan_el_group: [DRIVER] attribute group for those attributes not
- * created from the iio_chan_info array.
- * @pollq: [INTERN] wait queue to allow for polling on the buffer.
- * @stufftoread: [INTERN] flag to indicate new data.
- * @demux_list: [INTERN] list of operations required to demux the scan.
- * @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- **/
-struct iio_buffer {
- int length;
- int bytes_per_datum;
- struct attribute_group *scan_el_attrs;
- long *scan_mask;
- bool scan_timestamp;
- unsigned scan_index_timestamp;
- const struct iio_buffer_access_funcs *access;
- struct list_head scan_el_dev_attr_list;
- struct attribute_group scan_el_group;
- wait_queue_head_t pollq;
- bool stufftoread;
- const struct attribute_group *attrs;
- struct list_head demux_list;
- unsigned char *demux_bounce;
-};
-
-/**
- * iio_buffer_init() - Initialize the buffer structure
- * @buffer: buffer to be initialized
- **/
-void iio_buffer_init(struct iio_buffer *buffer);
-
-/**
- * __iio_update_buffer() - update common elements of buffers
- * @buffer: buffer that is the event source
- * @bytes_per_datum: size of individual datum including timestamp
- * @length: number of datums in buffer
- **/
-static inline void __iio_update_buffer(struct iio_buffer *buffer,
- int bytes_per_datum, int length)
-{
- buffer->bytes_per_datum = bytes_per_datum;
- buffer->length = length;
-}
-
-int iio_scan_mask_query(struct iio_dev *indio_dev,
- struct iio_buffer *buffer, int bit);
-
-/**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @buffer: the buffer whose scan mask we are interested in
- * @bit: the bit to be set.
- **/
-int iio_scan_mask_set(struct iio_dev *indio_dev,
- struct iio_buffer *buffer, int bit);
-
-/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer: IIO buffer structure for device
- * @scan: Full scan.
- * @timestamp:
- */
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
- s64 timestamp);
-
-int iio_update_demux(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_register() - register the buffer with IIO core
- * @indio_dev: device with the buffer to be registered
- **/
-int iio_buffer_register(struct iio_dev *indio_dev,
- const struct iio_chan_spec *channels,
- int num_channels);
-
-/**
- * iio_buffer_unregister() - unregister the buffer from IIO core
- * @indio_dev: the device with the buffer to be unregistered
- **/
-void iio_buffer_unregister(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_read_length() - attr func to get number of datums in the buffer
- **/
-ssize_t iio_buffer_read_length(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-/**
- * iio_buffer_write_length() - attr func to set number of datums in the buffer
- **/
-ssize_t iio_buffer_write_length(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len);
-/**
- * iio_buffer_store_enable() - attr to turn the buffer on
- **/
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len);
-/**
- * iio_buffer_show_enable() - attr to see if the buffer is on
- **/
-ssize_t iio_buffer_show_enable(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-#define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR, \
- iio_buffer_read_length, \
- iio_buffer_write_length)
-
-#define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, \
- iio_buffer_show_enable, \
- iio_buffer_store_enable)
-
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev);
-
-#else /* CONFIG_IIO_BUFFER */
-
-static inline int iio_buffer_register(struct iio_dev *indio_dev,
- struct iio_chan_spec *channels,
- int num_channels)
-{
- return 0;
-}
-
-static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
-{};
-
-#endif /* CONFIG_IIO_BUFFER */
-
-#endif /* _IIO_BUFFER_GENERIC_H_ */
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index e4a08dc..a16d1a2 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -13,9 +13,9 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* AD7150 registers definition
*/
@@ -104,7 +104,7 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,
struct ad7150_chip_info *chip = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_data(chip->client,
ad7150_addresses[chan->channel][0]);
if (ret < 0)
@@ -341,7 +341,7 @@ static ssize_t ad7150_show_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u8 value;
@@ -370,7 +370,7 @@ static ssize_t ad7150_store_timeout(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
@@ -429,7 +429,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -441,7 +442,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -556,7 +558,7 @@ static int __devinit ad7150_probe(struct i2c_client *client,
struct ad7150_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -619,7 +621,7 @@ error_free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -635,7 +637,7 @@ static int __devexit ad7150_remove(struct i2c_client *client)
if (client->dev.platform_data)
free_irq(*(unsigned int *)client->dev.platform_data, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index fdb83c3..98c3015 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -15,8 +15,8 @@
#include <linux/module.h>
#include <linux/delay.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* TODO: Check compliance of calibbias with abi (units)
@@ -97,7 +97,7 @@ static inline ssize_t ad7152_start_calib(struct device *dev,
size_t len,
u8 regval)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
bool doit;
@@ -169,7 +169,7 @@ static ssize_t ad7152_show_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
@@ -181,7 +181,7 @@ static ssize_t ad7152_store_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -329,7 +329,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* First set whether in differential mode */
regval = chip->setup[chan->channel];
@@ -436,7 +436,8 @@ static const struct iio_chan_spec ad7152_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
@@ -445,14 +446,16 @@ static const struct iio_chan_spec ad7152_channels[] = {
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
@@ -461,7 +464,8 @@ static const struct iio_chan_spec ad7152_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
@@ -477,7 +481,7 @@ static int __devinit ad7152_probe(struct i2c_client *client,
struct ad7152_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -509,7 +513,7 @@ static int __devinit ad7152_probe(struct i2c_client *client,
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -519,7 +523,7 @@ static int __devexit ad7152_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 40b8512..754e11e 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/stat.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad7746.h"
@@ -123,7 +123,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_VIN,
},
@@ -132,7 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_VDD_MON,
},
@@ -140,7 +142,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .processed_val = IIO_PROCESSED,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_INT_TEMP,
},
@@ -148,7 +150,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 1,
- .processed_val = IIO_PROCESSED,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_TEMP,
},
@@ -156,7 +158,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -168,7 +171,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -179,7 +183,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -192,7 +197,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -280,7 +286,7 @@ static inline ssize_t ad7746_start_calib(struct device *dev,
size_t len,
u8 regval)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
bool doit;
int ret, timeout = 10;
@@ -319,7 +325,7 @@ static ssize_t ad7746_start_offset_calib(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret = ad7746_select_channel(indio_dev,
&ad7746_channels[to_iio_dev_attr(attr)->address]);
if (ret < 0)
@@ -334,7 +340,7 @@ static ssize_t ad7746_start_gain_calib(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret = ad7746_select_channel(indio_dev,
&ad7746_channels[to_iio_dev_attr(attr)->address]);
if (ret < 0)
@@ -359,7 +365,7 @@ static ssize_t ad7746_show_cap_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[
@@ -371,7 +377,7 @@ static ssize_t ad7746_store_cap_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -399,7 +405,7 @@ static ssize_t ad7746_show_vt_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[
@@ -411,7 +417,7 @@ static ssize_t ad7746_store_vt_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -572,7 +578,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
ret = ad7746_select_channel(indio_dev, chan);
if (ret < 0)
goto out;
@@ -696,7 +703,7 @@ static int __devinit ad7746_probe(struct i2c_client *client,
int ret = 0;
unsigned char regval = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -756,7 +763,7 @@ static int __devinit ad7746_probe(struct i2c_client *client,
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -766,7 +773,7 @@ static int __devexit ad7746_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/consumer.h b/drivers/staging/iio/consumer.h
deleted file mode 100644
index 36a060c..0000000
--- a/drivers/staging/iio/consumer.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Industrial I/O in kernel consumer interface
- *
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- */
-#ifndef _IIO_INKERN_CONSUMER_H_
-#define _IIO_INKERN_CONSUMER_H
-#include "types.h"
-
-struct iio_dev;
-struct iio_chan_spec;
-
-/**
- * struct iio_channel - everything needed for a consumer to use a channel
- * @indio_dev: Device on which the channel exists.
- * @channel: Full description of the channel.
- */
-struct iio_channel {
- struct iio_dev *indio_dev;
- const struct iio_chan_spec *channel;
-};
-
-/**
- * iio_channel_get() - get description of all that is needed to access channel.
- * @name: Unique name of the device as provided in the iio_map
- * with which the desired provider to consumer mapping
- * was registered.
- * @consumer_channel: Unique name to identify the channel on the consumer
- * side. This typically describes the channels use within
- * the consumer. E.g. 'battery_voltage'
- */
-struct iio_channel *iio_st_channel_get(const char *name,
- const char *consumer_channel);
-
-/**
- * iio_st_channel_release() - release channels obtained via iio_st_channel_get
- * @chan: The channel to be released.
- */
-void iio_st_channel_release(struct iio_channel *chan);
-
-/**
- * iio_st_channel_get_all() - get all channels associated with a client
- * @name: name of consumer device.
- *
- * Returns an array of iio_channel structures terminated with one with
- * null iio_dev pointer.
- * This function is used by fairly generic consumers to get all the
- * channels registered as having this consumer.
- */
-struct iio_channel *iio_st_channel_get_all(const char *name);
-
-/**
- * iio_st_channel_release_all() - reverse iio_st_get_all
- * @chan: Array of channels to be released.
- */
-void iio_st_channel_release_all(struct iio_channel *chan);
-
-/**
- * iio_st_read_channel_raw() - read from a given channel
- * @channel: The channel being queried.
- * @val: Value read back.
- *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
- */
-int iio_st_read_channel_raw(struct iio_channel *chan,
- int *val);
-
-/**
- * iio_st_get_channel_type() - get the type of a channel
- * @channel: The channel being queried.
- * @type: The type of the channel.
- *
- * returns the enum iio_chan_type of the channel
- */
-int iio_st_get_channel_type(struct iio_channel *channel,
- enum iio_chan_type *type);
-
-/**
- * iio_st_read_channel_scale() - read the scale value for a channel
- * @channel: The channel being queried.
- * @val: First part of value read back.
- * @val2: Second part of value read back.
- *
- * Note returns a description of what is in val and val2, such
- * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
- * + val2/1e6
- */
-int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
- int *val2);
-
-#endif
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index a57803a..a626f03 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -56,12 +56,12 @@ config AD5624R_SPI
AD5664R converters (DAC). This driver uses the common SPI interface.
config AD5446
- tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver"
+ tristate "Analog Devices AD5446 and similar single channel DACs driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5444, AD5446,
- AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621,
- AD5640, AD5660, AD5662 DACs.
+ AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620,
+ AD5621, AD5640, AD5660, AD5662 DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.
diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c
index 06b1627..047148a 100644
--- a/drivers/staging/iio/dac/ad5064.c
+++ b/drivers/staging/iio/dac/ad5064.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5064_MAX_DAC_CHANNELS 8
@@ -144,14 +144,14 @@ static const char ad5064_powerdown_modes[][15] = {
};
static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
}
static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5064_state *st = iio_priv(indio_dev);
@@ -160,7 +160,8 @@ static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
}
static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, const char *buf, size_t len)
+ uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+ size_t len)
{
struct ad5064_state *st = iio_priv(indio_dev);
unsigned int mode, i;
@@ -187,7 +188,7 @@ static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
}
static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5064_state *st = iio_priv(indio_dev);
@@ -195,7 +196,8 @@ static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
}
static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, const char *buf, size_t len)
+ uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+ size_t len)
{
struct ad5064_state *st = iio_priv(indio_dev);
bool pwr_down;
@@ -235,7 +237,7 @@ static int ad5064_read_raw(struct iio_dev *indio_dev,
int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
*val = st->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -260,7 +262,7 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -308,7 +310,8 @@ static struct iio_chan_spec_ext_info ad5064_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = (chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = AD5064_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \
.ext_info = ad5064_ext_info, \
@@ -442,7 +445,7 @@ static int __devinit ad5064_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -499,7 +502,7 @@ error_free_reg:
if (!st->use_internal_vref)
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -517,7 +520,7 @@ static int __devexit ad5064_remove(struct spi_device *spi)
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c
index cec3693..38660ef 100644
--- a/drivers/staging/iio/dac/ad5360.c
+++ b/drivers/staging/iio/dac/ad5360.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5360_CMD(x) ((x) << 22)
@@ -103,7 +103,8 @@ enum ad5360_type {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
@@ -250,7 +251,7 @@ static ssize_t ad5360_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5360_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
@@ -278,7 +279,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
static ssize_t ad5360_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool pwr_down;
int ret;
@@ -319,7 +320,7 @@ static int ad5360_write_raw(struct iio_dev *indio_dev,
unsigned int ofs_index;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -376,7 +377,7 @@ static int ad5360_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
chan->address);
if (ret < 0)
@@ -464,7 +465,7 @@ static int __devinit ad5360_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -519,7 +520,7 @@ error_free_reg:
error_free_channels:
kfree(indio_dev->channels);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -536,7 +537,7 @@ static int __devexit ad5360_remove(struct spi_device *spi)
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c
index 4c50716..370d284 100644
--- a/drivers/staging/iio/dac/ad5380.c
+++ b/drivers/staging/iio/dac/ad5380.c
@@ -18,8 +18,8 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
@@ -85,7 +85,8 @@ enum ad5380_type {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)) \
@@ -167,7 +168,7 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
static ssize_t ad5380_read_dac_powerdown(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
@@ -176,7 +177,7 @@ static ssize_t ad5380_read_dac_powerdown(struct device *dev,
static ssize_t ad5380_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
bool pwr_down;
int ret;
@@ -212,7 +213,7 @@ static const char ad5380_powerdown_modes[][15] = {
static ssize_t ad5380_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
unsigned int mode;
int ret;
@@ -229,7 +230,7 @@ static ssize_t ad5380_read_powerdown_mode(struct device *dev,
static ssize_t ad5380_write_powerdown_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
unsigned int i;
int ret;
@@ -292,7 +293,7 @@ static int ad5380_write_raw(struct iio_dev *indio_dev,
struct ad5380_state *st = iio_priv(indio_dev);
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -322,7 +323,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev,
int ret;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
val);
@@ -388,7 +389,7 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
unsigned int ctrl = 0;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(dev, "Failed to allocate iio device\n");
ret = -ENOMEM;
@@ -454,7 +455,7 @@ error_free_reg:
kfree(indio_dev->channels);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_regmap_exit:
regmap_exit(regmap);
@@ -476,7 +477,7 @@ static int __devexit ad5380_remove(struct device *dev)
}
regmap_exit(st->regmap);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c
index 0b040b2..ffbd4c2 100644
--- a/drivers/staging/iio/dac/ad5421.c
+++ b/drivers/staging/iio/dac/ad5421.c
@@ -16,9 +16,9 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "dac.h"
#include "ad5421.h"
@@ -87,7 +87,8 @@ static const struct iio_chan_spec ad5421_channels[] = {
.indexed = 1,
.output = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SHARED_BIT |
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
@@ -304,7 +305,7 @@ static int ad5421_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
if (ret < 0)
return ret;
@@ -340,7 +341,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev,
const unsigned int max_val = 1 << 16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -456,7 +457,7 @@ static int __devinit ad5421_probe(struct spi_device *spi)
struct ad5421_state *st;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -511,7 +512,7 @@ error_free_irq:
if (spi->irq)
free_irq(spi->irq, indio_dev);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -523,7 +524,7 @@ static int __devexit ad5421_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
if (spi->irq)
free_irq(spi->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 633ffbb..daa65b3 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -18,229 +18,212 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5446.h"
-static void ad5446_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5446_write(struct ad5446_state *st, unsigned val)
{
- st->data.d16 = cpu_to_be16(AD5446_LOAD | val);
+ __be16 data = cpu_to_be16(val);
+ return spi_write(st->spi, &data, sizeof(data));
}
-static void ad5542_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5660_write(struct ad5446_state *st, unsigned val)
{
- st->data.d16 = cpu_to_be16(val);
-}
+ uint8_t data[3];
-static void ad5620_store_sample(struct ad5446_state *st, unsigned val)
-{
- st->data.d16 = cpu_to_be16(AD5620_LOAD | val);
-}
+ data[0] = (val >> 16) & 0xFF;
+ data[1] = (val >> 8) & 0xFF;
+ data[2] = val & 0xFF;
-static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
-{
- val |= AD5660_LOAD;
- st->data.d24[0] = (val >> 16) & 0xFF;
- st->data.d24[1] = (val >> 8) & 0xFF;
- st->data.d24[2] = val & 0xFF;
+ return spi_write(st->spi, data, sizeof(data));
}
-static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
-{
- st->data.d16 = cpu_to_be16(mode << 14);
-}
+static const char * const ad5446_powerdown_modes[] = {
+ "", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"
+};
-static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
+static ssize_t ad5446_read_powerdown_mode_available(struct iio_dev *indio_dev,
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
- unsigned val = mode << 16;
-
- st->data.d24[0] = (val >> 16) & 0xFF;
- st->data.d24[1] = (val >> 8) & 0xFF;
- st->data.d24[2] = val & 0xFF;
+ return sprintf(buf, "%s %s %s\n", ad5446_powerdown_modes[1],
+ ad5446_powerdown_modes[2], ad5446_powerdown_modes[3]);
}
-static ssize_t ad5446_write_powerdown_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t ad5446_write_powerdown_mode(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
+ int i;
- if (sysfs_streq(buf, "1kohm_to_gnd"))
- st->pwr_down_mode = MODE_PWRDWN_1k;
- else if (sysfs_streq(buf, "100kohm_to_gnd"))
- st->pwr_down_mode = MODE_PWRDWN_100k;
- else if (sysfs_streq(buf, "three_state"))
- st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
- else
+ for (i = 1; i < ARRAY_SIZE(ad5446_powerdown_modes); i++) {
+ if (sysfs_streq(buf, ad5446_powerdown_modes[i])) {
+ st->pwr_down_mode = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(ad5446_powerdown_modes))
return -EINVAL;
return len;
}
-static ssize_t ad5446_read_powerdown_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ad5446_read_powerdown_mode(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
- char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
-
- return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
+ return sprintf(buf, "%s\n", ad5446_powerdown_modes[st->pwr_down_mode]);
}
-static ssize_t ad5446_read_dac_powerdown(struct device *dev,
- struct device_attribute *attr,
+static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
-static ssize_t ad5446_write_dac_powerdown(struct device *dev,
- struct device_attribute *attr,
+static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
- unsigned long readin;
+ unsigned int shift;
+ unsigned int val;
+ bool powerdown;
int ret;
- ret = strict_strtol(buf, 10, &readin);
+ ret = strtobool(buf, &powerdown);
if (ret)
return ret;
- if (readin > 1)
- ret = -EINVAL;
-
mutex_lock(&indio_dev->mlock);
- st->pwr_down = readin;
+ st->pwr_down = powerdown;
- if (st->pwr_down)
- st->chip_info->store_pwr_down(st, st->pwr_down_mode);
- else
- st->chip_info->store_sample(st, st->cached_val);
+ if (st->pwr_down) {
+ shift = chan->scan_type.realbits + chan->scan_type.shift;
+ val = st->pwr_down_mode << shift;
+ } else {
+ val = st->cached_val;
+ }
- ret = spi_sync(st->spi, &st->msg);
+ ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR,
- ad5446_read_powerdown_mode,
- ad5446_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
- "1kohm_to_gnd 100kohm_to_gnd three_state");
-
-static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR,
- ad5446_read_dac_powerdown,
- ad5446_write_dac_powerdown, 0);
-
-static struct attribute *ad5446_attributes[] = {
- &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
- &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
- &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad5446_attribute_group = {
- .attrs = ad5446_attributes,
+static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+ {
+ .name = "powerdown",
+ .read = ad5446_read_dac_powerdown,
+ .write = ad5446_write_dac_powerdown,
+ }, {
+ .name = "powerdown_mode",
+ .read = ad5446_read_powerdown_mode,
+ .write = ad5446_write_powerdown_mode,
+ }, {
+ .name = "powerdown_mode_available",
+ .shared = true,
+ .read = ad5446_read_powerdown_mode_available,
+ },
+ { },
};
-#define AD5446_CHANNEL(bits, storage, shift) { \
+#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
- .scan_type = IIO_ST('u', (bits), (storage), (shift)) \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .scan_type = IIO_ST('u', (bits), (storage), (shift)), \
+ .ext_info = (ext), \
}
+#define AD5446_CHANNEL(bits, storage, shift) \
+ _AD5446_CHANNEL(bits, storage, shift, NULL)
+
+#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
+ _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
[ID_AD5444] = {
.channel = AD5446_CHANNEL(12, 16, 2),
- .store_sample = ad5446_store_sample,
+ .write = ad5446_write,
},
[ID_AD5446] = {
.channel = AD5446_CHANNEL(14, 16, 0),
- .store_sample = ad5446_store_sample,
+ .write = ad5446_write,
},
[ID_AD5541A] = {
.channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
- },
- [ID_AD5542A] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
- },
- [ID_AD5543] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5512A] = {
.channel = AD5446_CHANNEL(12, 16, 4),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5553] = {
.channel = AD5446_CHANNEL(14, 16, 0),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5601] = {
- .channel = AD5446_CHANNEL(8, 16, 6),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+ .write = ad5446_write,
},
[ID_AD5611] = {
- .channel = AD5446_CHANNEL(10, 16, 4),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+ .write = ad5446_write,
},
[ID_AD5621] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+ .write = ad5446_write,
},
[ID_AD5620_2500] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 2500,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5620_1250] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 1250,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5640_2500] = {
- .channel = AD5446_CHANNEL(14, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 2500,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5640_1250] = {
- .channel = AD5446_CHANNEL(14, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 1250,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5660_2500] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 2500,
- .store_sample = ad5660_store_sample,
- .store_pwr_down = ad5660_store_pwr_down,
+ .write = ad5660_write,
},
[ID_AD5660_1250] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 1250,
- .store_sample = ad5660_store_sample,
- .store_pwr_down = ad5660_store_pwr_down,
+ .write = ad5660_write,
+ },
+ [ID_AD5662] = {
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+ .write = ad5660_write,
},
};
@@ -254,6 +237,9 @@ static int ad5446_read_raw(struct iio_dev *indio_dev,
unsigned long scale_uv;
switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ *val = st->cached_val;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
*val = scale_uv / 1000;
@@ -271,18 +257,18 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad5446_state *st = iio_priv(indio_dev);
- int ret;
+ int ret = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
mutex_lock(&indio_dev->mlock);
st->cached_val = val;
- st->chip_info->store_sample(st, val);
- ret = spi_sync(st->spi, &st->msg);
+ if (!st->pwr_down)
+ ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
break;
default:
@@ -295,13 +281,6 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
static const struct iio_info ad5446_info = {
.read_raw = ad5446_read_raw,
.write_raw = ad5446_write_raw,
- .attrs = &ad5446_attribute_group,
- .driver_module = THIS_MODULE,
-};
-
-static const struct iio_info ad5446_info_no_pwr_down = {
- .read_raw = ad5446_read_raw,
- .write_raw = ad5446_write_raw,
.driver_module = THIS_MODULE,
};
@@ -321,7 +300,7 @@ static int __devinit ad5446_probe(struct spi_device *spi)
voltage_uv = regulator_get_voltage(reg);
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -337,38 +316,17 @@ static int __devinit ad5446_probe(struct spi_device *spi)
/* Establish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
- if (st->chip_info->store_pwr_down)
- indio_dev->info = &ad5446_info;
- else
- indio_dev->info = &ad5446_info_no_pwr_down;
+ indio_dev->info = &ad5446_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
- /* Setup default message */
-
- st->xfer.tx_buf = &st->data;
- st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8;
-
- spi_message_init(&st->msg);
- spi_message_add_tail(&st->xfer, &st->msg);
-
- switch (spi_get_device_id(spi)->driver_data) {
- case ID_AD5620_2500:
- case ID_AD5620_1250:
- case ID_AD5640_2500:
- case ID_AD5640_1250:
- case ID_AD5660_2500:
- case ID_AD5660_1250:
+ if (st->chip_info->int_vref_mv)
st->vref_mv = st->chip_info->int_vref_mv;
- break;
- default:
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- dev_warn(&spi->dev,
- "reference voltage unspecified\n");
- }
+ else if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev, "reference voltage unspecified\n");
ret = iio_device_register(indio_dev);
if (ret)
@@ -377,7 +335,7 @@ static int __devinit ad5446_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -398,7 +356,7 @@ static int ad5446_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
@@ -408,8 +366,8 @@ static const struct spi_device_id ad5446_id[] = {
{"ad5446", ID_AD5446},
{"ad5512a", ID_AD5512A},
{"ad5541a", ID_AD5541A},
- {"ad5542a", ID_AD5542A},
- {"ad5543", ID_AD5543},
+ {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
+ {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
{"ad5553", ID_AD5553},
{"ad5601", ID_AD5601},
{"ad5611", ID_AD5611},
@@ -420,6 +378,7 @@ static const struct spi_device_id ad5446_id[] = {
{"ad5640-1250", ID_AD5640_1250},
{"ad5660-2500", ID_AD5660_2500},
{"ad5660-1250", ID_AD5660_1250},
+ {"ad5662", ID_AD5662},
{}
};
MODULE_DEVICE_TABLE(spi, ad5446_id);
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
index 4ea3476..dfd68ce 100644
--- a/drivers/staging/iio/dac/ad5446.h
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -34,43 +34,30 @@
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
- * @poll_work: bottom half of polling interrupt handler
* @vref_mv: actual reference voltage used
- * @xfer: default spi transfer
- * @msg: default spi message
- * @data: spi transmit buffer
*/
struct ad5446_state {
struct spi_device *spi;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
- struct work_struct poll_work;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
unsigned pwr_down;
- struct spi_transfer xfer;
- struct spi_message msg;
- union {
- unsigned short d16;
- unsigned char d24[3];
- } data;
};
/**
* struct ad5446_chip_info - chip specific information
* @channel: channel spec for the DAC
* @int_vref_mv: AD5620/40/60: the internal reference voltage
- * @store_sample: chip specific helper function to store the datum
- * @store_sample: chip specific helper function to store the powerpown cmd
+ * @write: chip specific helper function to write to the register
*/
struct ad5446_chip_info {
struct iio_chan_spec channel;
u16 int_vref_mv;
- void (*store_sample) (struct ad5446_state *st, unsigned val);
- void (*store_pwr_down) (struct ad5446_state *st, unsigned mode);
+ int (*write)(struct ad5446_state *st, unsigned val);
};
/**
@@ -85,8 +72,6 @@ enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5541A,
- ID_AD5542A,
- ID_AD5543,
ID_AD5512A,
ID_AD5553,
ID_AD5601,
@@ -98,6 +83,7 @@ enum ad5446_supported_device_ids {
ID_AD5640_1250,
ID_AD5660_2500,
ID_AD5660_1250,
+ ID_AD5662,
};
#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c
index bc17205..019cf15 100644
--- a/drivers/staging/iio/dac/ad5504.c
+++ b/drivers/staging/iio/dac/ad5504.c
@@ -16,9 +16,9 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "dac.h"
#include "ad5504.h"
@@ -27,7 +27,8 @@
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = AD5504_ADDR_DAC(_chan), \
.scan_type = IIO_ST('u', 12, 16, 0), \
}
@@ -81,7 +82,7 @@ static int ad5504_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5504_spi_read(st->spi, chan->address);
if (ret < 0)
return ret;
@@ -109,7 +110,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -124,7 +125,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
static ssize_t ad5504_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
const char mode[][14] = {"20kohm_to_gnd", "three_state"};
@@ -136,7 +137,7 @@ static ssize_t ad5504_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
int ret;
@@ -154,7 +155,7 @@ static ssize_t ad5504_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -168,7 +169,7 @@ static ssize_t ad5504_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -287,7 +288,7 @@ static int __devinit ad5504_probe(struct spi_device *spi)
struct regulator *reg;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -350,7 +351,7 @@ error_put_reg:
if (!IS_ERR(reg))
regulator_put(reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -368,7 +369,7 @@ static int __devexit ad5504_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
index 10c7484..42ff644 100644
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -16,8 +16,8 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5624r.h"
@@ -26,7 +26,8 @@
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = (_chan), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
}
@@ -122,7 +123,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -140,7 +141,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
@@ -152,7 +153,7 @@ static ssize_t ad5624r_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
int ret;
@@ -172,7 +173,7 @@ static ssize_t ad5624r_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -186,7 +187,7 @@ static ssize_t ad5624r_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -255,7 +256,7 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -305,7 +306,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -321,7 +322,7 @@ static int __devexit ad5624r_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c
index 2415a6e..c1e903e 100644
--- a/drivers/staging/iio/dac/ad5686.c
+++ b/drivers/staging/iio/dac/ad5686.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5686_DAC_CHANNELS 4
@@ -98,7 +98,8 @@ enum ad5686_supported_device_ids {
.indexed = 1, \
.output = 1, \
.channel = chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = AD5686_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', bits, 16, shift) \
}
@@ -172,7 +173,7 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
static ssize_t ad5686_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -186,7 +187,7 @@ static ssize_t ad5686_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned mode;
@@ -210,7 +211,7 @@ static ssize_t ad5686_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -224,7 +225,7 @@ static ssize_t ad5686_write_dac_powerdown(struct device *dev,
{
bool readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -296,7 +297,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ad5686_spi_read(st, chan->address);
mutex_unlock(&indio_dev->mlock);
@@ -326,7 +327,7 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -358,7 +359,7 @@ static int __devinit ad5686_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, regdone = 0, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -410,7 +411,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -425,7 +426,7 @@ static int __devexit ad5686_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c
index f73a730..03dbd93 100644
--- a/drivers/staging/iio/dac/ad5764.c
+++ b/drivers/staging/iio/dac/ad5764.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5764_REG_SF_NOP 0x0
@@ -79,7 +79,8 @@ enum ad5764_type {
.output = 1, \
.channel = (_chan), \
.address = (_chan), \
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
@@ -188,7 +189,7 @@ static int ad5764_write_raw(struct iio_dev *indio_dev,
unsigned int reg;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
@@ -228,7 +229,7 @@ static int ad5764_read_raw(struct iio_dev *indio_dev,
int ret;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
reg = AD5764_REG_DATA(chan->address);
ret = ad5764_read(indio_dev, reg, val);
if (ret < 0)
@@ -280,7 +281,7 @@ static int __devinit ad5764_probe(struct spi_device *spi)
struct ad5764_state *st;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -335,7 +336,7 @@ error_free_reg:
if (st->chip_info->int_vref == 0)
regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -352,7 +353,7 @@ static int __devexit ad5764_remove(struct spi_device *spi)
regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c
index ac45636..13d8b5b 100644
--- a/drivers/staging/iio/dac/ad5791.c
+++ b/drivers/staging/iio/dac/ad5791.c
@@ -17,8 +17,8 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5791.h"
@@ -78,7 +78,8 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
.scan_type = IIO_ST('u', bits, 24, shift) \
}
@@ -93,7 +94,7 @@ static const struct iio_chan_spec ad5791_channels[] = {
static ssize_t ad5791_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
const char mode[][14] = {"6kohm_to_gnd", "three_state"};
@@ -105,7 +106,7 @@ static ssize_t ad5791_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
int ret;
@@ -123,7 +124,7 @@ static ssize_t ad5791_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
@@ -135,7 +136,7 @@ static ssize_t ad5791_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
ret = strict_strtol(buf, 10, &readin);
@@ -231,7 +232,7 @@ static int ad5791_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5791_spi_read(st->spi, chan->address, val);
if (ret)
return ret;
@@ -263,7 +264,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev,
struct ad5791_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
val &= AD5791_RES_MASK(chan->scan_type.realbits);
val <<= chan->scan_type.shift;
@@ -288,7 +289,7 @@ static int __devinit ad5791_probe(struct spi_device *spi)
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -368,7 +369,7 @@ error_put_reg_neg:
error_put_reg_pos:
if (!IS_ERR(st->reg_vdd))
regulator_put(st->reg_vdd);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -389,7 +390,7 @@ static int __devexit ad5791_remove(struct spi_device *spi)
regulator_disable(st->reg_vss);
regulator_put(st->reg_vss);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
index 41483c7..5287cad 100644
--- a/drivers/staging/iio/dac/max517.c
+++ b/drivers/staging/iio/dac/max517.c
@@ -25,8 +25,8 @@
#include <linux/i2c.h>
#include <linux/err.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "max517.h"
@@ -59,7 +59,7 @@ static ssize_t max517_set_value(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count, int channel)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max517_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[4]; /* 1x or 2x command + value */
@@ -128,7 +128,7 @@ static ssize_t max517_show_scale(struct device *dev,
struct device_attribute *attr,
char *buf, int channel)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max517_data *data = iio_priv(indio_dev);
/* Corresponds to Vref / 2^(bits) */
unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
@@ -218,7 +218,7 @@ static int max517_probe(struct i2c_client *client,
struct max517_platform_data *platform_data = client->dev.platform_data;
int err;
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit;
@@ -257,14 +257,15 @@ static int max517_probe(struct i2c_client *client,
return 0;
exit_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
static int max517_remove(struct i2c_client *client)
{
- iio_free_device(i2c_get_clientdata(client));
+ iio_device_unregister(i2c_get_clientdata(client));
+ iio_device_free(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h
deleted file mode 100644
index d8ac3a9..0000000
--- a/drivers/staging/iio/dds/dds.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * dds.h - sysfs attributes associated with DDS devices
- *
- * Copyright (c) 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY
- */
-
-#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \
- _mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY_scale
- */
-
-#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
- IIO_CONST_ATTR(dds##_channel##_freq_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqsymbol
- */
-
-#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY
- */
-
-#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \
- _mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY_scale
- */
-
-#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
- IIO_CONST_ATTR(dds##_channel##_phase_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phasesymbol
- */
-
-#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_out_enable
- */
-
-#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out_enable, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_enable
- */
-
-#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
- _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype
- */
-
-#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \
- S_IWUSR, NULL, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
- */
-
-#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
- IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\
- _modes);
diff --git a/drivers/staging/iio/driver.h b/drivers/staging/iio/driver.h
deleted file mode 100644
index a4f8b2e..0000000
--- a/drivers/staging/iio/driver.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Industrial I/O in kernel access map interface.
- *
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- */
-
-#ifndef _IIO_INKERN_H_
-#define _IIO_INKERN_H_
-
-struct iio_map;
-
-/**
- * iio_map_array_register() - tell the core about inkernel consumers
- * @indio_dev: provider device
- * @map: array of mappings specifying association of channel with client
- */
-int iio_map_array_register(struct iio_dev *indio_dev,
- struct iio_map *map);
-
-/**
- * iio_map_array_unregister() - tell the core to remove consumer mappings
- * @indio_dev: provider device
- * @map: array of mappings to remove. Note these must have same memory
- * addresses as those originally added not just equal parameter
- * values.
- */
-int iio_map_array_unregister(struct iio_dev *indio_dev,
- struct iio_map *map);
-
-#endif
diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
deleted file mode 100644
index c25f0e3..0000000
--- a/drivers/staging/iio/events.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* The industrial I/O - event passing to userspace
- *
- * Copyright (c) 2008-2011 Jonathan Cameron
- *
- * 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.
- */
-#ifndef _IIO_EVENTS_H_
-#define _IIO_EVENTS_H_
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-#include "types.h"
-
-/**
- * struct iio_event_data - The actual event being pushed to userspace
- * @id: event identifier
- * @timestamp: best estimate of time of event occurrence (often from
- * the interrupt handler)
- */
-struct iio_event_data {
- __u64 id;
- __s64 timestamp;
-};
-
-#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
-
-enum iio_event_type {
- IIO_EV_TYPE_THRESH,
- IIO_EV_TYPE_MAG,
- IIO_EV_TYPE_ROC,
- IIO_EV_TYPE_THRESH_ADAPTIVE,
- IIO_EV_TYPE_MAG_ADAPTIVE,
-};
-
-enum iio_event_direction {
- IIO_EV_DIR_EITHER,
- IIO_EV_DIR_RISING,
- IIO_EV_DIR_FALLING,
-};
-
-/**
- * IIO_EVENT_CODE() - create event identifier
- * @chan_type: Type of the channel. Should be one of enum iio_chan_type.
- * @diff: Whether the event is for an differential channel or not.
- * @modifier: Modifier for the channel. Should be one of enum iio_modifier.
- * @direction: Direction of the event. One of enum iio_event_direction.
- * @type: Type of the event. Should be one enum iio_event_type.
- * @chan: Channel number for non-differential channels.
- * @chan1: First channel number for differential channels.
- * @chan2: Second channel number for differential channels.
- */
-
-#define IIO_EVENT_CODE(chan_type, diff, modifier, direction, \
- type, chan, chan1, chan2) \
- (((u64)type << 56) | ((u64)diff << 55) | \
- ((u64)direction << 48) | ((u64)modifier << 40) | \
- ((u64)chan_type << 32) | (((u16)chan2) << 16) | ((u16)chan1) | \
- ((u16)chan))
-
-
-#define IIO_EV_DIR_MAX 4
-#define IIO_EV_BIT(type, direction) \
- (1 << (type*IIO_EV_DIR_MAX + direction))
-
-/**
- * IIO_MOD_EVENT_CODE() - create event identifier for modified channels
- * @chan_type: Type of the channel. Should be one of enum iio_chan_type.
- * @number: Channel number.
- * @modifier: Modifier for the channel. Should be one of enum iio_modifier.
- * @type: Type of the event. Should be one enum iio_event_type.
- * @direction: Direction of the event. One of enum iio_event_direction.
- */
-
-#define IIO_MOD_EVENT_CODE(chan_type, number, modifier, \
- type, direction) \
- IIO_EVENT_CODE(chan_type, 0, modifier, direction, type, number, 0, 0)
-
-/**
- * IIO_UNMOD_EVENT_CODE() - create event identifier for unmodified channels
- * @chan_type: Type of the channel. Should be one of enum iio_chan_type.
- * @number: Channel number.
- * @type: Type of the event. Should be one enum iio_event_type.
- * @direction: Direction of the event. One of enum iio_event_direction.
- */
-
-#define IIO_UNMOD_EVENT_CODE(chan_type, number, type, direction) \
- IIO_EVENT_CODE(chan_type, 0, 0, direction, type, number, 0, 0)
-
-#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
-
-#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF)
-
-#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
-
-/* Event code number extraction depends on which type of event we have.
- * Perhaps review this function in the future*/
-#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((__s16)(mask & 0xFFFF))
-#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((__s16)(((mask) >> 16) & 0xFFFF))
-
-#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
-#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1)
-
-#endif
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/frequency/Kconfig
index 93b7141..93b7141 100644
--- a/drivers/staging/iio/dds/Kconfig
+++ b/drivers/staging/iio/frequency/Kconfig
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/frequency/Makefile
index 1477461..1477461 100644
--- a/drivers/staging/iio/dds/Makefile
+++ b/drivers/staging/iio/frequency/Makefile
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/frequency/ad5930.c
index 9c32d1b..2d541d0 100644
--- a/drivers/staging/iio/dds/ad5930.c
+++ b/drivers/staging/iio/frequency/ad5930.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad5930"
@@ -48,7 +48,7 @@ static ssize_t ad5930_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad5903_config *config = (struct ad5903_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad5930_state *st = iio_priv(idev);
config->control = (config->control & ~value_mask);
@@ -97,7 +97,7 @@ static int __devinit ad5930_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -122,7 +122,7 @@ static int __devinit ad5930_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -130,7 +130,7 @@ error_ret:
static int __devexit ad5930_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 2ccf25d..fed3940 100644
--- a/drivers/staging/iio/dds/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dds.h"
#include "ad9832.h"
@@ -77,7 +77,7 @@ static ssize_t ad9832_write(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9832_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -177,18 +177,18 @@ static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
ad9832_write, AD9832_OUTPUT_EN);
static struct attribute *ad9832_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_dev_attr_dds0_phase2.dev_attr.attr,
- &iio_dev_attr_dds0_phase3.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase2.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase3.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
NULL,
};
@@ -221,7 +221,7 @@ static int __devinit ad9832_probe(struct spi_device *spi)
goto error_put_reg;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -313,7 +313,7 @@ static int __devinit ad9832_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -334,7 +334,7 @@ static int __devexit ad9832_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9832.h b/drivers/staging/iio/frequency/ad9832.h
index c5b701f..c5b701f 100644
--- a/drivers/staging/iio/dds/ad9832.h
+++ b/drivers/staging/iio/frequency/ad9832.h
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 38a2de0..1b2dc74 100644
--- a/drivers/staging/iio/dds/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -19,8 +19,8 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dds.h"
#include "ad9834.h"
@@ -66,7 +66,7 @@ static ssize_t ad9834_write(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -145,7 +145,7 @@ static ssize_t ad9834_store_wavetype(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret = 0;
@@ -203,7 +203,7 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
char *str;
@@ -218,14 +218,14 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
}
-static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO,
ad9834_show_out0_wavetype_available, NULL, 0);
static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
char *str;
@@ -237,7 +237,7 @@ static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
return sprintf(buf, "%s\n", str);
}
-static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO,
ad9834_show_out1_wavetype_available, NULL, 0);
/**
@@ -263,36 +263,36 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
static struct attribute *ad9834_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out1_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
- &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_wavetype_available.dev_attr.attr,
NULL,
};
static struct attribute *ad9833_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
NULL,
};
@@ -334,7 +334,7 @@ static int __devinit ad9834_probe(struct spi_device *spi)
goto error_put_reg;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -414,7 +414,7 @@ static int __devinit ad9834_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -434,7 +434,7 @@ static int __devexit ad9834_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/frequency/ad9834.h
index ed5ed8d..ed5ed8d 100644
--- a/drivers/staging/iio/dds/ad9834.h
+++ b/drivers/staging/iio/frequency/ad9834.h
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/frequency/ad9850.c
index f4f731b..74abee0 100644
--- a/drivers/staging/iio/dds/ad9850.c
+++ b/drivers/staging/iio/frequency/ad9850.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9850"
@@ -43,7 +43,7 @@ static ssize_t ad9850_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9850_config *config = (struct ad9850_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9850_state *st = iio_priv(idev);
xfer.len = len;
@@ -83,7 +83,7 @@ static int __devinit ad9850_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -108,7 +108,7 @@ static int __devinit ad9850_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -116,7 +116,7 @@ error_ret:
static int __devexit ad9850_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/frequency/ad9852.c
index 554266c..fd9d14a 100644
--- a/drivers/staging/iio/dds/ad9852.c
+++ b/drivers/staging/iio/frequency/ad9852.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9852"
@@ -71,7 +71,7 @@ static ssize_t ad9852_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9852_config *config = (struct ad9852_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9852_state *st = iio_priv(idev);
xfer.len = 3;
@@ -232,7 +232,7 @@ static int __devinit ad9852_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -258,7 +258,7 @@ static int __devinit ad9852_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
@@ -267,7 +267,7 @@ error_ret:
static int __devexit ad9852_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/frequency/ad9910.c
index 3985766..5a7ba30 100644
--- a/drivers/staging/iio/dds/ad9910.c
+++ b/drivers/staging/iio/frequency/ad9910.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9910"
@@ -123,7 +123,7 @@ static ssize_t ad9910_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9910_config *config = (struct ad9910_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9910_state *st = iio_priv(idev);
xfer.len = 5;
@@ -367,7 +367,7 @@ static int __devinit ad9910_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -392,7 +392,7 @@ static int __devinit ad9910_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -400,7 +400,7 @@ error_ret:
static int __devexit ad9910_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/frequency/ad9951.c
index 4d15004..ba6f49f 100644
--- a/drivers/staging/iio/dds/ad9951.c
+++ b/drivers/staging/iio/frequency/ad9951.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9951"
@@ -64,7 +64,7 @@ static ssize_t ad9951_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9951_config *config = (struct ad9951_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9951_state *st = iio_priv(idev);
xfer.len = 3;
@@ -176,7 +176,7 @@ static int __devinit ad9951_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -202,7 +202,7 @@ static int __devinit ad9951_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
@@ -211,7 +211,7 @@ error_ret:
static int __devexit ad9951_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h
new file mode 100644
index 0000000..c3342f6
--- /dev/null
+++ b/drivers/staging/iio/frequency/dds.h
@@ -0,0 +1,110 @@
+/*
+ * dds.h - sysfs attributes associated with DDS devices
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
+ */
+
+#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
+ */
+
+#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(out_altvoltage##_channel##_frequency_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
+ */
+
+#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY
+ */
+
+#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
+ */
+
+#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(out_altvoltage##_channel##_phase_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
+ */
+
+#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_out_enable
+ */
+
+#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
+ */
+
+#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
+ _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
+ */
+
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\
+ S_IWUSR, NULL, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
+ */
+
+#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
+ IIO_CONST_ATTR( \
+ out_altvoltage##_channel##_out##_output##_wavetype_available, _modes);
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index 02cc234..9931e206 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -15,8 +15,8 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
#define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */
@@ -85,7 +85,7 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
ret = adis16060_spi_write(indio_dev, chan->address);
@@ -120,22 +120,26 @@ static const struct iio_chan_spec adis16060_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = ADIS16060_TEMP_OUT,
}
@@ -148,7 +152,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -174,7 +178,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -183,7 +187,7 @@ error_ret:
static int adis16060_r_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 1815490..11f1dcc 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -14,8 +14,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
@@ -87,7 +87,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = adis16080_spi_write(indio_dev,
chan->address |
ADIS16080_DIN_WRITE);
@@ -110,21 +110,25 @@ static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_TEMP,
}
};
@@ -141,7 +145,7 @@ static int __devinit adis16080_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -167,7 +171,7 @@ static int __devinit adis16080_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -176,7 +180,7 @@ error_ret:
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index 947eb86..bf61cd0 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -16,8 +16,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16130_CON 0x0
#define ADIS16130_CON_RD (1 << 6)
@@ -100,11 +100,13 @@ static const struct iio_chan_spec adis16130_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16130_RATEDATA,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16130_TEMPDATA,
}
};
@@ -121,7 +123,7 @@ static int __devinit adis16130_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -145,7 +147,7 @@ static int __devinit adis16130_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -155,7 +157,7 @@ error_ret:
static int adis16130_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 8f6af47..ec765f9 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16260.h"
@@ -149,7 +149,7 @@ static ssize_t adis16260_read_frequency_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
if (spi_get_device_id(st->us)->driver_data)
return sprintf(buf, "%s\n", "0.129 ~ 256");
@@ -161,7 +161,7 @@ static ssize_t adis16260_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
int ret, len = 0;
u16 t;
@@ -186,7 +186,7 @@ static ssize_t adis16260_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -237,7 +237,7 @@ static ssize_t adis16260_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
switch (buf[0]) {
@@ -389,30 +389,76 @@ enum adis16260_channel {
};
#define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \
struct iio_chan_spec adis16260_channels_##axis[] = { \
- IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, mod, \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- gyro, ADIS16260_SCAN_GYRO, \
- IIO_ST('s', 14, 16, 0), 0), \
- IIO_CHAN(IIO_ANGL, 1, 0, 0, NULL, 0, mod, \
- 0, \
- angle, ADIS16260_SCAN_ANGL, \
- IIO_ST('u', 14, 16, 0), 0), \
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- temp, ADIS16260_SCAN_TEMP, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- in_supply, ADIS16260_SCAN_SUPPLY, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- in_aux, ADIS16260_SCAN_AUX_ADC, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN_SOFT_TIMESTAMP(5) \
+ { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = gyro, \
+ .scan_index = ADIS16260_SCAN_GYRO, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_ANGL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .address = angle, \
+ .scan_index = ADIS16260_SCAN_ANGL, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = temp, \
+ .scan_index = ADIS16260_SCAN_TEMP, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = "supply", \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = in_supply, \
+ .scan_index = ADIS16260_SCAN_SUPPLY, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = in_aux, \
+ .scan_index = ADIS16260_SCAN_AUX_ADC, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, \
+ IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X);
@@ -440,7 +486,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][0];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
@@ -581,7 +627,7 @@ static int __devinit adis16260_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -666,7 +712,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16260_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -687,7 +733,7 @@ static int adis16260_remove(struct spi_device *spi)
adis16260_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16260_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 711f151..0fe2d9d 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16260.h"
/**
* adis16260_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16260_read_ring_data(struct device *dev, u8 *rx)
+static int adis16260_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16260_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16260_OUTPUTS + 1];
int ret;
@@ -66,22 +65,21 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16260_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c
index 8299cd1..034559e 100644
--- a/drivers/staging/iio/gyro/adis16260_trigger.c
+++ b/drivers/staging/iio/gyro/adis16260_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16260.h"
/**
@@ -29,7 +29,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16260_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -60,7 +60,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -71,5 +71,5 @@ void adis16260_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/gyro/adxrs450.h b/drivers/staging/iio/gyro/adxrs450.h
index af0c870..f8cf21f 100644
--- a/drivers/staging/iio/gyro/adxrs450.h
+++ b/drivers/staging/iio/gyro/adxrs450.h
@@ -49,7 +49,7 @@ enum {
* @us: actual spi_device
* @buf_lock: mutex to protect tx and rx
* @tx: transmit buffer
- * @rx: recieve buffer
+ * @rx: receive buffer
**/
struct adxrs450_state {
struct spi_device *us;
diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c
index 15e2496..6513119 100644
--- a/drivers/staging/iio/gyro/adxrs450_core.c
+++ b/drivers/staging/iio/gyro/adxrs450_core.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "adxrs450.h"
@@ -265,7 +265,7 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev,
s16 t;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_ANGL_VEL:
ret = adxrs450_spi_sensor_data(indio_dev, &t);
@@ -329,14 +329,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
},
[ID_ADXRS453] = {
@@ -344,13 +346,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
},
};
@@ -368,7 +372,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -399,7 +403,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi)
error_initial:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -408,7 +412,7 @@ error_ret:
static int adxrs450_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
deleted file mode 100644
index b9cd454..0000000
--- a/drivers/staging/iio/iio.h
+++ /dev/null
@@ -1,471 +0,0 @@
-
-/* The industrial I/O core
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- */
-#ifndef _INDUSTRIAL_IO_H_
-#define _INDUSTRIAL_IO_H_
-
-#include <linux/device.h>
-#include <linux/cdev.h>
-#include "types.h"
-/* IIO TODO LIST */
-/*
- * Provide means of adjusting timer accuracy.
- * Currently assumes nano seconds.
- */
-
-enum iio_data_type {
- IIO_RAW,
- IIO_PROCESSED,
-};
-
-/* Could add the raw attributes as well - allowing buffer only devices */
-enum iio_chan_info_enum {
- /* 0 is reserved for raw attributes */
- IIO_CHAN_INFO_SCALE = 1,
- IIO_CHAN_INFO_OFFSET,
- IIO_CHAN_INFO_CALIBSCALE,
- IIO_CHAN_INFO_CALIBBIAS,
- IIO_CHAN_INFO_PEAK,
- IIO_CHAN_INFO_PEAK_SCALE,
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
- IIO_CHAN_INFO_AVERAGE_RAW,
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
-};
-
-#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
-#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
-
-#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_SCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_OFFSET_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAK_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT( \
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT( \
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT( \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT( \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-
-enum iio_endian {
- IIO_CPU,
- IIO_BE,
- IIO_LE,
-};
-
-struct iio_chan_spec;
-struct iio_dev;
-
-/**
- * struct iio_chan_spec_ext_info - Extended channel info attribute
- * @name: Info attribute name
- * @shared: Whether this attribute is shared between all channels.
- * @read: Read callback for this info attribute, may be NULL.
- * @write: Write callback for this info attribute, may be NULL.
- */
-struct iio_chan_spec_ext_info {
- const char *name;
- bool shared;
- ssize_t (*read)(struct iio_dev *, struct iio_chan_spec const *,
- char *buf);
- ssize_t (*write)(struct iio_dev *, struct iio_chan_spec const *,
- const char *buf, size_t len);
-};
-
-/**
- * struct iio_chan_spec - specification of a single channel
- * @type: What type of measurement is the channel making.
- * @channel: What number or name do we wish to assign the channel.
- * @channel2: If there is a second number for a differential
- * channel then this is it. If modified is set then the
- * value here specifies the modifier.
- * @address: Driver specific identifier.
- * @scan_index: Monotonic index to give ordering in scans when read
- * from a buffer.
- * @scan_type: Sign: 's' or 'u' to specify signed or unsigned
- * realbits: Number of valid bits of data
- * storage_bits: Realbits + padding
- * shift: Shift right by this before masking out
- * realbits.
- * endianness: little or big endian
- * @info_mask: What information is to be exported about this channel.
- * This includes calibbias, scale etc.
- * @event_mask: What events can this channel produce.
- * @ext_info: Array of extended info attributes for this channel.
- * The array is NULL terminated, the last element should
- * have it's name field set to NULL.
- * @extend_name: Allows labeling of channel attributes with an
- * informative name. Note this has no effect codes etc,
- * unlike modifiers.
- * @datasheet_name: A name used in in kernel mapping of channels. It should
- * correspond to the first name that the channel is referred
- * to by in the datasheet (e.g. IND), or the nearest
- * possible compound name (e.g. IND-INC).
- * @processed_val: Flag to specify the data access attribute should be
- * *_input rather than *_raw.
- * @modified: Does a modifier apply to this channel. What these are
- * depends on the channel type. Modifier is set in
- * channel2. Examples are IIO_MOD_X for axial sensors about
- * the 'x' axis.
- * @indexed: Specify the channel has a numerical index. If not,
- * the value in channel will be suppressed for attribute
- * but not for event codes. Typically set it to 0 when
- * the index is false.
- * @differential: Channel is differential.
- */
-struct iio_chan_spec {
- enum iio_chan_type type;
- int channel;
- int channel2;
- unsigned long address;
- int scan_index;
- struct {
- char sign;
- u8 realbits;
- u8 storagebits;
- u8 shift;
- enum iio_endian endianness;
- } scan_type;
- long info_mask;
- long event_mask;
- const struct iio_chan_spec_ext_info *ext_info;
- char *extend_name;
- const char *datasheet_name;
- unsigned processed_val:1;
- unsigned modified:1;
- unsigned indexed:1;
- unsigned output:1;
- unsigned differential:1;
-};
-
-#define IIO_ST(si, rb, sb, sh) \
- { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
-
-/* Macro assumes input channels */
-#define IIO_CHAN(_type, _mod, _indexed, _proc, _name, _chan, _chan2, \
- _inf_mask, _address, _si, _stype, _event_mask) \
- { .type = _type, \
- .output = 0, \
- .modified = _mod, \
- .indexed = _indexed, \
- .processed_val = _proc, \
- .extend_name = _name, \
- .channel = _chan, \
- .channel2 = _chan2, \
- .info_mask = _inf_mask, \
- .address = _address, \
- .scan_index = _si, \
- .scan_type = _stype, \
- .event_mask = _event_mask }
-
-#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
- { .type = IIO_TIMESTAMP, .channel = -1, \
- .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
-
-/**
- * iio_get_time_ns() - utility function to get a time stamp for events etc
- **/
-static inline s64 iio_get_time_ns(void)
-{
- struct timespec ts;
- /*
- * calls getnstimeofday.
- * If hrtimers then up to ns accurate, if not microsecond.
- */
- ktime_get_real_ts(&ts);
-
- return timespec_to_ns(&ts);
-}
-
-/* Device operating modes */
-#define INDIO_DIRECT_MODE 0x01
-#define INDIO_BUFFER_TRIGGERED 0x02
-#define INDIO_BUFFER_HARDWARE 0x08
-
-#define INDIO_ALL_BUFFER_MODES \
- (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE)
-
-struct iio_trigger; /* forward declaration */
-struct iio_dev;
-
-/**
- * struct iio_info - constant information about device
- * @driver_module: module structure used to ensure correct
- * ownership of chrdevs etc
- * @event_attrs: event control attributes
- * @attrs: general purpose device attributes
- * @read_raw: function to request a value from the device.
- * mask specifies which value. Note 0 means a reading of
- * the channel in question. Return value will specify the
- * type of value returned by the device. val and val2 will
- * contain the elements making up the returned value.
- * @write_raw: function to write a value to the device.
- * Parameters are the same as for read_raw.
- * @write_raw_get_fmt: callback function to query the expected
- * format/precision. If not set by the driver, write_raw
- * returns IIO_VAL_INT_PLUS_MICRO.
- * @read_event_config: find out if the event is enabled.
- * @write_event_config: set if the event is enabled.
- * @read_event_value: read a value associated with the event. Meaning
- * is event dependant. event_code specifies which event.
- * @write_event_value: write the value associated with the event.
- * Meaning is event dependent.
- * @validate_trigger: function to validate the trigger when the
- * current trigger gets changed.
- **/
-struct iio_info {
- struct module *driver_module;
- struct attribute_group *event_attrs;
- const struct attribute_group *attrs;
-
- int (*read_raw)(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val,
- int *val2,
- long mask);
-
- int (*write_raw)(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask);
-
- int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask);
-
- int (*read_event_config)(struct iio_dev *indio_dev,
- u64 event_code);
-
- int (*write_event_config)(struct iio_dev *indio_dev,
- u64 event_code,
- int state);
-
- int (*read_event_value)(struct iio_dev *indio_dev,
- u64 event_code,
- int *val);
- int (*write_event_value)(struct iio_dev *indio_dev,
- u64 event_code,
- int val);
- int (*validate_trigger)(struct iio_dev *indio_dev,
- struct iio_trigger *trig);
- int (*update_scan_mode)(struct iio_dev *indio_dev,
- const unsigned long *scan_mask);
- int (*debugfs_reg_access)(struct iio_dev *indio_dev,
- unsigned reg, unsigned writeval,
- unsigned *readval);
-};
-
-/**
- * struct iio_buffer_setup_ops - buffer setup related callbacks
- * @preenable: [DRIVER] function to run prior to marking buffer enabled
- * @postenable: [DRIVER] function to run after marking buffer enabled
- * @predisable: [DRIVER] function to run prior to marking buffer
- * disabled
- * @postdisable: [DRIVER] function to run after marking buffer disabled
- */
-struct iio_buffer_setup_ops {
- int (*preenable)(struct iio_dev *);
- int (*postenable)(struct iio_dev *);
- int (*predisable)(struct iio_dev *);
- int (*postdisable)(struct iio_dev *);
-};
-
-/**
- * struct iio_dev - industrial I/O device
- * @id: [INTERN] used to identify device internally
- * @modes: [DRIVER] operating modes supported by device
- * @currentmode: [DRIVER] current operating mode
- * @dev: [DRIVER] device structure, should be assigned a parent
- * and owner
- * @event_interface: [INTERN] event chrdevs associated with interrupt lines
- * @buffer: [DRIVER] any buffer present
- * @mlock: [INTERN] lock used to prevent simultaneous device state
- * changes
- * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
- * @masklength: [INTERN] the length of the mask established from
- * channels
- * @active_scan_mask: [INTERN] union of all scan masks requested by buffers
- * @trig: [INTERN] current device trigger (buffer modes)
- * @pollfunc: [DRIVER] function run on trigger being received
- * @channels: [DRIVER] channel specification structure table
- * @num_channels: [DRIVER] number of chanels specified in @channels.
- * @channel_attr_list: [INTERN] keep track of automatically created channel
- * attributes
- * @chan_attr_group: [INTERN] group for all attrs in base directory
- * @name: [DRIVER] name of the device.
- * @info: [DRIVER] callbacks and constant info from driver
- * @info_exist_lock: [INTERN] lock to prevent use during removal
- * @chrdev: [INTERN] associated character device
- * @groups: [INTERN] attribute groups
- * @groupcounter: [INTERN] index of next attribute group
- * @flags: [INTERN] file ops related flags including busy flag.
- * @debugfs_dentry: [INTERN] device specific debugfs dentry.
- * @cached_reg_addr: [INTERN] cached register address for debugfs reads.
- */
-struct iio_dev {
- int id;
-
- int modes;
- int currentmode;
- struct device dev;
-
- struct iio_event_interface *event_interface;
-
- struct iio_buffer *buffer;
- struct mutex mlock;
-
- const unsigned long *available_scan_masks;
- unsigned masklength;
- const unsigned long *active_scan_mask;
- struct iio_trigger *trig;
- struct iio_poll_func *pollfunc;
-
- struct iio_chan_spec const *channels;
- int num_channels;
-
- struct list_head channel_attr_list;
- struct attribute_group chan_attr_group;
- const char *name;
- const struct iio_info *info;
- struct mutex info_exist_lock;
- const struct iio_buffer_setup_ops *setup_ops;
- struct cdev chrdev;
-#define IIO_MAX_GROUPS 6
- const struct attribute_group *groups[IIO_MAX_GROUPS + 1];
- int groupcounter;
-
- unsigned long flags;
-#if defined(CONFIG_DEBUG_FS)
- struct dentry *debugfs_dentry;
- unsigned cached_reg_addr;
-#endif
-};
-
-/**
- * iio_find_channel_from_si() - get channel from its scan index
- * @indio_dev: device
- * @si: scan index to match
- */
-const struct iio_chan_spec
-*iio_find_channel_from_si(struct iio_dev *indio_dev, int si);
-
-/**
- * iio_device_register() - register a device with the IIO subsystem
- * @indio_dev: Device structure filled by the device driver
- **/
-int iio_device_register(struct iio_dev *indio_dev);
-
-/**
- * iio_device_unregister() - unregister a device from the IIO subsystem
- * @indio_dev: Device structure representing the device.
- **/
-void iio_device_unregister(struct iio_dev *indio_dev);
-
-/**
- * iio_push_event() - try to add event to the list for userspace reading
- * @indio_dev: IIO device structure
- * @ev_code: What event
- * @timestamp: When the event occurred
- **/
-int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
-
-extern struct bus_type iio_bus_type;
-
-/**
- * iio_put_device() - reference counted deallocation of struct device
- * @dev: the iio_device containing the device
- **/
-static inline void iio_put_device(struct iio_dev *indio_dev)
-{
- if (indio_dev)
- put_device(&indio_dev->dev);
-};
-
-/* Can we make this smaller? */
-#define IIO_ALIGN L1_CACHE_BYTES
-/**
- * iio_allocate_device() - allocate an iio_dev from a driver
- * @sizeof_priv: Space to allocate for private structure.
- **/
-struct iio_dev *iio_allocate_device(int sizeof_priv);
-
-static inline void *iio_priv(const struct iio_dev *indio_dev)
-{
- return (char *)indio_dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
-}
-
-static inline struct iio_dev *iio_priv_to_dev(void *priv)
-{
- return (struct iio_dev *)((char *)priv -
- ALIGN(sizeof(struct iio_dev), IIO_ALIGN));
-}
-
-/**
- * iio_free_device() - free an iio_dev from a driver
- * @dev: the iio_dev associated with the device
- **/
-void iio_free_device(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_enabled() - helper function to test if the buffer is enabled
- * @indio_dev: IIO device info structure for device
- **/
-static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
-{
- return indio_dev->currentmode
- & (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE);
-};
-
-/**
- * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry
- * @indio_dev: IIO device info structure for device
- **/
-#if defined(CONFIG_DEBUG_FS)
-static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
-{
- return indio_dev->debugfs_dentry;
-};
-#else
-static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
-{
- return NULL;
-};
-#endif
-
-#endif /* _INDUSTRIAL_IO_H_ */
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index f39f346..0cd4fe9 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -22,8 +22,8 @@
#include <linux/sysfs.h>
#include "iio_dummy_evgen.h"
-#include "iio.h"
-#include "sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c
index a603a5f..b03554f 100644
--- a/drivers/staging/iio/iio_hwmon.c
+++ b/drivers/staging/iio/iio_hwmon.c
@@ -14,8 +14,8 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include "consumer.h"
-#include "types.h"
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
/**
* struct iio_hwmon_state - device instance state
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index e3a9457..3104119 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -19,10 +19,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
-#include "buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "iio_simple_dummy.h"
/*
@@ -73,6 +73,12 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* What other information is available? */
.info_mask =
/*
+ * in_voltage0_raw
+ * Raw (unscaled no bias removal etc) measurement
+ * from the device.
+ */
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ /*
* in_voltage0_offset
* Offset for userspace to apply prior to scale
* when converting to standard units (microvolts)
@@ -114,6 +120,12 @@ static struct iio_chan_spec iio_dummy_channels[] = {
.channel2 = 2,
.info_mask =
/*
+ * in_voltage1-voltage2_raw
+ * Raw (unscaled no bias removal etc) measurement
+ * from the device.
+ */
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ /*
* in_voltage-voltage_scale
* Shared version of scale - shared by differential
* input channels of type IIO_VOLTAGE.
@@ -135,6 +147,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
.channel = 3,
.channel2 = 4,
.info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = diffvoltage3m4,
.scan_type = {
@@ -154,6 +167,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* Channel 2 is use for modifiers */
.channel2 = IIO_MOD_X,
.info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
/*
* Internal bias correction value. Applied
* by the hardware or driver prior to userspace
@@ -177,6 +191,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* DAC channel out_voltage0_raw */
{
.type = IIO_VOLTAGE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.output = 1,
.indexed = 1,
.channel = 0,
@@ -203,7 +218,7 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
mutex_lock(&st->lock);
switch (mask) {
- case 0: /* magic value - channel value read */
+ case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
switch (chan->type) {
case IIO_VOLTAGE:
if (chan->output) {
@@ -290,7 +305,7 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
struct iio_dummy_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (chan->output == 0)
return -EINVAL;
@@ -377,7 +392,7 @@ static int __devinit iio_dummy_probe(int index)
* It also has a region (accessed by iio_priv()
* for chip specific state information.
*/
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -455,9 +470,7 @@ error_unconfigure_buffer:
error_unregister_events:
iio_simple_dummy_events_unregister(indio_dev);
error_free_device:
- /* Note free device should only be called, before registration
- * has succeeded. */
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -494,7 +507,7 @@ static int iio_dummy_remove(int index)
goto error_ret;
/* Free all structures */
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index bb4daf7..fdfc8739 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -18,9 +18,9 @@
#include <linux/irq.h>
#include <linux/bitmap.h>
-#include "iio.h"
-#include "trigger_consumer.h"
-#include "kfifo_buf.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/kfifo_buf.h>
#include "iio_simple_dummy.h"
@@ -37,7 +37,7 @@ static const s16 fakedata[] = {
* @irq: the interrupt number
* @p: private data - always a pointer to the poll func.
*
- * This is the guts of buffered capture. On a trigger event occuring,
+ * This is the guts of buffered capture. On a trigger event occurring,
* if the pollfunc is attached then this handler is called as a threaded
* interrupt (and hence may sleep). It is responsible for grabbing data
* from the device and pushing it into the associated buffer.
@@ -48,12 +48,9 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
- /*
- * The datasize is obtained from the buffer. It was stored when
- * the preenable setup function was called.
- */
- size_t datasize = buffer->access->get_bytes_per_datum(buffer);
- u16 *data = kmalloc(datasize, GFP_KERNEL);
+ u16 *data;
+
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@@ -64,7 +61,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
* up a fast read. The capture will consist of all of them.
* Hence we just call the grab data function and fill the
* buffer without processing.
- * sofware scans: can be considered to be random access
+ * software scans: can be considered to be random access
* so efficient reading is just a case of minimal bus
* transactions.
* software culled hardware scans:
@@ -87,7 +84,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
}
}
/* Store a timestampe at an 8 byte boundary */
- if (buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= iio_get_time_ns();
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index 449c7a5..317b774 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -12,9 +12,9 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "iio_simple_dummy.h"
/* Evgen 'fakes' interrupt events for this example */
@@ -122,7 +122,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
* @private: pointer to device instance state.
*
* This handler is responsible for querying the device to find out what
- * event occured and for then pushing that event towards userspace.
+ * event occurred and for then pushing that event towards userspace.
* Here only one event occurs so we push that directly on with locally
* grabbed timestamp.
*/
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index cd82b56..a8e51bc 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -19,9 +19,9 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "../ring_sw.h"
#include "ad5933.h"
@@ -109,15 +109,46 @@ static struct ad5933_platform_data ad5933_default_pdata = {
};
static struct iio_chan_spec ad5933_channels[] = {
- IIO_CHAN(IIO_TEMP, 0, 1, 1, NULL, 0, 0, 0,
- 0, AD5933_REG_TEMP_DATA, IIO_ST('s', 14, 16, 0), 0),
- /* Ring Channels */
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "real_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- AD5933_REG_REAL_DATA, 0, IIO_ST('s', 16, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "imag_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- AD5933_REG_IMAG_DATA, 1, IIO_ST('s', 16, 16, 0), 0),
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .address = AD5933_REG_TEMP_DATA,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, { /* Ring Channels */
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "real_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = AD5933_REG_REAL_DATA,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "imag_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = AD5933_REG_IMAG_DATA,
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ },
};
static int ad5933_i2c_write(struct i2c_client *client,
@@ -260,7 +291,7 @@ static ssize_t ad5933_show_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -289,7 +320,7 @@ static ssize_t ad5933_store_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -323,7 +354,7 @@ static ssize_t ad5933_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret = 0, len = 0;
@@ -366,7 +397,7 @@ static ssize_t ad5933_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -495,7 +526,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto out;
@@ -537,19 +569,14 @@ static const struct iio_info ad5933_info = {
static int ad5933_ring_preenable(struct iio_dev *indio_dev)
{
struct ad5933_state *st = iio_priv(indio_dev);
- size_t d_size;
int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- ad5933_channels[1].scan_type.storagebits / 8;
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
ret = ad5933_reset(st);
if (ret < 0)
@@ -678,7 +705,7 @@ static int __devinit ad5933_probe(struct i2c_client *client,
int ret, voltage_uv = 0;
struct ad5933_platform_data *pdata = client->dev.platform_data;
struct ad5933_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -757,7 +784,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -774,7 +801,7 @@ static __devexit int ad5933_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index e73ad78..1f6bd85 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -26,9 +26,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16400.h"
enum adis16400_chip_variant {
@@ -179,7 +179,7 @@ static ssize_t adis16400_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret, len = 0;
ret = adis16400_get_freq(indio_dev);
if (ret < 0)
@@ -225,7 +225,7 @@ static ssize_t adis16400_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16400_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -279,7 +279,7 @@ static ssize_t adis16400_write_reset(struct device *dev,
if (ret < 0)
return ret;
if (val) {
- ret = adis16400_reset(dev_get_drvdata(dev));
+ ret = adis16400_reset(dev_to_iio_dev(dev));
if (ret < 0)
return ret;
}
@@ -545,7 +545,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = adis16400_spi_read_reg_16(indio_dev,
adis16400_addresses[chan->address][0],
@@ -635,7 +635,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 14, 16, 0)
@@ -643,7 +644,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -653,7 +655,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -663,7 +666,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
@@ -673,7 +677,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -683,7 +688,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -693,7 +699,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -703,7 +710,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_x,
.scan_index = ADIS16400_SCAN_MAGN_X,
@@ -712,7 +720,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_y,
.scan_index = ADIS16400_SCAN_MAGN_Y,
@@ -721,7 +730,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_z,
.scan_index = ADIS16400_SCAN_MAGN_Z,
@@ -730,7 +740,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16400_SCAN_TEMP,
@@ -739,7 +750,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16400_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -753,7 +765,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 12, 16, 0)
@@ -761,7 +774,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -771,7 +785,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -781,17 +796,19 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
.scan_index = ADIS16400_SCAN_GYRO_Z,
.scan_type = IIO_ST('s', 14, 16, 0),
}, {
- .type = IIO_ACCEL,
+ .type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -801,7 +818,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -811,7 +829,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -822,7 +841,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "x",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = temp0,
@@ -833,7 +853,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "y",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = temp1,
@@ -844,7 +865,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "z",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp2,
.scan_index = ADIS16350_SCAN_TEMP_Z,
@@ -853,7 +875,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16350_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -867,7 +890,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 12, 16, 0)
@@ -875,7 +899,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -885,7 +910,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -895,7 +921,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -905,7 +932,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -915,7 +943,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16400_SCAN_TEMP,
@@ -924,7 +953,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16350_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -932,7 +962,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_x,
.scan_index = ADIS16300_SCAN_INCLI_X,
.scan_type = IIO_ST('s', 13, 16, 0),
@@ -940,7 +971,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_y,
.scan_index = ADIS16300_SCAN_INCLI_Y,
.scan_type = IIO_ST('s', 13, 16, 0),
@@ -953,7 +985,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -963,7 +996,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -973,7 +1007,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
@@ -983,7 +1018,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -993,7 +1029,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -1003,7 +1040,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -1013,7 +1051,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = accel_z,
.scan_index = ADIS16400_SCAN_ACC_Z,
@@ -1122,7 +1161,7 @@ static int __devinit adis16400_probe(struct spi_device *spi)
{
int ret;
struct adis16400_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -1172,14 +1211,14 @@ static int __devinit adis16400_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq)
adis16400_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16400_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -1198,7 +1237,7 @@ static int adis16400_remove(struct spi_device *spi)
adis16400_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16400_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 8daa038..809e2c4 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -6,20 +6,19 @@
#include <linux/bitops.h>
#include <linux/export.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16400.h"
/**
* adis16400_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read (min size is 24 bytes)
**/
-static int adis16400_spi_read_burst(struct device *dev, u8 *rx)
+static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16400_state *st = iio_priv(indio_dev);
u32 old_speed_hz = st->us->max_speed_hz;
int ret;
@@ -71,9 +70,8 @@ static const u16 read_all_tx_array[] = {
cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)),
};
-static int adis16350_spi_read_all(struct device *dev, u8 *rx)
+static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16400_state *st = iio_priv(indio_dev);
struct spi_message msg;
@@ -119,12 +117,12 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0, j, ret = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
+
/* Asumption that long is enough for maximum channels */
unsigned long mask = *indio_dev->active_scan_mask;
int scan_count = bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
@@ -132,13 +130,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
if (scan_count) {
if (st->variant->flags & ADIS16400_NO_BURST) {
- ret = adis16350_spi_read_all(&indio_dev->dev, st->rx);
+ ret = adis16350_spi_read_all(indio_dev, st->rx);
if (ret < 0)
goto err;
for (; i < scan_count; i++)
data[i] = *(s16 *)(st->rx + i*2);
} else {
- ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx);
+ ret = adis16400_spi_read_burst(indio_dev, st->rx);
if (ret < 0)
goto err;
for (; i < scan_count; i++) {
diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c
index 5bf0007..42a678e 100644
--- a/drivers/staging/iio/imu/adis16400_trigger.c
+++ b/drivers/staging/iio/imu/adis16400_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16400.h"
/**
@@ -29,7 +29,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16400_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
indio_dev->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -59,7 +59,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -70,5 +70,5 @@ void adis16400_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h
deleted file mode 100644
index 9f7da01..0000000
--- a/drivers/staging/iio/kfifo_buf.h
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#include <linux/kfifo.h>
-#include "iio.h"
-#include "buffer.h"
-
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
-void iio_kfifo_free(struct iio_buffer *r);
-
diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index e7e9159..4bed30e 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -4,15 +4,26 @@
menu "Light sensors"
config SENSORS_ISL29018
- tristate "ISL 29018 light and proximity sensor"
- depends on I2C
- default n
- help
- If you say yes here you get support for ambient light sensing and
- proximity infrared sensing from Intersil ISL29018.
- This driver will provide the measurements of ambient light intensity
- in lux, proximity infrared sensing and normal infrared sensing.
- Data from sensor is accessible via sysfs.
+ tristate "ISL 29018 light and proximity sensor"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for ambient light sensing and
+ proximity infrared sensing from Intersil ISL29018.
+ This driver will provide the measurements of ambient light intensity
+ in lux, proximity infrared sensing and normal infrared sensing.
+ Data from sensor is accessible via sysfs.
+
+config SENSORS_ISL29028
+ tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Provides driver for the Intersil's ISL29028 device.
+ This driver supports the sysfs interface to get the ALS, IR intensity,
+ Proximity value via iio. The ISL29028 provides the concurrent sensing
+ of ambient light and proximity.
config SENSORS_TSL2563
tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
@@ -31,4 +42,12 @@ config TSL2583
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
Access ALS data via iio, sysfs.
+config TSL2x7x
+ tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
+ depends on I2C
+ help
+ Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
+ tmd2672, tsl2772, tmd2772 devices.
+ Provides iio_events and direct access via sysfs.
+
endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 3011fbf..141af1e 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -4,4 +4,6 @@
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
+obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
obj-$(CONFIG_TSL2583) += tsl2583.o
+obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 38ec52b6..0abbf18 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -26,9 +26,11 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
#define CONVERSION_TIME_MS 100
#define ISL29018_REG_ADD_COMMAND1 0x00
@@ -51,49 +53,22 @@
#define ISL29018_REG_ADD_DATA_LSB 0x02
#define ISL29018_REG_ADD_DATA_MSB 0x03
-#define ISL29018_MAX_REGS (ISL29018_REG_ADD_DATA_MSB+1)
#define ISL29018_REG_TEST 0x08
#define ISL29018_TEST_SHIFT 0
#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT)
struct isl29018_chip {
- struct i2c_client *client;
+ struct device *dev;
+ struct regmap *regmap;
struct mutex lock;
unsigned int lux_scale;
unsigned int range;
unsigned int adc_bit;
int prox_scheme;
- u8 reg_cache[ISL29018_MAX_REGS];
};
-static int isl29018_write_data(struct i2c_client *client, u8 reg,
- u8 val, u8 mask, u8 shift)
-{
- u8 regval = val;
- int ret;
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
-
- /* don't cache or mask REG_TEST */
- if (reg < ISL29018_MAX_REGS) {
- regval = chip->reg_cache[reg];
- regval &= ~mask;
- regval |= val << shift;
- }
-
- ret = i2c_smbus_write_byte_data(client, reg, regval);
- if (ret) {
- dev_err(&client->dev, "Write to device fails status %x\n", ret);
- } else {
- /* don't update cache on err */
- if (reg < ISL29018_MAX_REGS)
- chip->reg_cache[reg] = regval;
- }
-
- return ret;
-}
-
-static int isl29018_set_range(struct i2c_client *client, unsigned long range,
+static int isl29018_set_range(struct isl29018_chip *chip, unsigned long range,
unsigned int *new_range)
{
static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000};
@@ -109,11 +84,11 @@ static int isl29018_set_range(struct i2c_client *client, unsigned long range,
if (i >= ARRAY_SIZE(supp_ranges))
return -EINVAL;
- return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT);
+ return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_RANGE_MASK, i << COMMANDII_RANGE_SHIFT);
}
-static int isl29018_set_resolution(struct i2c_client *client,
+static int isl29018_set_resolution(struct isl29018_chip *chip,
unsigned long adcbit, unsigned int *conf_adc_bit)
{
static const unsigned long supp_adcbit[] = {16, 12, 8, 4};
@@ -129,48 +104,49 @@ static int isl29018_set_resolution(struct i2c_client *client,
if (i >= ARRAY_SIZE(supp_adcbit))
return -EINVAL;
- return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- i, COMMANDII_RESOLUTION_MASK,
- COMMANDII_RESOLUTION_SHIFT);
+ return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_RESOLUTION_MASK,
+ i << COMMANDII_RESOLUTION_SHIFT);
}
-static int isl29018_read_sensor_input(struct i2c_client *client, int mode)
+static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
{
int status;
- int lsb;
- int msb;
+ unsigned int lsb;
+ unsigned int msb;
/* Set mode */
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1,
- mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT);
+ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
+ mode << COMMMAND1_OPMODE_SHIFT);
if (status) {
- dev_err(&client->dev, "Error in setting operating mode\n");
+ dev_err(chip->dev,
+ "Error in setting operating mode err %d\n", status);
return status;
}
msleep(CONVERSION_TIME_MS);
- lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB);
- if (lsb < 0) {
- dev_err(&client->dev, "Error in reading LSB DATA\n");
- return lsb;
+ status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
+ if (status < 0) {
+ dev_err(chip->dev,
+ "Error in reading LSB DATA with err %d\n", status);
+ return status;
}
- msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB);
- if (msb < 0) {
- dev_err(&client->dev, "Error in reading MSB DATA\n");
- return msb;
+ status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb);
+ if (status < 0) {
+ dev_err(chip->dev,
+ "Error in reading MSB DATA with error %d\n", status);
+ return status;
}
- dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
+ dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
return (msb << 8) | lsb;
}
-static int isl29018_read_lux(struct i2c_client *client, int *lux)
+static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
{
int lux_data;
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
- lux_data = isl29018_read_sensor_input(client,
- COMMMAND1_OPMODE_ALS_ONCE);
+ lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
if (lux_data < 0)
return lux_data;
@@ -180,11 +156,11 @@ static int isl29018_read_lux(struct i2c_client *client, int *lux)
return 0;
}
-static int isl29018_read_ir(struct i2c_client *client, int *ir)
+static int isl29018_read_ir(struct isl29018_chip *chip, int *ir)
{
int ir_data;
- ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE);
+ ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@@ -194,7 +170,7 @@ static int isl29018_read_ir(struct i2c_client *client, int *ir)
return 0;
}
-static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
+static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
int *near_ir)
{
int status;
@@ -202,14 +178,15 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
int ir_data = -1;
/* Do proximity sensing with required scheme */
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT);
+ status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_SCHEME_MASK,
+ scheme << COMMANDII_SCHEME_SHIFT);
if (status) {
- dev_err(&client->dev, "Error in setting operating mode\n");
+ dev_err(chip->dev, "Error in setting operating mode\n");
return status;
}
- prox_data = isl29018_read_sensor_input(client,
+ prox_data = isl29018_read_sensor_input(chip,
COMMMAND1_OPMODE_PROX_ONCE);
if (prox_data < 0)
return prox_data;
@@ -219,8 +196,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
return 0;
}
- ir_data = isl29018_read_sensor_input(client,
- COMMMAND1_OPMODE_IR_ONCE);
+ ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@@ -238,7 +214,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
static ssize_t show_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%u\n", chip->range);
@@ -247,9 +223,8 @@ static ssize_t show_range(struct device *dev,
static ssize_t store_range(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
int status;
unsigned long lval;
unsigned int new_range;
@@ -264,10 +239,11 @@ static ssize_t store_range(struct device *dev,
}
mutex_lock(&chip->lock);
- status = isl29018_set_range(client, lval, &new_range);
+ status = isl29018_set_range(chip, lval, &new_range);
if (status < 0) {
mutex_unlock(&chip->lock);
- dev_err(dev, "Error in setting max range\n");
+ dev_err(dev,
+ "Error in setting max range with err %d\n", status);
return status;
}
chip->range = new_range;
@@ -280,7 +256,7 @@ static ssize_t store_range(struct device *dev,
static ssize_t show_resolution(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%u\n", chip->adc_bit);
@@ -289,9 +265,8 @@ static ssize_t show_resolution(struct device *dev,
static ssize_t store_resolution(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
int status;
unsigned long lval;
unsigned int new_adc_bit;
@@ -304,7 +279,7 @@ static ssize_t store_resolution(struct device *dev,
}
mutex_lock(&chip->lock);
- status = isl29018_set_resolution(client, lval, &new_adc_bit);
+ status = isl29018_set_resolution(chip, lval, &new_adc_bit);
if (status < 0) {
mutex_unlock(&chip->lock);
dev_err(dev, "Error in setting resolution\n");
@@ -320,7 +295,7 @@ static ssize_t store_resolution(struct device *dev,
static ssize_t show_prox_infrared_supression(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
/* return the "proximity scheme" i.e. if the chip does on chip
@@ -331,7 +306,7 @@ static ssize_t show_prox_infrared_supression(struct device *dev,
static ssize_t store_prox_infrared_supression(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
unsigned long lval;
@@ -379,20 +354,20 @@ static int isl29018_read_raw(struct iio_dev *indio_dev,
{
int ret = -EINVAL;
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
mutex_lock(&chip->lock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
- ret = isl29018_read_lux(client, val);
+ ret = isl29018_read_lux(chip, val);
break;
case IIO_INTENSITY:
- ret = isl29018_read_ir(client, val);
+ ret = isl29018_read_ir(chip, val);
break;
case IIO_PROXIMITY:
- ret = isl29018_read_proximity_ir(client,
+ ret = isl29018_read_proximity_ir(chip,
chip->prox_scheme, val);
break;
default:
@@ -419,15 +394,17 @@ static const struct iio_chan_spec isl29018_channels[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .processed_val = IIO_PROCESSED,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
}, {
.type = IIO_INTENSITY,
.modified = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.channel2 = IIO_MOD_LIGHT_IR,
}, {
/* Unindexed in current ABI. But perhaps it should be. */
.type = IIO_PROXIMITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -456,15 +433,12 @@ static const struct attribute_group isl29108_group = {
.attrs = isl29018_attributes,
};
-static int isl29018_chip_init(struct i2c_client *client)
+static int isl29018_chip_init(struct isl29018_chip *chip)
{
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
int status;
int new_adc_bit;
unsigned int new_range;
- memset(chip->reg_cache, 0, sizeof(chip->reg_cache));
-
/* Code added per Intersil Application Note 1534:
* When VDD sinks to approximately 1.8V or below, some of
* the part's registers may change their state. When VDD
@@ -485,10 +459,9 @@ static int isl29018_chip_init(struct i2c_client *client)
* the same thing EXCEPT the data sheet asks for a 1ms delay after
* writing the CMD1 register.
*/
- status = isl29018_write_data(client, ISL29018_REG_TEST, 0,
- ISL29018_TEST_MASK, ISL29018_TEST_SHIFT);
+ status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0);
if (status < 0) {
- dev_err(&client->dev, "Failed to clear isl29018 TEST reg."
+ dev_err(chip->dev, "Failed to clear isl29018 TEST reg."
"(%d)\n", status);
return status;
}
@@ -497,10 +470,9 @@ static int isl29018_chip_init(struct i2c_client *client)
* "Operating Mode" (COMMAND1) register is reprogrammed when
* data is read from the device.
*/
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0,
- 0xff, 0);
+ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0);
if (status < 0) {
- dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg."
+ dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg."
"(%d)\n", status);
return status;
}
@@ -508,13 +480,13 @@ static int isl29018_chip_init(struct i2c_client *client)
msleep(1); /* per data sheet, page 10 */
/* set defaults */
- status = isl29018_set_range(client, chip->range, &new_range);
+ status = isl29018_set_range(chip, chip->range, &new_range);
if (status < 0) {
- dev_err(&client->dev, "Init of isl29018 fails\n");
+ dev_err(chip->dev, "Init of isl29018 fails\n");
return status;
}
- status = isl29018_set_resolution(client, chip->adc_bit,
+ status = isl29018_set_resolution(chip, chip->adc_bit,
&new_adc_bit);
return 0;
@@ -527,6 +499,32 @@ static const struct iio_info isl29108_info = {
.write_raw = &isl29018_write_raw,
};
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ISL29018_REG_ADD_DATA_LSB:
+ case ISL29018_REG_ADD_DATA_MSB:
+ case ISL29018_REG_ADD_COMMAND1:
+ case ISL29018_REG_TEST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * isl29018_regmap_config: regmap configuration.
+ * Use RBTREE mechanism for caching.
+ */
+static const struct regmap_config isl29018_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = ISL29018_REG_TEST,
+ .num_reg_defaults_raw = ISL29018_REG_TEST + 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int __devinit isl29018_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -534,7 +532,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
dev_err(&client->dev, "iio allocation fails\n");
err = -ENOMEM;
@@ -543,7 +541,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
chip = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- chip->client = client;
+ chip->dev = &client->dev;
mutex_init(&chip->lock);
@@ -551,7 +549,14 @@ static int __devinit isl29018_probe(struct i2c_client *client,
chip->range = 1000;
chip->adc_bit = 16;
- err = isl29018_chip_init(client);
+ chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "regmap initialization failed: %d\n", err);
+ goto exit;
+ }
+
+ err = isl29018_chip_init(chip);
if (err)
goto exit_iio_free;
@@ -569,7 +574,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
return 0;
exit_iio_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
@@ -580,7 +585,7 @@ static int __devexit isl29018_remove(struct i2c_client *client)
dev_dbg(&client->dev, "%s()\n", __func__);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
@@ -593,7 +598,7 @@ static const struct i2c_device_id isl29018_id[] = {
MODULE_DEVICE_TABLE(i2c, isl29018_id);
static const struct of_device_id isl29018_of_match[] = {
- { .compatible = "invn,isl29018", },
+ { .compatible = "isil,isl29018", },
{ },
};
MODULE_DEVICE_TABLE(of, isl29018_of_match);
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
new file mode 100644
index 0000000..33a4c3f
--- /dev/null
+++ b/drivers/staging/iio/light/isl29028.c
@@ -0,0 +1,566 @@
+/*
+ * IIO driver for the light sensor ISL29028.
+ * ISL29028 is Concurrent Ambient Light and Proximity Sensor
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define CONVERSION_TIME_MS 100
+
+#define ISL29028_REG_CONFIGURE 0x01
+
+#define CONFIGURE_ALS_IR_MODE_ALS 0
+#define CONFIGURE_ALS_IR_MODE_IR BIT(0)
+#define CONFIGURE_ALS_IR_MODE_MASK BIT(0)
+
+#define CONFIGURE_ALS_RANGE_LOW_LUX 0
+#define CONFIGURE_ALS_RANGE_HIGH_LUX BIT(1)
+#define CONFIGURE_ALS_RANGE_MASK BIT(1)
+
+#define CONFIGURE_ALS_DIS 0
+#define CONFIGURE_ALS_EN BIT(2)
+#define CONFIGURE_ALS_EN_MASK BIT(2)
+
+#define CONFIGURE_PROX_DRIVE BIT(3)
+
+#define CONFIGURE_PROX_SLP_SH 4
+#define CONFIGURE_PROX_SLP_MASK (7 << CONFIGURE_PROX_SLP_SH)
+
+#define CONFIGURE_PROX_EN BIT(7)
+#define CONFIGURE_PROX_EN_MASK BIT(7)
+
+#define ISL29028_REG_INTERRUPT 0x02
+
+#define ISL29028_REG_PROX_DATA 0x08
+#define ISL29028_REG_ALSIR_L 0x09
+#define ISL29028_REG_ALSIR_U 0x0A
+
+#define ISL29028_REG_TEST1_MODE 0x0E
+#define ISL29028_REG_TEST2_MODE 0x0F
+
+#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
+
+enum als_ir_mode {
+ MODE_NONE = 0,
+ MODE_ALS,
+ MODE_IR
+};
+
+struct isl29028_chip {
+ struct device *dev;
+ struct mutex lock;
+ struct regmap *regmap;
+
+ unsigned int prox_sampling;
+ bool enable_prox;
+
+ int lux_scale;
+ int als_ir_mode;
+};
+
+static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
+ unsigned int sampling)
+{
+ static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0};
+ int sel;
+ unsigned int period = DIV_ROUND_UP(1000, sampling);
+
+ for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) {
+ if (period >= prox_period[sel])
+ break;
+ }
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH);
+}
+
+static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
+{
+ int ret;
+ int val = 0;
+
+ if (enable)
+ val = CONFIGURE_PROX_EN;
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_PROX_EN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for conversion to be complete for first sample */
+ mdelay(DIV_ROUND_UP(1000, chip->prox_sampling));
+ return 0;
+}
+
+static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
+{
+ int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX :
+ CONFIGURE_ALS_RANGE_LOW_LUX;
+
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_RANGE_MASK, val);
+}
+
+static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
+ enum als_ir_mode mode)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case MODE_ALS:
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_ALS);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_RANGE_MASK, CONFIGURE_ALS_RANGE_HIGH_LUX);
+ break;
+
+ case MODE_IR:
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_IR);
+ break;
+
+ case MODE_NONE:
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Enable the ALS/IR */
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN);
+ if (ret < 0)
+ return ret;
+
+ /* Need to wait for conversion time if ALS/IR mode enabled */
+ mdelay(CONVERSION_TIME_MS);
+ return 0;
+}
+
+static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
+{
+ unsigned int lsb;
+ unsigned int msb;
+ int ret;
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in reading register ALSIR_L err %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in reading register ALSIR_U err %d\n", ret);
+ return ret;
+ }
+
+ *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
+ return 0;
+}
+
+static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
+ if (ret < 0) {
+ dev_err(chip->dev, "Error in reading register %d, error %d\n",
+ ISL29028_REG_PROX_DATA, ret);
+ return ret;
+ }
+ *prox = data;
+ return 0;
+}
+
+static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
+{
+ int ret;
+
+ if (!chip->enable_prox) {
+ ret = isl29028_enable_proximity(chip, true);
+ if (ret < 0)
+ return ret;
+ chip->enable_prox = true;
+ }
+ return isl29028_read_proxim(chip, prox_data);
+}
+
+static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
+{
+ int ret;
+ int als_ir_data;
+
+ if (chip->als_ir_mode != MODE_ALS) {
+ ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in enabling ALS mode err %d\n", ret);
+ return ret;
+ }
+ chip->als_ir_mode = MODE_ALS;
+ }
+
+ ret = isl29028_read_als_ir(chip, &als_ir_data);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * convert als data count to lux.
+ * if lux_scale = 125, lux = count * 0.031
+ * if lux_scale = 2000, lux = count * 0.49
+ */
+ if (chip->lux_scale == 125)
+ als_ir_data = (als_ir_data * 31) / 1000;
+ else
+ als_ir_data = (als_ir_data * 49) / 100;
+
+ *als_data = als_ir_data;
+ return 0;
+}
+
+static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
+{
+ int ret;
+
+ if (chip->als_ir_mode != MODE_IR) {
+ ret = isl29028_set_als_ir_mode(chip, MODE_IR);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in enabling IR mode err %d\n", ret);
+ return ret;
+ }
+ chip->als_ir_mode = MODE_IR;
+ }
+ return isl29028_read_als_ir(chip, ir_data);
+}
+
+/* Channel IO */
+static int isl29028_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&chip->lock);
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
+ dev_err(chip->dev,
+ "proximity: mask value 0x%08lx not supported\n",
+ mask);
+ break;
+ }
+ if (val < 1 || val > 100) {
+ dev_err(chip->dev,
+ "Samp_freq %d is not in range[1:100]\n", val);
+ break;
+ }
+ ret = isl29028_set_proxim_sampling(chip, val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Setting proximity samp_freq fail, err %d\n",
+ ret);
+ break;
+ }
+ chip->prox_sampling = val;
+ break;
+
+ case IIO_LIGHT:
+ if (mask != IIO_CHAN_INFO_SCALE) {
+ dev_err(chip->dev,
+ "light: mask value 0x%08lx not supported\n",
+ mask);
+ break;
+ }
+ if ((val != 125) && (val != 2000)) {
+ dev_err(chip->dev,
+ "lux scale %d is invalid [125, 2000]\n", val);
+ break;
+ }
+ ret = isl29028_set_als_scale(chip, val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Setting lux scale fail with error %d\n", ret);
+ break;
+ }
+ chip->lux_scale = val;
+ break;
+
+ default:
+ dev_err(chip->dev, "Unsupported channel type\n");
+ break;
+ }
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static int isl29028_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&chip->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = isl29028_als_get(chip, val);
+ break;
+ case IIO_INTENSITY:
+ ret = isl29028_ir_get(chip, val);
+ break;
+ case IIO_PROXIMITY:
+ ret = isl29028_proxim_get(chip, val);
+ break;
+ default:
+ break;
+ }
+ if (ret < 0)
+ break;
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->type != IIO_PROXIMITY)
+ break;
+ *val = chip->prox_sampling;
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_LIGHT)
+ break;
+ *val = chip->lux_scale;
+ ret = IIO_VAL_INT;
+ break;
+
+ default:
+ dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
+ break;
+ }
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
+ "1, 3, 5, 10, 13, 20, 83, 100");
+static IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000");
+
+#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
+static struct attribute *isl29028_attributes[] = {
+ ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
+ ISL29028_CONST_ATTR(in_illuminance_scale_available),
+ NULL,
+};
+
+static const struct attribute_group isl29108_group = {
+ .attrs = isl29028_attributes,
+};
+
+static const struct iio_chan_spec isl29028_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT,
+ }
+};
+
+static const struct iio_info isl29028_info = {
+ .attrs = &isl29108_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &isl29028_read_raw,
+ .write_raw = &isl29028_write_raw,
+};
+
+static int isl29028_chip_init(struct isl29028_chip *chip)
+{
+ int ret;
+
+ chip->enable_prox = false;
+ chip->prox_sampling = 20;
+ chip->lux_scale = 2000;
+ chip->als_ir_mode = MODE_NONE;
+
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_TEST1_MODE, ret);
+ return ret;
+ }
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_TEST2_MODE, ret);
+ return ret;
+ }
+
+ ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_CONFIGURE, ret);
+ return ret;
+ }
+
+ ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): setting the proximity, err = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = isl29028_set_als_scale(chip, chip->lux_scale);
+ if (ret < 0)
+ dev_err(chip->dev, "%s(): setting als scale failed, err = %d\n",
+ __func__, ret);
+ return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ISL29028_REG_INTERRUPT:
+ case ISL29028_REG_PROX_DATA:
+ case ISL29028_REG_ALSIR_L:
+ case ISL29028_REG_ALSIR_U:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config isl29028_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = ISL29028_NUM_REGS - 1,
+ .num_reg_defaults_raw = ISL29028_NUM_REGS,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit isl29028_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct isl29028_chip *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*chip));
+ if (!indio_dev) {
+ dev_err(&client->dev, "iio allocation fails\n");
+ return -ENOMEM;
+ }
+
+ chip = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, indio_dev);
+ chip->dev = &client->dev;
+ mutex_init(&chip->lock);
+
+ chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
+ goto exit_iio_free;
+ }
+
+ ret = isl29028_chip_init(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip initialization failed: %d\n", ret);
+ goto exit_iio_free;
+ }
+
+ indio_dev->info = &isl29028_info;
+ indio_dev->channels = isl29028_channels;
+ indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(chip->dev, "iio registration fails with error %d\n",
+ ret);
+ goto exit_iio_free;
+ }
+ return 0;
+
+exit_iio_free:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int __devexit isl29028_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ iio_device_free(indio_dev);
+ return 0;
+}
+
+static const struct i2c_device_id isl29028_id[] = {
+ {"isl29028", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29028_id);
+
+static const struct of_device_id isl29028_of_match[] = {
+ { .compatible = "isil,isl29028", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, isl29028_of_match);
+
+static struct i2c_driver isl29028_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "isl29028",
+ .owner = THIS_MODULE,
+ .of_match_table = isl29028_of_match,
+ },
+ .probe = isl29028_probe,
+ .remove = __devexit_p(isl29028_remove),
+ .id_table = isl29028_id,
+};
+
+module_i2c_driver(isl29028_driver);
+
+MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index 546c95a..9d740be 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -35,9 +35,9 @@
#include <linux/err.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "tsl2563.h"
/* Use this many bits for fraction part. */
@@ -465,7 +465,7 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev,
{
struct tsl2563_chip *chip = iio_priv(indio_dev);
- if (chan->channel == 0)
+ if (chan->channel == IIO_MOD_LIGHT_BOTH)
chip->calib0 = calib_from_sysfs(val);
else
chip->calib1 = calib_from_sysfs(val);
@@ -485,7 +485,8 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
mutex_lock(&chip->lock);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
ret = tsl2563_get_adc(chip);
@@ -534,12 +535,14 @@ static const struct iio_chan_spec tsl2563_channels[] = {
{
.type = IIO_LIGHT,
.indexed = 1,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.channel = 0,
}, {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
@@ -548,7 +551,8 @@ static const struct iio_chan_spec tsl2563_channels[] = {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_IR,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
}
};
@@ -710,7 +714,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client,
int err = 0;
u8 id = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
@@ -797,7 +801,7 @@ fail2:
if (client->irq)
free_irq(client->irq, indio_dev);
fail1:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return err;
}
@@ -818,7 +822,7 @@ static int tsl2563_remove(struct i2c_client *client)
if (client->irq)
free_irq(client->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index 8671d98..5e23ad5 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -28,7 +28,7 @@
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#define TSL258X_MAX_DEVICE_REGS 32
@@ -483,7 +483,7 @@ static int taos_chip_off(struct iio_dev *indio_dev)
static ssize_t taos_power_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_chip_status);
@@ -492,7 +492,7 @@ static ssize_t taos_power_state_show(struct device *dev,
static ssize_t taos_power_state_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long value;
if (strict_strtoul(buf, 0, &value))
@@ -509,7 +509,7 @@ static ssize_t taos_power_state_store(struct device *dev,
static ssize_t taos_gain_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
char gain[4] = {0};
@@ -534,7 +534,7 @@ static ssize_t taos_gain_show(struct device *dev,
static ssize_t taos_gain_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -571,7 +571,7 @@ static ssize_t taos_gain_available_show(struct device *dev,
static ssize_t taos_als_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_time);
@@ -580,7 +580,7 @@ static ssize_t taos_als_time_show(struct device *dev,
static ssize_t taos_als_time_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -608,7 +608,7 @@ static ssize_t taos_als_time_available_show(struct device *dev,
static ssize_t taos_als_trim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
@@ -617,7 +617,7 @@ static ssize_t taos_als_trim_show(struct device *dev,
static ssize_t taos_als_trim_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -633,7 +633,7 @@ static ssize_t taos_als_trim_store(struct device *dev,
static ssize_t taos_als_cal_target_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target);
@@ -642,7 +642,7 @@ static ssize_t taos_als_cal_target_show(struct device *dev,
static ssize_t taos_als_cal_target_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -660,7 +660,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
{
int ret;
- ret = taos_get_lux(dev_get_drvdata(dev));
+ ret = taos_get_lux(dev_to_iio_dev(dev));
if (ret < 0)
return ret;
@@ -670,7 +670,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
static ssize_t taos_do_calibrate(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long value;
if (strict_strtoul(buf, 0, &value))
@@ -708,7 +708,7 @@ static ssize_t taos_luxtable_show(struct device *dev,
static ssize_t taos_luxtable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
int value[ARRAY_SIZE(taos_device_lux)*3 + 1];
int n;
@@ -815,7 +815,7 @@ static int __devinit taos_probe(struct i2c_client *clientp,
return -EOPNOTSUPP;
}
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
dev_err(&clientp->dev, "iio allocation failed\n");
@@ -879,7 +879,7 @@ static int __devinit taos_probe(struct i2c_client *clientp,
dev_info(&clientp->dev, "Light sensor found.\n");
return 0;
fail1:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
fail2:
return ret;
}
@@ -926,7 +926,7 @@ static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume);
static int __devexit taos_remove(struct i2c_client *client)
{
iio_device_unregister(i2c_get_clientdata(client));
- iio_free_device(i2c_get_clientdata(client));
+ iio_device_free(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
new file mode 100755
index 0000000..c4acf5f
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -0,0 +1,100 @@
+/*
+ * Device driver for monitoring ambient light intensity (lux)
+ * and proximity (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ */
+
+#ifndef __TSL2X7X_H
+#define __TSL2X7X_H
+#include <linux/pm.h>
+
+/* Max number of segments allowable in LUX table */
+#define TSL2X7X_MAX_LUX_TABLE_SIZE 9
+#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TSL2X7X_MAX_LUX_TABLE_SIZE)
+
+struct iio_dev;
+
+struct tsl2x7x_lux {
+ unsigned int ratio;
+ unsigned int ch0;
+ unsigned int ch1;
+};
+
+/**
+ * struct tsl2x7x_default_settings - power on defaults unless
+ * overridden by platform data.
+ * @als_time: ALS Integration time - multiple of 50mS
+ * @als_gain: Index into the ALS gain table.
+ * @als_gain_trim: default gain trim to account for
+ * aperture effects.
+ * @wait_time: Time between PRX and ALS cycles
+ * in 2.7 periods
+ * @prx_time: 5.2ms prox integration time -
+ * decrease in 2.7ms periods
+ * @prx_gain: Proximity gain index
+ * @prox_config: Prox configuration filters.
+ * @als_cal_target: Known external ALS reading for
+ * calibration.
+ * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als,
+ * 0x20 = prx, 0x30 = bth
+ * @persistence: H/W Filters, Number of 'out of limits'
+ * ADC readings PRX/ALS.
+ * @als_thresh_low: CH0 'low' count to trigger interrupt.
+ * @als_thresh_high: CH0 'high' count to trigger interrupt.
+ * @prox_thres_low: Low threshold proximity detection.
+ * @prox_thres_high: High threshold proximity detection
+ * @prox_pulse_count: Number if proximity emitter pulses
+ * @prox_max_samples_cal: Used for prox cal.
+ */
+struct tsl2x7x_settings {
+ int als_time;
+ int als_gain;
+ int als_gain_trim;
+ int wait_time;
+ int prx_time;
+ int prox_gain;
+ int prox_config;
+ int als_cal_target;
+ u8 interrupts_en;
+ u8 persistence;
+ int als_thresh_low;
+ int als_thresh_high;
+ int prox_thres_low;
+ int prox_thres_high;
+ int prox_pulse_count;
+ int prox_max_samples_cal;
+};
+
+/**
+ * struct tsl2X7X_platform_data - Platform callback, glass and defaults
+ * @platform_power: Suspend/resume platform callback
+ * @power_on: Power on callback
+ * @power_off: Power off callback
+ * @platform_lux_table: Device specific glass coefficents
+ * @platform_default_settings: Device specific power on defaults
+ *
+ */
+struct tsl2X7X_platform_data {
+ int (*platform_power)(struct device *dev, pm_message_t);
+ int (*power_on) (struct iio_dev *indio_dev);
+ int (*power_off) (struct i2c_client *dev);
+ struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
+ struct tsl2x7x_settings *platform_default_settings;
+};
+
+#endif /* __TSL2X7X_H */
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
new file mode 100755
index 0000000..c3b05a1
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -0,0 +1,2082 @@
+/*
+ * Device driver for monitoring ambient light intensity in (lux)
+ * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "tsl2x7x.h"
+
+/* Cal defs*/
+#define PROX_STAT_CAL 0
+#define PROX_STAT_SAMP 1
+#define MAX_SAMPLES_CAL 200
+
+/* TSL2X7X Device ID */
+#define TRITON_ID 0x00
+#define SWORDFISH_ID 0x30
+#define HALIBUT_ID 0x20
+
+/* Lux calculation constants */
+#define TSL2X7X_LUX_CALC_OVER_FLOW 65535
+
+/* TAOS Register definitions - note:
+ * depending on device, some of these register are not used and the
+ * register address is benign.
+ */
+/* 2X7X register offsets */
+#define TSL2X7X_MAX_CONFIG_REG 16
+
+/* Device Registers and Masks */
+#define TSL2X7X_CNTRL 0x00
+#define TSL2X7X_ALS_TIME 0X01
+#define TSL2X7X_PRX_TIME 0x02
+#define TSL2X7X_WAIT_TIME 0x03
+#define TSL2X7X_ALS_MINTHRESHLO 0X04
+#define TSL2X7X_ALS_MINTHRESHHI 0X05
+#define TSL2X7X_ALS_MAXTHRESHLO 0X06
+#define TSL2X7X_ALS_MAXTHRESHHI 0X07
+#define TSL2X7X_PRX_MINTHRESHLO 0X08
+#define TSL2X7X_PRX_MINTHRESHHI 0X09
+#define TSL2X7X_PRX_MAXTHRESHLO 0X0A
+#define TSL2X7X_PRX_MAXTHRESHHI 0X0B
+#define TSL2X7X_PERSISTENCE 0x0C
+#define TSL2X7X_PRX_CONFIG 0x0D
+#define TSL2X7X_PRX_COUNT 0x0E
+#define TSL2X7X_GAIN 0x0F
+#define TSL2X7X_NOTUSED 0x10
+#define TSL2X7X_REVID 0x11
+#define TSL2X7X_CHIPID 0x12
+#define TSL2X7X_STATUS 0x13
+#define TSL2X7X_ALS_CHAN0LO 0x14
+#define TSL2X7X_ALS_CHAN0HI 0x15
+#define TSL2X7X_ALS_CHAN1LO 0x16
+#define TSL2X7X_ALS_CHAN1HI 0x17
+#define TSL2X7X_PRX_LO 0x18
+#define TSL2X7X_PRX_HI 0x19
+
+/* tsl2X7X cmd reg masks */
+#define TSL2X7X_CMD_REG 0x80
+#define TSL2X7X_CMD_SPL_FN 0x60
+
+#define TSL2X7X_CMD_PROX_INT_CLR 0X05
+#define TSL2X7X_CMD_ALS_INT_CLR 0x06
+#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_ADC_ENBL 0x02
+#define TSL2X7X_CNTL_PWR_ON 0x01
+
+/* tsl2X7X status reg masks */
+#define TSL2X7X_STA_ADC_VALID 0x01
+#define TSL2X7X_STA_PRX_VALID 0x02
+#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\
+ TSL2X7X_STA_PRX_VALID)
+#define TSL2X7X_STA_ALS_INTR 0x10
+#define TSL2X7X_STA_PRX_INTR 0x20
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_REG_CLEAR 0x00
+#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20
+#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10
+#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08
+#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04
+#define TSL2X7X_CNTL_PWRON 0x01
+#define TSL2X7X_CNTL_ALSPON_ENBL 0x03
+#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13
+#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F
+#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F
+
+/*Prox diode to use */
+#define TSL2X7X_DIODE0 0x10
+#define TSL2X7X_DIODE1 0x20
+#define TSL2X7X_DIODE_BOTH 0x30
+
+/* LED Power */
+#define TSL2X7X_mA100 0x00
+#define TSL2X7X_mA50 0x40
+#define TSL2X7X_mA25 0x80
+#define TSL2X7X_mA13 0xD0
+#define TSL2X7X_MAX_TIMER_CNT (0xFF)
+
+/*Common device IIO EventMask */
+#define TSL2X7X_EVENT_MASK \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)),
+
+#define TSL2X7X_MIN_ITIME 3
+
+/* TAOS txx2x7x Device family members */
+enum {
+ tsl2571,
+ tsl2671,
+ tmd2671,
+ tsl2771,
+ tmd2771,
+ tsl2572,
+ tsl2672,
+ tmd2672,
+ tsl2772,
+ tmd2772
+};
+
+enum {
+ TSL2X7X_CHIP_UNKNOWN = 0,
+ TSL2X7X_CHIP_WORKING = 1,
+ TSL2X7X_CHIP_SUSPENDED = 2
+};
+
+struct tsl2x7x_parse_result {
+ int integer;
+ int fract;
+};
+
+/* Per-device data */
+struct tsl2x7x_als_info {
+ u16 als_ch0;
+ u16 als_ch1;
+ u16 lux;
+};
+
+struct tsl2x7x_prox_stat {
+ int min;
+ int max;
+ int mean;
+ unsigned long stddev;
+};
+
+struct tsl2x7x_chip_info {
+ int chan_table_elements;
+ struct iio_chan_spec channel[4];
+ const struct iio_info *info;
+};
+
+struct tsl2X7X_chip {
+ kernel_ulong_t id;
+ struct mutex prox_mutex;
+ struct mutex als_mutex;
+ struct i2c_client *client;
+ u16 prox_data;
+ struct tsl2x7x_als_info als_cur_info;
+ struct tsl2x7x_settings tsl2x7x_settings;
+ struct tsl2X7X_platform_data *pdata;
+ int als_time_scale;
+ int als_saturation;
+ int tsl2x7x_chip_status;
+ u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
+ const struct tsl2x7x_chip_info *chip_info;
+ const struct iio_info *info;
+ s64 event_timestamp;
+ /* This structure is intentionally large to accommodate
+ * updates via sysfs. */
+ /* Sized to 9 = max 8 segments + 1 termination segment */
+ struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
+};
+
+/* Different devices require different coefficents */
+static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
+ { 14461, 611, 1211 },
+ { 18540, 352, 623 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
+ { 11635, 115, 256 },
+ { 15536, 87, 179 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
+ { 14013, 466, 917 },
+ { 18222, 310, 552 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
+ { 13218, 130, 262 },
+ { 17592, 92, 169 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
+ [tsl2571] = tsl2x71_lux_table,
+ [tsl2671] = tsl2x71_lux_table,
+ [tmd2671] = tmd2x71_lux_table,
+ [tsl2771] = tsl2x71_lux_table,
+ [tmd2771] = tmd2x71_lux_table,
+ [tsl2572] = tsl2x72_lux_table,
+ [tsl2672] = tsl2x72_lux_table,
+ [tmd2672] = tmd2x72_lux_table,
+ [tsl2772] = tsl2x72_lux_table,
+ [tmd2772] = tmd2x72_lux_table,
+};
+
+static const struct tsl2x7x_settings tsl2x7x_default_settings = {
+ .als_time = 219, /* 101 ms */
+ .als_gain = 0,
+ .prx_time = 254, /* 5.4 ms */
+ .prox_gain = 1,
+ .wait_time = 245,
+ .prox_config = 0,
+ .als_gain_trim = 1000,
+ .als_cal_target = 150,
+ .als_thresh_low = 200,
+ .als_thresh_high = 256,
+ .persistence = 255,
+ .interrupts_en = 0,
+ .prox_thres_low = 0,
+ .prox_thres_high = 512,
+ .prox_max_samples_cal = 30,
+ .prox_pulse_count = 8
+};
+
+static const s16 tsl2X7X_als_gainadj[] = {
+ 1,
+ 8,
+ 16,
+ 120
+};
+
+static const s16 tsl2X7X_prx_gainadj[] = {
+ 1,
+ 2,
+ 4,
+ 8
+};
+
+/* Channel variations */
+enum {
+ ALS,
+ PRX,
+ ALSPRX,
+ PRX2,
+ ALSPRX2,
+};
+
+static const u8 device_channel_config[] = {
+ ALS,
+ PRX,
+ PRX,
+ ALSPRX,
+ ALSPRX,
+ ALS,
+ PRX2,
+ PRX2,
+ ALSPRX2,
+ ALSPRX2
+};
+
+/**
+ * tsl2x7x_parse_buffer() - parse a decimal result from a buffer.
+ * @*buf: pointer to char buffer to parse
+ * @*result: pointer to buffer to contain
+ * resulting interger / decimal as ints.
+ *
+ */
+static int
+tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result)
+{
+ int integer = 0, fract = 0, fract_mult = 100000;
+ bool integer_part = true, negative = false;
+
+ if (buf[0] == '-') {
+ negative = true;
+ buf++;
+ }
+
+ while (*buf) {
+ if ('0' <= *buf && *buf <= '9') {
+ if (integer_part)
+ integer = integer*10 + *buf - '0';
+ else {
+ fract += fract_mult*(*buf - '0');
+ if (fract_mult == 1)
+ break;
+ fract_mult /= 10;
+ }
+ } else if (*buf == '\n') {
+ if (*(buf + 1) == '\0')
+ break;
+ else
+ return -EINVAL;
+ } else if (*buf == '.') {
+ integer_part = false;
+ } else {
+ return -EINVAL;
+ }
+ buf++;
+ }
+ if (negative) {
+ if (integer)
+ integer = -integer;
+ else
+ fract = -fract;
+ }
+
+ result->integer = integer;
+ result->fract = fract;
+
+ return 0;
+}
+
+/**
+ * tsl2x7x_i2c_read() - Read a byte from a register.
+ * @client: i2c client
+ * @reg: device register to read from
+ * @*val: pointer to location to store register contents.
+ *
+ */
+static int
+tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int ret = 0;
+
+ /* select register to write */
+ ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg));
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: failed to write register %x\n"
+ , __func__, reg);
+ return ret;
+ }
+
+ /* read the data */
+ ret = i2c_smbus_read_byte(client);
+ if (ret >= 0)
+ *val = (u8)ret;
+ else
+ dev_err(&client->dev, "%s: failed to read register %x\n"
+ , __func__, reg);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_get_lux() - Reads and calculates current lux value.
+ * @indio_dev: pointer to IIO device
+ *
+ * The raw ch0 and ch1 values of the ambient light sensed in the last
+ * integration cycle are read from the device.
+ * Time scale factor array values are adjusted based on the integration time.
+ * The raw values are multiplied by a scale factor, and device gain is obtained
+ * using gain index. Limit checks are done next, then the ratio of a multiple
+ * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
+ * is then scanned to find the first ratio value that is just above the ratio
+ * we just calculated. The ch0 and ch1 multiplier constants in the array are
+ * then used along with the time scale factor array values, to calculate the
+ * lux.
+ */
+static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
+{
+ u16 ch0, ch1; /* separated ch0/ch1 data from device */
+ u32 lux; /* raw lux calculated from device data */
+ u64 lux64;
+ u32 ratio;
+ u8 buf[4];
+ struct tsl2x7x_lux *p;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int i, ret;
+ u32 ch0lux = 0;
+ u32 ch1lux = 0;
+
+ if (mutex_trylock(&chip->als_mutex) == 0)
+ return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
+
+ if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
+ /* device is not enabled */
+ dev_err(&chip->client->dev, "%s: device is not enabled\n",
+ __func__);
+ ret = -EBUSY ;
+ goto out_unlock;
+ }
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: Failed to read STATUS Reg\n", __func__);
+ goto out_unlock;
+ }
+ /* is data new & valid */
+ if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) {
+ dev_err(&chip->client->dev,
+ "%s: data not valid yet\n", __func__);
+ ret = chip->als_cur_info.lux; /* return LAST VALUE */
+ goto out_unlock;
+ }
+
+ for (i = 0; i < 4; i++) {
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)),
+ &buf[i]);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to read. err=%x\n", __func__, ret);
+ goto out_unlock;
+ }
+ }
+
+ /* clear any existing interrupt status */
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG |
+ TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_ALS_INT_CLR));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: i2c_write_command failed - err = %d\n",
+ __func__, ret);
+ goto out_unlock; /* have no data, so return failure */
+ }
+
+ /* extract ALS/lux data */
+ ch0 = le16_to_cpup((const __le16 *)&buf[0]);
+ ch1 = le16_to_cpup((const __le16 *)&buf[2]);
+
+ chip->als_cur_info.als_ch0 = ch0;
+ chip->als_cur_info.als_ch1 = ch1;
+
+ if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
+ lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+ goto return_max;
+ }
+
+ if (ch0 == 0) {
+ /* have no data, so return LAST VALUE */
+ ret = chip->als_cur_info.lux;
+ goto out_unlock;
+ }
+ /* calculate ratio */
+ ratio = (ch1 << 15) / ch0;
+ /* convert to unscaled lux using the pointer to the table */
+ p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux;
+ while (p->ratio != 0 && p->ratio < ratio)
+ p++;
+
+ if (p->ratio == 0) {
+ lux = 0;
+ } else {
+ ch0lux = DIV_ROUND_UP((ch0 * p->ch0),
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+ ch1lux = DIV_ROUND_UP((ch1 * p->ch1),
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+ lux = ch0lux - ch1lux;
+ }
+
+ /* note: lux is 31 bit max at this point */
+ if (ch1lux > ch0lux) {
+ dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
+ ret = chip->als_cur_info.lux;
+ goto out_unlock;
+ }
+
+ /* adjust for active time scale */
+ if (chip->als_time_scale == 0)
+ lux = 0;
+ else
+ lux = (lux + (chip->als_time_scale >> 1)) /
+ chip->als_time_scale;
+
+ /* adjust for active gain scale
+ * The tsl2x7x_device_lux tables have a factor of 256 built-in.
+ * User-specified gain provides a multiplier.
+ * Apply user-specified gain before shifting right to retain precision.
+ * Use 64 bits to avoid overflow on multiplication.
+ * Then go back to 32 bits before division to avoid using div_u64().
+ */
+
+ lux64 = lux;
+ lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
+ lux64 >>= 8;
+ lux = lux64;
+ lux = (lux + 500) / 1000;
+
+ if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
+ lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+
+ /* Update the structure with the latest lux. */
+return_max:
+ chip->als_cur_info.lux = lux;
+ ret = lux;
+
+out_unlock:
+ mutex_unlock(&chip->als_mutex);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_get_prox() - Reads proximity data registers and updates
+ * chip->prox_data.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
+{
+ int i;
+ int ret;
+ u8 status;
+ u8 chdata[2];
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (mutex_trylock(&chip->prox_mutex) == 0) {
+ dev_err(&chip->client->dev,
+ "%s: Can't get prox mutex\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: i2c err=%d\n", __func__, ret);
+ goto prox_poll_err;
+ }
+
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ if (!(status & TSL2X7X_STA_ADC_VALID))
+ goto prox_poll_err;
+ break;
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ if (!(status & TSL2X7X_STA_PRX_VALID))
+ goto prox_poll_err;
+ break;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG |
+ (TSL2X7X_PRX_LO + i)), &chdata[i]);
+ if (ret < 0)
+ goto prox_poll_err;
+ }
+
+ chip->prox_data =
+ le16_to_cpup((const __le16 *)&chdata[0]);
+
+prox_poll_err:
+
+ mutex_unlock(&chip->prox_mutex);
+
+ return chip->prox_data;
+}
+
+/**
+ * tsl2x7x_defaults() - Populates the device nominal operating parameters
+ * with those provided by a 'platform' data struct or
+ * with prefined defaults.
+ *
+ * @chip: pointer to device structure.
+ */
+static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
+{
+ /* If Operational settings defined elsewhere.. */
+ if (chip->pdata && chip->pdata->platform_default_settings != 0)
+ memcpy(&(chip->tsl2x7x_settings),
+ chip->pdata->platform_default_settings,
+ sizeof(tsl2x7x_default_settings));
+ else
+ memcpy(&(chip->tsl2x7x_settings),
+ &tsl2x7x_default_settings,
+ sizeof(tsl2x7x_default_settings));
+
+ /* Load up the proper lux table. */
+ if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+ memcpy(chip->tsl2x7x_device_lux,
+ chip->pdata->platform_lux_table,
+ sizeof(chip->pdata->platform_lux_table));
+ else
+ memcpy(chip->tsl2x7x_device_lux,
+ (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
+ MAX_DEFAULT_TABLE_BYTES);
+}
+
+/**
+ * tsl2x7x_als_calibrate() - Obtain single reading and calculate
+ * the als_gain_trim.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 reg_val;
+ int gain_trim_val;
+ int ret;
+ int lux_val;
+
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to write CNTRL register, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ reg_val = i2c_smbus_read_byte(chip->client);
+ if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
+ != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
+ dev_err(&chip->client->dev,
+ "%s: failed: ADC not enabled\n", __func__);
+ return -1;
+ }
+
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to write ctrl reg: ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ reg_val = i2c_smbus_read_byte(chip->client);
+ if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
+ dev_err(&chip->client->dev,
+ "%s: failed: STATUS - ADC not valid.\n", __func__);
+ return -ENODATA;
+ }
+
+ lux_val = tsl2x7x_get_lux(indio_dev);
+ if (lux_val < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to get lux\n", __func__);
+ return lux_val;
+ }
+
+ gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target)
+ * chip->tsl2x7x_settings.als_gain_trim) / lux_val);
+ if ((gain_trim_val < 250) || (gain_trim_val > 4000))
+ return -ERANGE;
+
+ chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
+ dev_info(&chip->client->dev,
+ "%s als_calibrate completed\n", chip->client->name);
+
+ return (int) gain_trim_val;
+}
+
+static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
+{
+ int i;
+ int ret = 0;
+ u8 *dev_reg;
+ u8 utmp;
+ int als_count;
+ int als_time;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 reg_val = 0;
+
+ if (chip->pdata && chip->pdata->power_on)
+ chip->pdata->power_on(indio_dev);
+
+ /* Non calculated parameters */
+ chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
+ chip->tsl2x7x_settings.prx_time;
+ chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
+ chip->tsl2x7x_settings.wait_time;
+ chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
+ chip->tsl2x7x_settings.prox_config;
+
+ chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
+ (chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
+ (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
+ (chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
+ (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
+ chip->tsl2x7x_settings.persistence;
+
+ chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
+ chip->tsl2x7x_settings.prox_pulse_count;
+ chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
+ chip->tsl2x7x_settings.prox_thres_low;
+ chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
+ chip->tsl2x7x_settings.prox_thres_high;
+
+ /* and make sure we're not already on */
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+ /* if forcing a register update - turn off, then on */
+ dev_info(&chip->client->dev, "device is already enabled\n");
+ return -EINVAL;
+ }
+
+ /* determine als integration regster */
+ als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
+ if (als_count == 0)
+ als_count = 1; /* ensure at least one cycle */
+
+ /* convert back to time (encompasses overrides) */
+ als_time = (als_count * 27 + 5) / 10;
+ chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
+
+ /* Set the gain based on tsl2x7x_settings struct */
+ chip->tsl2x7x_config[TSL2X7X_GAIN] =
+ (chip->tsl2x7x_settings.als_gain |
+ (TSL2X7X_mA100 | TSL2X7X_DIODE1)
+ | ((chip->tsl2x7x_settings.prox_gain) << 2));
+
+ /* set chip struct re scaling and saturation */
+ chip->als_saturation = als_count * 922; /* 90% of full scale */
+ chip->als_time_scale = (als_time + 25) / 50;
+
+ /* TSL2X7X Specific power-on / adc enable sequence
+ * Power on the device 1st. */
+ utmp = TSL2X7X_CNTL_PWR_ON;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on CNTRL reg.\n", __func__);
+ return ret;
+ }
+
+ /* Use the following shadow copy for our delay before enabling ADC.
+ * Write all the registers. */
+ for (i = 0, dev_reg = chip->tsl2x7x_config;
+ i < TSL2X7X_MAX_CONFIG_REG; i++) {
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG + i, *dev_reg++);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on write to reg %d.\n", __func__, i);
+ return ret;
+ }
+ }
+
+ mdelay(3); /* Power-on settling time */
+
+ /* NOW enable the ADC
+ * initialize the desired mode of operation */
+ utmp = TSL2X7X_CNTL_PWR_ON |
+ TSL2X7X_CNTL_ADC_ENBL |
+ TSL2X7X_CNTL_PROX_DET_ENBL;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on 2nd CTRL reg.\n", __func__);
+ return ret;
+ }
+
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
+
+ if (chip->tsl2x7x_settings.interrupts_en != 0) {
+ dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
+
+ reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
+ if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
+ (chip->tsl2x7x_settings.interrupts_en == 0x30))
+ reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
+
+ reg_val |= chip->tsl2x7x_settings.interrupts_en;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
+ __func__);
+
+ /* Clear out any initial interrupts */
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: Failed to clear Int status\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ /* turn device off */
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
+
+ if (chip->pdata && chip->pdata->power_off)
+ chip->pdata->power_off(chip->client);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_invoke_change
+ * @indio_dev: pointer to IIO device
+ *
+ * Obtain and lock both ALS and PROX resources,
+ * determine and save device state (On/Off),
+ * cycle device to implement updated parameter,
+ * put device back into proper state, and unlock
+ * resource.
+ */
+static
+int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int device_status = chip->tsl2x7x_chip_status;
+
+ mutex_lock(&chip->als_mutex);
+ mutex_lock(&chip->prox_mutex);
+
+ if (device_status == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ tsl2x7x_chip_on(indio_dev);
+
+ if (device_status != TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ mutex_unlock(&chip->prox_mutex);
+ mutex_unlock(&chip->als_mutex);
+
+ return 0;
+}
+
+static
+void tsl2x7x_prox_calculate(int *data, int length,
+ struct tsl2x7x_prox_stat *statP)
+{
+ int i;
+ int sample_sum;
+ int tmp;
+
+ if (length == 0)
+ length = 1;
+
+ sample_sum = 0;
+ statP->min = INT_MAX;
+ statP->max = INT_MIN;
+ for (i = 0; i < length; i++) {
+ sample_sum += data[i];
+ statP->min = min(statP->min, data[i]);
+ statP->max = max(statP->max, data[i]);
+ }
+
+ statP->mean = sample_sum / length;
+ sample_sum = 0;
+ for (i = 0; i < length; i++) {
+ tmp = data[i] - statP->mean;
+ sample_sum += tmp * tmp;
+ }
+ statP->stddev = int_sqrt((long)sample_sum)/length;
+}
+
+/**
+ * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
+ * @indio_dev: pointer to IIO device
+ *
+ * Calculates a standard deviation based on the samples,
+ * and sets the threshold accordingly.
+ */
+static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
+{
+ int prox_history[MAX_SAMPLES_CAL + 1];
+ int i;
+ struct tsl2x7x_prox_stat prox_stat_data[2];
+ struct tsl2x7x_prox_stat *calP;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 tmp_irq_settings;
+ u8 current_state = chip->tsl2x7x_chip_status;
+
+ if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
+ dev_err(&chip->client->dev,
+ "%s: max prox samples cal is too big: %d\n",
+ __func__, chip->tsl2x7x_settings.prox_max_samples_cal);
+ chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
+ }
+
+ /* have to stop to change settings */
+ tsl2x7x_chip_off(indio_dev);
+
+ /* Enable proximity detection save just in case prox not wanted yet*/
+ tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
+ chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
+
+ /*turn on device if not already on*/
+ tsl2x7x_chip_on(indio_dev);
+
+ /*gather the samples*/
+ for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
+ mdelay(15);
+ tsl2x7x_get_prox(indio_dev);
+ prox_history[i] = chip->prox_data;
+ dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
+ i, chip->prox_data);
+ }
+
+ tsl2x7x_chip_off(indio_dev);
+ calP = &prox_stat_data[PROX_STAT_CAL];
+ tsl2x7x_prox_calculate(prox_history,
+ chip->tsl2x7x_settings.prox_max_samples_cal, calP);
+ chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
+
+ dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
+ calP->min, calP->mean, calP->max);
+ dev_info(&chip->client->dev,
+ "%s proximity threshold set to %d\n",
+ chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
+
+ /* back to the way they were */
+ chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
+ if (current_state == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_on(indio_dev);
+}
+
+static ssize_t tsl2x7x_power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status);
+}
+
+static ssize_t tsl2x7x_power_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_chip_on(indio_dev);
+ else
+ tsl2x7x_chip_off(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_gain_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
+}
+
+static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
+}
+
+static ssize_t tsl2x7x_als_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z;
+
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ y /= 1000;
+ z %= 1000;
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_time_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+
+ result.integer = 0;
+ result.fract = 0;
+
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ result.fract /= 3;
+ chip->tsl2x7x_settings.als_time =
+ (TSL2X7X_MAX_TIMER_CNT - (u8)result.fract);
+
+ dev_info(&chip->client->dev, "%s: als time = %d",
+ __func__, chip->tsl2x7x_settings.als_time);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
+ ".00272 - .696");
+
+static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ chip->tsl2x7x_settings.als_cal_target);
+}
+
+static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ unsigned long value;
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (value)
+ chip->tsl2x7x_settings.als_cal_target = value;
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+/* persistence settings */
+static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z, filter_delay;
+
+ /* Determine integration time */
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
+ y = (filter_delay / 1000);
+ z = (filter_delay % 1000);
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+ int y, z, filter_delay;
+
+ result.integer = 0;
+ result.fract = 0;
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+
+ filter_delay =
+ DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+ chip->tsl2x7x_settings.persistence &= 0xF0;
+ chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
+
+ dev_info(&chip->client->dev, "%s: als persistence = %d",
+ __func__, filter_delay);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z, filter_delay;
+
+ /* Determine integration time */
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
+ y = (filter_delay / 1000);
+ z = (filter_delay % 1000);
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+ int y, z, filter_delay;
+
+ result.integer = 0;
+ result.fract = 0;
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+
+ filter_delay =
+ DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+ chip->tsl2x7x_settings.persistence &= 0x0F;
+ chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
+
+ dev_info(&chip->client->dev, "%s: prox persistence = %d",
+ __func__, filter_delay);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_do_calibrate(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_als_calibrate(indio_dev);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_luxtable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int i = 0;
+ int offset = 0;
+
+ while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
+ offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
+ chip->tsl2x7x_device_lux[i].ratio,
+ chip->tsl2x7x_device_lux[i].ch0,
+ chip->tsl2x7x_device_lux[i].ch1);
+ if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+ /* We just printed the first "0" entry.
+ * Now get rid of the extra "," and break. */
+ offset--;
+ break;
+ }
+ i++;
+ }
+
+ offset += snprintf(buf + offset, PAGE_SIZE, "\n");
+ return offset;
+}
+
+static ssize_t tsl2x7x_luxtable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1];
+ int n;
+
+ get_options(buf, ARRAY_SIZE(value), value);
+
+ /* We now have an array of ints starting at value[1], and
+ * enumerated by value[0].
+ * We expect each group of three ints is one table entry,
+ * and the last table entry is all 0.
+ */
+ n = value[0];
+ if ((n % 3) || n < 6 ||
+ n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
+ dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
+ return -EINVAL;
+ }
+
+ if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
+ dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
+ return -EINVAL;
+ }
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ /* Zero out the table */
+ memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
+ memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4));
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_prox_cal(indio_dev);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY)
+ ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
+ else
+ ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
+
+ return ret;
+}
+
+static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ if (val)
+ chip->tsl2x7x_settings.interrupts_en |= 0x10;
+ else
+ chip->tsl2x7x_settings.interrupts_en &= 0x20;
+ } else {
+ if (val)
+ chip->tsl2x7x_settings.interrupts_en |= 0x20;
+ else
+ chip->tsl2x7x_settings.interrupts_en &= 0x10;
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ chip->tsl2x7x_settings.als_thresh_high = val;
+ break;
+ case IIO_EV_DIR_FALLING:
+ chip->tsl2x7x_settings.als_thresh_low = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ chip->tsl2x7x_settings.prox_thres_high = val;
+ break;
+ case IIO_EV_DIR_FALLING:
+ chip->tsl2x7x_settings.prox_thres_low = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int *val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ *val = chip->tsl2x7x_settings.als_thresh_high;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = chip->tsl2x7x_settings.als_thresh_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ *val = chip->tsl2x7x_settings.prox_thres_high;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = chip->tsl2x7x_settings.prox_thres_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ int ret = -EINVAL;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ tsl2x7x_get_lux(indio_dev);
+ *val = chip->als_cur_info.lux;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ tsl2x7x_get_lux(indio_dev);
+ if (chan->channel == 0)
+ *val = chip->als_cur_info.als_ch0;
+ else
+ *val = chip->als_cur_info.als_ch1;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_PROXIMITY:
+ tsl2x7x_get_prox(indio_dev);
+ *val = chip->prox_data;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (chan->type == IIO_LIGHT)
+ *val =
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
+ else
+ *val =
+ tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = chip->tsl2x7x_settings.als_gain_trim;
+ ret = IIO_VAL_INT;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (chan->type == IIO_INTENSITY) {
+ switch (val) {
+ case 1:
+ chip->tsl2x7x_settings.als_gain = 0;
+ break;
+ case 8:
+ chip->tsl2x7x_settings.als_gain = 1;
+ break;
+ case 16:
+ chip->tsl2x7x_settings.als_gain = 2;
+ break;
+ case 120:
+ switch (chip->id) {
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ return -EINVAL;
+ break;
+ }
+ chip->tsl2x7x_settings.als_gain = 3;
+ break;
+ case 128:
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ return -EINVAL;
+ break;
+ }
+ chip->tsl2x7x_settings.als_gain = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (val) {
+ case 1:
+ chip->tsl2x7x_settings.prox_gain = 0;
+ break;
+ case 2:
+ chip->tsl2x7x_settings.prox_gain = 1;
+ break;
+ case 4:
+ chip->tsl2x7x_settings.prox_gain = 2;
+ break;
+ case 8:
+ chip->tsl2x7x_settings.prox_gain = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ chip->tsl2x7x_settings.als_gain_trim = val;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
+ tsl2x7x_power_state_show, tsl2x7x_power_state_store);
+
+static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO,
+ tsl2x7x_prox_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO,
+ tsl2x7x_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_time_show, tsl2x7x_als_time_store);
+
+static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store);
+
+static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL,
+ tsl2x7x_do_calibrate);
+
+static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL,
+ tsl2x7x_do_prox_calibrate);
+
+static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR,
+ tsl2x7x_luxtable_show, tsl2x7x_luxtable_store);
+
+static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store);
+
+static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR,
+ tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store);
+
+/* Use the default register values to identify the Taos device */
+static int tsl2x7x_device_id(unsigned char *id, int target)
+{
+ switch (target) {
+ case tsl2571:
+ case tsl2671:
+ case tsl2771:
+ return ((*id & 0xf0) == TRITON_ID);
+ break;
+ case tmd2671:
+ case tmd2771:
+ return ((*id & 0xf0) == HALIBUT_ID);
+ break;
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ return ((*id & 0xf0) == SWORDFISH_ID);
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ s64 timestamp = iio_get_time_ns();
+ int ret;
+ u8 value;
+
+ value = i2c_smbus_read_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+
+ /* What type of interrupt do we need to process */
+ if (value & TSL2X7X_STA_PRX_INTR) {
+ tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+
+ if (value & TSL2X7X_STA_ALS_INTR) {
+ tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+ /* Clear interrupt now that we have handled it. */
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: Failed to clear irq from event handler. err = %d\n",
+ __func__, ret);
+
+ return IRQ_HANDLED;
+}
+
+static struct attribute *tsl2x7x_ALS_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_PRX_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ &dev_attr_in_proximity0_calibscale_available.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ &dev_attr_in_proximity0_calibscale_available.attr,
+ NULL
+};
+
+static struct attribute *tsl2X7X_ALS_event_attrs[] = {
+ &dev_attr_in_intensity0_thresh_period.attr,
+ NULL,
+};
+static struct attribute *tsl2X7X_PRX_event_attrs[] = {
+ &dev_attr_in_proximity0_thresh_period.attr,
+ NULL,
+};
+
+static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
+ &dev_attr_in_intensity0_thresh_period.attr,
+ &dev_attr_in_proximity0_thresh_period.attr,
+ NULL,
+};
+
+static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
+ [ALS] = {
+ .attrs = tsl2x7x_ALS_device_attrs,
+ },
+ [PRX] = {
+ .attrs = tsl2x7x_PRX_device_attrs,
+ },
+ [ALSPRX] = {
+ .attrs = tsl2x7x_ALSPRX_device_attrs,
+ },
+ [PRX2] = {
+ .attrs = tsl2x7x_PRX2_device_attrs,
+ },
+ [ALSPRX2] = {
+ .attrs = tsl2x7x_ALSPRX2_device_attrs,
+ },
+};
+
+static struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
+ [ALS] = {
+ .attrs = tsl2X7X_ALS_event_attrs,
+ .name = "events",
+ },
+ [PRX] = {
+ .attrs = tsl2X7X_PRX_event_attrs,
+ .name = "events",
+ },
+ [ALSPRX] = {
+ .attrs = tsl2X7X_ALSPRX_event_attrs,
+ .name = "events",
+ },
+};
+
+static const struct iio_info tsl2X7X_device_info[] = {
+ [ALS] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALS],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [PRX] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[PRX],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [ALSPRX] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [PRX2] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [ALSPRX2] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+};
+
+static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
+ [ALS] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ },
+ },
+ .chan_table_elements = 3,
+ .info = &tsl2X7X_device_info[ALS],
+ },
+ [PRX] = {
+ .channel = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX],
+ },
+ [ALSPRX] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX],
+ },
+ [PRX2] = {
+ .channel = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX2],
+ },
+ [ALSPRX2] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX2],
+ },
+};
+
+static int __devinit tsl2x7x_probe(struct i2c_client *clientp,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ unsigned char device_id;
+ struct iio_dev *indio_dev;
+ struct tsl2X7X_chip *chip;
+
+ indio_dev = iio_device_alloc(sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+ chip->client = clientp;
+ i2c_set_clientdata(clientp, indio_dev);
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ TSL2X7X_CHIPID, &device_id);
+ if (ret < 0)
+ goto fail1;
+
+ if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
+ (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+ dev_info(&chip->client->dev,
+ "%s: i2c device found does not match expected id\n",
+ __func__);
+ goto fail1;
+ }
+
+ ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n",
+ __func__, ret);
+ goto fail1;
+ }
+
+ /* ALS and PROX functions can be invoked via user space poll
+ * or H/W interrupt. If busy return last sample. */
+ mutex_init(&chip->als_mutex);
+ mutex_init(&chip->prox_mutex);
+
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
+ chip->pdata = clientp->dev.platform_data;
+ chip->id = id->driver_data;
+ chip->chip_info =
+ &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
+
+ indio_dev->info = chip->chip_info->info;
+ indio_dev->dev.parent = &clientp->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = chip->client->name;
+ indio_dev->channels = chip->chip_info->channel;
+ indio_dev->num_channels = chip->chip_info->chan_table_elements;
+
+ if (clientp->irq) {
+ ret = request_threaded_irq(clientp->irq,
+ NULL,
+ &tsl2x7x_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "TSL2X7X_event",
+ indio_dev);
+ if (ret) {
+ dev_err(&clientp->dev,
+ "%s: irq request failed", __func__);
+ goto fail2;
+ }
+ }
+
+ /* Load up the defaults */
+ tsl2x7x_defaults(chip);
+ /* Make sure the chip is on */
+ tsl2x7x_chip_on(indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&clientp->dev,
+ "%s: iio registration failed\n", __func__);
+ goto fail1;
+ }
+
+ dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
+
+ return 0;
+
+fail1:
+ if (clientp->irq)
+ free_irq(clientp->irq, indio_dev);
+fail2:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int tsl2x7x_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+ ret = tsl2x7x_chip_off(indio_dev);
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+ }
+
+ if (chip->pdata && chip->pdata->platform_power) {
+ pm_message_t pmm = {PM_EVENT_SUSPEND};
+ chip->pdata->platform_power(dev, pmm);
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (chip->pdata && chip->pdata->platform_power) {
+ pm_message_t pmm = {PM_EVENT_RESUME};
+ chip->pdata->platform_power(dev, pmm);
+ }
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
+ ret = tsl2x7x_chip_on(indio_dev);
+
+ return ret;
+}
+
+static int __devexit tsl2x7x_remove(struct i2c_client *client)
+{
+ struct tsl2X7X_chip *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = iio_priv_to_dev(chip);
+
+ tsl2x7x_chip_off(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (client->irq)
+ free_irq(client->irq, chip->client->name);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static struct i2c_device_id tsl2x7x_idtable[] = {
+ { "tsl2571", tsl2571 },
+ { "tsl2671", tsl2671 },
+ { "tmd2671", tmd2671 },
+ { "tsl2771", tsl2771 },
+ { "tmd2771", tmd2771 },
+ { "tsl2572", tsl2572 },
+ { "tsl2672", tsl2672 },
+ { "tmd2672", tmd2672 },
+ { "tsl2772", tsl2772 },
+ { "tmd2772", tmd2772 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
+
+static const struct dev_pm_ops tsl2x7x_pm_ops = {
+ .suspend = tsl2x7x_suspend,
+ .resume = tsl2x7x_resume,
+};
+
+/* Driver definition */
+static struct i2c_driver tsl2x7x_driver = {
+ .driver = {
+ .name = "tsl2x7x",
+ .pm = &tsl2x7x_pm_ops,
+ },
+ .id_table = tsl2x7x_idtable,
+ .probe = tsl2x7x_probe,
+ .remove = __devexit_p(tsl2x7x_remove),
+};
+
+module_i2c_driver(tsl2x7x_driver);
+
+MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
+MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/machine.h b/drivers/staging/iio/machine.h
deleted file mode 100644
index 0b1f19b..0000000
--- a/drivers/staging/iio/machine.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Industrial I/O in kernel access map definitions for board files.
- *
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- */
-
-/**
- * struct iio_map - description of link between consumer and device channels
- * @adc_channel_label: Label used to identify the channel on the provider.
- * This is matched against the datasheet_name element
- * of struct iio_chan_spec.
- * @consumer_dev_name: Name to uniquely identify the consumer device.
- * @consumer_channel: Unique name used to idenitify the channel on the
- * consumer side.
- */
-struct iio_map {
- const char *adc_channel_label;
- const char *consumer_dev_name;
- const char *consumer_channel;
-};
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index 722c4e1..b9d9325 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -15,13 +15,13 @@ config SENSORS_AK8975
will be called ak8975.
config SENSORS_HMC5843
- tristate "Honeywell HMC5843 3-Axis Magnetometer"
+ tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
depends on I2C
help
- Say Y here to add support for the Honeywell HMC 5843 3-Axis
- Magnetometer (digital compass).
+ Say Y here to add support for the Honeywell HMC5843, HMC5883 and
+ HMC5883L 3-Axis Magnetometer (digital compass).
To compile this driver as a module, choose M here: the module
- will be called hmc5843
+ will be called hmc5843.
endmenu
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c
index ebc2d08..5834e4a 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/staging/iio/magnetometer/ak8975.c
@@ -30,8 +30,8 @@
#include <linux/gpio.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* Register definitions, as well as various shifts and masks to get at the
* individual fields of the registers.
@@ -242,7 +242,7 @@ static int ak8975_setup(struct i2c_client *client)
static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ak8975_data *data = iio_priv(indio_dev);
return sprintf(buf, "%u\n", data->mode);
@@ -255,7 +255,7 @@ static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ak8975_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
bool value;
@@ -431,7 +431,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
struct ak8975_data *data = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return ak8975_read_axis(indio_dev, chan->address, val);
case IIO_CHAN_INFO_SCALE:
*val = data->raw_to_gauss[chan->address];
@@ -445,7 +445,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = index, \
}
@@ -505,7 +506,7 @@ static int ak8975_probe(struct i2c_client *client,
}
/* Register with IIO */
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit_gpio;
@@ -536,7 +537,7 @@ static int ak8975_probe(struct i2c_client *client,
return 0;
exit_free_iio:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit_gpio:
if (gpio_is_valid(eoc_gpio))
gpio_free(eoc_gpio);
@@ -554,7 +555,7 @@ static int ak8975_remove(struct i2c_client *client)
if (gpio_is_valid(data->eoc_gpio))
gpio_free(data->eoc_gpio);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index e00b416..c1fa09f 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -2,6 +2,8 @@
Author: Shubhrajyoti Datta <shubhrajyoti@ti.com>
Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs.
+ Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -22,10 +24,8 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define HMC5843_I2C_ADDRESS 0x1E
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define HMC5843_CONFIG_REG_A 0x00
#define HMC5843_CONFIG_REG_B 0x01
@@ -36,110 +36,185 @@
#define HMC5843_DATA_OUT_Y_LSB_REG 0x06
#define HMC5843_DATA_OUT_Z_MSB_REG 0x07
#define HMC5843_DATA_OUT_Z_LSB_REG 0x08
+/* Beware: Y and Z are exchanged on HMC5883 */
+#define HMC5883_DATA_OUT_Z_MSB_REG 0x05
+#define HMC5883_DATA_OUT_Z_LSB_REG 0x06
+#define HMC5883_DATA_OUT_Y_MSB_REG 0x07
+#define HMC5883_DATA_OUT_Y_LSB_REG 0x08
#define HMC5843_STATUS_REG 0x09
#define HMC5843_ID_REG_A 0x0A
#define HMC5843_ID_REG_B 0x0B
#define HMC5843_ID_REG_C 0x0C
+enum hmc5843_ids {
+ HMC5843_ID,
+ HMC5883_ID,
+ HMC5883L_ID,
+};
+
+/*
+ * Beware: identification of the HMC5883 is still "H43";
+ * I2C address is also unchanged
+ */
#define HMC5843_ID_REG_LENGTH 0x03
#define HMC5843_ID_STRING "H43"
+#define HMC5843_I2C_ADDRESS 0x1E
/*
- * Range settings in (+-)Ga
- * */
-#define RANGE_GAIN_OFFSET 0x05
-
-#define RANGE_0_7 0x00
-#define RANGE_1_0 0x01 /* default */
-#define RANGE_1_5 0x02
-#define RANGE_2_0 0x03
-#define RANGE_3_2 0x04
-#define RANGE_3_8 0x05
-#define RANGE_4_5 0x06
-#define RANGE_6_5 0x07 /* Not recommended */
+ * Range gain settings in (+-)Ga
+ * Beware: HMC5843 and HMC5883 have different recommended sensor field
+ * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
+ */
+#define HMC5843_RANGE_GAIN_OFFSET 0x05
+#define HMC5843_RANGE_GAIN_DEFAULT 0x01
+#define HMC5843_RANGE_GAIN_MAX 0x07
/*
* Device status
*/
-#define DATA_READY 0x01
-#define DATA_OUTPUT_LOCK 0x02
-#define VOLTAGE_REGULATOR_ENABLED 0x04
+#define HMC5843_DATA_READY 0x01
+#define HMC5843_DATA_OUTPUT_LOCK 0x02
+/* Does not exist on HMC5883, not used */
+#define HMC5843_VOLTAGE_REGULATOR_ENABLED 0x04
/*
* Mode register configuration
*/
-#define MODE_CONVERSION_CONTINUOUS 0x00
-#define MODE_CONVERSION_SINGLE 0x01
-#define MODE_IDLE 0x02
-#define MODE_SLEEP 0x03
-
-/* Minimum Data Output Rate in 1/10 Hz */
-#define RATE_OFFSET 0x02
-#define RATE_BITMASK 0x1C
-#define RATE_5 0x00
-#define RATE_10 0x01
-#define RATE_20 0x02
-#define RATE_50 0x03
-#define RATE_100 0x04
-#define RATE_200 0x05
-#define RATE_500 0x06
-#define RATE_NOT_USED 0x07
+#define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00
+#define HMC5843_MODE_CONVERSION_SINGLE 0x01
+#define HMC5843_MODE_IDLE 0x02
+#define HMC5843_MODE_SLEEP 0x03
+#define HMC5843_MODE_MASK 0x03
+
+/*
+ * HMC5843: Minimum data output rate
+ * HMC5883: Typical data output rate
+ */
+#define HMC5843_RATE_OFFSET 0x02
+#define HMC5843_RATE_BITMASK 0x1C
+#define HMC5843_RATE_NOT_USED 0x07
/*
- * Device Configuration
+ * Device measurement configuration
*/
-#define CONF_NORMAL 0x00
-#define CONF_POSITIVE_BIAS 0x01
-#define CONF_NEGATIVE_BIAS 0x02
-#define CONF_NOT_USED 0x03
-#define MEAS_CONF_MASK 0x03
+#define HMC5843_MEAS_CONF_NORMAL 0x00
+#define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01
+#define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02
+#define HMC5843_MEAS_CONF_NOT_USED 0x03
+#define HMC5843_MEAS_CONF_MASK 0x03
-static int hmc5843_regval_to_nanoscale[] = {
+/*
+ * Scaling factors: 10000000/Gain
+ */
+static const int hmc5843_regval_to_nanoscale[] = {
6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
};
-static const int regval_to_input_field_mg[] = {
- 700,
- 1000,
- 1500,
- 2000,
- 3200,
- 3800,
- 4500,
- 6500
+static const int hmc5883_regval_to_nanoscale[] = {
+ 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
};
-static const char * const regval_to_samp_freq[] = {
- "0.5",
- "1",
- "2",
- "5",
- "10",
- "20",
- "50",
+
+static const int hmc5883l_regval_to_nanoscale[] = {
+ 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
+};
+
+/*
+ * From the HMC5843 datasheet:
+ * Value | Sensor input field range (Ga) | Gain (counts/milli-Gauss)
+ * 0 | (+-)0.7 | 1620
+ * 1 | (+-)1.0 | 1300
+ * 2 | (+-)1.5 | 970
+ * 3 | (+-)2.0 | 780
+ * 4 | (+-)3.2 | 530
+ * 5 | (+-)3.8 | 460
+ * 6 | (+-)4.5 | 390
+ * 7 | (+-)6.5 | 280
+ *
+ * From the HMC5883 datasheet:
+ * Value | Recommended sensor field range (Ga) | Gain (counts/Gauss)
+ * 0 | (+-)0.9 | 1280
+ * 1 | (+-)1.2 | 1024
+ * 2 | (+-)1.9 | 768
+ * 3 | (+-)2.5 | 614
+ * 4 | (+-)4.0 | 415
+ * 5 | (+-)4.6 | 361
+ * 6 | (+-)5.5 | 307
+ * 7 | (+-)7.9 | 219
+ *
+ * From the HMC5883L datasheet:
+ * Value | Recommended sensor field range (Ga) | Gain (LSB/Gauss)
+ * 0 | (+-)0.88 | 1370
+ * 1 | (+-)1.3 | 1090
+ * 2 | (+-)1.9 | 820
+ * 3 | (+-)2.5 | 660
+ * 4 | (+-)4.0 | 440
+ * 5 | (+-)4.7 | 390
+ * 6 | (+-)5.6 | 330
+ * 7 | (+-)8.1 | 230
+ */
+static const int hmc5843_regval_to_input_field_mga[] = {
+ 700, 1000, 1500, 2000, 3200, 3800, 4500, 6500
+};
+
+static const int hmc5883_regval_to_input_field_mga[] = {
+ 900, 1200, 1900, 2500, 4000, 4600, 5500, 7900
+};
+
+static const int hmc5883l_regval_to_input_field_mga[] = {
+ 880, 1300, 1900, 2500, 4000, 4700, 5600, 8100
+};
+
+/*
+ * From the datasheet:
+ * Value | HMC5843 | HMC5883/HMC5883L
+ * | Data output rate (Hz) | Data output rate (Hz)
+ * 0 | 0.5 | 0.75
+ * 1 | 1 | 1.5
+ * 2 | 2 | 3
+ * 3 | 5 | 7.5
+ * 4 | 10 (default) | 15
+ * 5 | 20 | 30
+ * 6 | 50 | 75
+ * 7 | Not used | Not used
+ */
+static const char * const hmc5843_regval_to_sample_freq[] = {
+ "0.5", "1", "2", "5", "10", "20", "50",
+};
+
+static const char * const hmc5883_regval_to_sample_freq[] = {
+ "0.75", "1.5", "3", "7.5", "15", "30", "75",
};
/* Addresses to scan: 0x1E */
static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
- I2C_CLIENT_END };
+ I2C_CLIENT_END };
+
+/* Describe chip variants */
+struct hmc5843_chip_info {
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ const char * const *regval_to_sample_freq;
+ const int *regval_to_input_field_mga;
+ const int *regval_to_nanoscale;
+};
/* Each client has this additional data */
struct hmc5843_data {
struct mutex lock;
- u8 rate;
- u8 meas_conf;
- u8 operating_mode;
- u8 range;
+ u8 rate;
+ u8 meas_conf;
+ u8 operating_mode;
+ u8 range;
+ const struct hmc5843_chip_info *variant;
};
-static void hmc5843_init_client(struct i2c_client *client);
-
+/* The lower two bits contain the current conversion mode */
static s32 hmc5843_configure(struct i2c_client *client,
u8 operating_mode)
{
- /* The lower two bits contain the current conversion mode */
return i2c_smbus_write_byte_data(client,
HMC5843_MODE_REG,
- (operating_mode & 0x03));
+ operating_mode & HMC5843_MODE_MASK);
}
/* Return the measurement value from the specified channel */
@@ -153,7 +228,7 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
mutex_lock(&data->lock);
result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
- while (!(result & DATA_READY))
+ while (!(result & HMC5843_DATA_READY))
result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
result = i2c_smbus_read_word_data(client, address);
@@ -161,30 +236,29 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
if (result < 0)
return -EINVAL;
- *val = (s16)swab16((u16)result);
+ *val = (s16)swab16((u16)result);
return IIO_VAL_INT;
}
-
/*
- * From the datasheet
+ * From the datasheet:
* 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
- * device continuously performs conversions and places the result in the
- * data register.
+ * device continuously performs conversions and places the result in
+ * the data register.
*
- * 1 - Single-Conversion Mode : device performs a single measurement,
- * sets RDY high and returned to sleep mode
+ * 1 - Single-Conversion Mode : Device performs a single measurement,
+ * sets RDY high and returns to sleep mode.
*
- * 2 - Idle Mode : Device is placed in idle mode.
+ * 2 - Idle Mode : Device is placed in idle mode.
*
- * 3 - Sleep Mode. Device is placed in sleep mode.
+ * 3 - Sleep Mode : Device is placed in sleep mode.
*
*/
static ssize_t hmc5843_show_operating_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->operating_mode);
}
@@ -194,21 +268,22 @@ static ssize_t hmc5843_set_operating_mode(struct device *dev,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct hmc5843_data *data = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long operating_mode = 0;
s32 status;
int error;
+
mutex_lock(&data->lock);
- error = strict_strtoul(buf, 10, &operating_mode);
+ error = kstrtoul(buf, 10, &operating_mode);
if (error) {
count = error;
goto exit;
}
- dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode);
- if (operating_mode > MODE_SLEEP) {
+ dev_dbg(dev, "set conversion mode to %lu\n", operating_mode);
+ if (operating_mode > HMC5843_MODE_SLEEP) {
count = -EINVAL;
goto exit;
}
@@ -225,6 +300,7 @@ exit:
mutex_unlock(&data->lock);
return count;
}
+
static IIO_DEVICE_ATTR(operating_mode,
S_IWUSR | S_IRUGO,
hmc5843_show_operating_mode,
@@ -234,25 +310,29 @@ static IIO_DEVICE_ATTR(operating_mode,
/*
* API for setting the measurement configuration to
* Normal, Positive bias and Negative bias
- * From the datasheet
*
- * Normal measurement configuration (default): In normal measurement
- * configuration the device follows normal measurement flow. Pins BP and BN
- * are left floating and high impedance.
+ * From the datasheet:
+ * 0 - Normal measurement configuration (default): In normal measurement
+ * configuration the device follows normal measurement flow. Pins BP
+ * and BN are left floating and high impedance.
*
- * Positive bias configuration: In positive bias configuration, a positive
- * current is forced across the resistive load on pins BP and BN.
+ * 1 - Positive bias configuration: In positive bias configuration, a
+ * positive current is forced across the resistive load on pins BP
+ * and BN.
*
- * Negative bias configuration. In negative bias configuration, a negative
- * current is forced across the resistive load on pins BP and BN.
+ * 2 - Negative bias configuration. In negative bias configuration, a
+ * negative current is forced across the resistive load on pins BP
+ * and BN.
*
*/
static s32 hmc5843_set_meas_conf(struct i2c_client *client,
u8 meas_conf)
{
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
u8 reg_val;
- reg_val = (meas_conf & MEAS_CONF_MASK) | (data->rate << RATE_OFFSET);
+ reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) |
+ (data->rate << HMC5843_RATE_OFFSET);
return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
}
@@ -260,7 +340,7 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->meas_conf);
}
@@ -270,16 +350,20 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
unsigned long meas_conf = 0;
- int error = strict_strtoul(buf, 10, &meas_conf);
+ int error;
+
+ error = kstrtoul(buf, 10, &meas_conf);
if (error)
return error;
- mutex_lock(&data->lock);
+ if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED)
+ return -EINVAL;
- dev_dbg(dev, "set mode to %lu\n", meas_conf);
+ mutex_lock(&data->lock);
+ dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf);
if (hmc5843_set_meas_conf(client, meas_conf)) {
count = -EINVAL;
goto exit;
@@ -290,71 +374,85 @@ exit:
mutex_unlock(&data->lock);
return count;
}
+
static IIO_DEVICE_ATTR(meas_conf,
S_IWUSR | S_IRUGO,
hmc5843_show_measurement_configuration,
hmc5843_set_measurement_configuration,
0);
-/*
- * From Datasheet
- * The table shows the minimum data output
- * Value | Minimum data output rate(Hz)
- * 0 | 0.5
- * 1 | 1
- * 2 | 2
- * 3 | 5
- * 4 | 10 (default)
- * 5 | 20
- * 6 | 50
- * 7 | Not used
- */
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.5 1 2 5 10 20 50");
+static ssize_t hmc5843_show_sampling_frequencies_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct hmc5843_data *data = iio_priv(indio_dev);
+ ssize_t total_n = 0;
+ int i;
+
+ for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+ ssize_t n = sprintf(buf, "%s ", data->variant->regval_to_sample_freq[i]);
+ buf += n;
+ total_n += n;
+ }
+ /* replace trailing space by newline */
+ buf[-1] = '\n';
+
+ return total_n;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_sampling_frequencies_available);
static s32 hmc5843_set_rate(struct i2c_client *client,
u8 rate)
{
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
u8 reg_val;
- reg_val = (data->meas_conf) | (rate << RATE_OFFSET);
- if (rate >= RATE_NOT_USED) {
+ if (rate >= HMC5843_RATE_NOT_USED) {
dev_err(&client->dev,
- "This data output rate is not supported\n");
+ "data output rate is not supported\n");
return -EINVAL;
}
+
+ reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET);
return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
}
-static ssize_t set_sampling_frequency(struct device *dev,
+static int hmc5843_check_sampling_frequency(struct hmc5843_data *data,
+ const char *buf)
+{
+ const char * const *samp_freq = data->variant->regval_to_sample_freq;
+ int i;
+
+ for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+ if (sysfs_streq(buf, samp_freq[i]))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t hmc5843_set_sampling_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct hmc5843_data *data = iio_priv(indio_dev);
- unsigned long rate = 0;
-
- if (strncmp(buf, "0.5" , 3) == 0)
- rate = RATE_5;
- else if (strncmp(buf, "1" , 1) == 0)
- rate = RATE_10;
- else if (strncmp(buf, "2", 1) == 0)
- rate = RATE_20;
- else if (strncmp(buf, "5", 1) == 0)
- rate = RATE_50;
- else if (strncmp(buf, "10", 2) == 0)
- rate = RATE_100;
- else if (strncmp(buf, "20" , 2) == 0)
- rate = RATE_200;
- else if (strncmp(buf, "50" , 2) == 0)
- rate = RATE_500;
- else
- return -EINVAL;
+ int rate;
+
+ rate = hmc5843_check_sampling_frequency(data, buf);
+ if (rate < 0) {
+ dev_err(&client->dev,
+ "sampling frequency is not supported\n");
+ return rate;
+ }
mutex_lock(&data->lock);
- dev_dbg(dev, "set rate to %lu\n", rate);
+ dev_dbg(dev, "set rate to %d\n", rate);
if (hmc5843_set_rate(client, rate)) {
count = -EINVAL;
goto exit;
@@ -366,89 +464,79 @@ exit:
return count;
}
-static ssize_t show_sampling_frequency(struct device *dev,
+static ssize_t hmc5843_show_sampling_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct hmc5843_data *data = iio_priv(indio_dev);
s32 rate;
- rate = i2c_smbus_read_byte_data(client, this_attr->address);
+ rate = i2c_smbus_read_byte_data(client, this_attr->address);
if (rate < 0)
return rate;
- rate = (rate & RATE_BITMASK) >> RATE_OFFSET;
- return sprintf(buf, "%s\n", regval_to_samp_freq[rate]);
+ rate = (rate & HMC5843_RATE_BITMASK) >> HMC5843_RATE_OFFSET;
+ return sprintf(buf, "%s\n", data->variant->regval_to_sample_freq[rate]);
}
+
static IIO_DEVICE_ATTR(sampling_frequency,
S_IWUSR | S_IRUGO,
- show_sampling_frequency,
- set_sampling_frequency,
+ hmc5843_show_sampling_frequency,
+ hmc5843_set_sampling_frequency,
HMC5843_CONFIG_REG_A);
-/*
- * From Datasheet
- * Nominal gain settings
- * Value | Sensor Input Field Range(Ga) | Gain(counts/ milli-gauss)
- *0 |(+-)0.7 |1620
- *1 |(+-)1.0 |1300
- *2 |(+-)1.5 |970
- *3 |(+-)2.0 |780
- *4 |(+-)3.2 |530
- *5 |(+-)3.8 |460
- *6 |(+-)4.5 |390
- *7 |(+-)6.5 |280
- */
-static ssize_t show_range(struct device *dev,
+static ssize_t hmc5843_show_range_gain(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u8 range;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
range = data->range;
- return sprintf(buf, "%d\n", regval_to_input_field_mg[range]);
+ return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]);
}
-static ssize_t set_range(struct device *dev,
+static ssize_t hmc5843_set_range_gain(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct hmc5843_data *data = iio_priv(indio_dev);
unsigned long range = 0;
int error;
+
mutex_lock(&data->lock);
- error = strict_strtoul(buf, 10, &range);
+ error = kstrtoul(buf, 10, &range);
if (error) {
count = error;
goto exit;
}
dev_dbg(dev, "set range to %lu\n", range);
- if (range > RANGE_6_5) {
+ if (range > HMC5843_RANGE_GAIN_MAX) {
count = -EINVAL;
goto exit;
}
data->range = range;
- range = range << RANGE_GAIN_OFFSET;
+ range = range << HMC5843_RANGE_GAIN_OFFSET;
if (i2c_smbus_write_byte_data(client, this_attr->address, range))
count = -EINVAL;
exit:
mutex_unlock(&data->lock);
return count;
-
}
+
static IIO_DEVICE_ATTR(in_magn_range,
S_IWUSR | S_IRUGO,
- show_range,
- set_range,
+ hmc5843_show_range_gain,
+ hmc5843_set_range_gain,
HMC5843_CONFIG_REG_B);
static int hmc5843_read_raw(struct iio_dev *indio_dev,
@@ -459,13 +547,13 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
struct hmc5843_data *data = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return hmc5843_read_measurement(indio_dev,
chan->address,
val);
case IIO_CHAN_INFO_SCALE:
*val = 0;
- *val2 = hmc5843_regval_to_nanoscale[data->range];
+ *val2 = data->variant->regval_to_nanoscale[data->range];
return IIO_VAL_INT_PLUS_NANO;
};
return -EINVAL;
@@ -476,7 +564,8 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = add \
}
@@ -486,12 +575,18 @@ static const struct iio_chan_spec hmc5843_channels[] = {
HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG),
};
+static const struct iio_chan_spec hmc5883_channels[] = {
+ HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG),
+ HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG),
+ HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG),
+};
+
static struct attribute *hmc5843_attributes[] = {
&iio_dev_attr_meas_conf.dev_attr.attr,
&iio_dev_attr_operating_mode.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_dev_attr_in_magn_range.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
@@ -499,6 +594,33 @@ static const struct attribute_group hmc5843_group = {
.attrs = hmc5843_attributes,
};
+static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
+ [HMC5843_ID] = {
+ .channels = hmc5843_channels,
+ .num_channels = ARRAY_SIZE(hmc5843_channels),
+ .regval_to_sample_freq = hmc5843_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5843_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5843_regval_to_nanoscale,
+ },
+ [HMC5883_ID] = {
+ .channels = hmc5883_channels,
+ .num_channels = ARRAY_SIZE(hmc5883_channels),
+ .regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5883_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5883_regval_to_nanoscale,
+ },
+ [HMC5883L_ID] = {
+ .channels = hmc5883_channels,
+ .num_channels = ARRAY_SIZE(hmc5883_channels),
+ .regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5883l_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
+ },
+};
+
static int hmc5843_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
@@ -518,18 +640,23 @@ static int hmc5843_detect(struct i2c_client *client,
return 0;
}
-/* Called when we have found a new HMC5843. */
-static void hmc5843_init_client(struct i2c_client *client)
+/* Called when we have found a new HMC58X3 */
+static void hmc5843_init_client(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct hmc5843_data *data = iio_priv(indio_dev);
+ data->variant = &hmc5843_chip_info_tbl[id->driver_data];
+ indio_dev->channels = data->variant->channels;
+ indio_dev->num_channels = data->variant->num_channels;
hmc5843_set_meas_conf(client, data->meas_conf);
hmc5843_set_rate(client, data->rate);
hmc5843_configure(client, data->operating_mode);
i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range);
mutex_init(&data->lock);
- pr_info("HMC5843 initialized\n");
+
+ pr_info("%s initialized\n", id->name);
}
static const struct iio_info hmc5843_info = {
@@ -545,35 +672,34 @@ static int hmc5843_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err = 0;
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit;
}
- data = iio_priv(indio_dev);
- /* default settings at probe */
- data->meas_conf = CONF_NORMAL;
- data->range = RANGE_1_0;
- data->operating_mode = MODE_CONVERSION_CONTINUOUS;
+ /* default settings at probe */
+ data = iio_priv(indio_dev);
+ data->meas_conf = HMC5843_MEAS_CONF_NORMAL;
+ data->range = HMC5843_RANGE_GAIN_DEFAULT;
+ data->operating_mode = HMC5843_MODE_CONVERSION_CONTINUOUS;
i2c_set_clientdata(client, indio_dev);
-
- /* Initialize the HMC5843 chip */
- hmc5843_init_client(client);
+ hmc5843_init_client(client, id);
indio_dev->info = &hmc5843_info;
indio_dev->name = id->name;
- indio_dev->channels = hmc5843_channels;
- indio_dev->num_channels = ARRAY_SIZE(hmc5843_channels);
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
+
err = iio_device_register(indio_dev);
if (err)
goto exit_free2;
+
return 0;
+
exit_free2:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
@@ -584,8 +710,8 @@ static int hmc5843_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
/* sleep mode to save power */
- hmc5843_configure(client, MODE_SLEEP);
- iio_free_device(indio_dev);
+ hmc5843_configure(client, HMC5843_MODE_SLEEP);
+ iio_device_free(indio_dev);
return 0;
}
@@ -593,14 +719,18 @@ static int hmc5843_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int hmc5843_suspend(struct device *dev)
{
- hmc5843_configure(to_i2c_client(dev), MODE_SLEEP);
+ hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP);
return 0;
}
static int hmc5843_resume(struct device *dev)
{
- struct hmc5843_data *data = i2c_get_clientdata(to_i2c_client(dev));
- hmc5843_configure(to_i2c_client(dev), data->operating_mode);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
+
+ hmc5843_configure(client, data->operating_mode);
+
return 0;
}
@@ -611,7 +741,9 @@ static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
#endif
static const struct i2c_device_id hmc5843_id[] = {
- { "hmc5843", 0 },
+ { "hmc5843", HMC5843_ID },
+ { "hmc5883", HMC5883_ID },
+ { "hmc5883l", HMC5883L_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, hmc5843_id);
@@ -630,5 +762,5 @@ static struct i2c_driver hmc5843_driver = {
module_i2c_driver(hmc5843_driver);
MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com");
-MODULE_DESCRIPTION("HMC5843 driver");
+MODULE_DESCRIPTION("HMC5843/5883/5883L driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index 57baac6..f04ece7 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7753.h"
@@ -28,7 +28,7 @@ static int ade7753_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7753_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7753_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
@@ -82,7 +82,7 @@ static int ade7753_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
@@ -104,7 +104,7 @@ static int ade7753_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -416,7 +416,7 @@ static ssize_t ade7753_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -517,7 +517,7 @@ static int __devinit ade7753_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -546,7 +546,7 @@ static int __devinit ade7753_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -564,7 +564,7 @@ static int ade7753_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
}
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 8d81c920..6cee28a 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7754.h"
@@ -28,7 +28,7 @@ static int ade7754_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7754_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7754_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
@@ -82,7 +82,7 @@ static int ade7754_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
@@ -104,7 +104,7 @@ static int ade7754_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -436,7 +436,7 @@ static ssize_t ade7754_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -540,7 +540,7 @@ static int __devinit ade7754_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -568,7 +568,7 @@ static int __devinit ade7754_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -585,7 +585,7 @@ static int ade7754_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index dcb2029..96d6114 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "meter.h"
#include "ade7758.h"
@@ -29,7 +29,7 @@ int ade7758_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -48,7 +48,7 @@ static int ade7758_spi_write_reg_16(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
@@ -77,7 +77,7 @@ static int ade7758_spi_write_reg_24(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
@@ -106,7 +106,7 @@ int ade7758_spi_read_reg_8(struct device *dev,
u8 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -149,7 +149,7 @@ static int ade7758_spi_read_reg_16(struct device *dev,
u16 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -195,7 +195,7 @@ static int ade7758_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -534,7 +534,7 @@ static ssize_t ade7758_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long val;
int ret;
u8 reg, t;
@@ -662,66 +662,217 @@ static const struct attribute_group ade7758_attribute_group = {
};
static struct iio_chan_spec ade7758_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
- 0, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
- 1, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
- 2, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
- 3, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
- 4, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
- 5, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
- 6, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
- 7, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
- 8, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
- 9, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
- 10, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
- 11, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
- 12, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
- 13, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
- 14, IIO_ST('s', 24, 32, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
+ .scan_index = 2,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
+ .scan_index = 3,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
+ .scan_index = 4,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
+ .scan_index = 5,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
+ .scan_index = 6,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
+ .scan_index = 7,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
+ .scan_index = 8,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
+ .scan_index = 9,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
+ .scan_index = 10,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
+ .scan_index = 11,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
+ .scan_index = 12,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
+ .scan_index = 13,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
+ .scan_index = 14,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(15),
};
@@ -734,7 +885,7 @@ static int __devinit ade7758_probe(struct spi_device *spi)
{
int i, ret;
struct ade7758_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
@@ -800,7 +951,7 @@ static int __devinit ade7758_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq)
ade7758_remove_trigger(indio_dev);
error_uninitialize_ring:
ade7758_uninitialize_ring(indio_dev);
@@ -811,7 +962,7 @@ error_free_tx:
error_free_rx:
kfree(st->rx);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -833,7 +984,7 @@ static int ade7758_remove(struct spi_device *spi)
kfree(st->tx);
kfree(st->rx);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index c45b23b..92159f2 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -12,18 +12,17 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "ade7758.h"
/**
* ade7758_spi_read_burst() - read data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
**/
-static int ade7758_spi_read_burst(struct device *dev)
+static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
@@ -68,11 +67,11 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
u32 *dat32 = (u32 *)dat64;
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
- if (ade7758_spi_read_burst(&indio_dev->dev) >= 0)
+ if (ade7758_spi_read_burst(indio_dev) >= 0)
*dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF;
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -92,29 +91,19 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
static int ade7758_ring_preenable(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
+
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
ade7758_write_waveform_type(&indio_dev->dev,
st->ade7758_ring_channels[channel].address);
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
index b6569c7..f9c6a34 100644
--- a/drivers/staging/iio/meter/ade7758_trigger.c
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -11,8 +11,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "ade7758.h"
/**
@@ -63,7 +63,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -94,7 +94,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -105,5 +105,5 @@ void ade7758_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 0beab47..b3f7e0fa9 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7759.h"
@@ -28,7 +28,7 @@ static int ade7759_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7759_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7759_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
@@ -82,7 +82,7 @@ static int ade7759_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
@@ -104,7 +104,7 @@ static int ade7759_spi_read_reg_40(struct device *dev,
u64 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -376,7 +376,7 @@ static ssize_t ade7759_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -463,7 +463,7 @@ static int __devinit ade7759_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -491,7 +491,7 @@ static int __devinit ade7759_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -507,7 +507,7 @@ static int ade7759_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
index 1e1faa0..0609046 100644
--- a/drivers/staging/iio/meter/ade7854-i2c.c
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_i2c_write_reg_8(struct device *dev,
@@ -20,7 +20,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev,
u8 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -39,7 +39,7 @@ static int ade7854_i2c_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -59,7 +59,7 @@ static int ade7854_i2c_write_reg_24(struct device *dev,
u32 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -80,7 +80,7 @@ static int ade7854_i2c_write_reg_32(struct device *dev,
u32 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -101,7 +101,7 @@ static int ade7854_i2c_read_reg_8(struct device *dev,
u16 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -127,7 +127,7 @@ static int ade7854_i2c_read_reg_16(struct device *dev,
u16 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -153,7 +153,7 @@ static int ade7854_i2c_read_reg_24(struct device *dev,
u16 reg_address,
u32 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -179,7 +179,7 @@ static int ade7854_i2c_read_reg_32(struct device *dev,
u16 reg_address,
u32 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -208,7 +208,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client,
struct ade7854_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
@@ -226,7 +226,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client,
ret = ade7854_probe(indio_dev, &client->dev);
if (ret)
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 8112186..9fb2f8b 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_spi_write_reg_8(struct device *dev,
@@ -21,7 +21,7 @@ static int ade7854_spi_write_reg_8(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -49,7 +49,7 @@ static int ade7854_spi_write_reg_16(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -78,7 +78,7 @@ static int ade7854_spi_write_reg_24(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -108,7 +108,7 @@ static int ade7854_spi_write_reg_32(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -138,7 +138,7 @@ static int ade7854_spi_read_reg_8(struct device *dev,
u8 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -180,7 +180,7 @@ static int ade7854_spi_read_reg_16(struct device *dev,
u16 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -221,7 +221,7 @@ static int ade7854_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -263,7 +263,7 @@ static int ade7854_spi_read_reg_32(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -306,7 +306,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi)
struct ade7854_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
@@ -325,7 +325,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi)
ret = ade7854_probe(indio_dev, &spi->dev);
if (ret)
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index 49c01c5..c642da8 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -17,8 +17,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7854.h"
@@ -28,7 +28,7 @@ static ssize_t ade7854_read_8bit(struct device *dev,
{
int ret;
u8 val = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -45,7 +45,7 @@ static ssize_t ade7854_read_16bit(struct device *dev,
{
int ret;
u16 val = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -62,7 +62,7 @@ static ssize_t ade7854_read_24bit(struct device *dev,
{
int ret;
u32 val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -80,7 +80,7 @@ static ssize_t ade7854_read_32bit(struct device *dev,
int ret;
u32 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
ret = st->read_reg_32(dev, this_attr->address, &val);
@@ -96,7 +96,7 @@ static ssize_t ade7854_write_8bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -117,7 +117,7 @@ static ssize_t ade7854_write_16bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -138,7 +138,7 @@ static ssize_t ade7854_write_24bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -159,7 +159,7 @@ static ssize_t ade7854_write_32bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -176,7 +176,7 @@ error_ret:
static int ade7854_reset(struct device *dev)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
u16 val;
@@ -425,7 +425,7 @@ static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit,
static int ade7854_set_irq(struct device *dev, bool enable)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -581,7 +581,7 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev)
error_unreg_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -590,7 +590,7 @@ EXPORT_SYMBOL(ade7854_probe);
int ade7854_remove(struct iio_dev *indio_dev)
{
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
index 6a3db14..23e1b5f4 100644
--- a/drivers/staging/iio/meter/meter.h
+++ b/drivers/staging/iio/meter/meter.h
@@ -1,4 +1,4 @@
-#include "../sysfs.h"
+#include <linux/iio/sysfs.h>
/* metering ic types of attribute */
diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c
index d8ce854..8b71eb0 100644
--- a/drivers/staging/iio/resolver/ad2s1200.c
+++ b/drivers/staging/iio/resolver/ad2s1200.c
@@ -19,8 +19,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad2s1200"
@@ -85,10 +85,12 @@ static const struct iio_chan_spec ad2s1200_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -110,7 +112,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi)
DRV_NAME, pins[pn]);
goto error_ret;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -140,7 +142,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
for (--pn; pn >= 0; pn--)
gpio_free(pins[pn]);
@@ -150,7 +152,7 @@ error_ret:
static int __devexit ad2s1200_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index c439fcf..f313859 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -18,8 +18,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad2s1210.h"
#define DRV_NAME "ad2s1210"
@@ -200,7 +200,7 @@ static ssize_t ad2s1210_store_softreset(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -214,7 +214,7 @@ static ssize_t ad2s1210_show_fclkin(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->fclkin);
}
@@ -223,7 +223,7 @@ static ssize_t ad2s1210_store_fclkin(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long fclkin;
int ret;
@@ -252,7 +252,7 @@ static ssize_t ad2s1210_show_fexcit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->fexcit);
}
@@ -260,7 +260,7 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long fexcit;
int ret;
@@ -287,7 +287,7 @@ static ssize_t ad2s1210_show_control(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
@@ -299,7 +299,7 @@ static ssize_t ad2s1210_store_control(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long udata;
unsigned char data;
int ret;
@@ -345,7 +345,7 @@ error_ret:
static ssize_t ad2s1210_show_resolution(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->resolution);
}
@@ -353,7 +353,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned char data;
unsigned long udata;
int ret;
@@ -403,7 +403,7 @@ error_ret:
static ssize_t ad2s1210_show_fault(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -418,7 +418,7 @@ static ssize_t ad2s1210_clear_fault(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -441,7 +441,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
int ret;
@@ -455,7 +455,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev,
static ssize_t ad2s1210_store_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long data;
int ret;
struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
@@ -580,10 +580,12 @@ static struct iio_chan_spec ad2s1210_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -688,7 +690,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi)
if (spi->dev.platform_data == NULL)
return -EINVAL;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -729,7 +731,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi)
error_free_gpios:
ad2s1210_free_gpios(st);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -740,7 +742,7 @@ static int __devexit ad2s1210_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
ad2s1210_free_gpios(iio_priv(indio_dev));
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
index 2a86f58..a805722 100644
--- a/drivers/staging/iio/resolver/ad2s90.c
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
struct ad2s90_state {
struct mutex lock;
@@ -55,6 +55,7 @@ static const struct iio_chan_spec ad2s90_chan = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
};
static int __devinit ad2s90_probe(struct spi_device *spi)
@@ -63,7 +64,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi)
struct ad2s90_state *st;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -92,7 +93,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -100,7 +101,7 @@ error_ret:
static int __devexit ad2s90_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index b9945ec..9358c6c 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -15,7 +15,7 @@
#include <linux/sched.h>
#include <linux/poll.h>
#include "ring_sw.h"
-#include "trigger.h"
+#include <linux/iio/trigger.h>
/**
* struct iio_sw_ring_buffer - software ring buffer
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index 7556e21..a5857aa 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -23,7 +23,7 @@
#ifndef _IIO_RING_SW_H_
#define _IIO_RING_SW_H_
-#include "buffer.h"
+#include <linux/iio/buffer.h>
struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
void iio_sw_rb_free(struct iio_buffer *ring);
diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h
deleted file mode 100644
index bfedb73..0000000
--- a/drivers/staging/iio/sysfs.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* The industrial I/O core
- *
- *Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- *
- * General attributes
- */
-
-#ifndef _INDUSTRIAL_IO_SYSFS_H_
-#define _INDUSTRIAL_IO_SYSFS_H_
-
-struct iio_chan_spec;
-
-/**
- * struct iio_dev_attr - iio specific device attribute
- * @dev_attr: underlying device attribute
- * @address: associated register address
- * @l: list head for maintaining list of dynamically created attrs.
- */
-struct iio_dev_attr {
- struct device_attribute dev_attr;
- u64 address;
- struct list_head l;
- struct iio_chan_spec const *c;
-};
-
-#define to_iio_dev_attr(_dev_attr) \
- container_of(_dev_attr, struct iio_dev_attr, dev_attr)
-
-ssize_t iio_read_const_attr(struct device *dev,
- struct device_attribute *attr,
- char *len);
-
-/**
- * struct iio_const_attr - constant device specific attribute
- * often used for things like available modes
- * @string: attribute string
- * @dev_attr: underlying device attribute
- */
-struct iio_const_attr {
- const char *string;
- struct device_attribute dev_attr;
-};
-
-#define to_iio_const_attr(_dev_attr) \
- container_of(_dev_attr, struct iio_const_attr, dev_attr)
-
-/* Some attributes will be hard coded (device dependent) and not require an
- address, in these cases pass a negative */
-#define IIO_ATTR(_name, _mode, _show, _store, _addr) \
- { .dev_attr = __ATTR(_name, _mode, _show, _store), \
- .address = _addr }
-
-#define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr) \
- struct iio_dev_attr iio_dev_attr_##_name \
- = IIO_ATTR(_name, _mode, _show, _store, _addr)
-
-#define IIO_DEVICE_ATTR_NAMED(_vname, _name, _mode, _show, _store, _addr) \
- struct iio_dev_attr iio_dev_attr_##_vname \
- = IIO_ATTR(_name, _mode, _show, _store, _addr)
-
-#define IIO_CONST_ATTR(_name, _string) \
- struct iio_const_attr iio_const_attr_##_name \
- = { .string = _string, \
- .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)}
-
-#define IIO_CONST_ATTR_NAMED(_vname, _name, _string) \
- struct iio_const_attr iio_const_attr_##_vname \
- = { .string = _string, \
- .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)}
-
-/* Generic attributes of onetype or another */
-/**
- * IIO_DEV_ATTR_RESET: resets the device
- **/
-#define IIO_DEV_ATTR_RESET(_store) \
- IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, _store, 0)
-
-/**
- * IIO_DEV_ATTR_SAMP_FREQ - sets any internal clock frequency
- * @_mode: sysfs file mode/permissions
- * @_show: output method for the attribute
- * @_store: input method for the attribute
- **/
-#define IIO_DEV_ATTR_SAMP_FREQ(_mode, _show, _store) \
- IIO_DEVICE_ATTR(sampling_frequency, _mode, _show, _store, 0)
-
-/**
- * IIO_DEV_ATTR_SAMP_FREQ_AVAIL - list available sampling frequencies
- * @_show: output method for the attribute
- *
- * May be mode dependent on some devices
- **/
-#define IIO_DEV_ATTR_SAMP_FREQ_AVAIL(_show) \
- IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, _show, NULL, 0)
-/**
- * IIO_CONST_ATTR_AVAIL_SAMP_FREQ - list available sampling frequencies
- * @_string: frequency string for the attribute
- *
- * Constant version
- **/
-#define IIO_CONST_ATTR_SAMP_FREQ_AVAIL(_string) \
- IIO_CONST_ATTR(sampling_frequency_available, _string)
-
-#define IIO_DEV_ATTR_TEMP_RAW(_show) \
- IIO_DEVICE_ATTR(in_temp_raw, S_IRUGO, _show, NULL, 0)
-
-#define IIO_CONST_ATTR_TEMP_OFFSET(_string) \
- IIO_CONST_ATTR(in_temp_offset, _string)
-
-#define IIO_CONST_ATTR_TEMP_SCALE(_string) \
- IIO_CONST_ATTR(in_temp_scale, _string)
-
-#endif /* _INDUSTRIAL_IO_SYSFS_H_ */
diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h
deleted file mode 100644
index 1cfca23..0000000
--- a/drivers/staging/iio/trigger.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* The industrial I/O core, trigger handling functions
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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/irq.h>
-#include <linux/module.h>
-
-#ifndef _IIO_TRIGGER_H_
-#define _IIO_TRIGGER_H_
-
-struct iio_subirq {
- bool enabled;
-};
-
-/**
- * struct iio_trigger_ops - operations structure for an iio_trigger.
- * @owner: used to monitor usage count of the trigger.
- * @set_trigger_state: switch on/off the trigger on demand
- * @try_reenable: function to reenable the trigger when the
- * use count is zero (may be NULL)
- * @validate_device: function to validate the device when the
- * current trigger gets changed.
- *
- * This is typically static const within a driver and shared by
- * instances of a given device.
- **/
-struct iio_trigger_ops {
- struct module *owner;
- int (*set_trigger_state)(struct iio_trigger *trig, bool state);
- int (*try_reenable)(struct iio_trigger *trig);
- int (*validate_device)(struct iio_trigger *trig,
- struct iio_dev *indio_dev);
-};
-
-
-/**
- * struct iio_trigger - industrial I/O trigger device
- *
- * @id: [INTERN] unique id number
- * @name: [DRIVER] unique name
- * @dev: [DRIVER] associated device (if relevant)
- * @private_data: [DRIVER] device specific data
- * @list: [INTERN] used in maintenance of global trigger list
- * @alloc_list: [DRIVER] used for driver specific trigger list
- * @use_count: use count for the trigger
- * @subirq_chip: [INTERN] associate 'virtual' irq chip.
- * @subirq_base: [INTERN] base number for irqs provided by trigger.
- * @subirqs: [INTERN] information about the 'child' irqs.
- * @pool: [INTERN] bitmap of irqs currently in use.
- * @pool_lock: [INTERN] protection of the irq pool.
- **/
-struct iio_trigger {
- const struct iio_trigger_ops *ops;
- int id;
- const char *name;
- struct device dev;
-
- void *private_data;
- struct list_head list;
- struct list_head alloc_list;
- int use_count;
-
- struct irq_chip subirq_chip;
- int subirq_base;
-
- struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
- unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
- struct mutex pool_lock;
-};
-
-
-static inline struct iio_trigger *to_iio_trigger(struct device *d)
-{
- return container_of(d, struct iio_trigger, dev);
-};
-
-static inline void iio_put_trigger(struct iio_trigger *trig)
-{
- module_put(trig->ops->owner);
- put_device(&trig->dev);
-};
-
-static inline void iio_get_trigger(struct iio_trigger *trig)
-{
- get_device(&trig->dev);
- __module_get(trig->ops->owner);
-};
-
-/**
- * iio_trigger_register() - register a trigger with the IIO core
- * @trig_info: trigger to be registered
- **/
-int iio_trigger_register(struct iio_trigger *trig_info);
-
-/**
- * iio_trigger_unregister() - unregister a trigger from the core
- * @trig_info: trigger to be unregistered
- **/
-void iio_trigger_unregister(struct iio_trigger *trig_info);
-
-/**
- * iio_trigger_poll() - called on a trigger occurring
- * @trig: trigger which occurred
- *
- * Typically called in relevant hardware interrupt handler.
- **/
-void iio_trigger_poll(struct iio_trigger *trig, s64 time);
-void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time);
-
-irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
-
-__printf(1, 2) struct iio_trigger *iio_allocate_trigger(const char *fmt, ...);
-void iio_free_trigger(struct iio_trigger *trig);
-
-#endif /* _IIO_TRIGGER_H_ */
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 665653d..f85734d 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -15,8 +15,8 @@
#include <asm/gptimers.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
struct bfin_timer {
unsigned short id, bit;
@@ -172,7 +172,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
st->timer_num = ret;
st->t = &iio_bfin_timer_code[st->timer_num];
- st->trig = iio_allocate_trigger("bfintmr%d", st->timer_num);
+ st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num);
if (!st->trig) {
ret = -ENOMEM;
goto out1;
@@ -203,7 +203,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
out4:
iio_trigger_unregister(st->trig);
out2:
- iio_put_trigger(st->trig);
+ iio_trigger_put(st->trig);
out1:
kfree(st);
out:
@@ -217,7 +217,7 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
disable_gptimers(st->t->bit);
free_irq(st->irq, st);
iio_trigger_unregister(st->trig);
- iio_put_trigger(st->trig);
+ iio_trigger_put(st->trig);
kfree(st);
return 0;
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index a346594..90b2684 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -22,8 +22,8 @@
#include <linux/gpio.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
static LIST_HEAD(iio_gpio_trigger_list);
static DEFINE_MUTEX(iio_gpio_trigger_list_lock);
@@ -72,7 +72,7 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev)
for (irq = irq_res->start; irq <= irq_res->end; irq++) {
- trig = iio_allocate_trigger("irqtrig%d", irq);
+ trig = iio_trigger_alloc("irqtrig%d", irq);
if (!trig) {
ret = -ENOMEM;
goto error_free_completed_registrations;
@@ -114,7 +114,7 @@ error_release_irq:
error_free_trig_info:
kfree(trig_info);
error_put_trigger:
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
error_free_completed_registrations:
/* The rest should have been added to the iio_gpio_trigger_list */
list_for_each_entry_safe(trig,
@@ -144,7 +144,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev)
iio_trigger_unregister(trig);
free_irq(trig_info->irq, trig);
kfree(trig_info);
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
}
mutex_unlock(&iio_gpio_trigger_list_lock);
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index a80cf67..9f2d055 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/rtc.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
static LIST_HEAD(iio_prtc_trigger_list);
static DEFINE_MUTEX(iio_prtc_trigger_list_lock);
@@ -112,7 +112,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
for (i = 0;; i++) {
if (pdata[i] == NULL)
break;
- trig = iio_allocate_trigger("periodic%s", pdata[i]);
+ trig = iio_trigger_alloc("periodic%s", pdata[i]);
if (!trig) {
ret = -ENOMEM;
goto error_free_completed_registrations;
@@ -152,7 +152,7 @@ error_free_trig_info:
kfree(trig_info);
error_put_trigger_and_remove_from_list:
list_del(&trig->alloc_list);
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
error_free_completed_registrations:
list_for_each_entry_safe(trig,
trig2,
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 174dc65..552763b 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -11,8 +11,8 @@
#include <linux/slab.h>
#include <linux/list.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
struct iio_sysfs_trig {
struct iio_trigger *trig;
@@ -139,7 +139,7 @@ static int iio_sysfs_trigger_probe(int id)
goto out1;
}
t->id = id;
- t->trig = iio_allocate_trigger("sysfstrig%d", id);
+ t->trig = iio_trigger_alloc("sysfstrig%d", id);
if (!t->trig) {
ret = -ENOMEM;
goto free_t;
@@ -158,7 +158,7 @@ static int iio_sysfs_trigger_probe(int id)
return 0;
out2:
- iio_put_trigger(t->trig);
+ iio_trigger_put(t->trig);
free_t:
kfree(t);
out1:
@@ -182,7 +182,7 @@ static int iio_sysfs_trigger_remove(int id)
}
iio_trigger_unregister(t->trig);
- iio_free_trigger(t->trig);
+ iio_trigger_free(t->trig);
list_del(&t->l);
kfree(t);
diff --git a/drivers/staging/iio/trigger_consumer.h b/drivers/staging/iio/trigger_consumer.h
deleted file mode 100644
index 60d64b3..0000000
--- a/drivers/staging/iio/trigger_consumer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* The industrial I/O core, trigger consumer functions
- *
- * Copyright (c) 2008-2011 Jonathan Cameron
- *
- * 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.
- */
-
-/**
- * struct iio_poll_func - poll function pair
- *
- * @indio_dev: data specific to device (passed into poll func)
- * @h: the function that is actually run on trigger
- * @thread: threaded interrupt part
- * @type: the type of interrupt (basically if oneshot)
- * @name: name used to identify the trigger consumer.
- * @irq: the corresponding irq as allocated from the
- * trigger pool
- * @timestamp: some devices need a timestamp grabbed as soon
- * as possible after the trigger - hence handler
- * passes it via here.
- **/
-struct iio_poll_func {
- struct iio_dev *indio_dev;
- irqreturn_t (*h)(int irq, void *p);
- irqreturn_t (*thread)(int irq, void *p);
- int type;
- char *name;
- int irq;
- s64 timestamp;
-};
-
-
-struct iio_poll_func
-*iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p),
- irqreturn_t (*thread)(int irq, void *p),
- int type,
- struct iio_dev *indio_dev,
- const char *fmt,
- ...);
-void iio_dealloc_pollfunc(struct iio_poll_func *pf);
-irqreturn_t iio_pollfunc_store_time(int irq, void *p);
-
-void iio_trigger_notify_done(struct iio_trigger *trig);
-
-/*
- * Two functions for common case where all that happens is a pollfunc
- * is attached and detached from a trigger
- */
-int iio_triggered_buffer_postenable(struct iio_dev *indio_dev);
-int iio_triggered_buffer_predisable(struct iio_dev *indio_dev);
diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h
deleted file mode 100644
index 0c32136..0000000
--- a/drivers/staging/iio/types.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* industrial I/O data types needed both in and out of kernel
- *
- * Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
- */
-
-#ifndef _IIO_TYPES_H_
-#define _IIO_TYPES_H_
-
-enum iio_chan_type {
- /* real channel types */
- IIO_VOLTAGE,
- IIO_CURRENT,
- IIO_POWER,
- IIO_ACCEL,
- IIO_ANGL_VEL,
- IIO_MAGN,
- IIO_LIGHT,
- IIO_INTENSITY,
- IIO_PROXIMITY,
- IIO_TEMP,
- IIO_INCLI,
- IIO_ROT,
- IIO_ANGL,
- IIO_TIMESTAMP,
- IIO_CAPACITANCE,
-};
-
-enum iio_modifier {
- IIO_NO_MOD,
- IIO_MOD_X,
- IIO_MOD_Y,
- IIO_MOD_Z,
- IIO_MOD_X_AND_Y,
- IIO_MOD_X_AND_Z,
- IIO_MOD_Y_AND_Z,
- IIO_MOD_X_AND_Y_AND_Z,
- IIO_MOD_X_OR_Y,
- IIO_MOD_X_OR_Z,
- IIO_MOD_Y_OR_Z,
- IIO_MOD_X_OR_Y_OR_Z,
- IIO_MOD_LIGHT_BOTH,
- IIO_MOD_LIGHT_IR,
-};
-
-#define IIO_VAL_INT 1
-#define IIO_VAL_INT_PLUS_MICRO 2
-#define IIO_VAL_INT_PLUS_NANO 3
-
-#endif /* _IIO_TYPES_H_ */
diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig
new file mode 100644
index 0000000..af32178
--- /dev/null
+++ b/drivers/staging/ipack/Kconfig
@@ -0,0 +1,20 @@
+#
+# IPACK configuration.
+#
+
+menuconfig IPACK_BUS
+ tristate "IndustryPack bus support"
+ ---help---
+ If you say Y here you get support for the IndustryPack Framework
+ for drivers for many types of boards that support this industrial
+ bus. The IndustryPack Framework is a virtual bus allowing to
+ communicate between carrier and mezzanine cards connected through
+ this bus.
+
+if IPACK_BUS
+
+source "drivers/staging/ipack/bridges/Kconfig"
+
+source "drivers/staging/ipack/devices/Kconfig"
+
+endif # IPACK
diff --git a/drivers/staging/ipack/Makefile b/drivers/staging/ipack/Makefile
new file mode 100644
index 0000000..85ff223
--- /dev/null
+++ b/drivers/staging/ipack/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the IPACK bridge device drivers.
+#
+obj-$(CONFIG_IPACK_BUS) += ipack.o
+obj-y += devices/
+obj-y += bridges/
diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO
new file mode 100644
index 0000000..3a45a53
--- /dev/null
+++ b/drivers/staging/ipack/TODO
@@ -0,0 +1,46 @@
+ TODO
+ ====
+Introduction
+============
+
+These drivers add support for IndustryPack devices: carrier and mezzanine
+boards.
+
+The ipack driver is just an abstraction of the bus providing the common
+operations between the two kind of boards.
+
+TODO
+====
+
+TPCI-200
+--------
+
+* It receives the name of the mezzanine plugged in each slot by SYSFS.
+ No autodetection supported yet, because the mezzanine driver could not be
+ loaded at the time that the tpci200 driver loads.
+
+* It has a linked list with the tpci200 devices it is managing. Get rid of it
+ and use driver_for_each_device() instead.
+
+IP-OCTAL
+--------
+
+* It has a linked list which saves the devices it is currently
+ managing. It should use the driver_for_each_device() function. It is not there
+ due to the impossibility of using container_of macro to recover the
+ corresponding "struct ipoctal" because the attribute "struct ipack_device" is
+ a pointer. This code should be refactored.
+
+Ipack
+-----
+
+* The structures and API exported can be improved a lot. For example, the
+ way to unregistering mezzanine devices, doing the mezzanine driver a call to
+ remove_device() to notify the carrier driver, or the opposite with the call to
+ the ipack_driver_ops' remove() function could be improved.
+
+
+Contact
+=======
+
+Contact: Samuel Iglesias Gonsalvez <siglesias@igalia.com> \ No newline at end of file
diff --git a/drivers/staging/ipack/bridges/Kconfig b/drivers/staging/ipack/bridges/Kconfig
new file mode 100644
index 0000000..97c837e
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Kconfig
@@ -0,0 +1,8 @@
+config BOARD_TPCI200
+ tristate "TEWS TPCI-200 support for IndustryPack bus"
+ depends on IPACK_BUS
+ depends on PCI
+ help
+ This driver supports the TEWS TPCI200 device for the IndustryPack bus.
+ default n
+
diff --git a/drivers/staging/ipack/bridges/Makefile b/drivers/staging/ipack/bridges/Makefile
new file mode 100644
index 0000000..d8b7645
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BOARD_TPCI200) += tpci200.o
diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c
new file mode 100644
index 0000000..ad28707
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.c
@@ -0,0 +1,1141 @@
+/**
+ * tpci200.c
+ *
+ * driver for the TEWS TPCI-200 device
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include "tpci200.h"
+
+static struct ipack_bus_ops tpci200_bus_ops;
+
+/* TPCI200 controls registers */
+static int control_reg[] = {
+ TPCI200_CONTROL_A_REG,
+ TPCI200_CONTROL_B_REG,
+ TPCI200_CONTROL_C_REG,
+ TPCI200_CONTROL_D_REG
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(tpci200_list);
+
+static int tpci200_slot_unregister(struct ipack_device *dev);
+
+static struct tpci200_board *check_slot(struct ipack_device *dev)
+{
+ struct tpci200_board *tpci200;
+ int found = 0;
+
+ if (dev == NULL) {
+ pr_info("Slot doesn't exist.\n");
+ return NULL;
+ }
+
+ list_for_each_entry(tpci200, &tpci200_list, list) {
+ if (tpci200->number == dev->bus_nr) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("Carrier not found\n");
+ return NULL;
+ }
+
+ if (dev->slot >= TPCI200_NB_SLOT) {
+ pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
+ dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
+ return NULL;
+ }
+
+ BUG_ON(tpci200->slots == NULL);
+ if (tpci200->slots[dev->slot].dev == NULL) {
+ pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr,
+ dev->slot);
+ return NULL;
+ }
+
+ return tpci200;
+}
+
+static inline unsigned char __tpci200_read8(void __iomem *address,
+ unsigned long offset)
+{
+ return ioread8(address + (offset^1));
+}
+
+static inline unsigned short __tpci200_read16(void __iomem *address,
+ unsigned long offset)
+{
+ return ioread16(address + offset);
+}
+
+static inline unsigned int __tpci200_read32(void __iomem *address,
+ unsigned long offset)
+{
+ return swahw32(ioread32(address + offset));
+}
+
+static inline void __tpci200_write8(unsigned char value,
+ void __iomem *address, unsigned long offset)
+{
+ iowrite8(value, address+(offset^1));
+}
+
+static inline void __tpci200_write16(unsigned short value,
+ void __iomem *address,
+ unsigned long offset)
+{
+ iowrite16(value, address+offset);
+}
+
+static inline void __tpci200_write32(unsigned int value,
+ void __iomem *address,
+ unsigned long offset)
+{
+ iowrite32(swahw32(value), address+offset);
+}
+
+static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
+ int space)
+{
+ struct ipack_addr_space *addr;
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ addr = &dev->io_space;
+ break;
+ case IPACK_ID_SPACE:
+ addr = &dev->id_space;
+ break;
+ case IPACK_MEM_SPACE:
+ addr = &dev->mem_space;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+ dev->bus_nr, dev->slot, space);
+ return NULL;
+ break;
+ }
+
+ if ((addr->size == 0) || (addr->address == NULL)) {
+ pr_err("Error, slot space not mapped !\n");
+ return NULL;
+ }
+
+ return addr;
+}
+
+static int tpci200_read8(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned char *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if (offset >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ *value = __tpci200_read8(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_read16(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned short *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+2) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+ *value = __tpci200_read16(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_read32(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned int *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+4) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ *value = __tpci200_read32(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write8(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned char value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if (offset >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write8(value, addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write16(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned short value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+2) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write16(value, addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write32(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned int value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+4) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write32(value, addr->address, offset);
+
+ return 0;
+}
+
+static void tpci200_unregister(struct tpci200_board *tpci200)
+{
+ int i;
+
+ free_irq(tpci200->info->pdev->irq, (void *) tpci200);
+
+ pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
+ pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
+ pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
+
+ pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+ pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+ pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
+
+ pci_disable_device(tpci200->info->pdev);
+ pci_dev_put(tpci200->info->pdev);
+
+ kfree(tpci200->info);
+
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ tpci200->slots[i].io_phys.address = NULL;
+ tpci200->slots[i].io_phys.size = 0;
+ tpci200->slots[i].id_phys.address = NULL;
+ tpci200->slots[i].id_phys.size = 0;
+ tpci200->slots[i].mem_phys.address = NULL;
+ tpci200->slots[i].mem_phys.size = 0;
+ }
+}
+
+static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
+{
+ struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
+ int i;
+ unsigned long flags;
+ unsigned short status_reg, reg_value;
+ unsigned short unhandled_ints = 0;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock_irqsave(&tpci200->info->access_lock, flags);
+
+ /* Read status register */
+ status_reg = readw(tpci200->info->interface_regs +
+ TPCI200_STATUS_REG);
+
+ if (status_reg & TPCI200_SLOT_INT_MASK) {
+ unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK;
+ /* callback to the IRQ handler for the corresponding slot */
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ if ((tpci200->slots[i].irq != NULL) &&
+ (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) {
+
+ ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg);
+
+ /* Dummy reads */
+ readw(tpci200->slots[i].dev->io_space.address +
+ 0xC0);
+ readw(tpci200->slots[i].dev->io_space.address +
+ 0xC2);
+
+ unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)));
+ }
+ }
+ }
+ /* Interrupt not handled are disabled */
+ if (unhandled_ints) {
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
+ pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
+ tpci200->number, i);
+ reg_value = readw(
+ tpci200->info->interface_regs +
+ control_reg[i]);
+ reg_value &=
+ ~(TPCI200_INT0_EN | TPCI200_INT1_EN);
+ writew(reg_value,
+ (tpci200->info->interface_regs +
+ control_reg[i]));
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&tpci200->info->access_lock, flags);
+ return ret;
+}
+
+#ifdef CONFIG_SYSFS
+
+static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number,
+ unsigned int slot_position)
+{
+ int found = 0;
+ struct ipack_device *dev;
+ struct tpci200_board *tpci200;
+
+ list_for_each_entry(tpci200, &tpci200_list, list) {
+ if (tpci200->number == tpci200_number) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("carrier board not found for the device\n");
+ return NULL;
+ }
+
+ if (slot_position >= TPCI200_NB_SLOT) {
+ pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number,
+ slot_position);
+ return NULL;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex))
+ return NULL;
+
+ if (tpci200->slots[slot_position].dev != NULL) {
+ pr_err("Slot [%d:%d] already installed !\n", tpci200_number,
+ slot_position);
+ goto err_unlock;
+ }
+
+ /*
+ * Give the same IRQ number as the slot number.
+ * The TPCI200 has assigned his own two IRQ by PCI bus driver
+ */
+ dev = ipack_device_register(tpci200->info->ipack_bus,
+ slot_position, slot_position);
+ if (dev == NULL) {
+ pr_info("Slot [%d:%d] Unable to register an ipack device\n",
+ tpci200_number, slot_position);
+ goto err_unlock;
+ }
+
+ tpci200->slots[slot_position].dev = dev;
+ mutex_unlock(&tpci200->mutex);
+ return dev;
+
+err_unlock:
+ mutex_unlock(&tpci200->mutex);
+ return NULL;
+}
+
+static ssize_t tpci200_store_board(struct device *pdev, const char *buf,
+ size_t count, int slot)
+{
+ struct tpci200_board *card = dev_get_drvdata(pdev);
+ struct ipack_device *dev = card->slots[slot].dev;
+
+ if (dev != NULL)
+ return -EBUSY;
+
+ dev = tpci200_slot_register(card->number, slot);
+ if (dev == NULL)
+ return -ENODEV;
+
+ return count;
+}
+
+static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot)
+{
+ struct tpci200_board *card = dev_get_drvdata(pdev);
+ struct ipack_device *dev = card->slots[slot].dev;
+
+ if (dev != NULL)
+ return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev));
+ else
+ return snprintf(buf, PAGE_SIZE, "none\n");
+}
+
+static ssize_t tpci200_show_description(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE,
+ "TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n");
+}
+
+static ssize_t tpci200_show_board_slot0(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 0);
+}
+
+static ssize_t tpci200_store_board_slot0(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 0);
+}
+
+static ssize_t tpci200_show_board_slot1(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 1);
+}
+
+static ssize_t tpci200_store_board_slot1(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 1);
+}
+
+static ssize_t tpci200_show_board_slot2(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 2);
+}
+
+static ssize_t tpci200_store_board_slot2(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 2);
+}
+
+
+static ssize_t tpci200_show_board_slot3(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 3);
+}
+
+static ssize_t tpci200_store_board_slot3(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 3);
+}
+
+/* Declaration of the device attributes for the TPCI200 */
+static DEVICE_ATTR(description, S_IRUGO,
+ tpci200_show_description, NULL);
+static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot0, tpci200_store_board_slot0);
+static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot1, tpci200_store_board_slot1);
+static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot2, tpci200_store_board_slot2);
+static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot3, tpci200_store_board_slot3);
+
+static struct attribute *tpci200_attrs[] = {
+ &dev_attr_description.attr,
+ &dev_attr_board_slot0.attr,
+ &dev_attr_board_slot1.attr,
+ &dev_attr_board_slot2.attr,
+ &dev_attr_board_slot3.attr,
+ NULL,
+};
+
+static struct attribute_group tpci200_attr_group = {
+ .attrs = tpci200_attrs,
+};
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+ return sysfs_create_group(&card->info->pdev->dev.kobj,
+ &tpci200_attr_group);
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+ sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group);
+}
+
+#else
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+ return 0;
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+}
+
+#endif /* CONFIG_SYSFS */
+
+static int tpci200_register(struct tpci200_board *tpci200)
+{
+ int i;
+ int res;
+ unsigned long ioidint_base;
+ unsigned long mem_base;
+ unsigned short slot_ctrl;
+
+ if (pci_enable_device(tpci200->info->pdev) < 0)
+ return -ENODEV;
+
+ if (tpci200_create_sysfs_files(tpci200) < 0) {
+ pr_err("failed creating sysfs files\n");
+ res = -EFAULT;
+ goto out_disable_pci;
+ }
+
+ /* Request IP interface register (Bar 2) */
+ res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
+ "Carrier IP interface registers");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_remove_sysfs;
+ }
+
+ /* Request IO ID INT space (Bar 3) */
+ res = pci_request_region(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR,
+ "Carrier IO ID INT space");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_release_ip_space;
+ }
+
+ /* Request MEM space (Bar 4) */
+ res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
+ "Carrier MEM space");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_release_ioid_int_space;
+ }
+
+ /* Map internal tpci200 driver user space */
+ tpci200->info->interface_regs =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_IP_INTERFACE_BAR),
+ TPCI200_IFACE_SIZE);
+ tpci200->info->ioidint_space =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR),
+ TPCI200_IOIDINT_SIZE);
+ tpci200->info->mem8_space =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_MEM8_SPACE_BAR),
+ TPCI200_MEM8_SIZE);
+
+ spin_lock_init(&tpci200->info->access_lock);
+ ioidint_base = pci_resource_start(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR);
+ mem_base = pci_resource_start(tpci200->info->pdev,
+ TPCI200_MEM8_SPACE_BAR);
+
+ /* Set the default parameters of the slot
+ * INT0 disabled, level sensitive
+ * INT1 disabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = 0;
+
+ /* Set all slot physical address space */
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ tpci200->slots[i].io_phys.address =
+ (void __iomem *)ioidint_base +
+ TPCI200_IO_SPACE_OFF + TPCI200_IO_SPACE_GAP*i;
+ tpci200->slots[i].io_phys.size = TPCI200_IO_SPACE_SIZE;
+
+ tpci200->slots[i].id_phys.address =
+ (void __iomem *)ioidint_base +
+ TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i;
+ tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE;
+
+ tpci200->slots[i].mem_phys.address =
+ (void __iomem *)mem_base + TPCI200_MEM8_GAP*i;
+ tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE;
+
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[i]));
+ }
+
+ res = request_irq(tpci200->info->pdev->irq,
+ tpci200_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, (void *) tpci200);
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ tpci200_unregister(tpci200);
+ goto out_err;
+ }
+
+ return 0;
+
+out_release_ioid_int_space:
+ pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+out_release_ip_space:
+ pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+out_remove_sysfs:
+ tpci200_remove_sysfs_files(tpci200);
+out_disable_pci:
+ pci_disable_device(tpci200->info->pdev);
+out_err:
+ return res;
+}
+
+static int __tpci200_request_irq(struct tpci200_board *tpci200,
+ struct ipack_device *dev)
+{
+ unsigned short slot_ctrl;
+
+ /* Set the default parameters of the slot
+ * INT0 enabled, level sensitive
+ * INT1 enabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN;
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[dev->slot]));
+
+ return 0;
+}
+
+static void __tpci200_free_irq(struct tpci200_board *tpci200,
+ struct ipack_device *dev)
+{
+ unsigned short slot_ctrl;
+
+ /* Set the default parameters of the slot
+ * INT0 disabled, level sensitive
+ * INT1 disabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = 0;
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[dev->slot]));
+}
+
+static int tpci200_free_irq(struct ipack_device *dev)
+{
+ int res;
+ struct slot_irq *slot_irq;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ if (tpci200->slots[dev->slot].irq == NULL) {
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ __tpci200_free_irq(tpci200, dev);
+ slot_irq = tpci200->slots[dev->slot].irq;
+ tpci200->slots[dev->slot].irq = NULL;
+ kfree(slot_irq);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
+{
+ int res;
+ struct ipack_addr_space *virt_addr_space;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ if (dev->io_space.address == NULL) {
+ pr_info("Slot [%d:%d] IO space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->io_space;
+ break;
+ case IPACK_ID_SPACE:
+ if (dev->id_space.address == NULL) {
+ pr_info("Slot [%d:%d] ID space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->id_space;
+ break;
+ case IPACK_MEM_SPACE:
+ if (dev->mem_space.address == NULL) {
+ pr_info("Slot [%d:%d] MEM space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->mem_space;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+ dev->bus_nr, dev->slot, space);
+ res = -EINVAL;
+ goto out_unlock;
+ break;
+ }
+
+ iounmap(virt_addr_space->address);
+
+ virt_addr_space->address = NULL;
+ virt_addr_space->size = 0;
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_slot_unregister(struct ipack_device *dev)
+{
+ struct tpci200_board *tpci200;
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ tpci200_free_irq(dev);
+
+ if (mutex_lock_interruptible(&tpci200->mutex))
+ return -ERESTARTSYS;
+
+ ipack_device_unregister(dev);
+ tpci200->slots[dev->slot].dev = NULL;
+ mutex_unlock(&tpci200->mutex);
+
+ return 0;
+}
+
+static int tpci200_slot_map_space(struct ipack_device *dev,
+ unsigned int memory_size, int space)
+{
+ int res;
+ unsigned int size_to_map;
+ void __iomem *phys_address;
+ struct ipack_addr_space *virt_addr_space;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ if (dev->io_space.address != NULL) {
+ pr_err("Slot [%d:%d] IO space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->io_space;
+
+ phys_address = tpci200->slots[dev->slot].io_phys.address;
+ size_to_map = tpci200->slots[dev->slot].io_phys.size;
+ break;
+ case IPACK_ID_SPACE:
+ if (dev->id_space.address != NULL) {
+ pr_err("Slot [%d:%d] ID space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->id_space;
+
+ phys_address = tpci200->slots[dev->slot].id_phys.address;
+ size_to_map = tpci200->slots[dev->slot].id_phys.size;
+ break;
+ case IPACK_MEM_SPACE:
+ if (dev->mem_space.address != NULL) {
+ pr_err("Slot [%d:%d] MEM space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->mem_space;
+
+ if (memory_size > tpci200->slots[dev->slot].mem_phys.size) {
+ pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n",
+ dev->bus_nr, dev->slot, memory_size,
+ tpci200->slots[dev->slot].mem_phys.size);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ phys_address = tpci200->slots[dev->slot].mem_phys.address;
+ size_to_map = memory_size;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space %d doesn't exist !\n",
+ tpci200->number, dev->slot, space);
+ res = -EINVAL;
+ goto out_unlock;
+ break;
+ }
+
+ virt_addr_space->size = size_to_map;
+ virt_addr_space->address =
+ ioremap((unsigned long)phys_address, size_to_map);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_request_irq(struct ipack_device *dev, int vector,
+ int (*handler)(void *), void *arg)
+{
+ int res;
+ struct slot_irq *slot_irq;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ if (tpci200->slots[dev->slot].irq != NULL) {
+ pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
+ dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
+ if (slot_irq == NULL) {
+ pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n",
+ dev->bus_nr, dev->slot);
+ res = -ENOMEM;
+ goto out_unlock;
+ }
+
+ /*
+ * WARNING: Setup Interrupt Vector in the IndustryPack device
+ * before an IRQ request.
+ * Read the User Manual of your IndustryPack device to know
+ * where to write the vector in memory.
+ */
+ slot_irq->vector = vector;
+ slot_irq->handler = handler;
+ slot_irq->arg = arg;
+ slot_irq->name = dev_name(&dev->dev);
+
+ tpci200->slots[dev->slot].irq = slot_irq;
+ res = __tpci200_request_irq(tpci200, dev);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static void tpci200_slot_remove(struct tpci200_slot *slot)
+{
+ if ((slot->dev == NULL) ||
+ (slot->dev->driver->ops->remove == NULL))
+ return;
+
+ slot->dev->driver->ops->remove(slot->dev);
+}
+
+static void tpci200_uninstall(struct tpci200_board *tpci200)
+{
+ int i;
+
+ for (i = 0; i < TPCI200_NB_SLOT; i++)
+ tpci200_slot_remove(&tpci200->slots[i]);
+
+ tpci200_unregister(tpci200);
+ kfree(tpci200->slots);
+}
+
+static struct ipack_bus_ops tpci200_bus_ops = {
+ .map_space = tpci200_slot_map_space,
+ .unmap_space = tpci200_slot_unmap_space,
+ .request_irq = tpci200_request_irq,
+ .free_irq = tpci200_free_irq,
+ .read8 = tpci200_read8,
+ .read16 = tpci200_read16,
+ .read32 = tpci200_read32,
+ .write8 = tpci200_write8,
+ .write16 = tpci200_write16,
+ .write32 = tpci200_write32,
+ .remove_device = tpci200_slot_unregister,
+};
+
+static int tpci200_install(struct tpci200_board *tpci200)
+{
+ int res;
+
+ tpci200->slots = kzalloc(
+ TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
+ if (tpci200->slots == NULL) {
+ res = -ENOMEM;
+ goto out_err;
+ }
+
+ res = tpci200_register(tpci200);
+ if (res)
+ goto out_free;
+
+ mutex_init(&tpci200->mutex);
+ return 0;
+
+out_free:
+ kfree(tpci200->slots);
+ tpci200->slots = NULL;
+out_err:
+ return res;
+}
+
+static int tpci200_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret;
+ struct tpci200_board *tpci200;
+
+ tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
+ if (!tpci200)
+ return -ENOMEM;
+
+ tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
+ if (!tpci200->info) {
+ kfree(tpci200);
+ return -ENOMEM;
+ }
+
+ /* Save struct pci_dev pointer */
+ tpci200->info->pdev = pdev;
+ tpci200->info->id_table = (struct pci_device_id *)id;
+
+ /* register the device and initialize it */
+ ret = tpci200_install(tpci200);
+ if (ret) {
+ pr_err("Error during tpci200 install !\n");
+ kfree(tpci200->info);
+ kfree(tpci200);
+ return -ENODEV;
+ }
+
+ /* Register the carrier in the industry pack bus driver */
+ tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
+ TPCI200_NB_SLOT,
+ &tpci200_bus_ops);
+ if (!tpci200->info->ipack_bus) {
+ pr_err("error registering the carrier on ipack driver\n");
+ tpci200_uninstall(tpci200);
+ kfree(tpci200->info);
+ kfree(tpci200);
+ return -EFAULT;
+ }
+
+ /* save the bus number given by ipack to logging purpose */
+ tpci200->number = tpci200->info->ipack_bus->bus_nr;
+ dev_set_drvdata(&pdev->dev, tpci200);
+ /* add the registered device in an internal linked list */
+ list_add_tail(&tpci200->list, &tpci200_list);
+ return ret;
+}
+
+static void __tpci200_pci_remove(struct tpci200_board *tpci200)
+{
+ tpci200_uninstall(tpci200);
+ tpci200_remove_sysfs_files(tpci200);
+ list_del(&tpci200->list);
+ ipack_bus_unregister(tpci200->info->ipack_bus);
+ kfree(tpci200->info);
+ kfree(tpci200);
+}
+
+static void __devexit tpci200_pci_remove(struct pci_dev *dev)
+{
+ struct tpci200_board *tpci200, *next;
+
+ /* Search the registered device to uninstall it */
+ list_for_each_entry_safe(tpci200, next, &tpci200_list, list) {
+ if (tpci200->info->pdev == dev) {
+ __tpci200_pci_remove(tpci200);
+ break;
+ }
+ }
+}
+
+static struct pci_device_id tpci200_idtable[2] = {
+ { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
+ TPCI200_SUBDEVICE_ID },
+ { 0, },
+};
+
+static struct pci_driver tpci200_pci_drv = {
+ .name = "tpci200",
+ .id_table = tpci200_idtable,
+ .probe = tpci200_pciprobe,
+ .remove = __devexit_p(tpci200_pci_remove),
+};
+
+static int __init tpci200_drvr_init_module(void)
+{
+ return pci_register_driver(&tpci200_pci_drv);
+}
+
+static void __exit tpci200_drvr_exit_module(void)
+{
+ struct tpci200_board *tpci200, *next;
+
+ list_for_each_entry_safe(tpci200, next, &tpci200_list, list)
+ __tpci200_pci_remove(tpci200);
+
+ pci_unregister_driver(&tpci200_pci_drv);
+}
+
+MODULE_DESCRIPTION("TEWS TPCI-200 device driver");
+MODULE_LICENSE("GPL");
+module_init(tpci200_drvr_init_module);
+module_exit(tpci200_drvr_exit_module);
diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h
new file mode 100644
index 0000000..0b547ee
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.h
@@ -0,0 +1,162 @@
+/**
+ * tpci200.h
+ *
+ * driver for the carrier TEWS TPCI-200
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#ifndef _TPCI200_H_
+#define _TPCI200_H_
+
+#include <linux/version.h>
+#include <linux/limits.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/swab.h>
+#include <linux/io.h>
+
+#include "../ipack.h"
+
+#define TPCI200_NB_SLOT 0x4
+#define TPCI200_NB_BAR 0x6
+
+#define TPCI200_VENDOR_ID 0x1498
+#define TPCI200_DEVICE_ID 0x30C8
+#define TPCI200_SUBVENDOR_ID 0x1498
+#define TPCI200_SUBDEVICE_ID 0x300A
+
+#define TPCI200_IP_INTERFACE_BAR 2
+#define TPCI200_IO_ID_INT_SPACES_BAR 3
+#define TPCI200_MEM16_SPACE_BAR 4
+#define TPCI200_MEM8_SPACE_BAR 5
+
+#define TPCI200_REVISION_REG 0x00
+#define TPCI200_CONTROL_A_REG 0x02
+#define TPCI200_CONTROL_B_REG 0x04
+#define TPCI200_CONTROL_C_REG 0x06
+#define TPCI200_CONTROL_D_REG 0x08
+#define TPCI200_RESET_REG 0x0A
+#define TPCI200_STATUS_REG 0x0C
+
+#define TPCI200_IFACE_SIZE 0x100
+
+#define TPCI200_IO_SPACE_OFF 0x0000
+#define TPCI200_IO_SPACE_GAP 0x0100
+#define TPCI200_IO_SPACE_SIZE 0x0080
+#define TPCI200_ID_SPACE_OFF 0x0080
+#define TPCI200_ID_SPACE_GAP 0x0100
+#define TPCI200_ID_SPACE_SIZE 0x0040
+#define TPCI200_INT_SPACE_OFF 0x00C0
+#define TPCI200_INT_SPACE_GAP 0x0100
+#define TPCI200_INT_SPACE_SIZE 0x0040
+#define TPCI200_IOIDINT_SIZE 0x0400
+
+#define TPCI200_MEM8_GAP 0x00400000
+#define TPCI200_MEM8_SIZE 0x00400000
+#define TPCI200_MEM16_GAP 0x00800000
+#define TPCI200_MEM16_SIZE 0x00800000
+
+#define TPCI200_INT0_EN 0x0040
+#define TPCI200_INT1_EN 0x0080
+#define TPCI200_INT0_EDGE 0x0010
+#define TPCI200_INT1_EDGE 0x0020
+#define TPCI200_ERR_INT_EN 0x0008
+#define TPCI200_TIME_INT_EN 0x0004
+#define TPCI200_RECOVER_EN 0x0002
+#define TPCI200_CLK32 0x0001
+
+#define TPCI200_A_RESET 0x0001
+#define TPCI200_B_RESET 0x0002
+#define TPCI200_C_RESET 0x0004
+#define TPCI200_D_RESET 0x0008
+
+#define TPCI200_A_TIMEOUT 0x1000
+#define TPCI200_B_TIMEOUT 0x2000
+#define TPCI200_C_TIMEOUT 0x4000
+#define TPCI200_D_TIMEOUT 0x8000
+
+#define TPCI200_A_ERROR 0x0100
+#define TPCI200_B_ERROR 0x0200
+#define TPCI200_C_ERROR 0x0400
+#define TPCI200_D_ERROR 0x0800
+
+#define TPCI200_A_INT0 0x0001
+#define TPCI200_A_INT1 0x0002
+#define TPCI200_B_INT0 0x0004
+#define TPCI200_B_INT1 0x0008
+#define TPCI200_C_INT0 0x0010
+#define TPCI200_C_INT1 0x0020
+#define TPCI200_D_INT0 0x0040
+#define TPCI200_D_INT1 0x0080
+
+#define TPCI200_SLOT_INT_MASK 0x00FF
+
+#define VME_IOID_SPACE "IOID"
+#define VME_MEM_SPACE "MEM"
+
+/**
+ * struct slot_irq - slot IRQ definition.
+ * @vector Vector number
+ * @handler Handler called when IRQ arrives
+ * @arg Handler argument
+ * @name IRQ name
+ *
+ */
+struct slot_irq {
+ int vector;
+ int (*handler)(void *);
+ void *arg;
+ const char *name;
+};
+
+/**
+ * struct tpci200_slot - data specific to the tpci200 slot.
+ * @slot_id Slot identification gived to external interface
+ * @irq Slot IRQ infos
+ * @io_phys IO physical base address register of the slot
+ * @id_phys ID physical base address register of the slot
+ * @mem_phys MEM physical base address register of the slot
+ *
+ */
+struct tpci200_slot {
+ struct ipack_device *dev;
+ struct slot_irq *irq;
+ struct ipack_addr_space io_phys;
+ struct ipack_addr_space id_phys;
+ struct ipack_addr_space mem_phys;
+};
+
+/**
+ * struct tpci200_infos - informations specific of the TPCI200 tpci200.
+ * @pci_dev PCI device
+ * @interface_regs Pointer to IP interface space (Bar 2)
+ * @ioidint_space Pointer to IP ID, IO and INT space (Bar 3)
+ * @mem8_space Pointer to MEM space (Bar 4)
+ * @access_lock Mutex lock for simultaneous access
+ *
+ */
+struct tpci200_infos {
+ struct pci_dev *pdev;
+ struct pci_device_id *id_table;
+ void __iomem *interface_regs;
+ void __iomem *ioidint_space;
+ void __iomem *mem8_space;
+ spinlock_t access_lock;
+ struct ipack_bus_device *ipack_bus;
+};
+struct tpci200_board {
+ struct list_head list;
+ unsigned int number;
+ struct mutex mutex;
+ struct tpci200_slot *slots;
+ struct tpci200_infos *info;
+};
+
+#endif /* _TPCI200_H_ */
diff --git a/drivers/staging/ipack/devices/Kconfig b/drivers/staging/ipack/devices/Kconfig
new file mode 100644
index 0000000..39f7188
--- /dev/null
+++ b/drivers/staging/ipack/devices/Kconfig
@@ -0,0 +1,7 @@
+config SERIAL_IPOCTAL
+ tristate "IndustryPack IP-OCTAL uart support"
+ depends on IPACK_BUS
+ help
+ This driver supports the IPOCTAL serial port device for the IndustryPack bus.
+ default n
+
diff --git a/drivers/staging/ipack/devices/Makefile b/drivers/staging/ipack/devices/Makefile
new file mode 100644
index 0000000..6de18bd
--- /dev/null
+++ b/drivers/staging/ipack/devices/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SERIAL_IPOCTAL) += ipoctal.o
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
new file mode 100644
index 0000000..29f6fa8
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -0,0 +1,901 @@
+/**
+ * ipoctal.c
+ *
+ * driver for the GE IP-OCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include "../ipack.h"
+#include "ipoctal.h"
+#include "scc2698.h"
+
+#define IP_OCTAL_MANUFACTURER_ID 0xF0
+#define IP_OCTAL_232_ID 0x22
+#define IP_OCTAL_422_ID 0x2A
+#define IP_OCTAL_485_ID 0x48
+
+#define IP_OCTAL_ID_SPACE_VECTOR 0x41
+#define IP_OCTAL_NB_BLOCKS 4
+
+static struct ipack_driver driver;
+static const struct tty_operations ipoctal_fops;
+
+struct ipoctal {
+ struct list_head list;
+ struct ipack_device *dev;
+ unsigned int board_id;
+ struct scc2698_channel *chan_regs;
+ struct scc2698_block *block_regs;
+ struct ipoctal_stats chan_stats[NR_CHANNELS];
+ char *buffer[NR_CHANNELS];
+ unsigned int nb_bytes[NR_CHANNELS];
+ unsigned int count_wr[NR_CHANNELS];
+ struct ipoctal_config chan_config[NR_CHANNELS];
+ wait_queue_head_t queue[NR_CHANNELS];
+ unsigned short error_flag[NR_CHANNELS];
+ spinlock_t lock[NR_CHANNELS];
+ unsigned int pointer_read[NR_CHANNELS];
+ unsigned int pointer_write[NR_CHANNELS];
+ atomic_t open[NR_CHANNELS];
+ unsigned char write;
+ struct tty_port tty_port[NR_CHANNELS];
+ struct tty_driver *tty_drv;
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(ipoctal_list);
+
+static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal,
+ unsigned char *dest,
+ unsigned char value)
+{
+ unsigned long offset;
+
+ offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address;
+ ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset,
+ value);
+}
+
+static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal,
+ unsigned char *dest,
+ unsigned char value)
+{
+ ipoctal_write_io_reg(ipoctal, dest, value);
+}
+
+static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal,
+ unsigned char *src)
+{
+ unsigned long offset;
+ unsigned char value;
+
+ offset = ((void __iomem *) src) - ipoctal->dev->io_space.address;
+ ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset,
+ &value);
+ return value;
+}
+
+static struct ipoctal *ipoctal_find_board(struct tty_struct *tty)
+{
+ struct ipoctal *p;
+
+ list_for_each_entry(p, &ipoctal_list, list) {
+ if (tty->driver->major == p->tty_drv->major)
+ return p;
+ }
+
+ return NULL;
+}
+
+static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct ipoctal *ipoctal;
+ int channel = tty->index;
+
+ ipoctal = ipoctal_find_board(tty);
+
+ if (ipoctal == NULL) {
+ pr_err("Device not found. Major %d\n", tty->driver->major);
+ return -ENODEV;
+ }
+
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+ tty->driver_data = ipoctal;
+
+ return 0;
+}
+
+static int ipoctal_open(struct tty_struct *tty, struct file *file)
+{
+ int channel = tty->index;
+ int res;
+ struct ipoctal *ipoctal;
+
+ ipoctal = ipoctal_find_board(tty);
+
+ if (ipoctal == NULL) {
+ pr_err("Device not found. Major %d\n", tty->driver->major);
+ return -ENODEV;
+ }
+
+ if (atomic_read(&ipoctal->open[channel]))
+ return -EBUSY;
+
+ res = tty_port_open(&ipoctal->tty_port[channel], tty, file);
+ if (res)
+ return res;
+
+ atomic_inc(&ipoctal->open[channel]);
+ return 0;
+}
+
+static void ipoctal_reset_stats(struct ipoctal_stats *stats)
+{
+ stats->tx = 0;
+ stats->rx = 0;
+ stats->rcv_break = 0;
+ stats->framing_err = 0;
+ stats->overrun_err = 0;
+ stats->parity_err = 0;
+}
+
+static void ipoctal_free_channel(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ if (ipoctal == NULL)
+ return;
+
+ ipoctal_reset_stats(&ipoctal->chan_stats[channel]);
+ ipoctal->pointer_read[channel] = 0;
+ ipoctal->pointer_write[channel] = 0;
+ ipoctal->nb_bytes[channel] = 0;
+}
+
+static void ipoctal_close(struct tty_struct *tty, struct file *filp)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ tty_port_close(&ipoctal->tty_port[channel], tty, filp);
+
+ if (atomic_dec_and_test(&ipoctal->open[channel]))
+ ipoctal_free_channel(tty);
+}
+
+static int ipoctal_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct ipoctal *ipoctal = tty->driver_data;
+ int channel = tty->index;
+
+ icount->cts = 0;
+ icount->dsr = 0;
+ icount->rng = 0;
+ icount->dcd = 0;
+ icount->rx = ipoctal->chan_stats[channel].rx;
+ icount->tx = ipoctal->chan_stats[channel].tx;
+ icount->frame = ipoctal->chan_stats[channel].framing_err;
+ icount->parity = ipoctal->chan_stats[channel].parity_err;
+ icount->brk = ipoctal->chan_stats[channel].rcv_break;
+ return 0;
+}
+
+static int ipoctal_irq_handler(void *arg)
+{
+ unsigned int channel;
+ unsigned int block;
+ unsigned char isr;
+ unsigned char sr;
+ unsigned char isr_tx_rdy, isr_rx_rdy;
+ unsigned char value;
+ unsigned char flag;
+ struct tty_struct *tty;
+ struct ipoctal *ipoctal = (struct ipoctal *) arg;
+
+ /* Check all channels */
+ for (channel = 0; channel < NR_CHANNELS; channel++) {
+ /* If there is no client, skip the check */
+ if (!atomic_read(&ipoctal->open[channel]))
+ continue;
+
+ tty = tty_port_tty_get(&ipoctal->tty_port[channel]);
+ if (!tty)
+ continue;
+
+ /*
+ * The HW is organized in pair of channels.
+ * See which register we need to read from
+ */
+ block = channel / 2;
+ isr = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->block_regs[block].u.r.isr);
+ sr = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.r.sr);
+
+ if ((channel % 2) == 1) {
+ isr_tx_rdy = isr & ISR_TxRDY_B;
+ isr_rx_rdy = isr & ISR_RxRDY_FFULL_B;
+ } else {
+ isr_tx_rdy = isr & ISR_TxRDY_A;
+ isr_rx_rdy = isr & ISR_RxRDY_FFULL_A;
+ }
+
+ /* In case of RS-485, change from TX to RX when finishing TX.
+ * Half-duplex.
+ */
+ if ((ipoctal->board_id == IP_OCTAL_485_ID) &&
+ (sr & SR_TX_EMPTY) &&
+ (ipoctal->nb_bytes[channel] == 0)) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_NEGATE_RTSN);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+ ipoctal->write = 1;
+ wake_up_interruptible(&ipoctal->queue[channel]);
+ }
+
+ /* RX data */
+ if (isr_rx_rdy && (sr & SR_RX_READY)) {
+ value = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.r.rhr);
+ flag = TTY_NORMAL;
+
+ /* Error: count statistics */
+ if (sr & SR_ERROR) {
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+
+ if (sr & SR_OVERRUN_ERROR) {
+ ipoctal->error_flag[channel] |= UART_OVERRUN;
+ ipoctal->chan_stats[channel].overrun_err++;
+ /* Overrun doesn't affect the current character*/
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ if (sr & SR_PARITY_ERROR) {
+ ipoctal->error_flag[channel] |= UART_PARITY;
+ ipoctal->chan_stats[channel].parity_err++;
+ flag = TTY_PARITY;
+ }
+ if (sr & SR_FRAMING_ERROR) {
+ ipoctal->error_flag[channel] |= UART_FRAMING;
+ ipoctal->chan_stats[channel].framing_err++;
+ flag = TTY_FRAME;
+ }
+ if (sr & SR_RECEIVED_BREAK) {
+ ipoctal->error_flag[channel] |= UART_BREAK;
+ ipoctal->chan_stats[channel].rcv_break++;
+ flag = TTY_BREAK;
+ }
+ }
+
+ tty_insert_flip_char(tty, value, flag);
+ }
+
+ /* TX of each character */
+ if (isr_tx_rdy && (sr & SR_TX_READY)) {
+ unsigned int *pointer_write =
+ &ipoctal->pointer_write[channel];
+
+ if (ipoctal->nb_bytes[channel] <= 0) {
+ ipoctal->nb_bytes[channel] = 0;
+ continue;
+ }
+ spin_lock(&ipoctal->lock[channel]);
+ value = ipoctal->buffer[channel][*pointer_write];
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.thr,
+ value);
+ ipoctal->chan_stats[channel].tx++;
+ ipoctal->count_wr[channel]++;
+ (*pointer_write)++;
+ *pointer_write = *pointer_write % PAGE_SIZE;
+ ipoctal->nb_bytes[channel]--;
+ spin_unlock(&ipoctal->lock[channel]);
+
+ if ((ipoctal->nb_bytes[channel] == 0) &&
+ (waitqueue_active(&ipoctal->queue[channel]))) {
+
+ if (ipoctal->board_id != IP_OCTAL_485_ID) {
+ ipoctal->write = 1;
+ wake_up_interruptible(&ipoctal->queue[channel]);
+ }
+ }
+ }
+
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+ return IRQ_HANDLED;
+}
+
+static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id)
+{
+ unsigned char manufacturerID;
+ unsigned char board_id;
+
+ dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+ IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID);
+ if (manufacturerID != IP_OCTAL_MANUFACTURER_ID)
+ return -ENODEV;
+
+ dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+ IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id);
+
+ switch (board_id) {
+ case IP_OCTAL_232_ID:
+ case IP_OCTAL_422_ID:
+ case IP_OCTAL_485_ID:
+ *id = board_id;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct tty_port_operations ipoctal_tty_port_ops = {
+ .dtr_rts = NULL,
+ .activate = ipoctal_port_activate,
+};
+
+static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
+ unsigned int slot, unsigned int vector)
+{
+ int res = 0;
+ int i;
+ struct tty_driver *tty;
+ char name[20];
+ unsigned char board_id;
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+ IPACK_ID_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot);
+ return res;
+ }
+
+ res = ipoctal_check_model(ipoctal->dev, &board_id);
+ if (res) {
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev,
+ IPACK_ID_SPACE);
+ goto out_unregister_id_space;
+ }
+ ipoctal->board_id = board_id;
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+ IPACK_IO_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot);
+ goto out_unregister_id_space;
+ }
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev,
+ 0x8000, IPACK_MEM_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot);
+ goto out_unregister_io_space;
+ }
+
+ /* Save the virtual address to access the registers easily */
+ ipoctal->chan_regs =
+ (struct scc2698_channel *) ipoctal->dev->io_space.address;
+ ipoctal->block_regs =
+ (struct scc2698_block *) ipoctal->dev->io_space.address;
+
+ /* Disable RX and TX before touching anything */
+ for (i = 0; i < NR_CHANNELS ; i++) {
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ }
+
+ for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.acr,
+ ACR_BRG_SET2);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.opcr,
+ OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN |
+ OPCR_MPOb_RTSN);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.imr,
+ IMR_TxRDY_A | IMR_RxRDY_FFULL_A |
+ IMR_DELTA_BREAK_A | IMR_TxRDY_B |
+ IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B);
+ }
+
+ /*
+ * IP-OCTAL has different addresses to copy its IRQ vector.
+ * Depending of the carrier these addresses are accesible or not.
+ * More info in the datasheet.
+ */
+ ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector,
+ ipoctal_irq_handler, ipoctal);
+ ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_ID_SPACE, 0, vector);
+
+ /* Register the TTY device */
+
+ /* Each IP-OCTAL channel is a TTY port */
+ tty = alloc_tty_driver(NR_CHANNELS);
+
+ if (!tty) {
+ res = -ENOMEM;
+ goto out_unregister_slot_unmap;
+ }
+
+ /* Fill struct tty_driver with ipoctal data */
+ tty->owner = THIS_MODULE;
+ tty->driver_name = "ipoctal";
+ sprintf(name, "ipoctal.%d.%d.", bus_nr, slot);
+ tty->name = name;
+ tty->major = 0;
+
+ tty->minor_start = 0;
+ tty->type = TTY_DRIVER_TYPE_SERIAL;
+ tty->subtype = SERIAL_TYPE_NORMAL;
+ tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty->init_termios = tty_std_termios;
+ tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->init_termios.c_ispeed = 9600;
+ tty->init_termios.c_ospeed = 9600;
+
+ tty_set_operations(tty, &ipoctal_fops);
+ res = tty_register_driver(tty);
+ if (res) {
+ pr_err("Can't register tty driver.\n");
+ put_tty_driver(tty);
+ goto out_unregister_slot_unmap;
+ }
+
+ /* Save struct tty_driver for use it when uninstalling the device */
+ ipoctal->tty_drv = tty;
+
+ for (i = 0; i < NR_CHANNELS; i++) {
+ tty_port_init(&ipoctal->tty_port[i]);
+ tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]);
+ ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops;
+
+ ipoctal_reset_stats(&ipoctal->chan_stats[i]);
+ ipoctal->nb_bytes[i] = 0;
+ init_waitqueue_head(&ipoctal->queue[i]);
+ ipoctal->error_flag[i] = UART_NOERROR;
+
+ spin_lock_init(&ipoctal->lock[i]);
+ ipoctal->pointer_read[i] = 0;
+ ipoctal->pointer_write[i] = 0;
+ ipoctal->nb_bytes[i] = 0;
+ tty_register_device(tty, i, NULL);
+
+ /*
+ * Enable again the RX. TX will be enabled when
+ * there is something to send
+ */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+ CR_ENABLE_RX);
+ }
+
+ return 0;
+
+out_unregister_slot_unmap:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE);
+out_unregister_io_space:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE);
+out_unregister_id_space:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE);
+ return res;
+}
+
+static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal,
+ unsigned int channel,
+ const unsigned char *buf,
+ int count)
+{
+ unsigned long flags;
+ int i;
+ unsigned int *pointer_read = &ipoctal->pointer_read[channel];
+
+ /* Copy the bytes from the user buffer to the internal one */
+ for (i = 0; i < count; i++) {
+ if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) {
+ spin_lock_irqsave(&ipoctal->lock[channel], flags);
+ ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i];
+ *pointer_read = (*pointer_read + 1) % PAGE_SIZE;
+ ipoctal->nb_bytes[channel]++;
+ spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+ } else {
+ break;
+ }
+ }
+ return i;
+}
+
+static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel,
+ const unsigned char *buf, int count)
+{
+ ipoctal->nb_bytes[channel] = 0;
+ ipoctal->count_wr[channel] = 0;
+
+ ipoctal_copy_write_buffer(ipoctal, channel, buf, count);
+
+ ipoctal->error_flag[channel] = UART_NOERROR;
+
+ /* As the IP-OCTAL 485 only supports half duplex, do it manually */
+ if (ipoctal->board_id == IP_OCTAL_485_ID) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX);
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_ASSERT_RTSN);
+ }
+
+ /*
+ * Send a packet and then disable TX to avoid failure after several send
+ * operations
+ */
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_TX);
+ wait_event_interruptible(ipoctal->queue[channel], ipoctal->write);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_TX);
+
+ ipoctal->write = 0;
+ return ipoctal->count_wr[channel];
+}
+
+static int ipoctal_write_tty(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ unsigned int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return ipoctal_write(ipoctal, channel, buf, count);
+}
+
+static int ipoctal_write_room(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return PAGE_SIZE - ipoctal->nb_bytes[channel];
+}
+
+static int ipoctal_chars_in_buffer(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return ipoctal->nb_bytes[channel];
+}
+
+static void ipoctal_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
+{
+ unsigned int cflag;
+ unsigned char mr1 = 0;
+ unsigned char mr2 = 0;
+ unsigned char csr = 0;
+ unsigned int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+ speed_t baud;
+
+ cflag = tty->termios->c_cflag;
+
+ /* Disable and reset everything before change the setup */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_RX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_MR);
+
+ /* Set Bits per chars */
+ switch (cflag & CSIZE) {
+ case CS6:
+ mr1 |= MR1_CHRL_6_BITS;
+ break;
+ case CS7:
+ mr1 |= MR1_CHRL_7_BITS;
+ break;
+ case CS8:
+ default:
+ mr1 |= MR1_CHRL_8_BITS;
+ /* By default, select CS8 */
+ tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+ break;
+ }
+
+ /* Set Parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD;
+ else
+ mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN;
+ else
+ mr1 |= MR1_PARITY_OFF;
+
+ /* Mark or space parity is not supported */
+ tty->termios->c_cflag &= ~CMSPAR;
+
+ /* Set stop bits */
+ if (cflag & CSTOPB)
+ mr2 |= MR2_STOP_BITS_LENGTH_2;
+ else
+ mr2 |= MR2_STOP_BITS_LENGTH_1;
+
+ /* Set the flow control */
+ switch (ipoctal->board_id) {
+ case IP_OCTAL_232_ID:
+ if (cflag & CRTSCTS) {
+ mr1 |= MR1_RxRTS_CONTROL_ON;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON;
+ ipoctal->chan_config[channel].flow_control = 1;
+ } else {
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ }
+ break;
+ case IP_OCTAL_422_ID:
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ break;
+ case IP_OCTAL_485_ID:
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ baud = tty_get_baud_rate(tty);
+ tty_termios_encode_baud_rate(tty->termios, baud, baud);
+
+ /* Set baud rate */
+ switch (tty->termios->c_ospeed) {
+ case 75:
+ csr |= TX_CLK_75 | RX_CLK_75;
+ break;
+ case 110:
+ csr |= TX_CLK_110 | RX_CLK_110;
+ break;
+ case 150:
+ csr |= TX_CLK_150 | RX_CLK_150;
+ break;
+ case 300:
+ csr |= TX_CLK_300 | RX_CLK_300;
+ break;
+ case 600:
+ csr |= TX_CLK_600 | RX_CLK_600;
+ break;
+ case 1200:
+ csr |= TX_CLK_1200 | RX_CLK_1200;
+ break;
+ case 1800:
+ csr |= TX_CLK_1800 | RX_CLK_1800;
+ break;
+ case 2000:
+ csr |= TX_CLK_2000 | RX_CLK_2000;
+ break;
+ case 2400:
+ csr |= TX_CLK_2400 | RX_CLK_2400;
+ break;
+ case 4800:
+ csr |= TX_CLK_4800 | RX_CLK_4800;
+ break;
+ case 9600:
+ csr |= TX_CLK_9600 | RX_CLK_9600;
+ break;
+ case 19200:
+ csr |= TX_CLK_19200 | RX_CLK_19200;
+ break;
+ case 38400:
+ default:
+ csr |= TX_CLK_38400 | RX_CLK_38400;
+ /* In case of default, we establish 38400 bps */
+ tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
+ break;
+ }
+
+ mr1 |= MR1_ERROR_CHAR;
+ mr1 |= MR1_RxINT_RxRDY;
+
+ /* Write the control registers */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1);
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2);
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr);
+
+ /* save the setup in the structure */
+ ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty);
+ ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE;
+ ipoctal->chan_config[channel].parity = cflag & PARENB;
+ ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB;
+
+ /* Enable again the RX */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+}
+
+static void ipoctal_hangup(struct tty_struct *tty)
+{
+ unsigned long flags;
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ if (ipoctal == NULL)
+ return;
+
+ spin_lock_irqsave(&ipoctal->lock[channel], flags);
+ ipoctal->nb_bytes[channel] = 0;
+ ipoctal->pointer_read[channel] = 0;
+ ipoctal->pointer_write[channel] = 0;
+ spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+
+ tty_port_hangup(&ipoctal->tty_port[channel]);
+
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_RX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_MR);
+
+ clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags);
+ wake_up_interruptible(&ipoctal->tty_port[channel].open_wait);
+}
+
+static const struct tty_operations ipoctal_fops = {
+ .ioctl = NULL,
+ .open = ipoctal_open,
+ .close = ipoctal_close,
+ .write = ipoctal_write_tty,
+ .set_termios = ipoctal_set_termios,
+ .write_room = ipoctal_write_room,
+ .chars_in_buffer = ipoctal_chars_in_buffer,
+ .get_icount = ipoctal_get_icount,
+ .hangup = ipoctal_hangup,
+};
+
+static int ipoctal_match(struct ipack_device *dev)
+{
+ int res;
+ unsigned char board_id;
+
+ if ((!dev->bus->ops) || (!dev->bus->ops->map_space) ||
+ (!dev->bus->ops->unmap_space))
+ return 0;
+
+ res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
+ if (res)
+ return 0;
+
+ res = ipoctal_check_model(dev, &board_id);
+ dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
+ if (!res)
+ return 1;
+
+ return 0;
+}
+
+static int ipoctal_probe(struct ipack_device *dev)
+{
+ int res;
+ struct ipoctal *ipoctal;
+
+ ipoctal = kzalloc(sizeof(struct ipoctal), GFP_KERNEL);
+ if (ipoctal == NULL)
+ return -ENOMEM;
+
+ ipoctal->dev = dev;
+ res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq);
+ if (res)
+ goto out_uninst;
+
+ list_add_tail(&ipoctal->list, &ipoctal_list);
+ return 0;
+
+out_uninst:
+ kfree(ipoctal);
+ return res;
+}
+
+static void __ipoctal_remove(struct ipoctal *ipoctal)
+{
+ int i;
+
+ for (i = 0; i < NR_CHANNELS; i++) {
+ tty_unregister_device(ipoctal->tty_drv, i);
+ tty_port_free_xmit_buf(&ipoctal->tty_port[i]);
+ }
+
+ tty_unregister_driver(ipoctal->tty_drv);
+ put_tty_driver(ipoctal->tty_drv);
+
+ /* Tell the carrier board to free all the resources for this device */
+ if (ipoctal->dev->bus->ops->remove_device != NULL)
+ ipoctal->dev->bus->ops->remove_device(ipoctal->dev);
+
+ list_del(&ipoctal->list);
+ kfree(ipoctal);
+}
+
+static void ipoctal_remove(struct ipack_device *device)
+{
+ struct ipoctal *ipoctal, *next;
+
+ list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) {
+ if (ipoctal->dev == device)
+ __ipoctal_remove(ipoctal);
+ }
+}
+
+static struct ipack_driver_ops ipoctal_drv_ops = {
+ .match = ipoctal_match,
+ .probe = ipoctal_probe,
+ .remove = ipoctal_remove,
+};
+
+static int __init ipoctal_init(void)
+{
+ driver.ops = &ipoctal_drv_ops;
+ return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME);
+}
+
+static void __exit ipoctal_exit(void)
+{
+ struct ipoctal *p, *next;
+
+ list_for_each_entry_safe(p, next, &ipoctal_list, list)
+ __ipoctal_remove(p);
+
+ ipack_driver_unregister(&driver);
+}
+
+MODULE_DESCRIPTION("IP-Octal 232, 422 and 485 device driver");
+MODULE_LICENSE("GPL");
+
+module_init(ipoctal_init);
+module_exit(ipoctal_exit);
diff --git a/drivers/staging/ipack/devices/ipoctal.h b/drivers/staging/ipack/devices/ipoctal.h
new file mode 100644
index 0000000..266f361
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.h
@@ -0,0 +1,80 @@
+/**
+ * ipoctal.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#ifndef _IPOCTAL_H
+#define _IPOCTAL_H_
+
+#define NR_CHANNELS 8
+#define IPOCTAL_MAX_BOARDS 16
+#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS)
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/**
+ * enum uart_parity_e - UART supported parity.
+ */
+enum uart_parity_e {
+ UART_NONE = 0,
+ UART_ODD = 1,
+ UART_EVEN = 2,
+};
+
+/**
+ * enum uart_error - UART error type
+ *
+ */
+enum uart_error {
+ UART_NOERROR = 0, /* No error during transmission */
+ UART_TIMEOUT = 1 << 0, /* Timeout error */
+ UART_OVERRUN = 1 << 1, /* Overrun error */
+ UART_PARITY = 1 << 2, /* Parity error */
+ UART_FRAMING = 1 << 3, /* Framing error */
+ UART_BREAK = 1 << 4, /* Received break */
+};
+
+/**
+ * struct ipoctal_config - Serial configuration
+ *
+ * @baud: Baud rate
+ * @stop_bits: Stop bits (1 or 2)
+ * @bits_per_char: data size in bits
+ * @parity
+ * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled)
+ */
+struct ipoctal_config {
+ unsigned int baud;
+ unsigned int stop_bits;
+ unsigned int bits_per_char;
+ unsigned short parity;
+ unsigned int flow_control;
+};
+
+/**
+ * struct ipoctal_stats -- Stats since last reset
+ *
+ * @tx: Number of transmitted bytes
+ * @rx: Number of received bytes
+ * @overrun: Number of overrun errors
+ * @parity_err: Number of parity errors
+ * @framing_err: Number of framing errors
+ * @rcv_break: Number of break received
+ */
+struct ipoctal_stats {
+ unsigned long tx;
+ unsigned long rx;
+ unsigned long overrun_err;
+ unsigned long parity_err;
+ unsigned long framing_err;
+ unsigned long rcv_break;
+};
+
+#endif /* _IPOCTAL_H_ */
diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h
new file mode 100644
index 0000000..47f6269
--- /dev/null
+++ b/drivers/staging/ipack/devices/scc2698.h
@@ -0,0 +1,228 @@
+/*
+ * scc2698.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#ifndef SCC2698_H_
+#define SCC2698_H_
+
+/*
+ * struct scc2698_channel - Channel access to scc2698 IO
+ *
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_channel {
+ union {
+ struct {
+ unsigned char d0, mr; /* Mode register 1/2*/
+ unsigned char d1, sr; /* Status register */
+ unsigned char d2, r1; /* reserved */
+ unsigned char d3, rhr; /* Receive holding register (R) */
+ unsigned char junk[8]; /* other crap for block control */
+ } r; /* Read access */
+ struct {
+ unsigned char d0, mr; /* Mode register 1/2 */
+ unsigned char d1, csr; /* Clock select register */
+ unsigned char d2, cr; /* Command register */
+ unsigned char d3, thr; /* Transmit holding register */
+ unsigned char junk[8]; /* other crap for block control */
+ } w; /* Write access */
+ } u;
+};
+
+/*
+ * struct scc2698_block - Block access to scc2698 IO
+ *
+ * The scc2698 contain 4 block.
+ * Each block containt two channel a and b.
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_block {
+ union {
+ struct {
+ unsigned char d0, mra; /* Mode register 1/2 (a) */
+ unsigned char d1, sra; /* Status register (a) */
+ unsigned char d2, r1; /* reserved */
+ unsigned char d3, rhra; /* Receive holding register (a) */
+ unsigned char d4, ipcr; /* Input port change register of block */
+ unsigned char d5, isr; /* Interrupt status register of block */
+ unsigned char d6, ctur; /* Counter timer upper register of block */
+ unsigned char d7, ctlr; /* Counter timer lower register of block */
+ unsigned char d8, mrb; /* Mode register 1/2 (b) */
+ unsigned char d9, srb; /* Status register (b) */
+ unsigned char da, r2; /* reserved */
+ unsigned char db, rhrb; /* Receive holding register (b) */
+ unsigned char dc, r3; /* reserved */
+ unsigned char dd, ip; /* Input port register of block */
+ unsigned char de, ctg; /* Start counter timer of block */
+ unsigned char df, cts; /* Stop counter timer of block */
+ } r; /* Read access */
+ struct {
+ unsigned char d0, mra; /* Mode register 1/2 (a) */
+ unsigned char d1, csra; /* Clock select register (a) */
+ unsigned char d2, cra; /* Command register (a) */
+ unsigned char d3, thra; /* Transmit holding register (a) */
+ unsigned char d4, acr; /* Auxiliary control register of block */
+ unsigned char d5, imr; /* Interrupt mask register of block */
+ unsigned char d6, ctu; /* Counter timer upper register of block */
+ unsigned char d7, ctl; /* Counter timer lower register of block */
+ unsigned char d8, mrb; /* Mode register 1/2 (b) */
+ unsigned char d9, csrb; /* Clock select register (a) */
+ unsigned char da, crb; /* Command register (b) */
+ unsigned char db, thrb; /* Transmit holding register (b) */
+ unsigned char dc, r1; /* reserved */
+ unsigned char dd, opcr; /* Output port configuration register of block */
+ unsigned char de, r2; /* reserved */
+ unsigned char df, r3; /* reserved */
+ } w; /* Write access */
+ } u;
+} ;
+
+#define MR1_CHRL_5_BITS (0x0 << 0)
+#define MR1_CHRL_6_BITS (0x1 << 0)
+#define MR1_CHRL_7_BITS (0x2 << 0)
+#define MR1_CHRL_8_BITS (0x3 << 0)
+#define MR1_PARITY_EVEN (0x1 << 2)
+#define MR1_PARITY_ODD (0x0 << 2)
+#define MR1_PARITY_ON (0x0 << 3)
+#define MR1_PARITY_FORCE (0x1 << 3)
+#define MR1_PARITY_OFF (0x2 << 3)
+#define MR1_PARITY_SPECIAL (0x3 << 3)
+#define MR1_ERROR_CHAR (0x0 << 5)
+#define MR1_ERROR_BLOCK (0x1 << 5)
+#define MR1_RxINT_RxRDY (0x0 << 6)
+#define MR1_RxINT_FFULL (0x1 << 6)
+#define MR1_RxRTS_CONTROL_ON (0x1 << 7)
+#define MR1_RxRTS_CONTROL_OFF (0x0 << 7)
+
+#define MR2_STOP_BITS_LENGTH_1 (0x7 << 0)
+#define MR2_STOP_BITS_LENGTH_2 (0xF << 0)
+#define MR2_CTS_ENABLE_TX_ON (0x1 << 4)
+#define MR2_CTS_ENABLE_TX_OFF (0x0 << 4)
+#define MR2_TxRTS_CONTROL_ON (0x1 << 5)
+#define MR2_TxRTS_CONTROL_OFF (0x0 << 5)
+#define MR2_CH_MODE_NORMAL (0x0 << 6)
+#define MR2_CH_MODE_ECHO (0x1 << 6)
+#define MR2_CH_MODE_LOCAL (0x2 << 6)
+#define MR2_CH_MODE_REMOTE (0x3 << 6)
+
+#define CR_ENABLE_RX (0x1 << 0)
+#define CR_DISABLE_RX (0x1 << 1)
+#define CR_ENABLE_TX (0x1 << 2)
+#define CR_DISABLE_TX (0x1 << 3)
+#define CR_CMD_RESET_MR (0x1 << 4)
+#define CR_CMD_RESET_RX (0x2 << 4)
+#define CR_CMD_RESET_TX (0x3 << 4)
+#define CR_CMD_RESET_ERR_STATUS (0x4 << 4)
+#define CR_CMD_RESET_BREAK_CHANGE (0x5 << 4)
+#define CR_CMD_START_BREAK (0x6 << 4)
+#define CR_CMD_STOP_BREAK (0x7 << 4)
+#define CR_CMD_ASSERT_RTSN (0x8 << 4)
+#define CR_CMD_NEGATE_RTSN (0x9 << 4)
+#define CR_CMD_SET_TIMEOUT_MODE (0xA << 4)
+#define CR_CMD_DISABLE_TIMEOUT_MODE (0xC << 4)
+
+#define SR_RX_READY (0x1 << 0)
+#define SR_FIFO_FULL (0x1 << 1)
+#define SR_TX_READY (0x1 << 2)
+#define SR_TX_EMPTY (0x1 << 3)
+#define SR_OVERRUN_ERROR (0x1 << 4)
+#define SR_PARITY_ERROR (0x1 << 5)
+#define SR_FRAMING_ERROR (0x1 << 6)
+#define SR_RECEIVED_BREAK (0x1 << 7)
+
+#define SR_ERROR (0xF0)
+
+#define ACR_DELTA_IP0_IRQ_EN (0x1 << 0)
+#define ACR_DELTA_IP1_IRQ_EN (0x1 << 1)
+#define ACR_DELTA_IP2_IRQ_EN (0x1 << 2)
+#define ACR_DELTA_IP3_IRQ_EN (0x1 << 3)
+#define ACR_CT_Mask (0x7 << 4)
+#define ACR_CExt (0x0 << 4)
+#define ACR_CTxCA (0x1 << 4)
+#define ACR_CTxCB (0x2 << 4)
+#define ACR_CClk16 (0x3 << 4)
+#define ACR_TExt (0x4 << 4)
+#define ACR_TExt16 (0x5 << 4)
+#define ACR_TClk (0x6 << 4)
+#define ACR_TClk16 (0x7 << 4)
+#define ACR_BRG_SET1 (0x0 << 7)
+#define ACR_BRG_SET2 (0x1 << 7)
+
+#define TX_CLK_75 (0x0 << 0)
+#define TX_CLK_110 (0x1 << 0)
+#define TX_CLK_38400 (0x2 << 0)
+#define TX_CLK_150 (0x3 << 0)
+#define TX_CLK_300 (0x4 << 0)
+#define TX_CLK_600 (0x5 << 0)
+#define TX_CLK_1200 (0x6 << 0)
+#define TX_CLK_2000 (0x7 << 0)
+#define TX_CLK_2400 (0x8 << 0)
+#define TX_CLK_4800 (0x9 << 0)
+#define TX_CLK_1800 (0xA << 0)
+#define TX_CLK_9600 (0xB << 0)
+#define TX_CLK_19200 (0xC << 0)
+#define RX_CLK_75 (0x0 << 4)
+#define RX_CLK_110 (0x1 << 4)
+#define RX_CLK_38400 (0x2 << 4)
+#define RX_CLK_150 (0x3 << 4)
+#define RX_CLK_300 (0x4 << 4)
+#define RX_CLK_600 (0x5 << 4)
+#define RX_CLK_1200 (0x6 << 4)
+#define RX_CLK_2000 (0x7 << 4)
+#define RX_CLK_2400 (0x8 << 4)
+#define RX_CLK_4800 (0x9 << 4)
+#define RX_CLK_1800 (0xA << 4)
+#define RX_CLK_9600 (0xB << 4)
+#define RX_CLK_19200 (0xC << 4)
+
+#define OPCR_MPOa_RTSN (0x0 << 0)
+#define OPCR_MPOa_C_TO (0x1 << 0)
+#define OPCR_MPOa_TxC1X (0x2 << 0)
+#define OPCR_MPOa_TxC16X (0x3 << 0)
+#define OPCR_MPOa_RxC1X (0x4 << 0)
+#define OPCR_MPOa_RxC16X (0x5 << 0)
+#define OPCR_MPOa_TxRDY (0x6 << 0)
+#define OPCR_MPOa_RxRDY_FF (0x7 << 0)
+
+#define OPCR_MPOb_RTSN (0x0 << 4)
+#define OPCR_MPOb_C_TO (0x1 << 4)
+#define OPCR_MPOb_TxC1X (0x2 << 4)
+#define OPCR_MPOb_TxC16X (0x3 << 4)
+#define OPCR_MPOb_RxC1X (0x4 << 4)
+#define OPCR_MPOb_RxC16X (0x5 << 4)
+#define OPCR_MPOb_TxRDY (0x6 << 4)
+#define OPCR_MPOb_RxRDY_FF (0x7 << 4)
+
+#define OPCR_MPP_INPUT (0x0 << 7)
+#define OPCR_MPP_OUTPUT (0x1 << 7)
+
+#define IMR_TxRDY_A (0x1 << 0)
+#define IMR_RxRDY_FFULL_A (0x1 << 1)
+#define IMR_DELTA_BREAK_A (0x1 << 2)
+#define IMR_COUNTER_READY (0x1 << 3)
+#define IMR_TxRDY_B (0x1 << 4)
+#define IMR_RxRDY_FFULL_B (0x1 << 5)
+#define IMR_DELTA_BREAK_B (0x1 << 6)
+#define IMR_INPUT_PORT_CHANGE (0x1 << 7)
+
+#define ISR_TxRDY_A (0x1 << 0)
+#define ISR_RxRDY_FFULL_A (0x1 << 1)
+#define ISR_DELTA_BREAK_A (0x1 << 2)
+#define ISR_COUNTER_READY (0x1 << 3)
+#define ISR_TxRDY_B (0x1 << 4)
+#define ISR_RxRDY_FFULL_B (0x1 << 5)
+#define ISR_DELTA_BREAK_B (0x1 << 6)
+#define ISR_INPUT_PORT_CHANGE (0x1 << 7)
+
+#endif /* SCC2698_H_ */
diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c
new file mode 100644
index 0000000..2b4fa51
--- /dev/null
+++ b/drivers/staging/ipack/ipack.c
@@ -0,0 +1,205 @@
+/*
+ * Industry-pack bus support functions.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include "ipack.h"
+
+#define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
+#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
+
+/* used when allocating bus numbers */
+#define IPACK_MAXBUS 64
+
+static DEFINE_MUTEX(ipack_mutex);
+
+struct ipack_busmap {
+ unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))];
+};
+static struct ipack_busmap busmap;
+
+static void ipack_device_release(struct device *dev)
+{
+ struct ipack_device *device = to_ipack_dev(dev);
+ kfree(device);
+}
+
+static int ipack_bus_match(struct device *device, struct device_driver *driver)
+{
+ int ret;
+ struct ipack_device *dev = to_ipack_dev(device);
+ struct ipack_driver *drv = to_ipack_driver(driver);
+
+ if ((!drv->ops) || (!drv->ops->match))
+ return -EINVAL;
+
+ ret = drv->ops->match(dev);
+ if (ret)
+ dev->driver = drv;
+
+ return 0;
+}
+
+static int ipack_bus_probe(struct device *device)
+{
+ struct ipack_device *dev = to_ipack_dev(device);
+
+ if (!dev->driver->ops->probe)
+ return -EINVAL;
+
+ return dev->driver->ops->probe(dev);
+}
+
+static int ipack_bus_remove(struct device *device)
+{
+ struct ipack_device *dev = to_ipack_dev(device);
+
+ if (!dev->driver->ops->remove)
+ return -EINVAL;
+
+ dev->driver->ops->remove(dev);
+ return 0;
+}
+
+static struct bus_type ipack_bus_type = {
+ .name = "ipack",
+ .probe = ipack_bus_probe,
+ .match = ipack_bus_match,
+ .remove = ipack_bus_remove,
+};
+
+static int ipack_assign_bus_number(void)
+{
+ int busnum;
+
+ mutex_lock(&ipack_mutex);
+ busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1);
+
+ if (busnum >= IPACK_MAXBUS) {
+ pr_err("too many buses\n");
+ busnum = -1;
+ goto error_find_busnum;
+ }
+
+ set_bit(busnum, busmap.busmap);
+
+error_find_busnum:
+ mutex_unlock(&ipack_mutex);
+ return busnum;
+}
+
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+ struct ipack_bus_ops *ops)
+{
+ int bus_nr;
+ struct ipack_bus_device *bus;
+
+ bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ bus_nr = ipack_assign_bus_number();
+ if (bus_nr < 0) {
+ kfree(bus);
+ return NULL;
+ }
+
+ bus->bus_nr = bus_nr;
+ bus->parent = parent;
+ bus->slots = slots;
+ bus->ops = ops;
+ return bus;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_register);
+
+int ipack_bus_unregister(struct ipack_bus_device *bus)
+{
+ mutex_lock(&ipack_mutex);
+ clear_bit(bus->bus_nr, busmap.busmap);
+ mutex_unlock(&ipack_mutex);
+ kfree(bus);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_unregister);
+
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
+ char *name)
+{
+ edrv->driver.owner = owner;
+ edrv->driver.name = name;
+ edrv->driver.bus = &ipack_bus_type;
+ return driver_register(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_register);
+
+void ipack_driver_unregister(struct ipack_driver *edrv)
+{
+ driver_unregister(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_unregister);
+
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
+ int slot, int irqv)
+{
+ int ret;
+ struct ipack_device *dev;
+
+ dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->dev.bus = &ipack_bus_type;
+ dev->dev.release = ipack_device_release;
+ dev->dev.parent = bus->parent;
+ dev->slot = slot;
+ dev->bus_nr = bus->bus_nr;
+ dev->irq = irqv;
+ dev->bus = bus;
+ dev_set_name(&dev->dev,
+ "ipack-dev.%u.%u", dev->bus_nr, dev->slot);
+
+ ret = device_register(&dev->dev);
+ if (ret < 0) {
+ pr_err("error registering the device.\n");
+ dev->driver->ops->remove(dev);
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(ipack_device_register);
+
+void ipack_device_unregister(struct ipack_device *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_unregister);
+
+static int __init ipack_init(void)
+{
+ return bus_register(&ipack_bus_type);
+}
+
+static void __exit ipack_exit(void)
+{
+ bus_unregister(&ipack_bus_type);
+}
+
+module_init(ipack_init);
+module_exit(ipack_exit);
+
+MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Industry-pack bus core");
diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h
new file mode 100644
index 0000000..8bc001e
--- /dev/null
+++ b/drivers/staging/ipack/ipack.h
@@ -0,0 +1,183 @@
+/*
+ * Industry-pack bus.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+
+#define IPACK_IDPROM_OFFSET_I 0x01
+#define IPACK_IDPROM_OFFSET_P 0x03
+#define IPACK_IDPROM_OFFSET_A 0x05
+#define IPACK_IDPROM_OFFSET_C 0x07
+#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID 0x09
+#define IPACK_IDPROM_OFFSET_MODEL 0x0B
+#define IPACK_IDPROM_OFFSET_REVISION 0x0D
+#define IPACK_IDPROM_OFFSET_RESERVED 0x0F
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_L 0x11
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_H 0x13
+#define IPACK_IDPROM_OFFSET_NUM_BYTES 0x15
+#define IPACK_IDPROM_OFFSET_CRC 0x17
+
+struct ipack_bus_ops;
+struct ipack_driver;
+
+enum ipack_space {
+ IPACK_IO_SPACE = 0,
+ IPACK_ID_SPACE = 1,
+ IPACK_MEM_SPACE = 2,
+};
+
+/**
+ * struct ipack_addr_space - Virtual address space mapped for a specified type.
+ *
+ * @address: virtual address
+ * @size: size of the mapped space
+ */
+struct ipack_addr_space {
+ void __iomem *address;
+ unsigned int size;
+};
+
+/**
+ * struct ipack_device
+ *
+ * @bus_nr: IP bus number where the device is plugged
+ * @slot: Slot where the device is plugged in the carrier board
+ * @irq: IRQ vector
+ * @driver: Pointer to the ipack_driver that manages the device
+ * @bus: ipack_bus_device where the device is plugged to.
+ * @id_space: Virtual address to ID space.
+ * @io_space: Virtual address to IO space.
+ * @mem_space: Virtual address to MEM space.
+ * @dev: device in kernel representation.
+ *
+ * Warning: Direct access to mapped memory is possible but the endianness
+ * is not the same with PCI carrier or VME carrier. The endianness is managed
+ * by the carrier board throught bus->ops.
+ */
+struct ipack_device {
+ unsigned int bus_nr;
+ unsigned int slot;
+ unsigned int irq;
+ struct ipack_driver *driver;
+ struct ipack_bus_device *bus;
+ struct ipack_addr_space id_space;
+ struct ipack_addr_space io_space;
+ struct ipack_addr_space mem_space;
+ struct device dev;
+};
+
+/**
+ * struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device
+ *
+ * @match: Match function
+ * @probe: Probe function
+ * @remove: tell the driver that the carrier board wants to remove one device
+ */
+
+struct ipack_driver_ops {
+ int (*match) (struct ipack_device *dev);
+ int (*probe) (struct ipack_device *dev);
+ void (*remove) (struct ipack_device *dev);
+};
+
+/**
+ * struct ipack_driver -- Specific data to each ipack board driver
+ *
+ * @driver: Device driver kernel representation
+ * @ops: Mezzanine driver operations specific for the ipack bus.
+ */
+struct ipack_driver {
+ struct device_driver driver;
+ struct ipack_driver_ops *ops;
+};
+
+/**
+ * struct ipack_bus_ops - available operations on a bridge module
+ *
+ * @map_space: map IP address space
+ * @unmap_space: unmap IP address space
+ * @request_irq: request IRQ
+ * @free_irq: free IRQ
+ * @read8: read unsigned char
+ * @read16: read unsigned short
+ * @read32: read unsigned int
+ * @write8: read unsigned char
+ * @write16: read unsigned short
+ * @write32: read unsigned int
+ * @remove_device: tell the bridge module that the device has been removed
+ */
+struct ipack_bus_ops {
+ int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space);
+ int (*unmap_space) (struct ipack_device *dev, int space);
+ int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg);
+ int (*free_irq) (struct ipack_device *dev);
+ int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value);
+ int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value);
+ int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value);
+ int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value);
+ int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value);
+ int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value);
+ int (*remove_device) (struct ipack_device *dev);
+};
+
+/**
+ * struct ipack_bus_device
+ *
+ * @dev: pointer to carrier device
+ * @slots: number of slots available
+ * @bus_nr: ipack bus number
+ * @ops: bus operations for the mezzanine drivers
+ */
+struct ipack_bus_device {
+ struct device *parent;
+ int slots;
+ int bus_nr;
+ struct ipack_bus_ops *ops;
+};
+
+/**
+ * ipack_bus_register -- register a new ipack bus
+ *
+ * @parent: pointer to the parent device, if any.
+ * @slots: number of slots available in the bus device.
+ * @ops: bus operations for the mezzanine drivers.
+ *
+ * The carrier board device should call this function to register itself as
+ * available bus device in ipack.
+ */
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+ struct ipack_bus_ops *ops);
+
+/**
+ * ipack_bus_unregister -- unregister an ipack bus
+ */
+int ipack_bus_unregister(struct ipack_bus_device *bus);
+
+/**
+ * ipack_driver_register -- Register a new driver
+ *
+ * Called by a ipack driver to register itself as a driver
+ * that can manage ipack devices.
+ */
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name);
+void ipack_driver_unregister(struct ipack_driver *edrv);
+
+/**
+ * ipack_device_register -- register a new mezzanine device
+ *
+ * @bus: ipack bus device it is plugged to.
+ * @slot: slot position in the bus device.
+ * @irqv: IRQ vector for the mezzanine.
+ *
+ * Register a new ipack device (mezzanine device). The call is done by
+ * the carrier device driver.
+ */
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv);
+void ipack_device_unregister(struct ipack_device *dev);
diff --git a/drivers/staging/line6/config.h b/drivers/staging/line6/config.h
deleted file mode 100644
index f8a5149..0000000
--- a/drivers/staging/line6/config.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
- *
- * 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.
- *
- */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG 1
-#endif
-
-
-/*
- * Development tools.
- */
-#define DO_DEBUG_MESSAGES 0
-#define DO_DUMP_URB_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_URB_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_PCM_SEND 0
-#define DO_DUMP_PCM_RECEIVE 0
-#define DO_DUMP_MIDI_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_MIDI_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_ANY (DO_DUMP_URB_SEND || DO_DUMP_URB_RECEIVE || \
- DO_DUMP_PCM_SEND || DO_DUMP_PCM_RECEIVE || \
- DO_DUMP_MIDI_SEND || DO_DUMP_MIDI_RECEIVE)
-#define CREATE_RAW_FILE 0
-
-#if DO_DEBUG_MESSAGES
-#define CHECKPOINT printk(KERN_INFO "line6usb: %s (%s:%d)\n", \
- __func__, __FILE__, __LINE__)
-#endif
-
-#if DO_DEBUG_MESSAGES
-#define DEBUG_MESSAGES(x) (x)
-#else
-#define DEBUG_MESSAGES(x)
-#endif
-
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index e8023af..4513f78 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -92,15 +92,10 @@ const unsigned char line6_midi_id[] = {
Code to request version of POD, Variax interface
(and maybe other devices).
*/
-static const char line6_request_version0[] = {
+static const char line6_request_version[] = {
0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
};
-/*
- Copy of version request code with GFP_KERNEL flag for use in URB.
-*/
-static const char *line6_request_version;
-
struct usb_line6 *line6_devices[LINE6_MAX_DEVICES];
/**
@@ -336,8 +331,21 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
*/
int line6_version_request_async(struct usb_line6 *line6)
{
- return line6_send_raw_message_async(line6, line6_request_version,
- sizeof(line6_request_version0));
+ char *buffer;
+ int retval;
+
+ buffer = kmalloc(sizeof(line6_request_version), GFP_ATOMIC);
+ if (buffer == NULL) {
+ dev_err(line6->ifcdev, "Out of memory");
+ return -ENOMEM;
+ }
+
+ memcpy(buffer, line6_request_version, sizeof(line6_request_version));
+
+ retval = line6_send_raw_message_async(line6, buffer,
+ sizeof(line6_request_version));
+ kfree(buffer);
+ return retval;
}
/*
@@ -1292,69 +1300,7 @@ static struct usb_driver line6_driver = {
.id_table = line6_id_table,
};
-/*
- Module initialization.
-*/
-static int __init line6_init(void)
-{
- int i, retval;
-
- printk(KERN_INFO "%s driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
-
- for (i = LINE6_MAX_DEVICES; i--;)
- line6_devices[i] = NULL;
-
- retval = usb_register(&line6_driver);
-
- if (retval) {
- err("usb_register failed. Error number %d", retval);
- return retval;
- }
-
- line6_request_version = kmalloc(sizeof(line6_request_version0),
- GFP_KERNEL);
-
- if (line6_request_version == NULL) {
- err("Out of memory");
- return -ENOMEM;
- }
-
- memcpy((char *)line6_request_version, line6_request_version0,
- sizeof(line6_request_version0));
-
- return retval;
-}
-
-/*
- Module cleanup.
-*/
-static void __exit line6_exit(void)
-{
- int i;
- struct usb_line6 *line6;
- struct snd_line6_pcm *line6pcm;
-
- /* stop all PCM channels */
- for (i = LINE6_MAX_DEVICES; i--;) {
- line6 = line6_devices[i];
-
- if (line6 == NULL)
- continue;
-
- line6pcm = line6->line6pcm;
-
- if (line6pcm == NULL)
- continue;
-
- line6_pcm_release(line6pcm, ~0);
- }
-
- usb_deregister(&line6_driver);
- kfree(line6_request_version);
-}
-
-module_init(line6_init);
-module_exit(line6_exit);
+module_usb_driver(line6_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 13d0293..5040729 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -406,7 +406,7 @@ int line6_init_midi(struct usb_line6 *line6)
line6midi->line6 = line6;
- switch(line6->product) {
+ switch (line6->product) {
case LINE6_DEVID_PODHD300:
case LINE6_DEVID_PODHD500:
line6midi->midi_mask_transmit = 1;
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
index 7b532e5..836e8c8 100644
--- a/drivers/staging/line6/midibuf.c
+++ b/drivers/staging/line6/midibuf.c
@@ -64,7 +64,7 @@ int line6_midibuf_init(struct MidiBuffer *this, int size, int split)
void line6_midibuf_status(struct MidiBuffer *this)
{
- printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d "
+ pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d "
"full=%d command_prev=%02x\n", this->size, this->split,
this->pos_read, this->pos_write, this->full, this->command_prev);
}
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 90d2d44..5e319e3 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -99,7 +99,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
unsigned long flags_new = flags_old | channels;
unsigned long flags_final = flags_old;
int err = 0;
-
+
line6pcm->prev_fbuf = NULL;
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index b754f69..31b624b 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -168,7 +168,7 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
if (ret < 0) {
- err("send failed (error %d)\n", ret);
+ dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
return ret;
}
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
index ea4f992..ac92eaf 100644
--- a/drivers/staging/media/as102/as102_drv.c
+++ b/drivers/staging/media/as102/as102_drv.c
@@ -279,40 +279,8 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev)
pr_info("Unregistered device %s", as102_dev->name);
}
-static int __init as102_driver_init(void)
-{
- int ret;
-
- /* register this driver with the low level subsystem */
- ret = usb_register(&as102_usb_driver);
- if (ret)
- err("usb_register failed (ret = %d)", ret);
-
- return ret;
-}
-
-/*
- * Mandatory function : Adds a special section to the module indicating
- * where initialisation function is defined
- */
-module_init(as102_driver_init);
-
-/**
- * as102_driver_exit - as102 driver exit point
- *
- * This function is called when device has to be removed.
- */
-static void __exit as102_driver_exit(void)
-{
- /* deregister this driver with the low level bus subsystem */
- usb_deregister(&as102_usb_driver);
-}
+module_usb_driver(as102_usb_driver);
-/*
- * required function for unload: Adds a special section to the module
- * indicating where unload function is defined
- */
-module_exit(as102_driver_exit);
/* modinfo details */
MODULE_DESCRIPTION(DRIVER_FULL_NAME);
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
index 5917657..9ce8c9d 100644
--- a/drivers/staging/media/as102/as102_fe.c
+++ b/drivers/staging/media/as102/as102_fe.c
@@ -17,8 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/version.h>
-
#include "as102_drv.h"
#include "as10x_types.h"
#include "as10x_cmd.h"
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
index 1075fb1..b9670ee 100644
--- a/drivers/staging/media/as102/as102_fw.c
+++ b/drivers/staging/media/as102/as102_fw.c
@@ -230,11 +230,8 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
pr_info("%s: firmware: %s loaded with success\n",
DRIVER_NAME, fw2);
error:
- /* free data buffer */
kfree(cmd_buf);
- /* release firmware if needed */
- if (firmware != NULL)
- release_firmware(firmware);
+ release_firmware(firmware);
LEAVE();
return errno;
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
index 0f6bfe7..aaf1bc2 100644
--- a/drivers/staging/media/as102/as102_usb_drv.c
+++ b/drivers/staging/media/as102/as102_usb_drv.c
@@ -367,7 +367,7 @@ static int as102_usb_probe(struct usb_interface *intf,
ENTER();
/* This should never actually happen */
- if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) !=
+ if (ARRAY_SIZE(as102_usb_id_table) !=
(sizeof(as102_device_names) / sizeof(const char *))) {
pr_err("Device names table invalid size");
return -EINVAL;
@@ -375,13 +375,12 @@ static int as102_usb_probe(struct usb_interface *intf,
as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
if (as102_dev == NULL) {
- err("%s: kzalloc failed", __func__);
+ dev_err(&intf->dev, "%s: kzalloc failed\n", __func__);
return -ENOMEM;
}
/* Assign the user-friendly device name */
- for (i = 0; i < (sizeof(as102_usb_id_table) /
- sizeof(struct usb_device_id)); i++) {
+ for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
if (id == &as102_usb_id_table[i]) {
as102_dev->name = as102_device_names[i];
as102_dev->elna_cfg = as102_elna_cfg[i];
@@ -411,8 +410,9 @@ static int as102_usb_probe(struct usb_interface *intf,
ret = usb_register_dev(intf, &as102_usb_class_driver);
if (ret < 0) {
/* something prevented us from registering this driver */
- err("%s: usb_register_dev() failed (errno = %d)",
- __func__, ret);
+ dev_err(&intf->dev,
+ "%s: usb_register_dev() failed (errno = %d)\n",
+ __func__, ret);
goto failed;
}
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h
index fc2884a..1ad1ec5 100644
--- a/drivers/staging/media/as102/as102_usb_drv.h
+++ b/drivers/staging/media/as102/as102_usb_drv.h
@@ -17,8 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/version.h>
-
#ifndef _AS102_USB_DRV_H_
#define _AS102_USB_DRV_H_
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
index 9413b37..3cee3cd 100644
--- a/drivers/staging/media/easycap/easycap_ioctl.c
+++ b/drivers/staging/media/easycap/easycap_ioctl.c
@@ -26,6 +26,7 @@
/*****************************************************************************/
#include "easycap.h"
+#include <linux/version.h>
/*--------------------------------------------------------------------------*/
/*
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
index d0fe34a..6f83d36 100644
--- a/drivers/staging/media/easycap/easycap_main.c
+++ b/drivers/staging/media/easycap/easycap_main.c
@@ -3578,7 +3578,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
if (0 != (video_register_device(&(peasycap->video_device),
VFL_TYPE_GRABBER, -1))) {
- err("Not able to register with videodev");
+ dev_err(&intf->dev,
+ "Not able to register with videodev\n");
videodev_release(&(peasycap->video_device));
return -ENODEV;
}
@@ -3822,7 +3823,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
rc = easycap_alsa_probe(peasycap);
if (rc) {
- err("easycap_alsa_probe() rc = %i\n", rc);
+ dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
+ rc);
return -ENODEV;
}
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
index 48f4476..aeba132 100644
--- a/drivers/staging/media/go7007/README
+++ b/drivers/staging/media/go7007/README
@@ -6,6 +6,6 @@ Todo:
- testing?
- handle churn in v4l layer.
-Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
+Please send patches to Greg Kroah-Hartman <greg@linuxfoundation.org> and Cc: Ross
Cohen <rcohen@snurgle.org> as well.
diff --git a/drivers/staging/media/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt
index 9db1f39..fcb3e23 100644
--- a/drivers/staging/media/go7007/go7007.txt
+++ b/drivers/staging/media/go7007/go7007.txt
@@ -87,7 +87,6 @@ kernel as built-in or modules:
CONFIG_SOUND - Sound card support
CONFIG_SND - Advanced Linux Sound Architecture
CONFIG_USB - Support for Host-side USB
- CONFIG_USB_DEVICEFS - USB device filesystem
CONFIG_USB_EHCI_HCD - EHCI HCD (USB 2.0) support
Additionally, to use the example application, the following options need to
diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c
index 4e13251..7c5af4f 100644
--- a/drivers/staging/media/go7007/s2250-loader.c
+++ b/drivers/staging/media/go7007/s2250-loader.c
@@ -160,31 +160,7 @@ static struct usb_driver s2250loader_driver = {
.id_table = s2250loader_ids,
};
-static int __init s2250loader_init(void)
-{
- int r;
- unsigned i = 0;
-
- for (i = 0; i < MAX_DEVICES; i++)
- s2250_dev_table[i] = NULL;
-
- r = usb_register(&s2250loader_driver);
- if (r) {
- printk(KERN_ERR "usb_register failed. Error number %d\n", r);
- return -1;
- }
-
- printk(KERN_INFO "s2250loader_init: driver registered\n");
- return 0;
-}
-module_init(s2250loader_init);
-
-static void __exit s2250loader_cleanup(void)
-{
- printk(KERN_INFO "s2250loader_cleanup\n");
- usb_deregister(&s2250loader_driver);
-}
-module_exit(s2250loader_cleanup);
+module_usb_driver(s2250loader_driver);
MODULE_AUTHOR("");
MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 5f7f8cd..d7cf5ef 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -209,8 +209,9 @@ static void deregister_from_lirc(struct imon_context *context)
retval = lirc_unregister_driver(minor);
if (retval)
- err("%s: unable to deregister from lirc(%d)",
- __func__, retval);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: unable to deregister from lirc(%d)",
+ __func__, retval);
else
printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
"(minor:%d)\n", minor);
@@ -234,16 +235,18 @@ static int display_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&imon_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: could not find interface for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
context = usb_get_intfdata(interface);
if (!context) {
- err("%s: no context found for minor %d",
- __func__, subminor);
+ dev_err(&interface->dev,
+ "%s: no context found for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -251,10 +254,12 @@ static int display_open(struct inode *inode, struct file *file)
mutex_lock(&context->ctx_lock);
if (!context->display) {
- err("%s: display not supported by device", __func__);
+ dev_err(&interface->dev,
+ "%s: display not supported by device\n", __func__);
retval = -ENODEV;
} else if (context->display_isopen) {
- err("%s: display port is already open", __func__);
+ dev_err(&interface->dev,
+ "%s: display port is already open\n", __func__);
retval = -EBUSY;
} else {
context->display_isopen = 1;
@@ -281,17 +286,20 @@ static int display_close(struct inode *inode, struct file *file)
context = file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->display) {
- err("%s: display not supported by device", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: display not supported by device\n", __func__);
retval = -ENODEV;
} else if (!context->display_isopen) {
- err("%s: display is not open", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: display is not open\n", __func__);
retval = -EIO;
} else {
context->display_isopen = 0;
@@ -340,19 +348,23 @@ static int send_packet(struct imon_context *context)
retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
if (retval) {
atomic_set(&(context->tx.busy), 0);
- err("%s: error submitting urb(%d)", __func__, retval);
+ dev_err(&context->usbdev->dev,
+ "%s: error submitting urb(%d)\n", __func__, retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&context->ctx_lock);
retval = wait_for_completion_interruptible(
&context->tx.finished);
if (retval)
- err("%s: task interrupted", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: task interrupted\n", __func__);
mutex_lock(&context->ctx_lock);
retval = context->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ dev_err(&context->usbdev->dev,
+ "%s: packet tx failed (%d)\n",
+ __func__, retval);
}
return retval;
@@ -383,20 +395,23 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
context = file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->dev_present) {
- err("%s: no iMON device present", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: no iMON device present\n", __func__);
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
- err("%s: invalid payload size", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: invalid payload size\n", __func__);
retval = -EINVAL;
goto exit;
}
@@ -425,8 +440,9 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
retval = send_packet(context);
if (retval) {
- err("%s: send packet failed for packet #%d",
- __func__, seq/2);
+ dev_err(&context->usbdev->dev,
+ "%s: send packet failed for packet #%d\n",
+ __func__, seq/2);
goto exit;
} else {
seq += 2;
@@ -441,7 +457,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
context->usb_tx_buf[7] = (unsigned char) seq;
retval = send_packet(context);
if (retval)
- err("%s: send packet failed for packet #%d",
+ dev_err(&context->usbdev->dev,
+ "%s: send packet failed for packet #%d\n",
__func__, seq/2);
}
@@ -508,7 +525,8 @@ static void ir_close(void *data)
context = (struct imon_context *)data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return;
}
@@ -732,7 +750,7 @@ static int imon_probe(struct usb_interface *interface,
context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
if (!context) {
- err("%s: kzalloc failed for context", __func__);
+ dev_err(dev, "%s: kzalloc failed for context\n", __func__);
alloc_status = 1;
goto alloc_status_switch;
}
@@ -797,7 +815,7 @@ static int imon_probe(struct usb_interface *interface,
/* Input endpoint is mandatory */
if (!ir_ep_found) {
- err("%s: no valid input (IR) endpoint found.", __func__);
+ dev_err(dev, "%s: no valid input (IR) endpoint found.\n", __func__);
retval = -ENODEV;
alloc_status = 2;
goto alloc_status_switch;
@@ -814,30 +832,30 @@ static int imon_probe(struct usb_interface *interface,
driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
if (!driver) {
- err("%s: kzalloc failed for lirc_driver", __func__);
+ dev_err(dev, "%s: kzalloc failed for lirc_driver\n", __func__);
alloc_status = 2;
goto alloc_status_switch;
}
rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
if (!rbuf) {
- err("%s: kmalloc failed for lirc_buffer", __func__);
+ dev_err(dev, "%s: kmalloc failed for lirc_buffer\n", __func__);
alloc_status = 3;
goto alloc_status_switch;
}
if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
- err("%s: lirc_buffer_init failed", __func__);
+ dev_err(dev, "%s: lirc_buffer_init failed\n", __func__);
alloc_status = 4;
goto alloc_status_switch;
}
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ dev_err(dev, "%s: usb_alloc_urb failed for IR urb\n", __func__);
alloc_status = 5;
goto alloc_status_switch;
}
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tx_urb) {
- err("%s: usb_alloc_urb failed for display urb",
+ dev_err(dev, "%s: usb_alloc_urb failed for display urb\n",
__func__);
alloc_status = 6;
goto alloc_status_switch;
@@ -865,7 +883,7 @@ static int imon_probe(struct usb_interface *interface,
lirc_minor = lirc_register_driver(driver);
if (lirc_minor < 0) {
- err("%s: lirc_register_driver failed", __func__);
+ dev_err(dev, "%s: lirc_register_driver failed\n", __func__);
alloc_status = 7;
goto unlock;
} else
@@ -900,8 +918,8 @@ static int imon_probe(struct usb_interface *interface,
retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
if (retval) {
- err("%s: usb_submit_urb failed for intf0 (%d)",
- __func__, retval);
+ dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n",
+ __func__, retval);
mutex_unlock(&context->ctx_lock);
goto exit;
}
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index 7442104..352a202 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -185,7 +185,7 @@ static void deregister_from_lirc(struct sasem_context *context)
retval = lirc_unregister_driver(minor);
if (retval)
- err("%s: unable to deregister from lirc (%d)",
+ printk(KERN_ERR "%s: unable to deregister from lirc (%d)\n",
__func__, retval);
else
printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
@@ -210,16 +210,18 @@ static int vfd_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&sasem_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: could not find interface for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
context = usb_get_intfdata(interface);
if (!context) {
- err("%s: no context found for minor %d",
- __func__, subminor);
+ dev_err(&interface->dev,
+ "%s: no context found for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -227,12 +229,13 @@ static int vfd_open(struct inode *inode, struct file *file)
mutex_lock(&context->ctx_lock);
if (context->vfd_isopen) {
- err("%s: VFD port is already open", __func__);
+ dev_err(&interface->dev,
+ "%s: VFD port is already open", __func__);
retval = -EBUSY;
} else {
context->vfd_isopen = 1;
file->private_data = context;
- printk(KERN_INFO "VFD port opened\n");
+ dev_info(&interface->dev, "VFD port opened\n");
}
mutex_unlock(&context->ctx_lock);
@@ -253,7 +256,8 @@ static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
@@ -287,14 +291,15 @@ static int vfd_close(struct inode *inode, struct file *file)
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->vfd_isopen) {
- err("%s: VFD is not open", __func__);
+ dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__);
retval = -EIO;
} else {
context->vfd_isopen = 0;
@@ -339,7 +344,8 @@ static int send_packet(struct sasem_context *context)
retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
if (retval) {
atomic_set(&(context->tx.busy), 0);
- err("%s: error submitting urb (%d)", __func__, retval);
+ dev_err(&context->dev->dev, "%s: error submitting urb (%d)\n",
+ __func__, retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&context->ctx_lock);
@@ -348,7 +354,9 @@ static int send_packet(struct sasem_context *context)
retval = context->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ dev_err(&context->dev->dev,
+ "%s: packet tx failed (%d)\n",
+ __func__, retval);
}
return retval;
@@ -369,20 +377,23 @@ static ssize_t vfd_write(struct file *file, const char *buf,
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->dev_present) {
- err("%s: no Sasem device present", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no Sasem device present\n", __func__);
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
- err("%s: invalid payload size", __func__);
+ dev_err(&context->dev->dev, "%s: invalid payload size\n",
+ __func__);
retval = -EINVAL;
goto exit;
}
@@ -440,9 +451,9 @@ static ssize_t vfd_write(struct file *file, const char *buf,
}
retval = send_packet(context);
if (retval) {
-
- err("%s: send packet failed for packet #%d",
- __func__, i);
+ dev_err(&context->dev->dev,
+ "%s: send packet failed for packet #%d\n",
+ __func__, i);
goto exit;
}
}
@@ -492,7 +503,8 @@ static int ir_open(void *data)
mutex_lock(&context->ctx_lock);
if (context->ir_isopen) {
- err("%s: IR port is already open", __func__);
+ dev_err(&context->dev->dev, "%s: IR port is already open\n",
+ __func__);
retval = -EBUSY;
goto exit;
}
@@ -506,8 +518,9 @@ static int ir_open(void *data)
retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
if (retval)
- err("%s: usb_submit_urb failed for ir_open (%d)",
- __func__, retval);
+ dev_err(&context->dev->dev,
+ "%s: usb_submit_urb failed for ir_open (%d)\n",
+ __func__, retval);
else {
context->ir_isopen = 1;
printk(KERN_INFO "IR port opened\n");
@@ -529,7 +542,8 @@ static void ir_close(void *data)
context = (struct sasem_context *)data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return;
}
@@ -687,7 +701,7 @@ static int sasem_probe(struct usb_interface *interface,
struct sasem_context *context = NULL;
int i;
- printk(KERN_INFO "%s: found Sasem device\n", __func__);
+ dev_info(&interface->dev, "%s: found Sasem device\n", __func__);
dev = usb_get_dev(interface_to_usbdev(interface));
@@ -719,8 +733,8 @@ static int sasem_probe(struct usb_interface *interface,
rx_endpoint = ep;
ir_ep_found = 1;
if (debug)
- printk(KERN_INFO "%s: found IR endpoint\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: found IR endpoint\n", __func__);
} else if (!vfd_ep_found &&
ep_dir == USB_DIR_OUT &&
@@ -729,22 +743,23 @@ static int sasem_probe(struct usb_interface *interface,
tx_endpoint = ep;
vfd_ep_found = 1;
if (debug)
- printk(KERN_INFO "%s: found VFD endpoint\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: found VFD endpoint\n", __func__);
}
}
/* Input endpoint is mandatory */
if (!ir_ep_found) {
-
- err("%s: no valid input (IR) endpoint found.", __func__);
+ dev_err(&interface->dev,
+ "%s: no valid input (IR) endpoint found.\n", __func__);
retval = -ENODEV;
goto exit;
}
if (!vfd_ep_found)
- printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: no valid output (VFD) endpoint found.\n",
+ __func__);
/* Allocate memory */
@@ -752,38 +767,44 @@ static int sasem_probe(struct usb_interface *interface,
context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
if (!context) {
- err("%s: kzalloc failed for context", __func__);
+ dev_err(&interface->dev,
+ "%s: kzalloc failed for context\n", __func__);
alloc_status = 1;
goto alloc_status_switch;
}
driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
if (!driver) {
- err("%s: kzalloc failed for lirc_driver", __func__);
+ dev_err(&interface->dev,
+ "%s: kzalloc failed for lirc_driver\n", __func__);
alloc_status = 2;
goto alloc_status_switch;
}
rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
if (!rbuf) {
- err("%s: kmalloc failed for lirc_buffer", __func__);
+ dev_err(&interface->dev,
+ "%s: kmalloc failed for lirc_buffer\n", __func__);
alloc_status = 3;
goto alloc_status_switch;
}
if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
- err("%s: lirc_buffer_init failed", __func__);
+ dev_err(&interface->dev,
+ "%s: lirc_buffer_init failed\n", __func__);
alloc_status = 4;
goto alloc_status_switch;
}
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ dev_err(&interface->dev,
+ "%s: usb_alloc_urb failed for IR urb\n", __func__);
alloc_status = 5;
goto alloc_status_switch;
}
if (vfd_ep_found) {
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tx_urb) {
- err("%s: usb_alloc_urb failed for VFD urb",
- __func__);
+ dev_err(&interface->dev,
+ "%s: usb_alloc_urb failed for VFD urb",
+ __func__);
alloc_status = 6;
goto alloc_status_switch;
}
@@ -807,7 +828,8 @@ static int sasem_probe(struct usb_interface *interface,
lirc_minor = lirc_register_driver(driver);
if (lirc_minor < 0) {
- err("%s: lirc_register_driver failed", __func__);
+ dev_err(&interface->dev,
+ "%s: lirc_register_driver failed\n", __func__);
alloc_status = 7;
retval = lirc_minor;
goto unlock;
diff --git a/drivers/staging/media/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c
index 7950887..3bb865c 100644
--- a/drivers/staging/media/lirc/lirc_ttusbir.c
+++ b/drivers/staging/media/lirc/lirc_ttusbir.c
@@ -113,8 +113,9 @@ static int set_use_inc(void *data)
for (i = 0; i < num_urbs; i++) {
retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
if (retval) {
- err("%s: usb_submit_urb failed on urb %d",
- __func__, i);
+ dev_err(&ttusbir->interf->dev,
+ "%s: usb_submit_urb failed on urb %d\n",
+ __func__, i);
return retval;
}
}
@@ -278,7 +279,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
if (ttusbir->alt_setting != -1)
DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
else {
- err("Could not find alternate setting\n");
+ dev_err(&intf->dev, "Could not find alternate setting\n");
kfree(ttusbir);
return -EINVAL;
}
@@ -291,7 +292,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
/* Register as a LIRC driver */
if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
- err("Could not get memory for LIRC data buffer\n");
+ dev_err(&intf->dev, "Could not get memory for LIRC data buffer\n");
usb_set_intfdata(intf, NULL);
kfree(ttusbir);
return -ENOMEM;
@@ -310,7 +311,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
ttusbir->driver.features = LIRC_CAN_REC_MODE2;
ttusbir->minor = lirc_register_driver(&ttusbir->driver);
if (ttusbir->minor < 0) {
- err("Error registering as LIRC driver\n");
+ dev_err(&intf->dev, "Error registering as LIRC driver\n");
usb_set_intfdata(intf, NULL);
lirc_buffer_free(&ttusbir->rbuf);
kfree(ttusbir);
@@ -321,7 +322,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
for (i = 0; i < num_urbs; i++) {
ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
if (!ttusbir->urb[i]) {
- err("Could not allocate memory for the URB\n");
+ dev_err(&intf->dev, "Could not allocate memory for the URB\n");
for (j = i - 1; j >= 0; j--)
kfree(ttusbir->urb[j]);
lirc_buffer_free(&ttusbir->rbuf);
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
deleted file mode 100644
index fc26601..0000000
--- a/drivers/staging/mei/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
- - Cleanup and split the timer function
-Upon Unstaging:
- - move mei.h to include/linux/mei.h
- - Documentation/ioctl/ioctl-number.txt
- - move mei.txt under Documentation/mei/
- - move mei-amt-version.c under Documentation/mei
- - add hostprogs-y for mei-amt-version.c
- - drop mei_version.h
- - Updated MAINTAINERS
diff --git a/drivers/staging/mei/mei-amt-version.c b/drivers/staging/mei/mei-amt-version.c
deleted file mode 100644
index ac2a507..0000000
--- a/drivers/staging/mei/mei-amt-version.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/******************************************************************************
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Intel MEI Interface Header
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * Intel Corporation.
- * linux-mei@linux.intel.com
- * http://www.intel.com
- *
- * BSD LICENSE
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <bits/wordsize.h>
-#include "mei.h"
-
-/*****************************************************************************
- * Intel Management Engine Interface
- *****************************************************************************/
-
-#define mei_msg(_me, fmt, ARGS...) do { \
- if (_me->verbose) \
- fprintf(stderr, fmt, ##ARGS); \
-} while (0)
-
-#define mei_err(_me, fmt, ARGS...) do { \
- fprintf(stderr, "Error: " fmt, ##ARGS); \
-} while (0)
-
-struct mei {
- uuid_le guid;
- bool initialized;
- bool verbose;
- unsigned int buf_size;
- unsigned char prot_ver;
- int fd;
-};
-
-static void mei_deinit(struct mei *cl)
-{
- if (cl->fd != -1)
- close(cl->fd);
- cl->fd = -1;
- cl->buf_size = 0;
- cl->prot_ver = 0;
- cl->initialized = false;
-}
-
-static bool mei_init(struct mei *me, const uuid_le *guid,
- unsigned char req_protocol_version, bool verbose)
-{
- int result;
- struct mei_client *cl;
- struct mei_connect_client_data data;
-
- mei_deinit(me);
-
- me->verbose = verbose;
-
- me->fd = open("/dev/mei", O_RDWR);
- if (me->fd == -1) {
- mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
- goto err;
- }
- memcpy(&me->guid, guid, sizeof(*guid));
- memset(&data, 0, sizeof(data));
- me->initialized = true;
-
- memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
- result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
- if (result) {
- mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
- goto err;
- }
- cl = &data.out_client_properties;
- mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
- mei_msg(me, "protocol_version %d\n", cl->protocol_version);
-
- if ((req_protocol_version > 0) &&
- (cl->protocol_version != req_protocol_version)) {
- mei_err(me, "Intel MEI protocol version not supported\n");
- goto err;
- }
-
- me->buf_size = cl->max_msg_length;
- me->prot_ver = cl->protocol_version;
-
- return true;
-err:
- mei_deinit(me);
- return false;
-}
-
-static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
- ssize_t len, unsigned long timeout)
-{
- ssize_t rc;
-
- mei_msg(me, "call read length = %zd\n", len);
-
- rc = read(me->fd, buffer, len);
- if (rc < 0) {
- mei_err(me, "read failed with status %zd %s\n",
- rc, strerror(errno));
- mei_deinit(me);
- } else {
- mei_msg(me, "read succeeded with result %zd\n", rc);
- }
- return rc;
-}
-
-static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
- ssize_t len, unsigned long timeout)
-{
- struct timeval tv;
- ssize_t written;
- ssize_t rc;
- fd_set set;
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000000;
-
- mei_msg(me, "call write length = %zd\n", len);
-
- written = write(me->fd, buffer, len);
- if (written < 0) {
- rc = -errno;
- mei_err(me, "write failed with status %zd %s\n",
- written, strerror(errno));
- goto out;
- }
-
- FD_ZERO(&set);
- FD_SET(me->fd, &set);
- rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
- if (rc > 0 && FD_ISSET(me->fd, &set)) {
- mei_msg(me, "write success\n");
- } else if (rc == 0) {
- mei_err(me, "write failed on timeout with status\n");
- goto out;
- } else { /* rc < 0 */
- mei_err(me, "write failed on select with status %zd\n", rc);
- goto out;
- }
-
- rc = written;
-out:
- if (rc < 0)
- mei_deinit(me);
-
- return rc;
-}
-
-/***************************************************************************
- * Intel Advanced Management Technolgy ME Client
- ***************************************************************************/
-
-#define AMT_MAJOR_VERSION 1
-#define AMT_MINOR_VERSION 1
-
-#define AMT_STATUS_SUCCESS 0x0
-#define AMT_STATUS_INTERNAL_ERROR 0x1
-#define AMT_STATUS_NOT_READY 0x2
-#define AMT_STATUS_INVALID_AMT_MODE 0x3
-#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
-
-#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
-#define AMT_STATUS_SDK_RESOURCES 0x1004
-
-
-#define AMT_BIOS_VERSION_LEN 65
-#define AMT_VERSIONS_NUMBER 50
-#define AMT_UNICODE_STRING_LEN 20
-
-struct amt_unicode_string {
- uint16_t length;
- char string[AMT_UNICODE_STRING_LEN];
-} __attribute__((packed));
-
-struct amt_version_type {
- struct amt_unicode_string description;
- struct amt_unicode_string version;
-} __attribute__((packed));
-
-struct amt_version {
- uint8_t major;
- uint8_t minor;
-} __attribute__((packed));
-
-struct amt_code_versions {
- uint8_t bios[AMT_BIOS_VERSION_LEN];
- uint32_t count;
- struct amt_version_type versions[AMT_VERSIONS_NUMBER];
-} __attribute__((packed));
-
-/***************************************************************************
- * Intel Advanced Management Technolgy Host Interface
- ***************************************************************************/
-
-struct amt_host_if_msg_header {
- struct amt_version version;
- uint16_t _reserved;
- uint32_t command;
- uint32_t length;
-} __attribute__((packed));
-
-struct amt_host_if_resp_header {
- struct amt_host_if_msg_header header;
- uint32_t status;
- unsigned char data[0];
-} __attribute__((packed));
-
-const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
- 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
-
-#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
-#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
-
-const struct amt_host_if_msg_header CODE_VERSION_REQ = {
- .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
- ._reserved = 0,
- .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
- .length = 0
-};
-
-
-struct amt_host_if {
- struct mei mei_cl;
- unsigned long send_timeout;
- bool initialized;
-};
-
-
-static bool amt_host_if_init(struct amt_host_if *acmd,
- unsigned long send_timeout, bool verbose)
-{
- acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
- acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
- return acmd->initialized;
-}
-
-static void amt_host_if_deinit(struct amt_host_if *acmd)
-{
- mei_deinit(&acmd->mei_cl);
- acmd->initialized = false;
-}
-
-static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
-{
- uint32_t status = AMT_STATUS_SUCCESS;
- struct amt_code_versions *code_ver;
- size_t code_ver_len;
- uint32_t ver_type_cnt;
- uint32_t len;
- uint32_t i;
-
- code_ver = (struct amt_code_versions *)resp->data;
- /* length - sizeof(status) */
- code_ver_len = resp->header.length - sizeof(uint32_t);
- ver_type_cnt = code_ver_len -
- sizeof(code_ver->bios) -
- sizeof(code_ver->count);
- if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
- status = AMT_STATUS_INTERNAL_ERROR;
- goto out;
- }
-
- for (i = 0; i < code_ver->count; i++) {
- len = code_ver->versions[i].description.length;
-
- if (len > AMT_UNICODE_STRING_LEN) {
- status = AMT_STATUS_INTERNAL_ERROR;
- goto out;
- }
-
- len = code_ver->versions[i].version.length;
- if (code_ver->versions[i].version.string[len] != '\0' ||
- len != strlen(code_ver->versions[i].version.string)) {
- status = AMT_STATUS_INTERNAL_ERROR;
- goto out;
- }
- }
-out:
- return status;
-}
-
-static uint32_t amt_verify_response_header(uint32_t command,
- const struct amt_host_if_msg_header *resp_hdr,
- uint32_t response_size)
-{
- if (response_size < sizeof(struct amt_host_if_resp_header)) {
- return AMT_STATUS_INTERNAL_ERROR;
- } else if (response_size != (resp_hdr->length +
- sizeof(struct amt_host_if_msg_header))) {
- return AMT_STATUS_INTERNAL_ERROR;
- } else if (resp_hdr->command != command) {
- return AMT_STATUS_INTERNAL_ERROR;
- } else if (resp_hdr->_reserved != 0) {
- return AMT_STATUS_INTERNAL_ERROR;
- } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
- resp_hdr->version.minor < AMT_MINOR_VERSION) {
- return AMT_STATUS_INTERNAL_ERROR;
- }
- return AMT_STATUS_SUCCESS;
-}
-
-static uint32_t amt_host_if_call(struct amt_host_if *acmd,
- const unsigned char *command, ssize_t command_sz,
- uint8_t **read_buf, uint32_t rcmd,
- unsigned int expected_sz)
-{
- uint32_t in_buf_sz;
- uint32_t out_buf_sz;
- ssize_t written;
- uint32_t status;
- struct amt_host_if_resp_header *msg_hdr;
-
- in_buf_sz = acmd->mei_cl.buf_size;
- *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
- if (*read_buf == NULL)
- return AMT_STATUS_SDK_RESOURCES;
- memset(*read_buf, 0, in_buf_sz);
- msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
-
- written = mei_send_msg(&acmd->mei_cl,
- command, command_sz, acmd->send_timeout);
- if (written != command_sz)
- return AMT_STATUS_INTERNAL_ERROR;
-
- out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
- if (out_buf_sz <= 0)
- return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
-
- status = msg_hdr->status;
- if (status != AMT_STATUS_SUCCESS)
- return status;
-
- status = amt_verify_response_header(rcmd,
- &msg_hdr->header, out_buf_sz);
- if (status != AMT_STATUS_SUCCESS)
- return status;
-
- if (expected_sz && expected_sz != out_buf_sz)
- return AMT_STATUS_INTERNAL_ERROR;
-
- return AMT_STATUS_SUCCESS;
-}
-
-
-static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
- struct amt_code_versions *versions)
-{
- struct amt_host_if_resp_header *response = NULL;
- uint32_t status;
-
- status = amt_host_if_call(cmd,
- (const unsigned char *)&CODE_VERSION_REQ,
- sizeof(CODE_VERSION_REQ),
- (uint8_t **)&response,
- AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
-
- if (status != AMT_STATUS_SUCCESS)
- goto out;
-
- status = amt_verify_code_versions(response);
- if (status != AMT_STATUS_SUCCESS)
- goto out;
-
- memcpy(versions, response->data, sizeof(struct amt_code_versions));
-out:
- if (response != NULL)
- free(response);
-
- return status;
-}
-
-/************************** end of amt_host_if_command ***********************/
-int main(int argc, char **argv)
-{
- struct amt_code_versions ver;
- struct amt_host_if acmd;
- unsigned int i;
- uint32_t status;
- int ret;
- bool verbose;
-
- verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
-
- if (!amt_host_if_init(&acmd, 5000, verbose)) {
- ret = 1;
- goto out;
- }
-
- status = amt_get_code_versions(&acmd, &ver);
-
- amt_host_if_deinit(&acmd);
-
- switch (status) {
- case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
- printf("Intel AMT: DISABLED\n");
- ret = 0;
- break;
- case AMT_STATUS_SUCCESS:
- printf("Intel AMT: ENABLED\n");
- for (i = 0; i < ver.count; i++) {
- printf("%s:\t%s\n", ver.versions[i].description.string,
- ver.versions[i].version.string);
- }
- ret = 0;
- break;
- default:
- printf("An error has occurred\n");
- ret = 1;
- break;
- }
-
-out:
- return ret;
-}
diff --git a/drivers/staging/mei/mei.h b/drivers/staging/mei/mei.h
deleted file mode 100644
index bc0d8b6..0000000
--- a/drivers/staging/mei/mei.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/******************************************************************************
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Intel MEI Interface Header
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * Intel Corporation.
- * linux-mei@linux.intel.com
- * http://www.intel.com
- *
- * BSD LICENSE
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#ifndef _LINUX_MEI_H
-#define _LINUX_MEI_H
-
-#include <linux/uuid.h>
-
-/*
- * This IOCTL is used to associate the current file descriptor with a
- * FW Client (given by UUID). This opens a communication channel
- * between a host client and a FW client. From this point every read and write
- * will communicate with the associated FW client.
- * Only in close() (file_operation release()) the communication between
- * the clients is disconnected
- *
- * The IOCTL argument is a struct with a union that contains
- * the input parameter and the output parameter for this IOCTL.
- *
- * The input parameter is UUID of the FW Client.
- * The output parameter is the properties of the FW client
- * (FW protocol version and max message size).
- *
- */
-#define IOCTL_MEI_CONNECT_CLIENT \
- _IOWR('H' , 0x01, struct mei_connect_client_data)
-
-/*
- * Intel MEI client information struct
- */
-struct mei_client {
- __u32 max_msg_length;
- __u8 protocol_version;
- __u8 reserved[3];
-};
-
-/*
- * IOCTL Connect Client Data structure
- */
-struct mei_connect_client_data {
- union {
- uuid_le in_client_uuid;
- struct mei_client out_client_properties;
- };
-};
-
-#endif /* _LINUX_MEI_H */
diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt
deleted file mode 100644
index 2785697..0000000
--- a/drivers/staging/mei/mei.txt
+++ /dev/null
@@ -1,215 +0,0 @@
-Intel(R) Management Engine Interface (Intel(R) MEI)
-=======================
-
-Introduction
-=======================
-
-The Intel Management Engine (Intel ME) is an isolated and protected computing
-resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
-provides support for computer/IT management features. The feature set
-depends on the Intel chipset SKU.
-
-The Intel Management Engine Interface (Intel MEI, previously known as HECI)
-is the interface between the Host and Intel ME. This interface is exposed
-to the host as a PCI device. The Intel MEI Driver is in charge of the
-communication channel between a host application and the Intel ME feature.
-
-Each Intel ME feature (Intel ME Client) is addressed by a GUID/UUID and
-each client has its own protocol. The protocol is message-based with a
-header and payload up to 512 bytes.
-
-Prominent usage of the Intel ME Interface is to communicate with Intel(R)
-Active Management Technology (Intel AMT)implemented in firmware running on
-the Intel ME.
-
-Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
-even when the operating system running on the host processor has crashed or
-is in a sleep state.
-
-Some examples of Intel AMT usage are:
- - Monitoring hardware state and platform components
- - Remote power off/on (useful for green computing or overnight IT
- maintenance)
- - OS updates
- - Storage of useful platform information such as software assets
- - Built-in hardware KVM
- - Selective network isolation of Ethernet and IP protocol flows based
- on policies set by a remote management console
- - IDE device redirection from remote management console
-
-Intel AMT (OOB) communication is based on SOAP (deprecated
-starting with Release 6.0) over HTTP/S or WS-Management protocol over
-HTTP/S that are received from a remote management console application.
-
-For more information about Intel AMT:
-http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-
-Intel MEI Driver
-=======================
-
-The driver exposes a misc device called /dev/mei.
-
-An application maintains communication with an Intel ME feature while
-/dev/mei is open. The binding to a specific features is performed by calling
-MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
-The number of instances of an Intel ME feature that can be opened
-at the same time depends on the Intel ME feature, but most of the
-features allow only a single instance.
-
-The Intel AMT Host Interface (Intel AMTHI) feature supports multiple
-simultaneous user applications. Therefore, the Intel MEI driver handles
-this internally by maintaining request queues for the applications.
-
-The driver is oblivious to data that is passed between firmware feature
-and host application.
-
-Because some of the Intel ME features can change the system
-configuration, the driver by default allows only a privileged
-user to access it.
-
-A code snippet for an application communicating with
-Intel AMTHI client:
- struct mei_connect_client_data data;
- fd = open(MEI_DEVICE);
-
- data.d.in_client_uuid = AMTHI_UUID;
-
- ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
-
- printf("Ver=%d, MaxLen=%ld\n",
- data.d.in_client_uuid.protocol_version,
- data.d.in_client_uuid.max_msg_length);
-
- [...]
-
- write(fd, amthi_req_data, amthi_req_data_len);
-
- [...]
-
- read(fd, &amthi_res_data, amthi_res_data_len);
-
- [...]
- close(fd);
-
-IOCTL:
-======
-The Intel MEI Driver supports the following IOCTL command:
- IOCTL_MEI_CONNECT_CLIENT Connect to firmware Feature (client).
-
- usage:
- struct mei_connect_client_data clientData;
- ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &clientData);
-
- inputs:
- mei_connect_client_data struct contain the following
- input field:
-
- in_client_uuid - UUID of the FW Feature that needs
- to connect to.
- outputs:
- out_client_properties - Client Properties: MTU and Protocol Version.
-
- error returns:
- EINVAL Wrong IOCTL Number
- ENODEV Device or Connection is not initialized or ready.
- (e.g. Wrong UUID)
- ENOMEM Unable to allocate memory to client internal data.
- EFAULT Fatal Error (e.g. Unable to access user input data)
- EBUSY Connection Already Open
-
- Notes:
- max_msg_length (MTU) in client properties describes the maximum
- data that can be sent or received. (e.g. if MTU=2K, can send
- requests up to bytes 2k and received responses upto 2k bytes).
-
-Intel ME Applications:
-==============
-
-1) Intel Local Management Service (Intel LMS)
-
- Applications running locally on the platform communicate with Intel AMT Release
- 2.0 and later releases in the same way that network applications do via SOAP
- over HTTP (deprecated starting with Release 6.0) or with WS-Management over
- SOAP over HTTP. This means that some Intel AMT features can be accessed from a
- local application using the same network interface as a remote application
- communicating with Intel AMT over the network.
-
- When a local application sends a message addressed to the local Intel AMT host
- name, the Intel LMS, which listens for traffic directed to the host name,
- intercepts the message and routes it to the Intel MEI.
- For more information:
- http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
- Under "About Intel AMT" => "Local Access"
-
- For downloading Intel LMS:
- http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
- The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS
- firmware feature using a defined UUID and then communicates with the feature
- using a protocol called Intel AMT Port Forwarding Protocol(Intel APF protocol).
- The protocol is used to maintain multiple sessions with Intel AMT from a
- single application.
-
- See the protocol specification in the Intel AMT Software Development Kit(SDK)
- http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
- Under "SDK Resources" => "Intel(R) vPro(TM) Gateway(MPS)"
- => "Information for Intel(R) vPro(TM) Gateway Developers"
- => "Description of the Intel AMT Port Forwarding (APF)Protocol"
-
- 2) Intel AMT Remote configuration using a Local Agent
- A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
- without requiring installing additional data to enable setup. The remote
- configuration process may involve an ISV-developed remote configuration
- agent that runs on the host.
- For more information:
- http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
- Under "Setup and Configuration of Intel AMT" =>
- "SDK Tools Supporting Setup and Configuration" =>
- "Using the Local Agent Sample"
-
- An open source Intel AMT configuration utility, implementing a local agent
- that accesses the Intel MEI driver, can be found here:
- http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
-
-Intel AMT OS Health Watchdog:
-=============================
-The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
-Whenever the OS hangs or crashes, Intel AMT will send an event
-to any subscriber to this event. This mechanism means that
-IT knows when a platform crashes even when there is a hard failure on the host.
-
-The Intel AMT Watchdog is composed of two parts:
- 1) Firmware feature - receives the heartbeats
- and sends an event when the heartbeats stop.
- 2) Intel MEI driver - connects to the watchdog feature, configures the
- watchdog and sends the heartbeats.
-
-The Intel MEI driver uses the kernel watchdog to configure the Intel AMT
-Watchdog and to send heartbeats to it. The default timeout of the
-watchdog is 120 seconds.
-
-If the Intel AMT Watchdog feature does not exist (i.e. the connection failed),
-the Intel MEI driver will disable the sending of heartbeats.
-
-Supported Chipsets:
-==================
-7 Series Chipset Family
-6 Series Chipset Family
-5 Series Chipset Family
-4 Series Chipset Family
-Mobile 4 Series Chipset Family
-ICH9
-82946GZ/GL
-82G35 Express
-82Q963/Q965
-82P965/G965
-Mobile PM965/GM965
-Mobile GME965/GLE960
-82Q35 Express
-82G33/G31/P35/P31 Express
-82Q33 Express
-82X38/X48 Express
-
----
-linux-mei@linux.intel.com
diff --git a/drivers/staging/net/Kconfig b/drivers/staging/net/Kconfig
new file mode 100644
index 0000000..a64e56b
--- /dev/null
+++ b/drivers/staging/net/Kconfig
@@ -0,0 +1,38 @@
+if NETDEVICES
+
+if WAN
+
+config PC300
+ tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
+ depends on HDLC && PCI && BROKEN
+ ---help---
+ This driver is broken because of struct tty_driver change.
+
+ Driver for the Cyclades-PC300 synchronous communication boards.
+
+ These boards provide synchronous serial interfaces to your
+ Linux box (interfaces currently available are RS-232/V.35, X.21 and
+ T1/E1). If you wish to support Multilink PPP, please select the
+ option later and read the file README.mlppp provided by PC300
+ package.
+
+ To compile this as a module, choose M here: the module
+ will be called pc300.
+
+ If unsure, say N.
+
+config PC300_MLPPP
+ bool "Cyclades-PC300 MLPPP support"
+ depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
+ help
+ Multilink PPP over the PC300 synchronous communication boards.
+
+comment "Cyclades-PC300 MLPPP support is disabled."
+ depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+comment "Refer to the file README.mlppp, provided by PC300 package."
+ depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+endif # WAN
+
+endif # NETDEVICES
diff --git a/drivers/staging/net/Makefile b/drivers/staging/net/Makefile
new file mode 100644
index 0000000..0799c43
--- /dev/null
+++ b/drivers/staging/net/Makefile
@@ -0,0 +1,5 @@
+pc300-y := pc300_drv.o
+pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
+pc300-objs := $(pc300-y)
+
+obj-$(CONFIG_PC300) += pc300.o
diff --git a/drivers/staging/net/TODO b/drivers/staging/net/TODO
new file mode 100644
index 0000000..e3446f2
--- /dev/null
+++ b/drivers/staging/net/TODO
@@ -0,0 +1,5 @@
+PC300
+The driver is very broken and cannot work with the current TTY layer. It is
+inevitable to convert it to the new TTY API.
+
+If no one steps in to adopt the driver, it will be removed in the 3.7 release.
diff --git a/drivers/net/wan/pc300-falc-lh.h b/drivers/staging/net/pc300-falc-lh.h
index 01ed23c..01ed23c 100644
--- a/drivers/net/wan/pc300-falc-lh.h
+++ b/drivers/staging/net/pc300-falc-lh.h
diff --git a/drivers/net/wan/pc300.h b/drivers/staging/net/pc300.h
index 2e4f84f..2e4f84f 100644
--- a/drivers/net/wan/pc300.h
+++ b/drivers/staging/net/pc300.h
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/staging/net/pc300_drv.c
index cb0f8d9..cb0f8d9 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/staging/net/pc300_drv.c
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/staging/net/pc300_tty.c
index 4709f42..4709f42 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/staging/net/pc300_tty.c
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index a4c17b0..ba6ed8f 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -42,7 +42,7 @@
* enum nvec_event_size - The size of an event message
* @NVEC_2BYTES: The message has one command byte and one data byte
* @NVEC_3BYTES: The message has one command byte and two data bytes
- * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and as
+ * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and has
* up to as many bytes as the number in the count byte. The
* maximum is 32
*
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index d91751f..34afc16 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -163,7 +163,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
/*
* We received a packet with either an alignment error
* or a FCS error. This may be signalling that we are
- * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK}
+ * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK]
* off. If this is the case we need to parse the
* packet to determine if we can remove a non spec
* preamble and generate a correct packet.
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 5877b2c..5631dd9 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -62,7 +62,7 @@
* You can define GET_SKBUFF_QOS() to override how the skbuff output
* function determines which output queue is used. The default
* implementation always uses the base queue for the port. If, for
- * example, you wanted to use the skb->priority fieid, define
+ * example, you wanted to use the skb->priority field, define
* GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority)
*/
#ifndef GET_SKBUFF_QOS
@@ -165,8 +165,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
/*
- * Prefetch the private data structure. It is larger that one
- * cache line.
+ * Prefetch the private data structure. It is larger than the
+ * one cache line.
*/
prefetch(priv);
@@ -291,8 +291,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
* See if we can put this skb in the FPA pool. Any strange
* behavior from the Linux networking stack will most likely
* be caused by a bug in the following code. If some field is
- * in use by the network stack and get carried over when a
- * buffer is reused, bad thing may happen. If in doubt and
+ * in use by the network stack and gets carried over when a
+ * buffer is reused, bad things may happen. If in doubt and
* you dont need the absolute best performance, disable the
* define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has
* shown a 25% increase in performance under some loads.
diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h
index 144fb99..2da5ce1 100644
--- a/drivers/staging/octeon/ethernet-util.h
+++ b/drivers/staging/octeon/ethernet-util.h
@@ -38,7 +38,7 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr)
}
/**
- * INTERFACE - convert IPD port to locgical interface
+ * INTERFACE - convert IPD port to logical interface
* @ipd_port: Port to check
*
* Returns Logical interface
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 60cba81..18f7a79 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -357,7 +357,7 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
/* Force accept multicast packets */
control.s.mcst = 2;
else
- /* Force reject multicat packets */
+ /* Force reject multicast packets */
control.s.mcst = 1;
if (dev->flags & IFF_PROMISC)
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 3d91993..992275c 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -71,8 +71,8 @@ static int dcon_hw_init(struct dcon_priv *dcon, int is_init)
ver = dcon_read(dcon, DCON_REG_ID);
if ((ver >> 8) != 0xDC) {
- printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x "
- "instead.\n", ver);
+ printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x instead.\n",
+ ver);
rc = -ENXIO;
goto err;
}
@@ -134,10 +134,10 @@ static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down)
power_up:
if (is_powered_down) {
x = 1;
- x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
if (x) {
- printk(KERN_WARNING "olpc-dcon: unable to force dcon "
- "to power up: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to force dcon to power up: %d!\n",
+ x);
return x;
}
msleep(10); /* we'll be conservative */
@@ -150,11 +150,10 @@ power_up:
x = dcon_read(dcon, DCON_REG_ID);
}
if (x < 0) {
- printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's "
- "smbus, reasserting power and praying.\n");
+ printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's smbus, reasserting power and praying.\n");
BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
x = 0;
- olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
msleep(100);
is_powered_down = 1;
goto power_up; /* argh, stupid hardware.. */
@@ -220,10 +219,10 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep)
if (sleep) {
x = 0;
- x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
if (x)
- printk(KERN_WARNING "olpc-dcon: unable to force dcon "
- "to power down: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to force dcon to power down: %d!\n",
+ x);
else
dcon->asleep = sleep;
} else {
@@ -232,8 +231,8 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep)
dcon->disp_mode |= MODE_BL_ENABLE;
x = dcon_bus_stabilize(dcon, 1);
if (x)
- printk(KERN_WARNING "olpc-dcon: unable to reinit dcon"
- " hardware: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to reinit dcon hardware: %d!\n",
+ x);
else
dcon->asleep = sleep;
@@ -304,7 +303,7 @@ static void dcon_source_switch(struct work_struct *work)
switch (source) {
case DCON_SOURCE_CPU:
- printk("dcon_source_switch to CPU\n");
+ printk(KERN_INFO "dcon_source_switch to CPU\n");
/* Enable the scanline interrupt bit */
if (dcon_write(dcon, DCON_REG_MODE,
dcon->disp_mode | MODE_SCAN_INT))
@@ -599,7 +598,7 @@ static int dcon_fb_notifier(struct notifier_block *self,
struct fb_event *evdata = data;
struct dcon_priv *dcon = container_of(self, struct dcon_priv,
fbevent_nb);
- int *blank = (int *) evdata->data;
+ int *blank = (int *)evdata->data;
if (((event != FB_EVENT_BLANK) && (event != FB_EVENT_CONBLANK)) ||
dcon->ignore_fb_events)
return 0;
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index cb6ce0c..c87fdfa 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -116,7 +116,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon)
cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS);
cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS);
- /* FIXME: Clear the posiitive status as well, just to be sure */
+ /* FIXME: Clear the positive status as well, just to be sure */
cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS);
cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS);
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index d9cdc12..1ca0e00 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -13,6 +13,7 @@ omapdrm-y := omap_drv.o \
omap_fb.o \
omap_fbdev.o \
omap_gem.o \
+ omap_gem_dmabuf.o \
omap_dmm_tiler.o \
tcm-sita.o
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 1ecb6a7..9d83060 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -347,7 +347,7 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area);
if (ret) {
kfree(block);
- return 0;
+ return ERR_PTR(-ENOMEM);
}
/* add to allocation list */
@@ -371,7 +371,7 @@ struct tiler_block *tiler_reserve_1d(size_t size)
if (tcm_reserve_1d(containers[TILFMT_PAGE], num_pages,
&block->area)) {
kfree(block);
- return 0;
+ return ERR_PTR(-ENOMEM);
}
spin_lock(&omap_dmm->list_lock);
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 620b8d5..0d2acca 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -746,7 +746,7 @@ static const struct file_operations omapdriver_fops = {
static struct drm_driver omap_drm_driver = {
.driver_features =
- DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = dev_load,
.unload = dev_unload,
.open = dev_open,
@@ -766,6 +766,10 @@ static struct drm_driver omap_drm_driver = {
.debugfs_init = omap_debugfs_init,
.debugfs_cleanup = omap_debugfs_cleanup,
#endif
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = omap_gem_prime_export,
+ .gem_prime_import = omap_gem_prime_import,
.gem_init_object = omap_gem_init_object,
.gem_free_object = omap_gem_free_object,
.gem_vm_ops = &omap_gem_vm_ops,
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index b7e0f07..f238d57 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -138,6 +138,8 @@ int omap_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args);
int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma);
int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op);
@@ -145,12 +147,24 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
void (*fxn)(void *arg), void *arg);
int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll);
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff);
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+ enum dma_data_direction dir);
int omap_gem_get_paddr(struct drm_gem_object *obj,
dma_addr_t *paddr, bool remap);
int omap_gem_put_paddr(struct drm_gem_object *obj);
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+ bool remap);
+int omap_gem_put_pages(struct drm_gem_object *obj);
+uint32_t omap_gem_flags(struct drm_gem_object *obj);
uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj);
size_t omap_gem_mmap_size(struct drm_gem_object *obj);
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buffer);
+
static inline int align_pitch(int pitch, int width, int bpp)
{
int bytespp = (bpp + 7) / 8;
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 04b235b..74260f0 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -167,7 +167,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
}
/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although
- * buffers to unpin are just just pushed to the unpin fifo so that the
+ * buffers to unpin are just pushed to the unpin fifo so that the
* caller can defer unpin until vblank.
*
* Note if this fails (ie. something went very wrong!), all buffers are
@@ -197,8 +197,11 @@ int omap_framebuffer_replace(struct drm_framebuffer *a,
pa->paddr = 0;
}
- if (pb && !ret)
+ if (pb && !ret) {
ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true);
+ if (!ret)
+ omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE);
+ }
}
if (ret) {
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index 921f058..3a0d035 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -207,13 +207,27 @@ static inline bool is_shmem(struct drm_gem_object *obj)
return obj->filp != NULL;
}
+/**
+ * shmem buffers that are mapped cached can simulate coherency via using
+ * page faulting to keep track of dirty pages
+ */
+static inline bool is_cached_coherent(struct drm_gem_object *obj)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ return is_shmem(obj) &&
+ ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
+}
+
static DEFINE_SPINLOCK(sync_lock);
/** ensure backing pages are allocated */
static int omap_gem_attach_pages(struct drm_gem_object *obj)
{
+ struct drm_device *dev = obj->dev;
struct omap_gem_object *omap_obj = to_omap_bo(obj);
struct page **pages;
+ int i, npages = obj->size >> PAGE_SHIFT;
+ dma_addr_t *addrs;
WARN_ON(omap_obj->pages);
@@ -231,16 +245,18 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
* DSS, GPU, etc. are not cache coherent:
*/
if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
- int i, npages = obj->size >> PAGE_SHIFT;
- dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
+ addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
for (i = 0; i < npages; i++) {
- addrs[i] = dma_map_page(obj->dev->dev, pages[i],
+ addrs[i] = dma_map_page(dev->dev, pages[i],
0, PAGE_SIZE, DMA_BIDIRECTIONAL);
}
- omap_obj->addrs = addrs;
+ } else {
+ addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL);
}
+ omap_obj->addrs = addrs;
omap_obj->pages = pages;
+
return 0;
}
@@ -258,14 +274,21 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj)
dma_unmap_page(obj->dev->dev, omap_obj->addrs[i],
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
- kfree(omap_obj->addrs);
- omap_obj->addrs = NULL;
}
+ kfree(omap_obj->addrs);
+ omap_obj->addrs = NULL;
+
_drm_gem_put_pages(obj, omap_obj->pages, true, false);
omap_obj->pages = NULL;
}
+/* get buffer flags */
+uint32_t omap_gem_flags(struct drm_gem_object *obj)
+{
+ return to_omap_bo(obj)->flags;
+}
+
/** get mmap offset */
static uint64_t mmap_offset(struct drm_gem_object *obj)
{
@@ -330,6 +353,7 @@ static int fault_1d(struct drm_gem_object *obj,
vma->vm_start) >> PAGE_SHIFT;
if (omap_obj->pages) {
+ omap_gem_cpu_sync(obj, pgoff);
pfn = page_to_pfn(omap_obj->pages[pgoff]);
} else {
BUG_ON(!(omap_obj->flags & OMAP_BO_DMA));
@@ -504,7 +528,6 @@ fail:
/** We override mainly to fix up some of the vm mapping flags.. */
int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
- struct omap_gem_object *omap_obj;
int ret;
ret = drm_gem_mmap(filp, vma);
@@ -513,8 +536,13 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret;
}
- /* after drm_gem_mmap(), it is safe to access the obj */
- omap_obj = to_omap_bo(vma->vm_private_data);
+ return omap_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_flags |= VM_MIXEDMAP;
@@ -524,12 +552,31 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
} else if (omap_obj->flags & OMAP_BO_UNCACHED) {
vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
} else {
+ /*
+ * We do have some private objects, at least for scanout buffers
+ * on hardware without DMM/TILER. But these are allocated write-
+ * combine
+ */
+ if (WARN_ON(!obj->filp))
+ return -EINVAL;
+
+ /*
+ * Shunt off cached objs to shmem file so they have their own
+ * address_space (so unmap_mapping_range does what we want,
+ * in particular in the case of mmap'd dmabufs)
+ */
+ fput(vma->vm_file);
+ get_file(obj->filp);
+ vma->vm_pgoff = 0;
+ vma->vm_file = obj->filp;
+
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
}
- return ret;
+ return 0;
}
+
/**
* omap_gem_dumb_create - create a dumb buffer
* @drm_file: our client file
@@ -639,6 +686,48 @@ fail:
return ret;
}
+/* Sync the buffer for CPU access.. note pages should already be
+ * attached, ie. omap_gem_get_pages()
+ */
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff)
+{
+ struct drm_device *dev = obj->dev;
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+ if (is_cached_coherent(obj) && omap_obj->addrs[pgoff]) {
+ dma_unmap_page(dev->dev, omap_obj->addrs[pgoff],
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ omap_obj->addrs[pgoff] = 0;
+ }
+}
+
+/* sync the buffer for DMA access */
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+ enum dma_data_direction dir)
+{
+ struct drm_device *dev = obj->dev;
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+ if (is_cached_coherent(obj)) {
+ int i, npages = obj->size >> PAGE_SHIFT;
+ struct page **pages = omap_obj->pages;
+ bool dirty = false;
+
+ for (i = 0; i < npages; i++) {
+ if (!omap_obj->addrs[i]) {
+ omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ dirty = true;
+ }
+ }
+
+ if (dirty) {
+ unmap_mapping_range(obj->filp->f_mapping, 0,
+ omap_gem_mmap_size(obj), 1);
+ }
+ }
+}
+
/* Get physical address for DMA.. if 'remap' is true, and the buffer is not
* already contiguous, remap it to pin in physically contiguous memory.. (ie.
* map in TILER)
@@ -703,6 +792,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
*paddr = omap_obj->paddr;
} else {
ret = -EINVAL;
+ goto fail;
}
fail:
@@ -764,9 +854,27 @@ static int get_pages(struct drm_gem_object *obj, struct page ***pages)
return 0;
}
-int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages)
+/* if !remap, and we don't have pages backing, then fail, rather than
+ * increasing the pin count (which we don't really do yet anyways,
+ * because we don't support swapping pages back out). And 'remap'
+ * might not be quite the right name, but I wanted to keep it working
+ * similarly to omap_gem_get_paddr(). Note though that mutex is not
+ * aquired if !remap (because this can be called in atomic ctxt),
+ * but probably omap_gem_get_paddr() should be changed to work in the
+ * same way. If !remap, a matching omap_gem_put_pages() call is not
+ * required (and should not be made).
+ */
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+ bool remap)
{
int ret;
+ if (!remap) {
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ if (!omap_obj->pages)
+ return -ENOMEM;
+ *pages = omap_obj->pages;
+ return 0;
+ }
mutex_lock(&obj->dev->struct_mutex);
ret = get_pages(obj, pages);
mutex_unlock(&obj->dev->struct_mutex);
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c
new file mode 100644
index 0000000..42728e0
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c
@@ -0,0 +1,220 @@
+/*
+ * drivers/staging/omapdrm/omap_gem_dmabuf.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.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.
+ *
+ * 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 "omap_drv.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *omap_gem_map_dma_buf(
+ struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = attachment->dmabuf->priv;
+ struct sg_table *sg;
+ dma_addr_t paddr;
+ int ret;
+
+ sg = kzalloc(sizeof(*sg), GFP_KERNEL);
+ if (!sg)
+ return ERR_PTR(-ENOMEM);
+
+ /* camera, etc, need physically contiguous.. but we need a
+ * better way to know this..
+ */
+ ret = omap_gem_get_paddr(obj, &paddr, true);
+ if (ret)
+ goto out;
+
+ ret = sg_alloc_table(sg, 1, GFP_KERNEL);
+ if (ret)
+ goto out;
+
+ sg_init_table(sg->sgl, 1);
+ sg_dma_len(sg->sgl) = obj->size;
+ sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0);
+ sg_dma_address(sg->sgl) = paddr;
+
+ /* this should be after _get_paddr() to ensure we have pages attached */
+ omap_gem_dma_sync(obj, dir);
+
+out:
+ if (ret)
+ return ERR_PTR(ret);
+ return sg;
+}
+
+static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = attachment->dmabuf->priv;
+ omap_gem_put_paddr(obj);
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void omap_gem_dmabuf_release(struct dma_buf *buffer)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ /* release reference that was taken when dmabuf was exported
+ * in omap_gem_prime_set()..
+ */
+ drm_gem_object_unreference_unlocked(obj);
+}
+
+
+static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
+ size_t start, size_t len, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ if (omap_gem_flags(obj) & OMAP_BO_TILED) {
+ /* TODO we would need to pin at least part of the buffer to
+ * get de-tiled view. For now just reject it.
+ */
+ return -ENOMEM;
+ }
+ /* make sure we have the pages: */
+ return omap_gem_get_pages(obj, &pages, true);
+}
+
+static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
+ size_t start, size_t len, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ omap_gem_put_pages(obj);
+}
+
+
+static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer,
+ unsigned long page_num)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ omap_gem_cpu_sync(obj, page_num);
+ return kmap_atomic(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer,
+ unsigned long page_num, void *addr)
+{
+ kunmap_atomic(addr);
+}
+
+static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer,
+ unsigned long page_num)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ omap_gem_cpu_sync(obj, page_num);
+ return kmap(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer,
+ unsigned long page_num, void *addr)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ kunmap(pages[page_num]);
+}
+
+/*
+ * TODO maybe we can split up drm_gem_mmap to avoid duplicating
+ * some here.. or at least have a drm_dmabuf_mmap helper.
+ */
+static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
+ struct vm_area_struct *vma)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ int ret = 0;
+
+ if (WARN_ON(!obj->filp))
+ return -EINVAL;
+
+ /* Check for valid size. */
+ if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!obj->dev->driver->gem_vm_ops) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
+ vma->vm_ops = obj->dev->driver->gem_vm_ops;
+ vma->vm_private_data = obj;
+ vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+ /* Take a ref for this mapping of the object, so that the fault
+ * handler can dereference the mmap offset's pointer to the object.
+ * This reference is cleaned up by the corresponding vm_close
+ * (which should happen whether the vma was created by this call, or
+ * by a vm_open due to mremap or partial unmap or whatever).
+ */
+ vma->vm_ops->open(vma);
+
+out_unlock:
+
+ return omap_gem_mmap_obj(obj, vma);
+}
+
+struct dma_buf_ops omap_dmabuf_ops = {
+ .map_dma_buf = omap_gem_map_dma_buf,
+ .unmap_dma_buf = omap_gem_unmap_dma_buf,
+ .release = omap_gem_dmabuf_release,
+ .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+ .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+ .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+ .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+ .kmap = omap_gem_dmabuf_kmap,
+ .kunmap = omap_gem_dmabuf_kunmap,
+ .mmap = omap_gem_dmabuf_mmap,
+};
+
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags)
+{
+ return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600);
+}
+
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buffer)
+{
+ struct drm_gem_object *obj;
+
+ /* is this one of own objects? */
+ if (buffer->ops == &omap_dmabuf_ops) {
+ obj = buffer->priv;
+ /* is it from our device? */
+ if (obj->dev == dev) {
+ drm_gem_object_reference(obj);
+ return obj;
+ }
+ }
+
+ /*
+ * TODO add support for importing buffers from other devices..
+ * for now we don't need this but would be nice to add eventually
+ */
+ return ERR_PTR(-EINVAL);
+}
diff --git a/drivers/staging/omapdrm/tcm-sita.c b/drivers/staging/omapdrm/tcm-sita.c
index 10d5ac3..efb6095 100644
--- a/drivers/staging/omapdrm/tcm-sita.c
+++ b/drivers/staging/omapdrm/tcm-sita.c
@@ -200,7 +200,7 @@ static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
*
* @param w width
* @param h height
- * @param area pointer to the area that will be populated with the reesrved
+ * @param area pointer to the area that will be populated with the reserved
* area
*
* @return 0 on success, non-0 error value on failure.
diff --git a/drivers/staging/ozwpan/README b/drivers/staging/ozwpan/README
index bb1a69b..7c055ec 100644
--- a/drivers/staging/ozwpan/README
+++ b/drivers/staging/ozwpan/README
@@ -9,7 +9,7 @@ technology.
To operate the driver must be bound to a suitable network interface. This can
be done when the module is loaded (specifying the name of the network interface
-as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
+as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
loading using an ioctl call. See the ozappif.h file and the ioctls
OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index af02732..1b59b07 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -11,13 +11,13 @@
#define OZ_IOCTL_MAGIC 0xf4
struct oz_mac_addr {
- unsigned char a[6];
+ __u8 a[6];
};
#define OZ_MAX_PDS 8
struct oz_pd_list {
- int count;
+ __u32 count;
struct oz_mac_addr addr[OZ_MAX_PDS];
};
@@ -27,18 +27,10 @@ struct oz_binding_info {
char name[OZ_MAX_BINDING_LEN];
};
-struct oz_test {
- int action;
-};
-
#define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
#define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
#define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_CLEAR_EVENTS _IO(OZ_IOCTL_MAGIC, 3)
-#define OZ_IOCTL_GET_EVENTS _IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist)
#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_TEST _IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test)
-#define OZ_IOCTL_SET_EVENT_MASK _IOW(OZ_IOCTL_MAGIC, 7, unsigned long)
#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
#define OZ_IOCTL_MAX 9
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 1c380d6..27325f7 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -41,9 +41,6 @@ struct oz_serial_ctx {
};
/*------------------------------------------------------------------------------
*/
-int g_taction;
-/*------------------------------------------------------------------------------
- */
static struct oz_cdev g_cdev;
/*------------------------------------------------------------------------------
* Context: process and softirq
@@ -276,20 +273,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -EFAULT;
}
break;
-#ifdef WANT_EVENT_TRACE
- case OZ_IOCTL_CLEAR_EVENTS:
- oz_events_clear();
- break;
- case OZ_IOCTL_GET_EVENTS:
- rc = oz_events_copy((void __user *)arg);
- break;
- case OZ_IOCTL_SET_EVENT_MASK:
- if (copy_from_user(&g_evt_mask, (void __user *)arg,
- sizeof(unsigned long))) {
- return -EFAULT;
- }
- break;
-#endif /* WANT_EVENT_TRACE */
case OZ_IOCTL_ADD_BINDING:
case OZ_IOCTL_REMOVE_BINDING: {
struct oz_binding_info b;
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
index 73703d3..7f66b4f 100644
--- a/drivers/staging/ozwpan/ozevent.c
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -5,29 +5,46 @@
*/
#include "ozconfig.h"
#ifdef WANT_EVENT_TRACE
+#include <linux/module.h>
+#include <linux/debugfs.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include "oztrace.h"
#include "ozevent.h"
+#include "ozappif.h"
/*------------------------------------------------------------------------------
+ * Although the event mask is logically part of the oz_evtdev structure, it is
+ * needed outside of this file so define it seperately to avoid the need to
+ * export definition of struct oz_evtdev.
*/
-unsigned long g_evt_mask = 0xffffffff;
+u32 g_evt_mask;
/*------------------------------------------------------------------------------
*/
#define OZ_MAX_EVTS 2048 /* Must be power of 2 */
-DEFINE_SPINLOCK(g_eventlock);
-static int g_evt_in;
-static int g_evt_out;
-static int g_missed_events;
-static struct oz_event g_events[OZ_MAX_EVTS];
+struct oz_evtdev {
+ struct dentry *root_dir;
+ int evt_in;
+ int evt_out;
+ int missed_events;
+ int present;
+ atomic_t users;
+ spinlock_t lock;
+ struct oz_event evts[OZ_MAX_EVTS];
+};
+
+static struct oz_evtdev g_evtdev;
+
/*------------------------------------------------------------------------------
* Context: process
*/
void oz_event_init(void)
{
+ /* Because g_evtdev is static external all fields initally zero so no
+ * need to reinitialised those.
+ */
oz_trace("Event tracing initialized\n");
- g_evt_in = g_evt_out = 0;
- g_missed_events = 0;
+ spin_lock_init(&g_evtdev.lock);
+ atomic_set(&g_evtdev.users, 0);
}
/*------------------------------------------------------------------------------
* Context: process
@@ -43,74 +60,136 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
{
unsigned long irqstate;
int ix;
- spin_lock_irqsave(&g_eventlock, irqstate);
- ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
- if (ix != g_evt_out) {
- struct oz_event *e = &g_events[g_evt_in];
+ spin_lock_irqsave(&g_evtdev.lock, irqstate);
+ ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
+ if (ix != g_evtdev.evt_out) {
+ struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
e->jiffies = jiffies;
e->evt = evt;
e->ctx1 = ctx1;
e->ctx2 = ctx2;
- e->ctx3 = ctx3;
+ e->ctx3 = (__u32)(unsigned long)ctx3;
e->ctx4 = ctx4;
- g_evt_in = ix;
+ g_evtdev.evt_in = ix;
} else {
- g_missed_events++;
+ g_evtdev.missed_events++;
}
- spin_unlock_irqrestore(&g_eventlock, irqstate);
+ spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
}
/*------------------------------------------------------------------------------
* Context: process
*/
-int oz_events_copy(struct oz_evtlist __user *lst)
+static void oz_events_clear(struct oz_evtdev *dev)
{
- int first;
- int ix;
- struct hdr {
- int count;
- int missed;
- } hdr;
- ix = g_evt_out;
- hdr.count = g_evt_in - ix;
- if (hdr.count < 0)
- hdr.count += OZ_MAX_EVTS;
- if (hdr.count > OZ_EVT_LIST_SZ)
- hdr.count = OZ_EVT_LIST_SZ;
- hdr.missed = g_missed_events;
- g_missed_events = 0;
- if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
- return -EFAULT;
- first = OZ_MAX_EVTS - ix;
- if (first > hdr.count)
- first = hdr.count;
- if (first) {
- int sz = first*sizeof(struct oz_event);
- void __user *p = (void __user *)lst->evts;
- if (copy_to_user(p, &g_events[ix], sz))
- return -EFAULT;
- if (hdr.count > first) {
- p = (void __user *)&lst->evts[first];
- sz = (hdr.count-first)*sizeof(struct oz_event);
- if (copy_to_user(p, g_events, sz))
- return -EFAULT;
- }
+ unsigned long irqstate;
+ oz_trace("Clearing events\n");
+ spin_lock_irqsave(&dev->lock, irqstate);
+ dev->evt_in = dev->evt_out = 0;
+ dev->missed_events = 0;
+ spin_unlock_irqrestore(&dev->lock, irqstate);
+}
+#ifdef CONFIG_DEBUG_FS
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_open(struct inode *inode, struct file *filp)
+{
+ oz_trace("oz_evt_open()\n");
+ oz_trace("Open flags: 0x%x\n", filp->f_flags);
+ if (atomic_add_return(1, &g_evtdev.users) == 1) {
+ oz_events_clear(&g_evtdev);
+ return nonseekable_open(inode, filp);
+ } else {
+ atomic_dec(&g_evtdev.users);
+ return -EBUSY;
}
- ix += hdr.count;
- if (ix >= OZ_MAX_EVTS)
- ix -= OZ_MAX_EVTS;
- g_evt_out = ix;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_release(struct inode *inode, struct file *filp)
+{
+ oz_events_clear(&g_evtdev);
+ atomic_dec(&g_evtdev.users);
+ g_evt_mask = 0;
+ oz_trace("oz_evt_release()\n");
return 0;
}
/*------------------------------------------------------------------------------
* Context: process
*/
-void oz_events_clear(void)
+ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *fpos)
{
- unsigned long irqstate;
- spin_lock_irqsave(&g_eventlock, irqstate);
- g_evt_in = g_evt_out = 0;
- g_missed_events = 0;
- spin_unlock_irqrestore(&g_eventlock, irqstate);
+ struct oz_evtdev *dev = &g_evtdev;
+ int rc = 0;
+ int nb_evts = count / sizeof(struct oz_event);
+ int n;
+ int sz;
+
+ n = dev->evt_in - dev->evt_out;
+ if (n < 0)
+ n += OZ_MAX_EVTS;
+ if (nb_evts > n)
+ nb_evts = n;
+ if (nb_evts == 0)
+ goto out;
+ n = OZ_MAX_EVTS - dev->evt_out;
+ if (n > nb_evts)
+ n = nb_evts;
+ sz = n * sizeof(struct oz_event);
+ if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ if (n == nb_evts)
+ goto out2;
+ n = nb_evts - n;
+ if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
+ rc = -EFAULT;
+ goto out;
+ }
+out2:
+ dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
+ rc = nb_evts * sizeof(struct oz_event);
+out:
+ return rc;
}
-#endif /* WANT_EVENT_TRACE */
+/*------------------------------------------------------------------------------
+ */
+const struct file_operations oz_events_fops = {
+ .owner = THIS_MODULE,
+ .open = oz_events_open,
+ .release = oz_events_release,
+ .read = oz_events_read,
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_init(void)
+{
+ struct dentry *parent;
+ parent = debugfs_create_dir("ozwpan", NULL);
+ if (parent == NULL) {
+ oz_trace("Failed to create debugfs directory ozmo\n");
+ return;
+ } else {
+ g_evtdev.root_dir = parent;
+ if (debugfs_create_file("events", S_IRUSR, parent, NULL,
+ &oz_events_fops) == NULL)
+ oz_trace("Failed to create file ozmo/events\n");
+ if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent,
+ &g_evt_mask) == NULL)
+ oz_trace("Failed to create file ozmo/event_mask\n");
+ }
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_remove(void)
+{
+ debugfs_remove_recursive(g_evtdev.root_dir);
+}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* WANT_EVENT_TRACE */
diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h
index f033d01..32f6f98 100644
--- a/drivers/staging/ozwpan/ozevent.h
+++ b/drivers/staging/ozwpan/ozevent.h
@@ -9,23 +9,24 @@
#include "ozeventdef.h"
#ifdef WANT_EVENT_TRACE
-extern unsigned long g_evt_mask;
+extern u32 g_evt_mask;
void oz_event_init(void);
void oz_event_term(void);
void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
+void oz_debugfs_init(void);
+void oz_debugfs_remove(void);
#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \
do { \
if ((1<<(__evt)) & g_evt_mask) \
oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \
} while (0)
-int oz_events_copy(struct oz_evtlist __user *lst);
-void oz_events_clear(void);
+
#else
#define oz_event_init()
#define oz_event_term()
#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
-#define oz_events_copy(__lst)
-#define oz_events_clear()
+#define oz_debugfs_init()
+#define oz_debugfs_remove()
#endif /* WANT_EVENT_TRACE */
#endif /* _OZEVENT_H */
diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h
index a880288..4b93898 100644
--- a/drivers/staging/ozwpan/ozeventdef.h
+++ b/drivers/staging/ozwpan/ozeventdef.h
@@ -29,19 +29,12 @@
#define OZ_EVT_DEBUG 20
struct oz_event {
- unsigned long jiffies;
- unsigned char evt;
- unsigned char ctx1;
- unsigned short ctx2;
- void *ctx3;
- unsigned ctx4;
-};
-
-#define OZ_EVT_LIST_SZ 64
-struct oz_evtlist {
- int count;
- int missed;
- struct oz_event evts[OZ_EVT_LIST_SZ];
+ __u32 jiffies;
+ __u8 evt;
+ __u8 ctx1;
+ __u16 ctx2;
+ __u32 ctx3;
+ __u32 ctx4;
};
#endif /* _OZEVENTDEF_H */
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index 750b14e..251f07c 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -1416,7 +1416,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
break;
case USB_REQ_GET_CONFIGURATION:
- /* We short curcuit this case and reply directly since
+ /* We short circuit this case and reply directly since
* we have the selected configuration number cached.
*/
oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1432,7 +1432,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
}
break;
case USB_REQ_GET_INTERFACE:
- /* We short curcuit this case and reply directly since
+ /* We short circuit this case and reply directly since
* we have the selected interface alternative cached.
*/
oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1463,7 +1463,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
rc = -ENOMEM;
} else {
/* Note: we are queuing the request after we have
- * submitted it to be tranmitted. If the request were
+ * submitted it to be transmitted. If the request were
* to complete before we queued it then it would not
* be found in the queue. It seems impossible for
* this to happen but if it did the request would
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index aaf2ccc..7579645 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -33,6 +33,9 @@ static int __init ozwpan_init(void)
oz_protocol_init(g_net_dev);
oz_app_enable(OZ_APPID_USB, 1);
oz_apps_init();
+#ifdef CONFIG_DEBUG_FS
+ oz_debugfs_init();
+#endif
return 0;
}
/*------------------------------------------------------------------------------
@@ -44,6 +47,9 @@ static void __exit ozwpan_exit(void)
oz_apps_term();
oz_cdev_deregister();
oz_event_term();
+#ifdef CONFIG_DEBUG_FS
+ oz_debugfs_remove();
+#endif
}
/*------------------------------------------------------------------------------
*/
@@ -53,6 +59,6 @@ module_exit(ozwpan_exit);
MODULE_AUTHOR("Chris Kelly");
MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.8");
+MODULE_VERSION("1.0.9");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
index 9e74f96..8fa7f25 100644
--- a/drivers/staging/ozwpan/ozusbsvc.c
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -7,7 +7,7 @@
* The implementation of this service is split into two parts the first of which
* is protocol independent and the second contains protocol specific details.
* This split is to allow alternative protocols to be defined.
- * The implemenation of this service uses ozhcd.c to implement a USB HCD.
+ * The implementation of this service uses ozhcd.c to implement a USB HCD.
* -----------------------------------------------------------------------------
*/
#include <linux/init.h>
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 6183573..7365089 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -754,7 +754,7 @@ static void lcd_backlight(int on)
if (lcd_bl_pin == PIN_NONE)
return;
- /* The backlight is activated by seting the AUTOFEED line to +5V */
+ /* The backlight is activated by setting the AUTOFEED line to +5V */
spin_lock(&pprt_lock);
bits.bl = on;
panel_set_bits();
diff --git a/drivers/staging/quatech_usb2/Kconfig b/drivers/staging/quatech_usb2/Kconfig
deleted file mode 100644
index 1494f42..0000000
--- a/drivers/staging/quatech_usb2/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_SERIAL_QUATECH_USB2
- tristate "USB Quatech xSU2-[14]00 USB Serial Driver"
- depends on USB_SERIAL
- help
- Say Y here if you want to use a Quatech USB2.0 to serial adaptor. This
- driver supports the SSU2-100, DSU2-100, DSU2-400, QSU2-100, QSU2-400,
- ESU2-400 and ESU2-100 USB2.0 to RS232 / 485 / 422 serial adaptors.
-
- Some hardware has an incorrect product string and announces itself as
- ESU-100 (which uses the serqt driver) even though it is an ESU2-100.
- Check the label on the bottom of your device.
-
- To compile this driver as a module, choose M here: the module will be
- called quatech_usb2 .
-
diff --git a/drivers/staging/quatech_usb2/Makefile b/drivers/staging/quatech_usb2/Makefile
deleted file mode 100644
index bcd1f89..0000000
--- a/drivers/staging/quatech_usb2/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2.o
diff --git a/drivers/staging/quatech_usb2/TODO b/drivers/staging/quatech_usb2/TODO
deleted file mode 100644
index 67f61db..0000000
--- a/drivers/staging/quatech_usb2/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-Incomplete list of things that this driver does not yet implement completely or
-at all. some of these may not be possible to implement because the hardware
-support does not exist. Others may be possible, but the magic control codes to
-make them happen are unknown, and some may just need the driver support to
-implement them writing.
-
-* Mark/Space parity is not implemented (reported back correctly)
-* IXANY flow control mode is not implemented (flag ignored completely)
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
deleted file mode 100644
index bb977e0..0000000
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*
- * Driver for Quatech Inc USB2.0 to serial adaptors. Largely unrelated to the
- * serqt_usb driver, based on a re-write of the vendor supplied serqt_usb2 code,
- * which is unrelated to the serqt_usb2 in the staging kernel
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static bool debug;
-
-/* Version Information */
-#define DRIVER_VERSION "v2.00"
-#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc"
-#define DRIVER_DESC "Quatech USB 2.0 to Serial Driver"
-
-/* vendor and device IDs */
-#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
-#define QUATECH_SSU2_100 0xC120 /* RS232 single port */
-#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
-#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
-#define QUATECH_QSU2_100 0xC160 /* RS232 four port */
-#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
-#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
-#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
-
-/* magic numbers go here, when we find out which ones are needed */
-
-#define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */
-#define QU2BOX232 0x40 /* RS232 mode on MEI devices */
-#define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */
-#define QT2_FIFO_DEPTH 1024 /* size of hardware fifos */
-#define QT2_TX_HEADER_LENGTH 5
-/* length of the header sent to the box with each write URB */
-
-/* directions for USB transfers */
-#define USBD_TRANSFER_DIRECTION_IN 0xc0
-#define USBD_TRANSFER_DIRECTION_OUT 0x40
-
-/* special Quatech command IDs. These are pushed down the
- USB control pipe to get the box on the end to do things */
-#define QT_SET_GET_DEVICE 0xc2
-#define QT_OPEN_CLOSE_CHANNEL 0xca
-/*#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
-#define QT_SET_ATF 0xcd*/
-#define QT2_GET_SET_REGISTER 0xc0
-#define QT2_GET_SET_UART 0xc1
-#define QT2_HW_FLOW_CONTROL_MASK 0xc5
-#define QT2_SW_FLOW_CONTROL_MASK 0xc6
-#define QT2_SW_FLOW_CONTROL_DISABLE 0xc7
-#define QT2_BREAK_CONTROL 0xc8
-#define QT2_STOP_RECEIVE 0xe0
-#define QT2_FLUSH_DEVICE 0xc4
-#define QT2_GET_SET_QMCR 0xe1
-
-/* sorts of flush we can do on */
-#define QT2_FLUSH_RX 0x00
-#define QT2_FLUSH_TX 0x01
-
-/* port setting constants, used to set up serial port speeds, flow
- * control and so on */
-#define QT2_SERIAL_MCR_DTR 0x01
-#define QT2_SERIAL_MCR_RTS 0x02
-#define QT2_SERIAL_MCR_LOOP 0x10
-
-#define QT2_SERIAL_MSR_CTS 0x10
-#define QT2_SERIAL_MSR_CD 0x80
-#define QT2_SERIAL_MSR_RI 0x40
-#define QT2_SERIAL_MSR_DSR 0x20
-#define QT2_SERIAL_MSR_MASK 0xf0
-
-#define QT2_SERIAL_8_DATA 0x03
-#define QT2_SERIAL_7_DATA 0x02
-#define QT2_SERIAL_6_DATA 0x01
-#define QT2_SERIAL_5_DATA 0x00
-
-#define QT2_SERIAL_ODD_PARITY 0x08
-#define QT2_SERIAL_EVEN_PARITY 0x18
-#define QT2_SERIAL_TWO_STOPB 0x04
-#define QT2_SERIAL_ONE_STOPB 0x00
-
-#define QT2_MAX_BAUD_RATE 921600
-#define QT2_MAX_BAUD_REMAINDER 4608
-
-#define QT2_SERIAL_LSR_OE 0x02
-#define QT2_SERIAL_LSR_PE 0x04
-#define QT2_SERIAL_LSR_FE 0x08
-#define QT2_SERIAL_LSR_BI 0x10
-
-/* value of Line Status Register when UART has completed
- * emptying data out on the line */
-#define QT2_LSR_TEMT 0x40
-
-/* register numbers on each UART, for use with qt2_box_[get|set]_register*/
-#define QT2_XMT_HOLD_REGISTER 0x00
-#define QT2_XVR_BUFFER_REGISTER 0x00
-#define QT2_FIFO_CONTROL_REGISTER 0x02
-#define QT2_LINE_CONTROL_REGISTER 0x03
-#define QT2_MODEM_CONTROL_REGISTER 0x04
-#define QT2_LINE_STATUS_REGISTER 0x05
-#define QT2_MODEM_STATUS_REGISTER 0x06
-
-/* handy macros for doing escape sequence parsing on data reads */
-#define THISCHAR ((unsigned char *)(urb->transfer_buffer))[i]
-#define NEXTCHAR ((unsigned char *)(urb->transfer_buffer))[i + 1]
-#define THIRDCHAR ((unsigned char *)(urb->transfer_buffer))[i + 2]
-#define FOURTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 3]
-#define FIFTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 4]
-
-static const struct usb_device_id quausb2_id_table[] = {
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, quausb2_id_table);
-
-/* custom structures we need go here */
-static struct usb_driver quausb2_usb_driver = {
- .name = "quatech-usb2-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = quausb2_id_table,
-};
-
-/**
- * quatech2_port: Structure in which to keep all the messy stuff that this
- * driver needs alongside the usb_serial_port structure
- * @read_urb_busy: Flag indicating that port->read_urb is in use
- * @close_pending: flag indicating that this port is in the process of
- * being closed (and so no new reads / writes should be started).
- * @shadowLSR: Last received state of the line status register, holds the
- * value of the line status flags from the port
- * @shadowMSR: Last received state of the modem status register, holds
- * the value of the modem status received from the port
- * @rcv_flush: Flag indicating that a receive flush has occurred on
- * the hardware.
- * @xmit_flush: Flag indicating that a transmit flush has been processed by
- * the hardware.
- * @tx_pending_bytes: Number of bytes waiting to be sent. This total
- * includes the size (excluding header) of URBs that have been submitted but
- * have not yet been sent to to the device, and bytes that have been sent out
- * of the port but not yet reported sent by the "xmit_empty" messages (which
- * indicate the number of bytes sent each time they are received, despite the
- * misleading name).
- * - Starts at zero when port is initialised.
- * - is incremented by the size of the data to be written (no headers)
- * each time a write urb is dispatched.
- * - is decremented each time a "transmit empty" message is received
- * by the driver in the data stream.
- * @lock: Mutex to lock access to this structure when we need to ensure that
- * races don't occur to access bits of it.
- * @open_count: The number of uses of the port currently having
- * it open, i.e. the reference count.
- */
-struct quatech2_port {
- int magic;
- bool read_urb_busy;
- bool close_pending;
- __u8 shadowLSR;
- __u8 shadowMSR;
- bool rcv_flush;
- bool xmit_flush;
- int tx_pending_bytes;
- struct mutex modelock;
- int open_count;
-
- char active; /* someone has this device open */
- unsigned char *xfer_to_tty_buffer;
- wait_queue_head_t wait;
- __u8 shadowLCR; /* last LCR value received */
- __u8 shadowMCR; /* last MCR value received */
- char RxHolding;
- struct semaphore pend_xmit_sem; /* locks this structure */
- spinlock_t lock;
-};
-
-/**
- * Structure to hold device-wide internal status information
- * @param ReadBulkStopped The last bulk read attempt ended in tears
- * @param open_ports The number of serial ports currently in use on the box
- * @param current_port Pointer to the serial port structure of the port which
- * the read stream is currently directed to. Escape sequences in the read
- * stream will change this around as data arrives from different ports on the
- * box
- * @buffer_size: The max size buffer each URB can take, used to set the size of
- * the buffers allocated for writing to each port on the device (we need to
- * store this because it is known only to the endpoint, but used each time a
- * port is opened and a new buffer is allocated.
- */
-struct quatech2_dev {
- bool ReadBulkStopped;
- char open_ports;
- struct usb_serial_port *current_port;
- int buffer_size;
-};
-
-/* structure which holds line and modem status flags */
-struct qt2_status_data {
- __u8 line_status;
- __u8 modem_status;
-};
-
-/* Function prototypes */
-static int qt2_boxpoweron(struct usb_serial *serial);
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
- __u8 QMCR_Value);
-static int port_paranoia_check(struct usb_serial_port *port,
- const char *function);
-static int serial_paranoia_check(struct usb_serial *serial,
- const char *function);
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
- *port);
-static inline void qt2_set_port_private(struct usb_serial_port *port,
- struct quatech2_port *data);
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
- *serial);
-static inline void qt2_set_dev_private(struct usb_serial *serial,
- struct quatech2_dev *data);
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
- Uart_Number, struct qt2_status_data *pDeviceData);
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16
- Uart_Number);
-static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short divisor, unsigned char LCR);
-static void qt2_read_bulk_callback(struct urb *urb);
-static void qt2_write_bulk_callback(struct urb *urb);
-static void qt2_process_line_status(struct usb_serial_port *port,
- unsigned char LineStatus);
-static void qt2_process_modem_status(struct usb_serial_port *port,
- unsigned char ModemStatus);
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
- unsigned char fourth_char, unsigned char fifth_char);
-static void qt2_process_port_change(struct usb_serial_port *port,
- unsigned char New_Current_Port);
-static void qt2_process_rcv_flush(struct usb_serial_port *port);
-static void qt2_process_xmit_flush(struct usb_serial_port *port);
-static void qt2_process_rx_char(struct usb_serial_port *port,
- unsigned char data);
-static int qt2_box_get_register(struct usb_serial *serial,
- unsigned char uart_number, unsigned short register_num,
- __u8 *pValue);
-static int qt2_box_set_register(struct usb_serial *serial,
- unsigned short Uart_Number, unsigned short Register_Num,
- unsigned short Value);
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short default_divisor, unsigned char default_LCR);
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
- unsigned int UartNumber, bool bSet);
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
- unsigned char stop_char, unsigned char start_char);
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber);
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
- unsigned short stop);
-
-/* implementation functions, roughly in order of use, are here */
-static int qt2_calc_num_ports(struct usb_serial *serial)
-{
- int num_ports;
- int flag_as_400;
- switch (serial->dev->descriptor.idProduct) {
- case QUATECH_SSU2_100:
- num_ports = 1;
- break;
-
- case QUATECH_DSU2_400:
- flag_as_400 = true;
- case QUATECH_DSU2_100:
- num_ports = 2;
- break;
-
- case QUATECH_QSU2_400:
- flag_as_400 = true;
- case QUATECH_QSU2_100:
- num_ports = 4;
- break;
-
- case QUATECH_ESU2_400:
- flag_as_400 = true;
- case QUATECH_ESU2_100:
- num_ports = 8;
- break;
- default:
- num_ports = 1;
- break;
- }
- return num_ports;
-}
-
-static int qt2_attach(struct usb_serial *serial)
-{
- struct usb_serial_port *port;
- struct quatech2_port *qt2_port; /* port-specific private data pointer */
- struct quatech2_dev *qt2_dev; /* dev-specific private data pointer */
- int i;
- /* stuff for storing endpoint addresses now */
- struct usb_endpoint_descriptor *endpoint;
- struct usb_host_interface *iface_desc;
- struct usb_serial_port *port0; /* first port structure on device */
-
- /* check how many endpoints there are on the device, for
- * sanity's sake */
- dbg("%s(): Endpoints: %d bulk in, %d bulk out, %d interrupt in",
- __func__, serial->num_bulk_in,
- serial->num_bulk_out, serial->num_interrupt_in);
- if ((serial->num_bulk_in != 1) || (serial->num_bulk_out != 1)) {
- dbg("Device has wrong number of bulk endpoints!");
- return -ENODEV;
- }
- iface_desc = serial->interface->cur_altsetting;
-
- /* Set up per-device private data, storing extra data alongside
- * struct usb_serial */
- qt2_dev = kzalloc(sizeof(*qt2_dev), GFP_KERNEL);
- if (!qt2_dev) {
- dbg("%s: kmalloc for quatech2_dev failed!",
- __func__);
- return -ENOMEM;
- }
- qt2_dev->open_ports = 0; /* no ports open */
- qt2_set_dev_private(serial, qt2_dev); /* store private data */
-
- /* Now setup per port private data, which replaces all the things
- * that quatech added to standard kernel structures in their driver */
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL);
- if (!qt2_port) {
- dbg("%s: kmalloc for quatech2_port (%d) failed!.",
- __func__, i);
- return -ENOMEM;
- }
- /* initialise stuff in the structure */
- qt2_port->open_count = 0; /* port is not open */
- spin_lock_init(&qt2_port->lock);
- mutex_init(&qt2_port->modelock);
- qt2_set_port_private(port, qt2_port);
- }
-
- /* gain access to port[0]'s structure because we want to store
- * device-level stuff in it */
- if (serial_paranoia_check(serial, __func__))
- return -ENODEV;
- port0 = serial->port[0]; /* get the first port's device structure */
-
- /* print endpoint addresses so we can check them later
- * by hand */
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in at %#.2x",
- endpoint->bEndpointAddress);
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out at %#.2x",
- endpoint->bEndpointAddress);
- qt2_dev->buffer_size = endpoint->wMaxPacketSize;
- /* max size of URB needs recording for the device */
- }
- } /* end printing endpoint addresses */
-
- /* switch on power to the hardware */
- if (qt2_boxpoweron(serial) < 0) {
- dbg("qt2_boxpoweron() failed");
- goto startup_error;
- }
- /* set all ports to RS232 mode */
- for (i = 0; i < serial->num_ports; ++i) {
- if (qt2_boxsetQMCR(serial, i, QU2BOX232) < 0) {
- dbg("qt2_boxsetQMCR() on port %d failed",
- i);
- goto startup_error;
- }
- }
-
- return 0;
-
-startup_error:
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- qt2_port = qt2_get_port_private(port);
- kfree(qt2_port);
- qt2_set_port_private(port, NULL);
- }
- qt2_dev = qt2_get_dev_private(serial);
- kfree(qt2_dev);
- qt2_set_dev_private(serial, NULL);
-
- dbg("Exit fail %s\n", __func__);
- return -EIO;
-}
-
-static void qt2_release(struct usb_serial *serial)
-{
- struct usb_serial_port *port;
- struct quatech2_port *qt_port;
- int i;
-
- dbg("enterting %s", __func__);
-
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- if (!port)
- continue;
-
- qt_port = usb_get_serial_port_data(port);
- kfree(qt_port);
- usb_set_serial_port_data(port, NULL);
- }
-}
-/* This function is called once per serial port on the device, when
- * that port is opened by a userspace application.
- * The tty_struct and the usb_serial_port belong to this port,
- * i.e. there are multiple ones for a multi-port device.
- * However the usb_serial_port structure has a back-pointer
- * to the parent usb_serial structure which belongs to the device,
- * so we can access either the device-wide information or
- * any other port's information (because there are also forward
- * pointers) via that pointer.
- * This is most helpful if the device shares resources (e.g. end
- * points) between different ports
- */
-int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
- struct usb_serial *serial; /* device structure */
- struct usb_serial_port *port0; /* first port structure on device */
- struct quatech2_port *port_extra; /* extra data for this port */
- struct quatech2_port *port0_extra; /* extra data for first port */
- struct quatech2_dev *dev_extra; /* extra data for the device */
- struct qt2_status_data ChannelData;
- unsigned short default_divisor = QU2BOXSPD9600;
- unsigned char default_LCR = QT2_SERIAL_8_DATA;
- int status;
- int result;
-
- if (port_paranoia_check(port, __func__))
- return -ENODEV;
-
- dbg("%s(): port %d", __func__, port->number);
-
- serial = port->serial; /* get the parent device structure */
- if (serial_paranoia_check(serial, __func__)) {
- dbg("usb_serial struct failed sanity check");
- return -ENODEV;
- }
- dev_extra = qt2_get_dev_private(serial);
- /* get the device private data */
- if (dev_extra == NULL) {
- dbg("device extra data pointer is null");
- return -ENODEV;
- }
- port0 = serial->port[0]; /* get the first port's device structure */
- if (port_paranoia_check(port0, __func__)) {
- dbg("port0 usb_serial_port struct failed sanity check");
- return -ENODEV;
- }
-
- port_extra = qt2_get_port_private(port);
- port0_extra = qt2_get_port_private(port0);
- if (port_extra == NULL || port0_extra == NULL) {
- dbg("failed to get private data for port or port0");
- return -ENODEV;
- }
-
- /* FIXME: are these needed? Does it even do anything useful? */
- /* get the modem and line status values from the UART */
- status = qt2_openboxchannel(serial, port->number,
- &ChannelData);
- if (status < 0) {
- dbg("qt2_openboxchannel on channel %d failed",
- port->number);
- return status;
- }
- port_extra->shadowLSR = ChannelData.line_status &
- (QT2_SERIAL_LSR_OE | QT2_SERIAL_LSR_PE |
- QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
- port_extra->shadowMSR = ChannelData.modem_status &
- (QT2_SERIAL_MSR_CTS | QT2_SERIAL_MSR_DSR |
- QT2_SERIAL_MSR_RI | QT2_SERIAL_MSR_CD);
-
-/* port_extra->fifo_empty_flag = true;*/
- dbg("qt2_openboxchannel on channel %d completed.",
- port->number);
-
- /* Set Baud rate to default and turn off flow control here */
- status = qt2_conf_uart(serial, port->number, default_divisor,
- default_LCR);
- if (status < 0) {
- dbg("qt2_conf_uart() failed on channel %d",
- port->number);
- return status;
- }
- dbg("qt2_conf_uart() completed on channel %d",
- port->number);
-
- /*
- * At this point we will need some end points to make further progress.
- * Handlily, the correct endpoint addresses have been filled out into
- * the usb_serial_port structure for us by the driver core, so we
- * already have access to them.
- * As there is only one bulk in and one bulk out end-point, these are in
- * port[0]'s structure, and the rest are uninitialised. Handily,
- * when we do a write to a port, we will use the same endpoint
- * regardless of the port, with a 5-byte header added on to
- * tell the box which port it should eventually come out of, so we only
- * need the one set of endpoints. We will have one URB per port for
- * writing, so that multiple ports can be writing at once.
- * Finally we need a bulk in URB to use for background reads from the
- * device, which will deal with uplink data from the box to host.
- */
- dbg("port0 bulk in endpoint is %#.2x", port0->bulk_in_endpointAddress);
- dbg("port0 bulk out endpoint is %#.2x",
- port0->bulk_out_endpointAddress);
-
- /* set up write_urb for bulk out transfers on this port. The USB
- * serial framework will have allocated a blank URB, buffer etc for
- * port0 when it put the endpoints there, but not for any of the other
- * ports on the device because there are no more endpoints. Thus we
- * have to allocate our own URBs for ports 1-7
- */
- if (port->write_urb == NULL) {
- dbg("port->write_urb == NULL, allocating one");
- port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urb) {
- err("Allocating write URB failed");
- return -ENOMEM;
- }
- /* buffer same size as port0 */
- port->bulk_out_size = dev_extra->buffer_size;
- port->bulk_out_buffer = kmalloc(port->bulk_out_size,
- GFP_KERNEL);
- if (!port->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- return -ENOMEM;
- }
- }
- if (serial->dev == NULL)
- dbg("serial->dev == NULL");
- dbg("port->bulk_out_size is %d", port->bulk_out_size);
-
- usb_fill_bulk_urb(port->write_urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port0->bulk_out_endpointAddress),
- port->bulk_out_buffer,
- port->bulk_out_size,
- qt2_write_bulk_callback,
- port);
- port_extra->tx_pending_bytes = 0;
-
- if (dev_extra->open_ports == 0) {
- /* this is first port to be opened, so need the read URB
- * initialised for bulk in transfers (this is shared amongst
- * all the ports on the device) */
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer,
- port0->bulk_in_size,
- qt2_read_bulk_callback, serial);
- dbg("port0 bulk in URB initialised");
-
- /* submit URB, i.e. start reading from device (async) */
- dev_extra->ReadBulkStopped = false;
- port_extra->read_urb_busy = true;
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- dev_err(&port->dev,
- "%s(): Error %d submitting bulk in urb",
- __func__, result);
- port_extra->read_urb_busy = false;
- dev_extra->ReadBulkStopped = true;
- }
-
- /* When the first port is opened, initialise the value of
- * current_port in dev_extra to this port, so it is set
- * to something. Once the box sends data it will send the
- * relevant escape sequences to get it to the right port anyway
- */
- dev_extra->current_port = port;
- }
-
- /* initialize our wait queues */
- init_waitqueue_head(&port_extra->wait);
- /* increment the count of openings of this port by one */
- port_extra->open_count++;
-
- /* remember to store dev_extra, port_extra and port0_extra back again at
- * end !*/
- qt2_set_port_private(port, port_extra);
- qt2_set_port_private(serial->port[0], port0_extra);
- qt2_set_dev_private(serial, dev_extra);
-
- dev_extra->open_ports++; /* one more port opened */
-
- return 0;
-}
-
-/* called when a port is closed by userspace. It won't be called, however,
- * until calls to chars_in_buffer() reveal that the port has completed
- * sending buffered data, and there is nothing else to do. Thus we don't have
- * to rely on forcing data through in this function. */
-/* Setting close_pending should keep new data from being written out,
- * once all the data in the enpoint buffers is moved out we won't get
- * any more. */
-/* BoxStopReceive would keep any more data from coming from a given
- * port, but isn't called by the vendor driver, although their comments
- * mention it. Should it be used here to stop the inbound data
- * flow?
- */
-static void qt2_close(struct usb_serial_port *port)
-{
- /* time out value for flush loops */
- unsigned long jift;
- struct quatech2_port *port_extra; /* extra data for this port */
- struct usb_serial *serial; /* device structure */
- struct quatech2_dev *dev_extra; /* extra data for the device */
- __u8 lsr_value = 0; /* value of Line Status Register */
- int status; /* result of last USB comms function */
-
- dbg("%s(): port %d", __func__, port->number);
- serial = port->serial; /* get the parent device structure */
- dev_extra = qt2_get_dev_private(serial);
- /* get the device private data */
- port_extra = qt2_get_port_private(port); /* port private data */
-
- /* we can now (and only now) stop reading data */
- port_extra->close_pending = true;
- dbg("%s(): port_extra->close_pending = true", __func__);
- /* although the USB side is now empty, the UART itself may
- * still be pushing characters out over the line, so we have to
- * wait testing the actual line status until the lines change
- * indicating that the data is done transferring. */
- /* FIXME: slow this polling down so it doesn't run the USB bus flat out
- * if it actually has to spend any time in this loop (which it normally
- * doesn't because the buffer is nearly empty) */
- jift = jiffies + (10 * HZ); /* 10 sec timeout */
- do {
- status = qt2_box_get_register(serial, port->number,
- QT2_LINE_STATUS_REGISTER, &lsr_value);
- if (status < 0) {
- dbg("%s(): qt2_box_get_register failed", __func__);
- break;
- }
- if ((lsr_value & QT2_LSR_TEMT)) {
- dbg("UART done sending");
- break;
- }
- schedule();
- } while (jiffies <= jift);
-
- status = qt2_closeboxchannel(serial, port->number);
- if (status < 0)
- dbg("%s(): port %d qt2_box_open_close_channel failed",
- __func__, port->number);
- /* to avoid leaking URBs, we should now free the write_urb for this
- * port and set the pointer to null so that next time the port is opened
- * a new URB is allocated. This avoids leaking URBs when the device is
- * removed */
- usb_free_urb(port->write_urb);
- kfree(port->bulk_out_buffer);
- port->bulk_out_buffer = NULL;
- port->bulk_out_size = 0;
-
- /* decrement the count of openings of this port by one */
- port_extra->open_count--;
- /* one less overall open as well */
- dev_extra->open_ports--;
- dbg("%s(): Exit, dev_extra->open_ports = %d", __func__,
- dev_extra->open_ports);
-}
-
-/**
- * qt2_write - write bytes from the tty layer out to the USB device.
- * @buf: The data to be written, size at least count.
- * @count: The number of bytes requested for transmission.
- * @return The number of bytes actually accepted for transmission to the device.
- */
-static int qt2_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial; /* parent device struct */
- __u8 header_array[5]; /* header used to direct writes to the correct
- port on the device */
- struct quatech2_port *port_extra; /* extra data for this port */
- int result;
-
- serial = port->serial; /* get the parent device of the port */
- port_extra = qt2_get_port_private(port); /* port extra info */
- if (serial == NULL)
- return -ENODEV;
- dbg("%s(): port %d, requested to write %d bytes, %d already pending",
- __func__, port->number, count, port_extra->tx_pending_bytes);
-
- if (count <= 0) {
- dbg("%s(): write request of <= 0 bytes", __func__);
- return 0; /* no bytes written */
- }
-
- /* check if the write urb is already in use, i.e. data already being
- * sent to this port */
- if ((port->write_urb->status == -EINPROGRESS)) {
- /* Fifo hasn't been emptied since last write to this port */
- dbg("%s(): already writing, port->write_urb->status == "
- "-EINPROGRESS", __func__);
- /* schedule_work(&port->work); commented in vendor driver */
- return 0;
- } else if (port_extra->tx_pending_bytes >= QT2_FIFO_DEPTH) {
- /* buffer is full (==). > should not occur, but would indicate
- * that an overflow had occurred */
- dbg("%s(): port transmit buffer is full!", __func__);
- /* schedule_work(&port->work); commented in vendor driver */
- return 0;
- }
-
- /* We must fill the first 5 bytes of anything we sent with a transmit
- * header which directes the data to the correct port. The maximum
- * size we can send out in one URB is port->bulk_out_size, which caps
- * the number of bytes of real data we can send in each write. As the
- * semantics of write allow us to write less than we were give, we cap
- * the maximum we will ever write to the device as 5 bytes less than
- * one URB's worth, by reducing the value of the count argument
- * appropriately*/
- if (count > port->bulk_out_size - QT2_TX_HEADER_LENGTH) {
- count = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
- dbg("%s(): write request bigger than urb, only accepting "
- "%d bytes", __func__, count);
- }
- /* we must also ensure that the FIFO at the other end can cope with the
- * URB we send it, otherwise it will have problems. As above, we can
- * restrict the write size by just shrinking count.*/
- if (count > (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes)) {
- count = QT2_FIFO_DEPTH - port_extra->tx_pending_bytes;
- dbg("%s(): not enough room in buffer, only accepting %d bytes",
- __func__, count);
- }
- /* now build the header for transmission */
- header_array[0] = 0x1b;
- header_array[1] = 0x1b;
- header_array[2] = (__u8)port->number;
- header_array[3] = (__u8)count;
- header_array[4] = (__u8)count >> 8;
- /* copy header into URB */
- memcpy(port->write_urb->transfer_buffer, header_array,
- QT2_TX_HEADER_LENGTH);
- /* and actual data to write */
- memcpy(port->write_urb->transfer_buffer + 5, buf, count);
-
- dbg("%s(): first data byte to send = %#.2x", __func__, *buf);
-
- /* set up our urb */
- usb_fill_bulk_urb(port->write_urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
- port->write_urb->transfer_buffer, count + 5,
- (qt2_write_bulk_callback), port);
- /* send the data out the bulk port */
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result) {
- /* error couldn't submit urb */
- result = 0; /* return 0 as nothing got written */
- dbg("%s(): failed submitting write urb, error %d",
- __func__, result);
- } else {
- port_extra->tx_pending_bytes += count;
- result = count; /* return number of bytes written, i.e. count */
- dbg("%s(): submitted write urb, wrote %d bytes, "
- "total pending bytes %d",
- __func__, result, port_extra->tx_pending_bytes);
- }
- return result;
-}
-
-/* This is used by the next layer up to know how much space is available
- * in the buffer on the device. It is used on a device closure to avoid
- * calling close() until the buffer is reported to be empty.
- * The returned value must never go down by more than the number of bytes
- * written for correct behaviour further up the driver stack, i.e. if I call
- * it, then write 6 bytes, then call again I should get 6 less, or possibly
- * only 5 less if one was written in the meantime, etc. I should never get 7
- * less (or any bigger number) because I only wrote 6 bytes.
- */
-static int qt2_write_room(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- /* parent usb_serial_port pointer */
- struct quatech2_port *port_extra; /* extra data for this port */
- int room = 0;
- port_extra = qt2_get_port_private(port);
-
- if (port_extra->close_pending == true) {
- dbg("%s(): port_extra->close_pending == true", __func__);
- return -ENODEV;
- }
- /* Q: how many bytes would a write() call actually succeed in writing
- * if it happened now?
- * A: one QT2_FIFO_DEPTH, less the number of bytes waiting to be sent
- * out of the port, unless this is more than the size of the
- * write_urb output buffer less the header, which is the maximum
- * size write we can do.
-
- * Most of the implementation of this is done when writes to the device
- * are started or terminate. When we send a write to the device, we
- * reduce the free space count by the size of the dispatched write.
- * When a "transmit empty" message comes back up the USB read stream,
- * we decrement the count by the number of bytes reported sent, thus
- * keeping track of the difference between sent and received bytes.
- */
-
- room = (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes);
- /* space in FIFO */
- if (room > port->bulk_out_size - QT2_TX_HEADER_LENGTH)
- room = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
- /* if more than the URB can hold, then cap to that limit */
-
- dbg("%s(): port %d: write room is %d", __func__, port->number, room);
- return room;
-}
-
-static int qt2_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- /* parent usb_serial_port pointer */
- struct quatech2_port *port_extra; /* extra data for this port */
- port_extra = qt2_get_port_private(port);
-
- dbg("%s(): port %d: chars_in_buffer = %d", __func__,
- port->number, port_extra->tx_pending_bytes);
- return port_extra->tx_pending_bytes;
-}
-
-/* called when userspace does an ioctl() on the device. Note that
- * TIOCMGET and TIOCMSET are filtered off to their own methods before they get
- * here, so we don't have to handle them.
- */
-static int qt2_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- __u8 mcr_value; /* Modem Control Register value */
- __u8 msr_value; /* Modem Status Register value */
- unsigned short prev_msr_value; /* Previous value of Modem Status
- * Register used to implement waiting for a line status change to
- * occur */
- struct quatech2_port *port_extra; /* extra data for this port */
- DECLARE_WAITQUEUE(wait, current);
- /* Declare a wait queue named "wait" */
-
- unsigned int value;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
- UartNumber = tty->index - serial->minor;
- port_extra = qt2_get_port_private(port);
-
- dbg("%s(): port %d, UartNumber %d, tty =0x%p", __func__,
- port->number, UartNumber, tty);
-
- if (cmd == TIOCMBIS || cmd == TIOCMBIC) {
- if (qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value) < 0)
- return -ESPIPE;
- if (copy_from_user(&value, (unsigned int *)arg,
- sizeof(value)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (value & TIOCM_RTS)
- mcr_value |= QT2_SERIAL_MCR_RTS;
- if (value & TIOCM_DTR)
- mcr_value |= QT2_SERIAL_MCR_DTR;
- if (value & TIOCM_LOOP)
- mcr_value |= QT2_SERIAL_MCR_LOOP;
- break;
- case TIOCMBIC:
- if (value & TIOCM_RTS)
- mcr_value &= ~QT2_SERIAL_MCR_RTS;
- if (value & TIOCM_DTR)
- mcr_value &= ~QT2_SERIAL_MCR_DTR;
- if (value & TIOCM_LOOP)
- mcr_value &= ~QT2_SERIAL_MCR_LOOP;
- break;
- default:
- break;
- } /* end of local switch on cmd */
- if (qt2_box_set_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, mcr_value) < 0) {
- return -ESPIPE;
- } else {
- port_extra->shadowMCR = mcr_value;
- return 0;
- }
- } else if (cmd == TIOCMIWAIT) {
- dbg("%s() port %d, cmd == TIOCMIWAIT enter",
- __func__, port->number);
- prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
- barrier();
- __set_current_state(TASK_INTERRUPTIBLE);
- while (1) {
- add_wait_queue(&port_extra->wait, &wait);
- schedule();
- dbg("%s(): port %d, cmd == TIOCMIWAIT here\n",
- __func__, port->number);
- remove_wait_queue(&port_extra->wait, &wait);
- /* see if a signal woke us up */
- if (signal_pending(current))
- return -ERESTARTSYS;
- set_current_state(TASK_INTERRUPTIBLE);
- msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
- if (msr_value == prev_msr_value) {
- __set_current_state(TASK_RUNNING);
- return -EIO; /* no change - error */
- }
- if ((arg & TIOCM_RNG &&
- ((prev_msr_value & QT2_SERIAL_MSR_RI) ==
- (msr_value & QT2_SERIAL_MSR_RI))) ||
- (arg & TIOCM_DSR &&
- ((prev_msr_value & QT2_SERIAL_MSR_DSR) ==
- (msr_value & QT2_SERIAL_MSR_DSR))) ||
- (arg & TIOCM_CD &&
- ((prev_msr_value & QT2_SERIAL_MSR_CD) ==
- (msr_value & QT2_SERIAL_MSR_CD))) ||
- (arg & TIOCM_CTS &&
- ((prev_msr_value & QT2_SERIAL_MSR_CTS) ==
- (msr_value & QT2_SERIAL_MSR_CTS)))) {
- __set_current_state(TASK_RUNNING);
- return 0;
- }
- } /* end inifinite while */
- /* FIXME: This while loop needs a way to break out if the device
- * is disconnected while a process is waiting for the MSR to
- * change, because once it's disconnected, it isn't going to
- * change state ... */
- } else {
- /* any other ioctls we don't know about come here */
- dbg("%s(): No ioctl for that one. port = %d", __func__,
- port->number);
- return -ENOIOCTLCMD;
- }
-}
-
-/* Called when the user wishes to change the port settings using the termios
- * userspace interface */
-static void qt2_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
-{
- struct usb_serial *serial; /* parent serial device */
- int baud, divisor, remainder;
- unsigned char LCR_change_to = 0;
- int status;
- __u16 UartNumber;
-
- dbg("%s(): port %d", __func__, port->number);
-
- serial = port->serial;
-
- UartNumber = port->number;
-
- if (old_termios && !tty_termios_hw_change(old_termios, tty->termios))
- return;
-
- switch (tty->termios->c_cflag) {
- case CS5:
- LCR_change_to |= QT2_SERIAL_5_DATA;
- break;
- case CS6:
- LCR_change_to |= QT2_SERIAL_6_DATA;
- break;
- case CS7:
- LCR_change_to |= QT2_SERIAL_7_DATA;
- break;
- default:
- case CS8:
- LCR_change_to |= QT2_SERIAL_8_DATA;
- break;
- }
-
- /* Parity stuff */
- if (tty->termios->c_cflag & PARENB) {
- if (tty->termios->c_cflag & PARODD)
- LCR_change_to |= QT2_SERIAL_ODD_PARITY;
- else
- LCR_change_to |= QT2_SERIAL_EVEN_PARITY;
- }
- /* Because LCR_change_to is initialised to zero, we don't have to worry
- * about the case where PARENB is not set or clearing bits, because by
- * default all of them are cleared, turning parity off.
- * as we don't support mark/space parity, we should clear the
- * mark/space parity bit in c_cflag, so the caller can tell we have
- * ignored the request */
- tty->termios->c_cflag &= ~CMSPAR;
-
- if (tty->termios->c_cflag & CSTOPB)
- LCR_change_to |= QT2_SERIAL_TWO_STOPB;
- else
- LCR_change_to |= QT2_SERIAL_ONE_STOPB;
-
- /* Thats the LCR stuff, next we need to work out the divisor as the
- * LCR and the divisor are set together */
- baud = tty_get_baud_rate(tty);
- if (!baud) {
- /* pick a default, any default... */
- baud = 9600;
- }
- dbg("%s(): got baud = %d", __func__, baud);
-
- divisor = QT2_MAX_BAUD_RATE / baud;
- remainder = QT2_MAX_BAUD_RATE % baud;
- /* Round to nearest divisor */
- if (((remainder * 2) >= baud) && (baud != 110))
- divisor++;
- dbg("%s(): setting divisor = %d, QT2_MAX_BAUD_RATE = %d , LCR = %#.2x",
- __func__, divisor, QT2_MAX_BAUD_RATE, LCR_change_to);
-
- status = qt2_boxsetuart(serial, UartNumber, (unsigned short) divisor,
- LCR_change_to);
- if (status < 0) {
- dbg("qt2_boxsetuart() failed");
- return;
- } else {
- /* now encode the baud rate we actually set, which may be
- * different to the request */
- baud = QT2_MAX_BAUD_RATE / divisor;
- tty_encode_baud_rate(tty, baud, baud);
- }
-
- /* Now determine flow control */
- if (tty->termios->c_cflag & CRTSCTS) {
- dbg("%s(): Enabling HW flow control port %d", __func__,
- port->number);
- /* Enable RTS/CTS flow control */
- status = qt2_boxsethw_flowctl(serial, UartNumber, true);
- if (status < 0) {
- dbg("qt2_boxsethw_flowctl() failed");
- return;
- }
- } else {
- /* Disable RTS/CTS flow control */
- dbg("%s(): disabling HW flow control port %d", __func__,
- port->number);
- status = qt2_boxsethw_flowctl(serial, UartNumber, false);
- if (status < 0) {
- dbg("qt2_boxsethw_flowctl failed");
- return;
- }
- }
- /* if we are implementing XON/XOFF, set the start and stop character
- * in the device */
- if (I_IXOFF(tty) || I_IXON(tty)) {
- unsigned char stop_char = STOP_CHAR(tty);
- unsigned char start_char = START_CHAR(tty);
- status = qt2_boxsetsw_flowctl(serial, UartNumber, stop_char,
- start_char);
- if (status < 0)
- dbg("qt2_boxsetsw_flowctl (enabled) failed");
- } else {
- /* disable SW flow control */
- status = qt2_boxunsetsw_flowctl(serial, UartNumber);
- if (status < 0)
- dbg("qt2_boxunsetsw_flowctl (disabling) failed");
- }
-}
-
-static int qt2_tiocmget(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
-
- __u8 mcr_value; /* Modem Control Register value */
- __u8 msr_value; /* Modem Status Register value */
- unsigned int result = 0;
- int status;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
-
- dbg("%s(): port %d, tty =0x%p", __func__, port->number, tty);
- UartNumber = tty->index - serial->minor;
- dbg("UartNumber is %d", UartNumber);
-
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value);
- if (status >= 0) {
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_STATUS_REGISTER, &msr_value);
- }
- if (status >= 0) {
- result = ((mcr_value & QT2_SERIAL_MCR_DTR) ? TIOCM_DTR : 0)
- /*DTR set */
- | ((mcr_value & QT2_SERIAL_MCR_RTS) ? TIOCM_RTS : 0)
- /*RTS set */
- | ((msr_value & QT2_SERIAL_MSR_CTS) ? TIOCM_CTS : 0)
- /* CTS set */
- | ((msr_value & QT2_SERIAL_MSR_CD) ? TIOCM_CAR : 0)
- /*Carrier detect set */
- | ((msr_value & QT2_SERIAL_MSR_RI) ? TIOCM_RI : 0)
- /* Ring indicator set */
- | ((msr_value & QT2_SERIAL_MSR_DSR) ? TIOCM_DSR : 0);
- /* DSR set */
- return result;
- } else {
- return -ESPIPE;
- }
-}
-
-static int qt2_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- __u8 mcr_value; /* Modem Control Register value */
- int status;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
-
- UartNumber = tty->index - serial->minor;
- dbg("%s(): port %d, UartNumber %d", __func__, port->number, UartNumber);
-
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value);
- if (status < 0)
- return -ESPIPE;
-
- /* Turn off RTS, DTR and loopback, then only turn on what was asked
- * for */
- mcr_value &= ~(QT2_SERIAL_MCR_RTS | QT2_SERIAL_MCR_DTR |
- QT2_SERIAL_MCR_LOOP);
- if (set & TIOCM_RTS)
- mcr_value |= QT2_SERIAL_MCR_RTS;
- if (set & TIOCM_DTR)
- mcr_value |= QT2_SERIAL_MCR_DTR;
- if (set & TIOCM_LOOP)
- mcr_value |= QT2_SERIAL_MCR_LOOP;
-
- status = qt2_box_set_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, mcr_value);
- if (status < 0)
- return -ESPIPE;
- else
- return 0;
-}
-
-/** qt2_break - Turn BREAK on and off on the UARTs
- */
-static void qt2_break(struct tty_struct *tty, int break_state)
-{
- struct usb_serial_port *port = tty->driver_data; /* parent port */
- struct usb_serial *serial = port->serial; /* parent device */
- struct quatech2_port *port_extra; /* extra data for this port */
- __u16 break_value;
- unsigned int result;
-
- port_extra = qt2_get_port_private(port);
- if (!serial) {
- dbg("%s(): port %d: no serial object", __func__, port->number);
- return;
- }
-
- if (break_state == -1)
- break_value = 1;
- else
- break_value = 0;
- dbg("%s(): port %d, break_value %d", __func__, port->number,
- break_value);
-
- mutex_lock(&port_extra->modelock);
- if (!port_extra->open_count) {
- dbg("%s(): port not open", __func__);
- goto exit;
- }
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_BREAK_CONTROL, 0x40, break_value,
- port->number, NULL, 0, 300);
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): exit port %d", __func__, port->number);
-
-}
-/**
- * qt2_throttle: - stop reading new data from the port
- */
-static void qt2_throttle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- struct quatech2_port *port_extra; /* extra data for this port */
- dbg("%s(): port %d", __func__, port->number);
-
- port_extra = qt2_get_port_private(port);
- if (!serial) {
- dbg("%s(): enter port %d no serial object", __func__,
- port->number);
- return;
- }
-
- mutex_lock(&port_extra->modelock); /* lock structure */
- if (!port_extra->open_count) {
- dbg("%s(): port not open", __func__);
- goto exit;
- }
- /* Send command to box to stop receiving stuff. This will stop this
- * particular UART from filling the endpoint - in the multiport case the
- * FPGA UART will handle any flow control implemented, but for the single
- * port it's handed differently and we just quit submitting urbs
- */
- if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100)
- qt2_boxstoprx(serial, port->number, 1);
-
- port->throttled = 1;
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): port %d: setting port->throttled", __func__, port->number);
- return;
-}
-
-/**
- * qt2_unthrottle: - start receiving data through the port again after being
- * throttled
- */
-static void qt2_unthrottle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- struct quatech2_port *port_extra; /* extra data for this port */
- struct usb_serial_port *port0; /* first port structure on device */
- struct quatech2_dev *dev_extra; /* extra data for the device */
-
- if (!serial) {
- dbg("%s() enter port %d no serial object!", __func__,
- port->number);
- return;
- }
- dbg("%s(): enter port %d", __func__, port->number);
- dev_extra = qt2_get_dev_private(serial);
- port_extra = qt2_get_port_private(port);
- port0 = serial->port[0]; /* get the first port's device structure */
-
- mutex_lock(&port_extra->modelock);
- if (!port_extra->open_count) {
- dbg("%s(): port %d not open", __func__, port->number);
- goto exit;
- }
-
- if (port->throttled != 0) {
- dbg("%s(): port %d: unsetting port->throttled", __func__,
- port->number);
- port->throttled = 0;
- /* Send command to box to start receiving stuff */
- if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100) {
- qt2_boxstoprx(serial, port->number, 0);
- } else if (dev_extra->ReadBulkStopped == true) {
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer,
- port0->bulk_in_size,
- qt2_read_bulk_callback,
- serial);
- }
- }
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): exit port %d", __func__, port->number);
- return;
-}
-
-/* internal, private helper functions for the driver */
-
-/* Power up the FPGA in the box to get it working */
-static int qt2_boxpoweron(struct usb_serial *serial)
-{
- int result;
- __u8 Direcion;
- unsigned int pipe;
- Direcion = USBD_TRANSFER_DIRECTION_OUT;
- pipe = usb_rcvctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_SET_GET_DEVICE,
- Direcion, QU2BOXPWRON, 0x00, NULL, 0x00,
- 5000);
- return result;
-}
-
-/*
- * qt2_boxsetQMCR Issue a QT2_GET_SET_QMCR vendor-spcific request on the
- * default control pipe. If successful return the number of bytes written,
- * otherwise return a negative error number of the problem.
- */
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
- __u8 QMCR_Value)
-{
- int result;
- __u16 PortSettings;
-
- PortSettings = (__u16)(QMCR_Value);
-
- dbg("%s(): Port = %d, PortSettings = 0x%x", __func__,
- Uart_Number, PortSettings);
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_QMCR, 0x40, PortSettings,
- (__u16)Uart_Number, NULL, 0, 5000);
- return result;
-}
-
-static int port_paranoia_check(struct usb_serial_port *port,
- const char *function)
-{
- if (!port) {
- dbg("%s - port == NULL", function);
- return -1;
- }
- if (!port->serial) {
- dbg("%s - port->serial == NULL\n", function);
- return -1;
- }
- return 0;
-}
-
-static int serial_paranoia_check(struct usb_serial *serial,
- const char *function)
-{
- if (!serial) {
- dbg("%s - serial == NULL\n", function);
- return -1;
- }
-
- if (!serial->type) {
- dbg("%s - serial->type == NULL!", function);
- return -1;
- }
-
- return 0;
-}
-
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
- *port)
-{
- return (struct quatech2_port *)usb_get_serial_port_data(port);
-}
-
-static inline void qt2_set_port_private(struct usb_serial_port *port,
- struct quatech2_port *data)
-{
- usb_set_serial_port_data(port, (void *)data);
-}
-
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
- *serial)
-{
- return (struct quatech2_dev *)usb_get_serial_data(serial);
-}
-static inline void qt2_set_dev_private(struct usb_serial *serial,
- struct quatech2_dev *data)
-{
- usb_set_serial_data(serial, (void *)data);
-}
-
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
- Uart_Number, struct qt2_status_data *status)
-{
- int result;
- __u16 length;
- __u8 Direcion;
- unsigned int pipe;
- length = sizeof(struct qt2_status_data);
- Direcion = USBD_TRANSFER_DIRECTION_IN;
- pipe = usb_rcvctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
- Direcion, 0x00, Uart_Number, status, length, 5000);
- return result;
-}
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16 Uart_Number)
-{
- int result;
- __u8 direcion;
- unsigned int pipe;
- direcion = USBD_TRANSFER_DIRECTION_OUT;
- pipe = usb_sndctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
- direcion, 0, Uart_Number, NULL, 0, 5000);
- return result;
-}
-
-/* qt2_conf_uart Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value
- */
-static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short divisor, unsigned char LCR)
-{
- int result;
- unsigned short UartNumandLCR;
-
- UartNumandLCR = (LCR << 8) + Uart_Number;
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_UART, 0x40, divisor, UartNumandLCR,
- NULL, 0, 300);
- return result;
-}
-
-/** @brief Callback for asynchronous submission of read URBs on bulk in
- * endpoints
- *
- * Registered in qt2_open_port(), used to deal with incomming data
- * from the box.
- */
-static void qt2_read_bulk_callback(struct urb *urb)
-{
- /* Get the device pointer (struct usb_serial) back out of the URB */
- struct usb_serial *serial = urb->context;
- /* get the extra struct for the device */
- struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
- /* Get first port structure from the device */
- struct usb_serial_port *port0 = serial->port[0];
- /* Get the currently active port structure from serial struct */
- struct usb_serial_port *active = dev_extra->current_port;
- /* get the extra struct for port 0 */
- struct quatech2_port *port0_extra = qt2_get_port_private(port0);
- /* and for the currently active port */
- struct quatech2_port *active_extra = qt2_get_port_private(active);
- /* When we finally get to doing some tty stuff, we will need this */
- struct tty_struct *tty_st;
- unsigned int RxCount; /* the length of the data to process */
- unsigned int i; /* loop counter over the data to process */
- int result; /* return value cache variable */
- bool escapeflag; /* flag set to true if this loop iteration is
- * parsing an escape sequence, rather than
- * ordinary data */
- dbg("%s(): callback running, active port is %d", __func__,
- active->number);
-
- if (urb->status) {
- /* read didn't go well */
- dev_extra->ReadBulkStopped = true;
- dbg("%s(): nonzero bulk read status received: %d",
- __func__, urb->status);
- return;
- }
-
- /* inline port_sofrint() here */
- if (port_paranoia_check(port0, __func__) != 0) {
- dbg("%s - port_paranoia_check on port0 failed, exiting\n",
-__func__);
- return;
- }
- if (port_paranoia_check(active, __func__) != 0) {
- dbg("%s - port_paranoia_check on current_port "
- "failed, exiting", __func__);
- return;
- }
-
-/* This single callback function has to do for all the ports on
- * the device. Data being read up the USB can contain certain
- * escape sequences which are used to communicate out-of-band
- * information from the serial port in-band over the USB.
- * These escapes include sending modem and flow control line
- * status, and switching the port. The concept of a "Current Port"
- * is used, which is where data is going until a port change
- * escape seqence is received. This Current Port is kept between
- * callbacks so that when this function enters we know which the
- * currently active port is and can get to work right away without
- * the box having to send repeat escape sequences (anyway, how
- * would it know to do so?).
- */
-
- if (active_extra->close_pending == true) {
- /* We are closing , stop reading */
- dbg("%s - (active->close_pending == true", __func__);
- if (dev_extra->open_ports <= 0) {
- /* If this is the only port left open - stop the
- * bulk read */
- dev_extra->ReadBulkStopped = true;
- dbg("%s - (ReadBulkStopped == true;", __func__);
- return;
- }
- }
-
- /*
- * RxHolding is asserted by throttle, if we assert it, we're not
- * receiving any more characters and let the box handle the flow
- * control
- */
- if ((port0_extra->RxHolding == true) &&
- (serial->dev->descriptor.idProduct == QUATECH_SSU2_100)) {
- /* single port device, input is already stopped, so we don't
- * need any more input data */
- dev_extra->ReadBulkStopped = true;
- return;
- }
- /* finally, we are in a situation where we might consider the data
- * that is contained within the URB, and what to do about it.
- * This is likely to involved communicating up to the TTY layer, so
- * we will need to get hold of the tty for the port we are currently
- * dealing with */
-
- /* active is a usb_serial_port. It has a member port which is a
- * tty_port. From this we get a tty_struct pointer which is what we
- * actually wanted, and keep it on tty_st */
- tty_st = tty_port_tty_get(&active->port);
- if (!tty_st) {
- dbg("%s - bad tty pointer - exiting", __func__);
- return;
- }
- RxCount = urb->actual_length; /* grab length of data handy */
-
- if (RxCount) {
- /* skip all this if no data to process */
- for (i = 0; i < RxCount ; ++i) {
- /* Look ahead code here -works on several bytes at onc*/
- if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b)
- && (NEXTCHAR == 0x1b)) {
- /* we are in an escape sequence, type
- * determined by the 3rd char */
- escapeflag = false;
- switch (THIRDCHAR) {
- case 0x00:
- /* Line status change 4th byte must
- * follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_line_status(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- break;
- case 0x01:
- /* Modem status status change 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_modem_status(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- break;
- case 0x02:
- /* xmit hold empty 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_xmit_empty(active,
- FOURTHCHAR, FIFTHCHAR);
- i += 4;
- escapeflag = true;
- break;
- case 0x03:
- /* Port number change 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- /* Port change. If port open push
- * current data up to tty layer */
- if (active_extra->open_count > 0)
- tty_flip_buffer_push(tty_st);
-
- dbg("Port Change: new port = %d",
- FOURTHCHAR);
- qt2_process_port_change(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- /* having changed port, the pointers for
- * the currently active port are all out
- * of date and need updating */
- active = dev_extra->current_port;
- active_extra =
- qt2_get_port_private(active);
- tty_st = tty_port_tty_get(
- &active->port);
- break;
- case 0x04:
- /* Recv flush 3rd byte must
- * follow */
- if (i > (RxCount - 3)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_rcv_flush(active);
- i += 2;
- escapeflag = true;
- break;
- case 0x05:
- /* xmit flush 3rd byte must follow */
- if (i > (RxCount - 3)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_xmit_flush(active);
- i += 2;
- escapeflag = true;
- break;
- case 0xff:
- dbg("No status sequence");
- qt2_process_rx_char(active, THISCHAR);
- qt2_process_rx_char(active, NEXTCHAR);
- i += 2;
- break;
- default:
- qt2_process_rx_char(active, THISCHAR);
- i += 1;
- break;
- } /*end switch*/
- if (escapeflag == true)
- continue;
- /* if we did an escape char, we don't need
- * to mess around pushing data through the
- * tty layer, and can go round again */
- } /*endif*/
- if (tty_st && urb->actual_length) {
- tty_buffer_request_room(tty_st, 1);
- tty_insert_flip_string(tty_st, &(
- (unsigned char *)
- (urb->transfer_buffer)
- )[i], 1);
- }
- } /*endfor*/
- tty_flip_buffer_push(tty_st);
- } /*endif*/
-
- /* at this point we have complete dealing with the data for this
- * callback. All we have to do now is to start the async read process
- * back off again. */
-
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer, port0->bulk_in_size,
- qt2_read_bulk_callback, serial);
- result = usb_submit_urb(port0->read_urb, GFP_ATOMIC);
- if (result) {
- dbg("%s(): failed resubmitting read urb, error %d",
- __func__, result);
- } else {
- dbg("%s() successfully resubmitted read urb", __func__);
- if (tty_st && RxCount) {
- /* if some inbound data was processed, then
- * we need to push that through the tty layer
- */
- tty_flip_buffer_push(tty_st);
- tty_schedule_flip(tty_st);
- }
- }
-
- /* cribbed from serqt_usb2 driver, but not sure which work needs
- * scheduling - port0 or currently active port? */
- /* schedule_work(&port->work); */
- dbg("%s() completed", __func__);
- return;
-}
-
-/** @brief Callback for asynchronous submission of write URBs on bulk in
- * endpoints
- *
- * Registered in qt2_write(), used to deal with outgoing data
- * to the box.
- */
-static void qt2_write_bulk_callback(struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = port->serial;
- dbg("%s(): port %d", __func__, port->number);
- if (!serial) {
- dbg("%s(): bad serial pointer, exiting", __func__);
- return;
- }
- if (urb->status) {
- dbg("%s(): nonzero write bulk status received: %d",
- __func__, urb->status);
- return;
- }
- /* FIXME What is supposed to be going on here?
- * does this actually do anything useful, and should it?
- */
- /*port_softint((void *) serial); commented in vendor driver */
- schedule_work(&port->work);
- dbg("%s(): port %d exit", __func__, port->number);
- return;
-}
-
-static void qt2_process_line_status(struct usb_serial_port *port,
- unsigned char LineStatus)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->shadowLSR = LineStatus & (QT2_SERIAL_LSR_OE |
- QT2_SERIAL_LSR_PE | QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
-}
-static void qt2_process_modem_status(struct usb_serial_port *port,
- unsigned char ModemStatus)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->shadowMSR = ModemStatus;
- wake_up_interruptible(&port_extra->wait);
- /* this wakes up the otherwise indefinitely waiting code for
- * the TIOCMIWAIT ioctl, so that it can notice that
- * port_extra->shadowMSR has changed and the ioctl needs to return.
- */
-}
-
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
- unsigned char fourth_char, unsigned char fifth_char)
-{
- int byte_count;
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
-
- byte_count = (int)(fifth_char * 16);
- byte_count += (int)fourth_char;
- /* byte_count indicates how many bytes the device has written out. This
- * message appears to occur regularly, and is used in the vendor driver
- * to keep track of the fill state of the port transmit buffer */
- port_extra->tx_pending_bytes -= byte_count;
- /* reduce the stored data queue length by the known number of bytes
- * sent */
- dbg("port %d: %d bytes reported sent, %d still pending", port->number,
- byte_count, port_extra->tx_pending_bytes);
-
- /*port_extra->xmit_fifo_room_bytes = FIFO_DEPTH; ???*/
-}
-
-static void qt2_process_port_change(struct usb_serial_port *port,
- unsigned char New_Current_Port)
-{
- /* obtain the parent usb serial device structure */
- struct usb_serial *serial = port->serial;
- /* obtain the private structure for the device */
- struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
- dev_extra->current_port = serial->port[New_Current_Port];
- /* what should I do with this? commented out in upstream
- * driver */
- /*schedule_work(&port->work);*/
-}
-
-static void qt2_process_rcv_flush(struct usb_serial_port *port)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->rcv_flush = true;
-}
-static void qt2_process_xmit_flush(struct usb_serial_port *port)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->xmit_flush = true;
-}
-
-static void qt2_process_rx_char(struct usb_serial_port *port,
- unsigned char data)
-{
- /* get the tty_struct for this port */
- struct tty_struct *tty = tty_port_tty_get(&(port->port));
- /* get the URB with the data in to push */
- struct urb *urb = port->serial->port[0]->read_urb;
-
- if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, 1);
- tty_insert_flip_string(tty, &data, 1);
- /* should this be commented out here? */
- /*tty_flip_buffer_push(tty);*/
- }
-}
-
-/** @brief Retrieve the value of a register from the device
- *
- * Issues a GET_REGISTER vendor-spcific request over the USB control
- * pipe to obtain a value back from a specific register on a specific
- * UART
- * @param serial Serial device handle to access the device through
- * @param uart_number Which UART the value is wanted from
- * @param register_num Which register to read the value from
- * @param pValue Pointer to somewhere to put the retrieved value
- */
-static int qt2_box_get_register(struct usb_serial *serial,
- unsigned char uart_number, unsigned short register_num,
- __u8 *pValue)
-{
- int result;
- result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- QT2_GET_SET_REGISTER, 0xC0, register_num,
- uart_number, (void *)pValue, sizeof(*pValue), 300);
- return result;
-}
-
-/** qt2_box_set_register
- * Issue a SET_REGISTER vendor-specific request on the default control pipe
- */
-static int qt2_box_set_register(struct usb_serial *serial,
- unsigned short Uart_Number, unsigned short Register_Num,
- unsigned short Value)
-{
- int result;
- unsigned short reg_and_byte;
-
- reg_and_byte = Value;
- reg_and_byte = reg_and_byte << 8;
- reg_and_byte = reg_and_byte + Register_Num;
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_REGISTER, 0x40, reg_and_byte,
- Uart_Number, NULL, 0, 300);
- return result;
-}
-
-/** qt2_boxsetuart - Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value.
- */
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short default_divisor, unsigned char default_LCR)
-{
- unsigned short UartNumandLCR;
-
- UartNumandLCR = (default_LCR << 8) + Uart_Number;
-
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_UART, 0x40, default_divisor, UartNumandLCR,
- NULL, 0, 300);
-}
-
-/** qt2_boxsethw_flowctl - Turn hardware (RTS/CTS) flow control on and off for
- * a hardware UART.
- */
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
- unsigned int UartNumber, bool bSet)
-{
- __u8 MCR_Value = 0;
- __u8 MSR_Value = 0;
- __u16 MOUT_Value = 0;
-
- if (bSet == true) {
- MCR_Value = QT2_SERIAL_MCR_RTS;
- /* flow control, box will clear RTS line to prevent remote
- * device from transmitting more chars */
- } else {
- /* no flow control to remote device */
- MCR_Value = 0;
- }
- MOUT_Value = MCR_Value << 8;
-
- if (bSet == true) {
- MSR_Value = QT2_SERIAL_MSR_CTS;
- /* flow control on, box will inhibit tx data if CTS line is
- * asserted */
- } else {
- /* Box will not inhibit tx data due to CTS line */
- MSR_Value = 0;
- }
- MOUT_Value |= MSR_Value;
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, UartNumber,
- NULL, 0, 300);
-}
-
-/** qt2_boxsetsw_flowctl - Turn software (XON/XOFF) flow control on for
- * a hardware UART, and set the XON and XOFF characters.
- */
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
- unsigned char stop_char, unsigned char start_char)
-{
- __u16 nSWflowout;
-
- nSWflowout = start_char << 8;
- nSWflowout = (unsigned short)stop_char;
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, UartNumber,
- NULL, 0, 300);
-}
-
-/** qt2_boxunsetsw_flowctl - Turn software (XON/XOFF) flow control off for
- * a hardware UART.
- */
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber)
-{
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_SW_FLOW_CONTROL_DISABLE, 0x40, 0, UartNumber, NULL,
- 0, 300);
-}
-
-/**
- * qt2_boxstoprx - Start and stop reception of data by the FPGA UART in
- * response to requests from the tty layer
- * @serial: pointer to the usb_serial structure for the parent device
- * @uart_number: which UART on the device we are addressing
- * @stop: Whether to start or stop data reception. Set to 1 to stop data being
- * received, and to 0 to start it being received.
- */
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
- unsigned short stop)
-{
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_STOP_RECEIVE, 0x40, stop, uart_number, NULL, 0, 300);
-}
-
-
-/*
- * last things in file: stuff to register this driver into the generic
- * USB serial framework.
- */
-
-static struct usb_serial_driver quatech2_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "quatech_usb2",
- },
- .description = DRIVER_DESC,
- .id_table = quausb2_id_table,
- .num_ports = 8,
- .open = qt2_open,
- .close = qt2_close,
- .write = qt2_write,
- .write_room = qt2_write_room,
- .chars_in_buffer = qt2_chars_in_buffer,
- .throttle = qt2_throttle,
- .unthrottle = qt2_unthrottle,
- .calc_num_ports = qt2_calc_num_ports,
- .ioctl = qt2_ioctl,
- .set_termios = qt2_set_termios,
- .break_ctl = qt2_break,
- .tiocmget = qt2_tiocmget,
- .tiocmset = qt2_tiocmset,
- .attach = qt2_attach,
- .release = qt2_release,
- .read_bulk_callback = qt2_read_bulk_callback,
- .write_bulk_callback = qt2_write_bulk_callback,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &quatech2_device, NULL
-};
-
-module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig
index 4af1f8d..8349887 100644
--- a/drivers/staging/ramster/Kconfig
+++ b/drivers/staging/ramster/Kconfig
@@ -1,6 +1,6 @@
config RAMSTER
bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
- depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM
+ depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET
select LZO_COMPRESS
select LZO_DECOMPRESS
default n
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
index b9721c1..d0a07d7 100644
--- a/drivers/staging/ramster/cluster/tcp.c
+++ b/drivers/staging/ramster/cluster/tcp.c
@@ -111,7 +111,7 @@ static struct socket *r2net_listen_sock;
* r2net_wq. teardown detaches the callbacks before destroying the workqueue.
* quorum work is queued as sock containers are shutdown.. stop_listening
* tears down all the node's sock containers, preventing future shutdowns
- * and queued quroum work, before canceling delayed quorum work and
+ * and queued quorum work, before canceling delayed quorum work and
* destroying the work queue.
*/
static struct workqueue_struct *r2net_wq;
@@ -660,7 +660,7 @@ out:
/*
* we register callbacks so we can queue work on events before calling
- * the original callbacks. our callbacks our careful to test user_data
+ * the original callbacks. our callbacks are careful to test user_data
* to discover when they've reaced with r2net_unregister_callbacks().
*/
static void r2net_register_callbacks(struct sock *sk,
diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c
index 93ba8e9..44ceb0b 100644
--- a/drivers/staging/ramster/xvmalloc.c
+++ b/drivers/staging/ramster/xvmalloc.c
@@ -132,7 +132,7 @@ static u32 find_block(struct xv_pool *pool, u32 size,
if (!pool->flbitmap)
return 0;
- /* Get freelist index correspoding to this size */
+ /* Get freelist index corresponding to this size */
slindex = get_index(size);
slbitmap = pool->slbitmap[slindex / BITS_PER_LONG];
slbitstart = slindex % BITS_PER_LONG;
diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c
index 68b2e05..4e7ef0e 100644
--- a/drivers/staging/ramster/zcache-main.c
+++ b/drivers/staging/ramster/zcache-main.c
@@ -1331,7 +1331,7 @@ static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
* when that limit is reached, further puts will be rejected (until
* some pages have been flushed). Note that, due to compression,
* this number may exceed 100; it defaults to 75 and we set an
- * arbitary limit of 150. A poor choice will almost certainly result
+ * arbitrary limit of 150. A poor choice will almost certainly result
* in OOM's, so this value should only be changed prudently.
*/
static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
@@ -2004,7 +2004,7 @@ int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
* Called by the message handler after a (still compressed) page has been
* fetched from the remote machine in response to an "is_remote" tmem_get
* or persistent tmem_localify. For a tmem_get, "extra" is the address of
- * the page that is to be filled to succesfully resolve the tmem_get; for
+ * the page that is to be filled to successfully resolve the tmem_get; for
* a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
* in the local zcache). "data" points to "size" bytes of (compressed) data
* passed in the message. In the case of a persistent remote get, if
@@ -2095,7 +2095,7 @@ out:
/*
* Called on a remote persistent tmem_get to attempt to preallocate
* local storage for the data contained in the remote persistent page.
- * If succesfully preallocated, returns the pampd, marked as remote and
+ * If successfully preallocated, returns the pampd, marked as remote and
* in_transit. Else returns NULL. Note that the appropriate tmem data
* structure must be locked.
*/
diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile
index 72db504..91d1aa2 100644
--- a/drivers/staging/rtl8187se/Makefile
+++ b/drivers/staging/rtl8187se/Makefile
@@ -10,7 +10,7 @@ ccflags-y += -DHIGH_POWER
ccflags-y += -DSW_DIG
ccflags-y += -DRATE_ADAPT
-#enable it for legacy power save, disable it for leisure power save
+#enable it for legacy power save, disable it for leisure power save
ccflags-y += -DENABLE_LPS
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c
index 309bb8b..0e93eb0 100644
--- a/drivers/staging/rtl8187se/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c
@@ -55,7 +55,7 @@ Dot11d_Reset(struct ieee80211_device *ieee)
//
// Description:
-// Update country IE from Beacon or Probe Resopnse
+// Update country IE from Beacon or Probe Response
// and configure PHY for operation in the regulatory domain.
//
// TODO:
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 40dd715..b94c48b 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -834,7 +834,7 @@ enum ieee80211_state {
/* the association procedure is sending AUTH request*/
IEEE80211_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
IEEE80211_ASSOCIATING_AUTHENTICATED,
@@ -934,7 +934,7 @@ struct ieee80211_device {
* with RX of broad/multicast frames */
/* Fragmentation structures */
- // each streaming contain a entry
+ /* each stream contains an entry */
struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
unsigned int frag_next_idx[17];
u16 fts; /* Fragmentation Threshold */
@@ -972,7 +972,7 @@ struct ieee80211_device {
int rate; /* current rate */
int basic_rate;
- //FIXME: pleace callback, see if redundant with softmac_features
+ //FIXME: please callback, see if redundant with softmac_features
short active_scan;
/* this contains flags for selectively enable softmac support */
@@ -1106,7 +1106,7 @@ struct ieee80211_device {
/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
* if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+ * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
* then also management frames are sent via this callback.
* This function can't sleep.
*/
@@ -1124,7 +1124,7 @@ struct ieee80211_device {
/* ask to the driver to retune the radio .
* This function can sleep. the driver should ensure
- * the radio has been swithced before return.
+ * the radio has been switched before return.
*/
void (*set_chan)(struct net_device *dev,short ch);
@@ -1135,7 +1135,7 @@ struct ieee80211_device {
* The syncro version is similar to the start_scan but
* does not return until all channels has been scanned.
* this is called in user context and should sleep,
- * it is called in a work_queue when swithcing to ad-hoc mode
+ * it is called in a work_queue when switching to ad-hoc mode
* or in behalf of iwlist scan when the card is associated
* and root user ask for a scan.
* the function stop_scan should stop both the syncro and
@@ -1196,7 +1196,7 @@ struct ieee80211_device {
/* Generate probe requests */
#define IEEE_SOFTMAC_PROBERQ (1<<4)
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
#define IEEE_SOFTMAC_PROBERS (1<<5)
/* The ieee802.11 stack will manages the netif queue
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 26bacb9..8173240 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -42,7 +42,7 @@ short ieee80211_is_shortslot(const struct ieee80211_network *net)
return net->capability & WLAN_CAPABILITY_SHORT_SLOT;
}
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
* tag and the EXTENDED RATE MFIE tag if needed.
* It encludes two bytes per tag for the tag itself and its len
*/
@@ -60,7 +60,7 @@ unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
return rate_len;
}
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) poised.
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
@@ -467,7 +467,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
* So we switch to IEEE80211_LINKED_SCANNING to remember
* that we are still logically linked (not interested in
* new network events, despite for updating the net list,
- * but we are temporarly 'unlinked' as the driver shall
+ * but we are temporarily 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
* So the only situation in witch are interested is to check
* if the state become LINKED because of the #1 situation
@@ -530,7 +530,7 @@ void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee)
* So we switch to IEEE80211_LINKED_SCANNING to remember
* that we are still logically linked (not interested in
* new network events, despite for updating the net list,
- * but we are temporarly 'unlinked' as the driver shall
+ * but we are temporarily 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
* So the only situation in witch are interested is to check
* if the state become LINKED because of the #1 situation
@@ -1140,7 +1140,7 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
ieee->associate_seq++;
- /* don't scan, and avoid to have the RX path possibily
+ /* don't scan, and avoid to have the RX path possibly
* try again to associate. Even do not react to AUTH or
* ASSOC response. Just wait for the retry wq to be scheduled.
* Here we will check if there are good nets to associate
@@ -1346,14 +1346,14 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
//printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch);
if ( /* if the user set the AP check if match.
- * if the network does not broadcast essid we check the user supplyed ANY essid
+ * if the network does not broadcast essid we check the user supplied ANY essid
* if the network does broadcast and the user does not set essid it is OK
* if the network does broadcast and the user did set essid chech if essid match
*/
( apset && apmatch &&
((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
/* if the ap is not set, check that the user set the bssid
- * and the network does bradcast and that those two bssid matches
+ * and the network does broadcast and that those two bssid matches
*/
(!apset && ssidset && ssidbroad && ssidmatch)
){
@@ -1821,7 +1821,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
while (left >= sizeof(struct ieee80211_info_element_hdr)) {
if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
- printk(KERN_WARNING "[re]associate reeponse error!");
+ printk(KERN_WARNING "[re]associate response error!");
return 1;
}
switch (info_element->id) {
@@ -1905,7 +1905,7 @@ associate_complete:
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
- IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+ IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
ieee80211_associate_abort(ieee);
}
@@ -2184,15 +2184,15 @@ void ieee80211_start_ibss_wq(struct work_struct *work)
if(ieee->state == IEEE80211_NOLINK)
ieee->current_network.channel = 10;
- /* if not then the state is not linked. Maybe the user swithced to
+ /* if not then the state is not linked. Maybe the user switched to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
* time to scan all the chans..) or we have just run up the iface
* after setting ad-hoc mode. So we have to give another try..
* Here, in ibss mode, should be safe to do this without extra care
- * (in bss mode we had to make sure no-one tryed to associate when
+ * (in bss mode we had to make sure no-one tried to associate when
* we had just checked the ieee->state and we was going to start the
- * scan) beacause in ibss mode the ieee80211_new_net function, when
+ * scan) because in ibss mode the ieee80211_new_net function, when
* finds a good net, just set the ieee->state to IEEE80211_LINKED,
* so, at worst, we waste a bit of time to initiate an unneeded syncro
* scan, that will stop at the first round because it sees the state
@@ -2342,7 +2342,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
goto exit;
/* until we do not set the state to IEEE80211_NOLINK
* there are no possibility to have someone else trying
- * to start an association procdure (we get here with
+ * to start an association procedure (we get here with
* ieee->state = IEEE80211_ASSOCIATING).
* When we set the state to IEEE80211_NOLINK it is possible
* that the RX path run an attempt to associate, but
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index e46ff2f..5d20490 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -362,7 +362,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
ieee80211_stop_protocol(ieee);
/* this is just to be sure that the GET wx callback
- * has consisten infos. not needed otherwise
+ * has consistent infos. not needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 552115c..89ed86e 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -328,7 +328,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb,
//printk(KERN_WARNING "upper layer packet!\n");
spin_lock_irqsave(&ieee->lock, flags);
- /* If there is no driver handler to take the TXB, dont' bother
+ /* If there is no driver handler to take the TXB, don't bother
* creating it... */
if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))||
((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
@@ -413,10 +413,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb,
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
-// if (is_multicast_ether_addr(dest) ||
-// is_broadcast_ether_addr(dest)) {
- if (is_multicast_ether_addr(header.addr1) ||
- is_broadcast_ether_addr(header.addr1)) {
+ if (is_multicast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
qos_ctl = QOS_CTL_NOTCONTAIN_ACK;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index ca414a9..c7917b2 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -363,7 +363,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
- * explicitely set */
+ * explicitly set */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
ieee->tx_keyidx = key;//by wb 080312
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index a2c46ae..2682afb 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -11,7 +11,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -514,12 +514,12 @@ typedef struct r8180_priv
bool bDefaultAntenna1;
u8 SignalStrength;
long Stats_SignalStrength;
- long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average.
+ long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average.
u8 SignalQuality; // in 0-100 index.
long Stats_SignalQuality;
long RecvSignalPower; // in dBm.
long Stats_RecvSignalPower;
- u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
+ u8 LastRxPktAntenna; // +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
u32 AdRxOkCnt;
long AdRxSignalStrength;
u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx).
@@ -530,7 +530,7 @@ typedef struct r8180_priv
long AdRxSsThreshold; // Signal strength threshold to switch antenna.
long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold.
bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna.
- long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna.
+ long AdRxSsBeforeSwitched; // Rx signal strength before we switched antenna.
struct timer_list SwAntennaDiversityTimer;
//by amy for antenna
//{by amy 080312
@@ -553,7 +553,7 @@ typedef struct r8180_priv
bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow.
bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko.
u32 FalseAlarmRegValue;
- u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG.
+ u8 RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG.
u8 DIG_NumberFallbackVote;
u8 DIG_NumberUpgradeVote;
// For HW antenna diversity, added by Roger, 2008.01.30.
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 4fe52f6..fd22b75 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1329,7 +1329,7 @@ u16 N_DBPSOfRate(u16 DataRate)
}
/*
- * For Netgear case, they want good-looking singal strength.
+ * For Netgear case, they want good-looking signal strength.
*/
long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
{
@@ -1380,7 +1380,7 @@ long TranslateToDbm8185(u8 SignalStrengthIndex)
/*
* Perform signal smoothing for dynamic mechanism.
- * This is different with PerformSignalSmoothing8185 in smoothing fomula.
+ * This is different with PerformSignalSmoothing8185 in smoothing formula.
* No dramatic adjustion is apply because dynamic mechanism need some degree
* of correctness. Ported from 8187B.
*/
@@ -1535,7 +1535,7 @@ void rtl8180_rx(struct net_device *dev)
/* HW is probably passing several buggy frames
* without FD or LD flag set.
* Throw this garbage away to prevent skb
- * memory exausting
+ * memory exhausting
*/
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
@@ -1648,14 +1648,14 @@ void rtl8180_rx(struct net_device *dev)
priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
- /* Figure out which antenna that received the lasted packet. */
+ /* Figure out which antenna that received the last packet. */
priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
if (first) {
if (!priv->rx_skb_complete) {
- /* seems that HW sometimes fails to reiceve and
+ /* seems that HW sometimes fails to receive and
doesn't provide the last descriptor */
dev_kfree_skb_any(priv->rx_skb);
priv->stats.rxnolast++;
@@ -1672,7 +1672,7 @@ void rtl8180_rx(struct net_device *dev)
priv->rx_skb_complete = 0;
priv->rx_skb->dev = dev;
} else {
- /* if we are here we should have already RXed
+ /* if we are here we should have already RXed
* the first frame.
* If we get here and the skb is not allocated then
* we have just throw out garbage (skb not allocated)
@@ -1821,15 +1821,15 @@ rate) {
/*
* This is a rough attempt to TX a frame
* This is called by the ieee 80211 stack to TX management frames.
- * If the ring is full packet are dropped (for data frame the queue
+ * If the ring is full packets are dropped (for data frame the queue
* is stopped before this can happen). For this reason it is better
* if the descriptors are larger than the largest management frame
- * we intend to TX: i'm unsure what the HW does if it will not found
+ * we intend to TX: i'm unsure what the HW does if it will not find
* the last fragment of a frame because it has been dropped...
* Since queues for Management and Data frames are different we
* might use a different lock than tx_lock (for example mgmt_tx_lock)
*/
-/* these function may loops if invoked with 0 descriptors or 0 len buffer */
+/* these function may loop if invoked with 0 descriptors or 0 len buffer */
int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -2003,8 +2003,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
}
memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest)) {
+ if (is_multicast_ether_addr(dest)) {
Duration = 0;
RtsDur = 0;
bRTSEnable = 0;
@@ -2378,7 +2377,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
u8 u1bAIFS;
u32 u4bAcParam;
pAcParam = (PAC_PARAM)(&AcParam);
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
@@ -2414,7 +2413,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
u8 u1bAIFS;
u32 u4bAcParam;
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
eACI = pAcParam->f.AciAifsn.f.ACI;
/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
@@ -2700,7 +2699,7 @@ short rtl8180_init(struct net_device *dev)
priv->bTxPowerTrack = false;
priv->ThermalMeter = 0;
priv->FalseAlarmRegValue = 0;
- priv->RegDigOfdmFaUpTh = 0xc; /* Upper threhold of OFDM false alarm, which is used in DIG. */
+ priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
priv->DIG_NumberFallbackVote = 0;
priv->DIG_NumberUpgradeVote = 0;
priv->LastSignalStrengthInPercent = 0;
@@ -2896,7 +2895,7 @@ short rtl8180_init(struct net_device *dev)
priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
}
- /* 3Read crystal calibtration and thermal meter indication on 87SE. */
+ /* 3Read crystal calibration and thermal meter indication on 87SE. */
eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
/* Crystal calibration for Xin and Xout resp. */
@@ -3140,7 +3139,7 @@ void rtl8180_adapter_start(struct net_device *dev)
/*
* The following is very strange. seems to be that 1 means test mode,
- * but we need to acknolwledges the nic when a packet is ready
+ * but we need to acknowledges the nic when a packet is ready
* although we set it to 0
*/
@@ -3971,7 +3970,7 @@ irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
}
if (inta == 0xffff) {
- /* HW disappared */
+ /* HW disappeared */
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index 4d7a595..b8f2ba0 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -2,7 +2,7 @@
#include "r8180_hw.h"
#include "r8180_93cx6.h"
- /* Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. */
+ /* Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */
#define RATE_ADAPTIVE_TIMER_PERIOD 300
bool CheckHighPower(struct net_device *dev)
@@ -105,7 +105,7 @@ void rtl8180_tx_pw_wq(struct work_struct *work)
/*
- * Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
+ * Return TRUE if we shall perform DIG Mechanism, FALSE otherwise.
*/
bool CheckDig(struct net_device *dev)
{
@@ -507,7 +507,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
* and retry rate.
* (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
* situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
- * (4) Add the mehanism of trying to upgrade tx rate.
+ * (4) Add the mechanism of trying to upgrade tx rate.
* (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
*
*/
@@ -528,7 +528,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
if (priv->bTryuping == true) {
/* 2 For Test Upgrading mechanism
* Note:
- * Sometimes the throughput is upon on the capability bwtween the AP and NIC,
+ * Sometimes the throughput is upon on the capability between the AP and NIC,
* thus the low data rate does not improve the performance.
* We randomly upgrade the data rate and check if the retry rate is improved.
*/
@@ -704,7 +704,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
/*
* The difference in throughput between 48Mbps and 36Mbps is 8M.
- * So, we must be carefully in this rate scale. Isaiah 2008-02-15.
+ * So, we must be careful in this rate scale. Isaiah 2008-02-15.
*/
if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
(priv->FailTxRateCount > 2))
@@ -1009,7 +1009,7 @@ void SwAntennaDiversity(struct net_device *dev)
if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
priv->AdCheckPeriod = priv->AdMaxCheckPeriod;
- /* Wrong deceision => switch back. */
+ /* Wrong decision => switch back. */
SwitchAntenna(dev);
} else {
/* Rx Signal Strength is improved. */
@@ -1057,7 +1057,7 @@ void SwAntennaDiversity(struct net_device *dev)
}
/*
* <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
- * didn't changed by HW evaluation.
+ * didn't change by HW evaluation.
* 2008.02.27.
*
* [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
@@ -1098,7 +1098,7 @@ void SwAntennaDiversity(struct net_device *dev)
priv->AdAuxAntennaRxOkCnt = 0;
}
- /* Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. */
+ /* Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */
bool CheckTxPwrTracking(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index ee5b867..d28c1d9 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -190,7 +190,7 @@ static void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch)
write_phy_cck(dev, 0x44 + i, power);
}
- /* FIXME Is this delay really needeed ? */
+ /* FIXME Is this delay really needed ? */
force_pci_posting(dev);
mdelay(1);
@@ -479,7 +479,7 @@ s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode,
/*
* TRUE if we want to use a default implementation.
- * We shall set it to FALSE when we have exact translation formular
+ * We shall set it to FALSE when we have exact translation formula
* for target IC. 070622, by rcnjko.
*/
if (bUseDefault) {
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 303ec69..46ee6f4 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -13,7 +13,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -1181,7 +1181,7 @@ static iw_handler r8180_wx_handlers[] = {
r8180_wx_set_wap, /* SIOCSIWAP */
r8180_wx_get_wap, /* SIOCGIWAP */
r8180_wx_set_mlme, /* SIOCSIWMLME*/
- dummy, /* SIOCGIWAPLIST -- depricated */
+ dummy, /* SIOCGIWAPLIST -- deprecated */
r8180_wx_set_scan, /* SIOCSIWSCAN */
r8180_wx_get_scan, /* SIOCGIWSCAN */
r8180_wx_set_essid, /* SIOCSIWESSID */
@@ -1369,7 +1369,7 @@ static inline int is_same_network(struct ieee80211_network *src,
(dst->capability & WLAN_CAPABILITY_BSS)));
}
-/* WB modefied to show signal to GUI on 18-01-2008 */
+/* WB modified to show signal to GUI on 18-01-2008 */
static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h
index 735d03d..4081914 100644
--- a/drivers/staging/rtl8187se/r8180_wx.h
+++ b/drivers/staging/rtl8187se/r8180_wx.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thanks the Authors of such projects and the Ndiswrapper project Authors.
*/
/* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 4b0b830..9144957 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -1,22 +1,22 @@
-/*++
-Copyright (c) Realtek Semiconductor Corp. All rights reserved.
-
-Module Name:
- r8185b_init.c
-
-Abstract:
- Hardware Initialization and Hardware IO for RTL8185B
-
-Major Change History:
- When Who What
- ---------- --------------- -------------------------------
- 2006-11-15 Xiong Created
-
-Notes:
- This file is ported from RTL8185B Windows driver.
-
-
---*/
+/*
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Module Name:
+ * r8185b_init.c
+ *
+ * Abstract:
+ * Hardware Initialization and Hardware IO for RTL8185B
+ *
+ * Major Change History:
+ * When Who What
+ * ---------- --------------- -------------------------------
+ * 2006-11-15 Xiong Created
+ *
+ * Notes:
+ * This file is ported from RTL8185B Windows driver.
+ *
+ *
+ */
/*--------------------------Include File------------------------------------*/
#include <linux/spinlock.h>
@@ -25,155 +25,134 @@ Notes:
#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
#include "r8180_93cx6.h" /* Card EEPROM */
#include "r8180_wx.h"
-
#include "ieee80211/dot11d.h"
-
-
/* #define CONFIG_RTL8180_IO_MAP */
-
#define TC_3W_POLL_MAX_TRY_CNT 5
+
static u8 MAC_REG_TABLE[][2] = {
- /*PAGA 0: */
- /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */
- /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */
- /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */
- {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
- {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
- {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
- {0x94, 0x0F}, {0x95, 0x32},
- {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
- {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
- {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
- {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
- {0xff, 0x00},
-
- /*PAGE 1: */
- /* For Flextronics system Logo PCIHCT failure: */
- /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */
- {0x5e, 0x01},
- {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
- {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
- {0x82, 0xFF}, {0x83, 0x03},
- {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
- {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},/* lzm add 080826 */
- {0xe2, 0x00},
-
-
- /* PAGE 2: */
- {0x5e, 0x02},
- {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
- {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
- {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
- {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
- {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
- {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
- {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
-
- /* PAGA 0: */
- {0x5e, 0x00}, {0x9f, 0x03}
- };
-
-
-static u8 ZEBRA_AGC[] = {
- 0,
- 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
- 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
- 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
- 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
- 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
- 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
- 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
- };
-
-static u32 ZEBRA_RF_RX_GAIN_TABLE[] = {
- 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
- 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
- 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
- 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
- 0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+ /*PAGA 0: */
+ /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */
+ /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */
+ /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */
+ {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
+ {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
+ {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
+ {0x94, 0x0F}, {0x95, 0x32},
+ {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
+ {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
+ {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
+ {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
+ {0xff, 0x00},
+
+ /*PAGE 1: */
+ /* For Flextronics system Logo PCIHCT failure: */
+ /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */
+ {0x5e, 0x01},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
+ {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
+ {0x82, 0xFF}, {0x83, 0x03},
+ {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
+ {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22}, /* lzm add 080826 */
+ {0xe2, 0x00},
+
+
+ /* PAGE 2: */
+ {0x5e, 0x02},
+ {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
+ {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
+ {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
+ {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
+ {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
+ {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
+
+ /* PAGA 0: */
+ {0x5e, 0x00}, {0x9f, 0x03}
+ };
+
+
+static u8 ZEBRA_AGC[] = {
+ 0,
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
+ 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
+ 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
+ 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
+ 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
+ };
+
+static u32 ZEBRA_RF_RX_GAIN_TABLE[] = {
+ 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
+ 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
+ 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
+ 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
+ 0x0183, 0x0163, 0x0143, 0x0123, 0x0103
};
-static u8 OFDM_CONFIG[] = {
- /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */
- /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */
- /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */
-
- /* 0x00 */
- 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
- 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
- /* 0x10 */
- 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
- 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
- /* 0x20 */
- 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
- 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
- /* 0x30 */
- 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
- 0xD8, 0x3C, 0x7B, 0x10, 0x10
- };
-
-/* ---------------------------------------------------------------
- * Hardware IO
- * the code is ported from Windows source code
- ----------------------------------------------------------------*/
-
-void
-PlatformIOWrite1Byte(
- struct net_device *dev,
- u32 offset,
- u8 data
- )
+static u8 OFDM_CONFIG[] = {
+ /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */
+ /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */
+ /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */
+ /* 0x00 */
+ 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
+ /* 0x10 */
+ 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
+ 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
+ /* 0x20 */
+ 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
+ 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
+ /* 0x30 */
+ 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
+ 0xD8, 0x3C, 0x7B, 0x10, 0x10
+ };
+
+ /*---------------------------------------------------------------
+ * Hardware IO
+ * the code is ported from Windows source code
+ *---------------------------------------------------------------
+ */
+
+void PlatformIOWrite1Byte(struct net_device *dev, u32 offset, u8 data)
{
write_nic_byte(dev, offset, data);
- read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
-
+ read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
}
-void
-PlatformIOWrite2Byte(
- struct net_device *dev,
- u32 offset,
- u16 data
- )
+void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data)
{
write_nic_word(dev, offset, data);
read_nic_word(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
-
-
}
+
u8 PlatformIORead1Byte(struct net_device *dev, u32 offset);
-void
-PlatformIOWrite4Byte(
- struct net_device *dev,
- u32 offset,
- u32 data
- )
+void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data)
{
-/* {by amy 080312 */
-if (offset == PhyAddr) {
-/* For Base Band configuration. */
+ if (offset == PhyAddr) {
+ /* For Base Band configuration. */
unsigned char cmdByte;
unsigned long dataBytes;
unsigned char idx;
- u8 u1bTmp;
+ u8 u1bTmp;
cmdByte = (u8)(data & 0x000000ff);
dataBytes = data>>8;
/*
- 071010, rcnjko:
- The critical section is only BB read/write race condition.
- Assumption:
- 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
- acquiring the spinlock in such context.
- 2. PlatformIOWrite4Byte() MUST NOT be recursive.
- */
-/* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */
-
- for (idx = 0; idx < 30; idx++) {
- /* Make sure command bit is clear before access it. */
+ * 071010, rcnjko:
+ * The critical section is only BB read/write race condition.
+ * Assumption:
+ * 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
+ * acquiring the spinlock in such context.
+ * 2. PlatformIOWrite4Byte() MUST NOT be recursive.
+ */
+ /* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */
+
+ for (idx = 0; idx < 30; idx++) {
+ /* Make sure command bit is clear before access it. */
u1bTmp = PlatformIORead1Byte(dev, PhyAddr);
if ((u1bTmp & BIT7) == 0)
break;
@@ -186,20 +165,14 @@ if (offset == PhyAddr) {
write_nic_byte(dev, offset, cmdByte);
-/* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
- }
-/* by amy 080312} */
- else {
+ /* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
+ } else {
write_nic_dword(dev, offset, data);
read_nic_dword(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
}
}
-u8
-PlatformIORead1Byte(
- struct net_device *dev,
- u32 offset
- )
+u8 PlatformIORead1Byte(struct net_device *dev, u32 offset)
{
u8 data = 0;
@@ -209,11 +182,7 @@ PlatformIORead1Byte(
return data;
}
-u16
-PlatformIORead2Byte(
- struct net_device *dev,
- u32 offset
- )
+u16 PlatformIORead2Byte(struct net_device *dev, u32 offset)
{
u16 data = 0;
@@ -223,11 +192,7 @@ PlatformIORead2Byte(
return data;
}
-u32
-PlatformIORead4Byte(
- struct net_device *dev,
- u32 offset
- )
+u32 PlatformIORead4Byte(struct net_device *dev, u32 offset)
{
u32 data = 0;
@@ -242,22 +207,19 @@ void SetOutputEnableOfRfPins(struct net_device *dev)
write_nic_word(dev, RFPinsEnable, 0x1bff);
}
-static int
-HwHSSIThreeWire(
- struct net_device *dev,
- u8 *pDataBuf,
- u8 nDataBufBitCnt,
- int bSI,
- int bWrite
- )
+static int HwHSSIThreeWire(struct net_device *dev,
+ u8 *pDataBuf,
+ u8 nDataBufBitCnt,
+ int bSI,
+ int bWrite)
{
int bResult = 1;
u8 TryCnt;
u8 u1bTmp;
- do {
+ do {
/* Check if WE and RE are cleared. */
- for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
+ for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
if ((u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0)
break;
@@ -275,15 +237,15 @@ HwHSSIThreeWire(
u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
if (bSI)
- u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */
+ u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */
else
- u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */
+ u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */
write_nic_byte(dev, RF_SW_CONFIG, u1bTmp);
- if (bSI) {
+ if (bSI) {
/* jong: HW SI read must set reg84[3]=0. */
u1bTmp = read_nic_byte(dev, RFPinsSelect);
u1bTmp &= ~BIT3;
@@ -291,14 +253,14 @@ HwHSSIThreeWire(
}
/* Fill up data buffer for write operation. */
- if (bWrite) {
- if (nDataBufBitCnt == 16) {
+ if (bWrite) {
+ if (nDataBufBitCnt == 16) {
write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
- } else if (nDataBufBitCnt == 64) {
+ } else if (nDataBufBitCnt == 64) {
/* RTL8187S shouldn't enter this case */
write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf));
write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4)));
- } else {
+ } else {
int idx;
int ByteCnt = nDataBufBitCnt / 8;
/* printk("%d\n",nDataBufBitCnt); */
@@ -324,11 +286,11 @@ HwHSSIThreeWire(
write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
}
- } else { /* read */
- if (bSI) {
- /* SI - reg274[3:0] : RF register's Address */
+ } else { /* read */
+ if (bSI) {
+ /* SI - reg274[3:0] : RF register's Address */
write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
- } else {
+ } else {
/* PI - reg274[15:12] : RF register's Address */
write_nic_word(dev, SW_3W_DB0, (*((u16 *)pDataBuf)) << 12);
}
@@ -343,7 +305,7 @@ HwHSSIThreeWire(
/* Check if DONE is set. */
- for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
+ for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
if ((u1bTmp & SW_3W_CMD1_DONE) != 0)
break;
@@ -353,12 +315,12 @@ HwHSSIThreeWire(
write_nic_byte(dev, SW_3W_CMD1, 0);
- /* Read back data for read operation. */
- if (bWrite == 0) {
- if (bSI) {
+ /* Read back data for read operation. */
+ if (bWrite == 0) {
+ if (bSI) {
/* Serial Interface : reg363_362[11:0] */
*((u16 *)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ;
- } else {
+ } else {
/* Parallel Interface : reg361_360[11:0] */
*((u16 *)pDataBuf) = read_nic_word(dev, PI_DATA_READ);
}
@@ -366,13 +328,12 @@ HwHSSIThreeWire(
*((u16 *)pDataBuf) &= 0x0FFF;
}
- } while (0);
+ } while (0);
return bResult;
}
-void
-RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
+void RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
{
u32 data2Write;
u8 len;
@@ -400,11 +361,7 @@ u32 RF_ReadReg(struct net_device *dev, u8 offset)
/* by Owen on 04/07/14 for writing BB register successfully */
-void
-WriteBBPortUchar(
- struct net_device *dev,
- u32 Data
- )
+void WriteBBPortUchar(struct net_device *dev, u32 Data)
{
/* u8 TimeoutCounter; */
u8 RegisterContent;
@@ -421,11 +378,7 @@ WriteBBPortUchar(
}
}
-u8
-ReadBBPortUchar(
- struct net_device *dev,
- u32 addr
- )
+u8 ReadBBPortUchar(struct net_device *dev, u32 addr)
{
/*u8 TimeoutCounter; */
u8 RegisterContent;
@@ -435,66 +388,62 @@ ReadBBPortUchar(
return RegisterContent;
}
-/* {by amy 080312 */
/*
- Description:
- Perform Antenna settings with antenna diversity on 87SE.
- Created by Roger, 2008.01.25.
-*/
-bool
-SetAntennaConfig87SE(
- struct net_device *dev,
- u8 DefaultAnt, /* 0: Main, 1: Aux. */
- bool bAntDiversity /* 1:Enable, 0: Disable. */
-)
+ * Description:
+ * Perform Antenna settings with antenna diversity on 87SE.
+ * Created by Roger, 2008.01.25.
+ */
+bool SetAntennaConfig87SE(struct net_device *dev,
+ u8 DefaultAnt, /* 0: Main, 1: Aux. */
+ bool bAntDiversity) /* 1:Enable, 0: Disable. */
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
bool bAntennaSwitched = true;
/* printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); */
- /* Threshold for antenna diversity. */
+ /* Threshold for antenna diversity. */
write_phy_cck(dev, 0x0c, 0x09); /* Reg0c : 09 */
- if (bAntDiversity) { /* Enable Antenna Diversity. */
- if (DefaultAnt == 1) { /* aux antenna */
+ if (bAntDiversity) { /* Enable Antenna Diversity. */
+ if (DefaultAnt == 1) { /* aux antenna */
- /* Mac register, aux antenna */
+ /* Mac register, aux antenna */
write_nic_byte(dev, ANTSEL, 0x00);
- /* Config CCK RX antenna. */
+ /* Config CCK RX antenna. */
write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
- /* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
- write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
- } else { /* use main antenna */
- /* Mac register, main antenna */
+ /* Config OFDM RX antenna. */
+ write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
+ write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
+ } else { /* use main antenna */
+ /* Mac register, main antenna */
write_nic_byte(dev, ANTSEL, 0x03);
- /* base band */
- /* Config CCK RX antenna. */
- write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
- write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
+ /* base band */
+ /* Config CCK RX antenna. */
+ write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
+ write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
/* Config OFDM RX antenna. */
write_phy_ofdm(dev, 0x0d, 0x5c); /* Reg0d : 5c */
write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
}
- } else {
+ } else {
/* Disable Antenna Diversity. */
- if (DefaultAnt == 1) { /* aux Antenna */
+ if (DefaultAnt == 1) { /* aux Antenna */
/* Mac register, aux antenna */
write_nic_byte(dev, ANTSEL, 0x00);
/* Config CCK RX antenna. */
- write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
- write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
+ write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
+ write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
/* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
- write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */
- } else { /* main Antenna */
+ write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
+ write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */
+ } else { /* main Antenna */
/* Mac register, main antenna */
write_nic_byte(dev, ANTSEL, 0x03);
@@ -502,25 +451,22 @@ SetAntennaConfig87SE(
write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
- /* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */
- write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */
+ /* Config OFDM RX antenna. */
+ write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */
+ write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */
}
}
priv->CurrAntennaIndex = DefaultAnt; /* Update default settings. */
return bAntennaSwitched;
}
-/* by amy 080312 */
/*
----------------------------------------------------------------
- * Hardware Initialization.
- * the code is ported from Windows source code
-----------------------------------------------------------------*/
-
-void
-ZEBRA_Config_85BASIC_HardCode(
- struct net_device *dev
- )
+ *--------------------------------------------------------------
+ * Hardware Initialization.
+ * the code is ported from Windows source code
+ *--------------------------------------------------------------
+ */
+
+void ZEBRA_Config_85BASIC_HardCode(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -532,163 +478,151 @@ ZEBRA_Config_85BASIC_HardCode(
/*
-=============================================================================
- 87S_PCIE :: RADIOCFG.TXT
-=============================================================================
-*/
+ *===========================================================================
+ * 87S_PCIE :: RADIOCFG.TXT
+ *===========================================================================
+ */
/* Page1 : reg16-reg30 */
- RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */
- u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1);
- u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */
+ u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1);
+ u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1);
if (u4bRF23 == 0x818 && u4bRF24 == 0x70C) {
d_cut = 1;
printk(KERN_INFO "rtl8187se: card type changed from C- to D-cut\n");
}
- /* Page0 : reg0-reg15 */
-
- RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */
-
- RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1);
-
- RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */
-
- RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */
-
- RF_WriteReg(dev, 0x04, 0x0975); mdelay(1);
- RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1);
- RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1);
- RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1);
- RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1);
- RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1);
- RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1);
- RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1);
- RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1);
-
+ /* Page0 : reg0-reg15 */
+
+ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */
+ RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1);
+ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */
+ RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */
+ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1);
+ RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1);
+ RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1);
+ RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1);
+ RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1);
+ RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1);
+ RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1);
+ RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1);
/* Page1 : reg16-reg30 */
- RF_WriteReg(dev, 0x00, 0x013f); mdelay(1);
-
- RF_WriteReg(dev, 0x03, 0x0806); mdelay(1);
-
- RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1);
- RF_WriteReg(dev, 0x05, 0x059b); mdelay(1);
- RF_WriteReg(dev, 0x06, 0x0081); mdelay(1);
-
-
- RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1);
+ RF_WriteReg(dev, 0x03, 0x0806); mdelay(1);
+ RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1);
+ RF_WriteReg(dev, 0x05, 0x059b); mdelay(1);
+ RF_WriteReg(dev, 0x06, 0x0081); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1);
/* Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. */
- RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
- RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
+ RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1);
if (d_cut) {
- RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */
- } else {
- RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */
+ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */
+ } else {
+ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */
}
- RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
-
- RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */
+ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */
+ RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1);
+ RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1);
- RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1);
- RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1);
- for (i = 0; i <= 36; i++) {
- RF_WriteReg(dev, 0x01, i); mdelay(1);
+ for (i = 0; i <= 36; i++) {
+ RF_WriteReg(dev, 0x01, i); mdelay(1);
RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1);
}
- RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */
- RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */
+ RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */
+ RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */
+ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */
+ mdelay(200); /* Deay 200 ms. */ /* 0xfd */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */
- mdelay(200); /* Deay 200 ms. */ /* 0xfd */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
-
- RF_WriteReg(dev, 0x07, 0x0000); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x0180); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x0220); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0000); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0180); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0220); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1);
/* DAC calibration off 20070702 */
- RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1);
- RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
-/* {by amy 080312 */
+ RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
/* For crystal calibration, added by Roger, 2007.12.11. */
- if (priv->bXtalCalibration) { /* reg 30. */
- /* enable crystal calibration.
- RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0].
- (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
- (3)RF signal on/off when calibration[13], default: on, set BIT13=0.
- So we should minus 4 BITs offset. */
- RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1);
+ if (priv->bXtalCalibration) { /* reg 30. */
+ /*
+ * enable crystal calibration.
+ * RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0].
+ * (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
+ * (3)RF signal on/off when calibration[13], default: on, set BIT13=0.
+ * So we should minus 4 BITs offset.
+ */
+ RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1);
printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n",
- (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
- } else {
+ (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
+ } else {
/* using default value. Xin=6, Xout=6. */
- RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
+ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
}
-/* by amy 080312 */
- RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */
- RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */
- RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */
- RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */
+ RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */
+ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */
+ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */
+ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
- RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */
-
- RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
- /* power save parameters. */
+ RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
+ /* power save parameters. */
u1b24E = read_nic_byte(dev, 0x24E);
write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6))));
/*=============================================================================
-
- =============================================================================
- CCKCONF.TXT
- =============================================================================
- */
- /* [POWER SAVE] Power Saving Parameters by jong. 2007-11-27
- CCK reg0x00[7]=1'b1 :power saving for TX (default)
- CCK reg0x00[6]=1'b1: power saving for RX (default)
- CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
- CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
- CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
- */
+ *
+ *===========================================================================
+ * CCKCONF.TXT
+ *===========================================================================
+ *
+ * [POWER SAVE] Power Saving Parameters by jong. 2007-11-27
+ * CCK reg0x00[7]=1'b1 :power saving for TX (default)
+ * CCK reg0x00[6]=1'b1: power saving for RX (default)
+ * CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
+ * CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
+ * CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
+ */
write_phy_cck(dev, 0x00, 0xc8);
write_phy_cck(dev, 0x06, 0x1c);
@@ -697,7 +631,7 @@ ZEBRA_Config_85BASIC_HardCode(
write_phy_cck(dev, 0x2f, 0x06);
write_phy_cck(dev, 0x01, 0x46);
- /* power control */
+ /* power control */
write_nic_byte(dev, CCK_TXAGC, 0x10);
write_nic_byte(dev, OFDM_TXAGC, 0x1B);
write_nic_byte(dev, ANTSEL, 0x03);
@@ -705,14 +639,14 @@ ZEBRA_Config_85BASIC_HardCode(
/*
- =============================================================================
- AGC.txt
- =============================================================================
- */
+ *===========================================================================
+ * AGC.txt
+ *===========================================================================
+ */
write_phy_ofdm(dev, 0x00, 0x12);
- for (i = 0; i < 128; i++) {
+ for (i = 0; i < 128; i++) {
data = ZEBRA_AGC[i+1];
data = data << 8;
@@ -730,49 +664,43 @@ ZEBRA_Config_85BASIC_HardCode(
PlatformIOWrite4Byte(dev, PhyAddr, 0x00001080); /* Annie, 2006-05-05 */
/*
- =============================================================================
-
- =============================================================================
- OFDMCONF.TXT
- =============================================================================
- */
-
- for (i = 0; i < 60; i++) {
+ *===========================================================================
+ *
+ *===========================================================================
+ * OFDMCONF.TXT
+ *===========================================================================
+ */
+
+ for (i = 0; i < 60; i++) {
u4bRegOffset = i;
u4bRegValue = OFDM_CONFIG[i];
WriteBBPortUchar(dev,
- (0x00000080 |
- (u4bRegOffset & 0x7f) |
- ((u4bRegValue & 0xff) << 8)));
+ (0x00000080 |
+ (u4bRegOffset & 0x7f) |
+ ((u4bRegValue & 0xff) << 8)));
}
/*
- =============================================================================
- by amy for antenna
- =============================================================================
- */
-/* {by amy 080312 */
+ *===========================================================================
+ * by amy for antenna
+ *===========================================================================
+ */
/* Config Sw/Hw Combinational Antenna Diversity. Added by Roger, 2008.02.26. */
SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity);
-/* by amy 080312} */
-/* by amy for antenna */
}
-void
-UpdateInitialGain(
- struct net_device *dev
- )
+void UpdateInitialGain(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/* lzm add 080826 */
- if (priv->eRFPowerState != eRfOn) {
+ if (priv->eRFPowerState != eRfOn) {
/* Don't access BB/RF under disable PLL situation.
- RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
- Back to the original state
- */
+ * RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
+ * Back to the original state
+ */
priv->InitialGain = priv->InitialGainBackUp;
return;
}
@@ -826,7 +754,7 @@ UpdateInitialGain(
write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
break;
- default: /* MP */
+ default: /* MP */
write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
@@ -834,14 +762,11 @@ UpdateInitialGain(
}
}
/*
- Description:
- Tx Power tracking mechanism routine on 87SE.
- Created by Roger, 2007.12.11.
-*/
-void
-InitTxPwrTracking87SE(
- struct net_device *dev
-)
+ * Description:
+ * Tx Power tracking mechanism routine on 87SE.
+ * Created by Roger, 2007.12.11.
+ */
+void InitTxPwrTracking87SE(struct net_device *dev)
{
u32 u4bRfReg;
@@ -851,49 +776,41 @@ InitTxPwrTracking87SE(
RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1);
}
-void
-PhyConfig8185(
- struct net_device *dev
- )
+void PhyConfig8185(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, RCR, priv->ReceiveConfig);
priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03;
/* RF config */
ZEBRA_Config_85BASIC_HardCode(dev);
-/* {by amy 080312 */
/* Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. */
- if (priv->bDigMechanism) {
+ if (priv->bDigMechanism) {
if (priv->InitialGain == 0)
priv->InitialGain = 4;
}
/*
- Enable thermal meter indication to implement TxPower tracking on 87SE.
- We initialize thermal meter here to avoid unsuccessful configuration.
- Added by Roger, 2007.12.11.
- */
+ * Enable thermal meter indication to implement TxPower tracking on 87SE.
+ * We initialize thermal meter here to avoid unsuccessful configuration.
+ * Added by Roger, 2007.12.11.
+ */
if (priv->bTxPowerTrack)
InitTxPwrTracking87SE(dev);
-/* by amy 080312} */
priv->InitialGainBackUp = priv->InitialGain;
UpdateInitialGain(dev);
return;
}
-void
-HwConfigureRTL8185(
- struct net_device *dev
- )
+void HwConfigureRTL8185(struct net_device *dev)
{
/* RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. */
- u8 bUNIVERSAL_CONTROL_RL = 0;
- u8 bUNIVERSAL_CONTROL_AGC = 1;
- u8 bUNIVERSAL_CONTROL_ANT = 1;
- u8 bAUTO_RATE_FALLBACK_CTL = 1;
- u8 val8;
+ u8 bUNIVERSAL_CONTROL_RL = 0;
+ u8 bUNIVERSAL_CONTROL_AGC = 1;
+ u8 bUNIVERSAL_CONTROL_ANT = 1;
+ u8 bAUTO_RATE_FALLBACK_CTL = 1;
+ u8 val8;
write_nic_word(dev, BRSR, 0x0fff);
/* Retry limit */
val8 = read_nic_byte(dev, CW_CONF);
@@ -907,24 +824,24 @@ HwConfigureRTL8185(
/* Tx AGC */
val8 = read_nic_byte(dev, TXAGC_CTL);
- if (bUNIVERSAL_CONTROL_AGC) {
+ if (bUNIVERSAL_CONTROL_AGC) {
write_nic_byte(dev, CCK_TXAGC, 128);
write_nic_byte(dev, OFDM_TXAGC, 128);
val8 = val8 & 0xfe;
- } else {
+ } else {
val8 = val8 | 0x01 ;
}
write_nic_byte(dev, TXAGC_CTL, val8);
- /* Tx Antenna including Feedback control */
+ /* Tx Antenna including Feedback control */
val8 = read_nic_byte(dev, TXAGC_CTL);
- if (bUNIVERSAL_CONTROL_ANT) {
+ if (bUNIVERSAL_CONTROL_ANT) {
write_nic_byte(dev, ANTSEL, 0x00);
val8 = val8 & 0xfd;
- } else {
+ } else {
val8 = val8 & (val8|0x02); /* xiong-2006-11-15 */
}
@@ -933,7 +850,7 @@ HwConfigureRTL8185(
/* Auto Rate fallback control */
val8 = read_nic_byte(dev, RATE_FALLBACK);
val8 &= 0x7c;
- if (bAUTO_RATE_FALLBACK_CTL) {
+ if (bAUTO_RATE_FALLBACK_CTL) {
val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1;
/* <RJ_TODO_8185B> We shall set up the ARFR according to user's setting. */
@@ -942,40 +859,34 @@ HwConfigureRTL8185(
write_nic_byte(dev, RATE_FALLBACK, val8);
}
-static void
-MacConfig_85BASIC_HardCode(
- struct net_device *dev)
+static void MacConfig_85BASIC_HardCode(struct net_device *dev)
{
/*
- ============================================================================
- MACREG.TXT
- ============================================================================
- */
- int nLinesRead = 0;
-
- u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
- int i;
+ *==========================================================================
+ * MACREG.TXT
+ *==========================================================================
+ */
+ int nLinesRead = 0;
+ u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
+ int i;
nLinesRead = sizeof(MAC_REG_TABLE)/2;
- for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */
+ for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */
u4bRegOffset = MAC_REG_TABLE[i][0];
u4bRegValue = MAC_REG_TABLE[i][1];
if (u4bRegOffset == 0x5e)
u4bPageIndex = u4bRegValue;
-
else
- u4bRegOffset |= (u4bPageIndex << 8);
+ u4bRegOffset |= (u4bPageIndex << 8);
write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue);
}
/* ============================================================================ */
}
-static void
-MacConfig_85BASIC(
- struct net_device *dev)
+static void MacConfig_85BASIC(struct net_device *dev)
{
u8 u1DA;
@@ -994,18 +905,18 @@ MacConfig_85BASIC(
PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000);
PlatformIOWrite1Byte(dev, 0x1F8, 0x00);
- /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */
- /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */
+ /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */
+ /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */
/* Enable DA10 TX power saving */
u1DA = read_nic_byte(dev, PHYPR);
write_nic_byte(dev, PHYPR, (u1DA | BIT2));
- /* POWER: */
+ /* POWER: */
write_nic_word(dev, 0x360, 0x1000);
write_nic_word(dev, 0x362, 0x1000);
- /* AFE. */
+ /* AFE. */
write_nic_word(dev, 0x370, 0x0560);
write_nic_word(dev, 0x372, 0x0560);
write_nic_word(dev, 0x374, 0x0DA4);
@@ -1013,54 +924,48 @@ MacConfig_85BASIC(
write_nic_word(dev, 0x378, 0x0560);
write_nic_word(dev, 0x37A, 0x0560);
write_nic_word(dev, 0x37C, 0x00EC);
- write_nic_word(dev, 0x37E, 0x00EC); /*+edward */
+ write_nic_word(dev, 0x37E, 0x00EC); /* +edward */
write_nic_byte(dev, 0x24E, 0x01);
}
-u8
-GetSupportedWirelessMode8185(
- struct net_device *dev
-)
+u8 GetSupportedWirelessMode8185(struct net_device *dev)
{
- u8 btSupportedWirelessMode = 0;
+ u8 btSupportedWirelessMode = 0;
btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G);
return btSupportedWirelessMode;
}
-void
-ActUpdateChannelAccessSetting(
- struct net_device *dev,
- WIRELESS_MODE WirelessMode,
- PCHANNEL_ACCESS_SETTING ChnlAccessSetting
- )
+void ActUpdateChannelAccessSetting(struct net_device *dev,
+ WIRELESS_MODE WirelessMode,
+ PCHANNEL_ACCESS_SETTING ChnlAccessSetting)
{
- struct r8180_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee80211;
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
AC_CODING eACI;
AC_PARAM AcParam;
- u8 bFollowLegacySetting = 0;
- u8 u1bAIFS;
+ u8 bFollowLegacySetting = 0;
+ u8 u1bAIFS;
/*
- <RJ_TODO_8185B>
- TODO: We still don't know how to set up these registers, just follow WMAC to
- verify 8185B FPAG.
-
- <RJ_TODO_8185B>
- Jong said CWmin/CWmax register are not functional in 8185B,
- so we shall fill channel access realted register into AC parameter registers,
- even in nQBss.
- */
+ * <RJ_TODO_8185B>
+ * TODO: We still don't know how to set up these registers, just follow WMAC to
+ * verify 8185B FPAG.
+ *
+ * <RJ_TODO_8185B>
+ * Jong said CWmin/CWmax register are not functional in 8185B,
+ * so we shall fill channel access realted register into AC parameter registers,
+ * even in nQBss.
+ */
ChnlAccessSetting->SIFS_Timer = 0x22; /* Suggested by Jong, 2005.12.08. */
- ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */
- ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */
+ ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer);
- write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
+ write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer);
@@ -1074,17 +979,17 @@ ActUpdateChannelAccessSetting(
}
/* this setting is copied from rtl8187B. xiong-2006-11-13 */
- if (bFollowLegacySetting) {
+ if (bFollowLegacySetting) {
/*
- Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
- 2005.12.01, by rcnjko.
- */
+ * Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
+ * 2005.12.01, by rcnjko.
+ */
AcParam.longData = 0;
AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
AcParam.f.AciAifsn.f.ACM = 0;
- AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */
- AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */
+ AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */
+ AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */
AcParam.f.TXOPLimit = 0;
/* lzm reserved 080826 */
@@ -1095,7 +1000,7 @@ ActUpdateChannelAccessSetting(
if (ieee->iw_mode == IW_MODE_ADHOC)
AcParam.f.TXOPLimit = 0x0020;
- for (eACI = 0; eACI < AC_MAX; eACI++) {
+ for (eACI = 0; eACI < AC_MAX; eACI++) {
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
{
PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam);
@@ -1103,7 +1008,7 @@ ActUpdateChannelAccessSetting(
u8 u1bAIFS;
u32 u4bAcParam;
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
eACI = pAcParam->f.AciAifsn.f.ACI;
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
@@ -1111,7 +1016,7 @@ ActUpdateChannelAccessSetting(
(((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
- switch (eACI) {
+ switch (eACI) {
case AC1_BK:
/* write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); */
break;
@@ -1133,47 +1038,46 @@ ActUpdateChannelAccessSetting(
break;
}
- /* Cehck ACM bit. */
+ /* Cehck ACM bit. */
/* If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. */
{
PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn);
AC_CODING eACI = pAciAifsn->f.ACI;
- /*modified Joseph */
- /*for 8187B AsynIORead issue */
+ /*for 8187B AsynIORead issue */
u8 AcmCtrl = 0;
- if (pAciAifsn->f.ACM) {
+ if (pAciAifsn->f.ACM) {
/* ACM bit is 1. */
- switch (eACI) {
+ switch (eACI) {
case AC0_BE:
- AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */
+ AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */
break;
case AC2_VI:
- AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */
+ AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */
break;
case AC3_VO:
- AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */
+ AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */
break;
default:
DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI);
break;
}
- } else {
+ } else {
/* ACM bit is 0. */
- switch (eACI) {
+ switch (eACI) {
case AC0_BE:
- AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */
+ AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */
break;
case AC2_VI:
- AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */
+ AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */
break;
case AC3_VO:
- AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */
+ AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */
break;
default:
@@ -1187,53 +1091,51 @@ ActUpdateChannelAccessSetting(
}
}
-void
-ActSetWirelessMode8185(
- struct net_device *dev,
- u8 btWirelessMode
- )
+void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee80211;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev);
if ((btWirelessMode & btSupportedWirelessMode) == 0) {
- /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */
+ /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */
DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n",
btWirelessMode, btSupportedWirelessMode);
return;
}
- /* 1. Assign wireless mode to swtich if necessary. */
- if (btWirelessMode == WIRELESS_MODE_AUTO) {
- if ((btSupportedWirelessMode & WIRELESS_MODE_A)) {
+ /* 1. Assign wireless mode to switch if necessary. */
+ if (btWirelessMode == WIRELESS_MODE_AUTO) {
+ if ((btSupportedWirelessMode & WIRELESS_MODE_A)) {
btWirelessMode = WIRELESS_MODE_A;
- } else if (btSupportedWirelessMode & WIRELESS_MODE_G) {
+ } else if (btSupportedWirelessMode & WIRELESS_MODE_G) {
btWirelessMode = WIRELESS_MODE_G;
- } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) {
- btWirelessMode = WIRELESS_MODE_B;
- } else {
- DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
- btSupportedWirelessMode);
+ } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) {
btWirelessMode = WIRELESS_MODE_B;
+ } else {
+ DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
+ btSupportedWirelessMode);
+ btWirelessMode = WIRELESS_MODE_B;
}
}
- /* 2. Swtich band: RF or BB specific actions,
+ /*
+ * 2. Swtich band: RF or BB specific actions,
* for example, refresh tables in omc8255, or change initial gain if necessary.
* Nothing to do for Zebra to switch band.
- * Update current wireless mode if we swtich to specified band successfully. */
+ * Update current wireless mode if we switch to specified band successfully.
+ */
ieee->mode = (WIRELESS_MODE)btWirelessMode;
- /* 3. Change related setting. */
- if( ieee->mode == WIRELESS_MODE_A ) {
+ /* 3. Change related setting. */
+ if( ieee->mode == WIRELESS_MODE_A ) {
DMESG("WIRELESS_MODE_A\n");
- } else if( ieee->mode == WIRELESS_MODE_B ) {
- DMESG("WIRELESS_MODE_B\n");
- } else if( ieee->mode == WIRELESS_MODE_G ) {
- DMESG("WIRELESS_MODE_G\n");
+ } else if( ieee->mode == WIRELESS_MODE_B ) {
+ DMESG("WIRELESS_MODE_B\n");
+ } else if( ieee->mode == WIRELESS_MODE_G ) {
+ DMESG("WIRELESS_MODE_G\n");
}
ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting);
}
@@ -1245,22 +1147,16 @@ void rtl8185b_irq_enable(struct net_device *dev)
priv->irq_enabled = 1;
write_nic_dword(dev, IMR, priv->IntrMask);
}
-/* by amy for power save */
-void
-DrvIFIndicateDisassociation(
- struct net_device *dev,
- u16 reason
- )
+
+void DrvIFIndicateDisassociation(struct net_device *dev, u16 reason)
{
/* nothing is needed after disassociation request. */
- }
-void
-MgntDisconnectIBSS(
- struct net_device *dev
-)
+}
+
+void MgntDisconnectIBSS(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- u8 i;
+ u8 i;
DrvIFIndicateDisassociation(dev, unspec_reason);
@@ -1271,166 +1167,143 @@ MgntDisconnectIBSS(
priv->ieee80211->state = IEEE80211_NOLINK;
/*
- Stop Beacon.
-
- Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
- Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
- Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
-
- Disable Beacon Queue Own bit, suggested by jong */
+ * Stop Beacon.
+ *
+ * Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
+ * Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
+ * Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
+ *
+ * Disable Beacon Queue Own bit, suggested by jong
+ */
ieee80211_stop_send_beacons(priv->ieee80211);
priv->ieee80211->link_change(dev);
notify_wx_assoc_event(priv->ieee80211);
}
-void
-MlmeDisassociateRequest(
- struct net_device *dev,
- u8 *asSta,
- u8 asRsn
- )
+
+void MlmeDisassociateRequest(struct net_device *dev, u8 *asSta, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u8 i;
SendDisassociation(priv->ieee80211, asSta, asRsn);
- if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) {
- /*ShuChen TODO: change media status. */
- /*ShuChen TODO: What to do when disassociate. */
+ if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) {
+ /* ShuChen TODO: change media status. */
+ /* ShuChen TODO: What to do when disassociate. */
DrvIFIndicateDisassociation(dev, unspec_reason);
-
-
for (i = 0; i < 6; i++)
priv->ieee80211->current_network.bssid[i] = 0x22;
ieee80211_disassociate(priv->ieee80211);
}
-
}
-void
-MgntDisconnectAP(
- struct net_device *dev,
- u8 asRsn
-)
+void MgntDisconnectAP(struct net_device *dev, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- Commented out by rcnjko, 2005.01.27:
- I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
-
- 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
-
- In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
- 2004.10.11, by rcnjko. */
+ * Commented out by rcnjko, 2005.01.27:
+ * I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
+ *
+ * 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
+ *
+ * In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
+ * 2004.10.11, by rcnjko.
+ */
MlmeDisassociateRequest(dev, priv->ieee80211->current_network.bssid, asRsn);
priv->ieee80211->state = IEEE80211_NOLINK;
}
-bool
-MgntDisconnect(
- struct net_device *dev,
- u8 asRsn
-)
+
+bool MgntDisconnect(struct net_device *dev, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
- */
+ * Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
+ */
if (IS_DOT11D_ENABLE(priv->ieee80211))
Dot11d_Reset(priv->ieee80211);
- /* In adhoc mode, update beacon frame. */
+ /* In adhoc mode, update beacon frame. */
if (priv->ieee80211->state == IEEE80211_LINKED) {
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
MgntDisconnectIBSS(dev);
- if (priv->ieee80211->iw_mode == IW_MODE_INFRA) {
- /* We clear key here instead of MgntDisconnectAP() because that
- MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
- e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
- used to handle disassociation related things to AP, e.g. send Disassoc
- frame to AP. 2005.01.27, by rcnjko. */
+ if (priv->ieee80211->iw_mode == IW_MODE_INFRA) {
+ /*
+ * We clear key here instead of MgntDisconnectAP() because that
+ * MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
+ * e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
+ * used to handle disassociation related things to AP, e.g. send Disassoc
+ * frame to AP. 2005.01.27, by rcnjko.
+ */
MgntDisconnectAP(dev, asRsn);
}
- /* Inidicate Disconnect, 2005.02.23, by rcnjko. */
+ /* Indicate Disconnect, 2005.02.23, by rcnjko. */
}
return true;
}
/*
- Description:
- Chang RF Power State.
- Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
-
- Assumption:
- PASSIVE LEVEL.
-*/
-bool
-SetRFPowerState(
- struct net_device *dev,
- RT_RF_POWER_STATE eRFPowerState
- )
+ * Description:
+ * Chang RF Power State.
+ * Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
+ *
+ * Assumption:
+ * PASSIVE LEVEL.
+ */
+bool SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- bool bResult = false;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bResult = false;
if (eRFPowerState == priv->eRFPowerState)
return bResult;
- bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
+ bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
return bResult;
}
-void
-HalEnableRx8185Dummy(
- struct net_device *dev
- )
+
+void HalEnableRx8185Dummy(struct net_device *dev)
{
}
-void
-HalDisableRx8185Dummy(
- struct net_device *dev
- )
+
+void HalDisableRx8185Dummy(struct net_device *dev)
{
}
-bool
-MgntActSet_RF_State(
- struct net_device *dev,
- RT_RF_POWER_STATE StateToSet,
- u32 ChangeSource
- )
+bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- bool bActionAllowed = false;
- bool bConnectBySSID = false;
- RT_RF_POWER_STATE rtState;
- u16 RFWaitCounter = 0;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bActionAllowed = false;
+ bool bConnectBySSID = false;
+ RT_RF_POWER_STATE rtState;
+ u16 RFWaitCounter = 0;
unsigned long flag;
/*
- Prevent the race condition of RF state change. By Bruce, 2007-11-28.
- Only one thread can change the RF state at one time, and others should wait to be executed.
- */
- while (true) {
+ * Prevent the race condition of RF state change. By Bruce, 2007-11-28.
+ * Only one thread can change the RF state at one time, and others should wait to be executed.
+ */
+ while (true) {
spin_lock_irqsave(&priv->rf_ps_lock, flag);
- if (priv->RFChangeInProgress) {
+ if (priv->RFChangeInProgress) {
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
/* Set RF after the previous action is done. */
- while (priv->RFChangeInProgress) {
+ while (priv->RFChangeInProgress) {
RFWaitCounter++;
udelay(1000); /* 1 ms */
- /* Wait too long, return FALSE to avoid to be stuck here. */
- if (RFWaitCounter > 1000) { /* 1sec */
+ /* Wait too long, return FALSE to avoid to be stuck here. */
+ if (RFWaitCounter > 1000) { /* 1sec */
printk("MgntActSet_RF_State(): Wait too long to set RF\n");
- /* TODO: Reset RF state? */
+ /* TODO: Reset RF state? */
return false;
}
}
- } else {
+ } else {
priv->RFChangeInProgress = true;
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
break;
@@ -1438,12 +1311,12 @@ MgntActSet_RF_State(
}
rtState = priv->eRFPowerState;
- switch (StateToSet) {
+ switch (StateToSet) {
case eRfOn:
/*
- Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
- the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
- */
+ * Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
+ * the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
+ */
priv->RfOffReason &= (~ChangeSource);
if (!priv->RfOffReason) {
@@ -1453,25 +1326,24 @@ MgntActSet_RF_State(
if (rtState == eRfOff && ChangeSource >= RF_CHANGE_BY_HW && !priv->bInHctTest)
bConnectBySSID = true;
- } else
- ;
+ } else
+ ;
break;
case eRfOff:
- /* 070125, rcnjko: we always keep connected in AP mode. */
-
- if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
- /*
- 060808, Annie:
- Disconnect to current BSS when radio off. Asked by QuanTa.
-
- Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
- because we do NOT need to set ssid to dummy ones.
- */
- MgntDisconnect(dev, disas_lv_ss);
-
- /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */
- }
+ /* 070125, rcnjko: we always keep connected in AP mode. */
+
+ if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
+ /*
+ * 060808, Annie:
+ * Disconnect to current BSS when radio off. Asked by QuanTa.
+ *
+ * Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
+ * because we do NOT need to set ssid to dummy ones.
+ */
+ MgntDisconnect(dev, disas_lv_ss);
+ /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */
+ }
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
@@ -1484,14 +1356,14 @@ MgntActSet_RF_State(
break;
}
- if (bActionAllowed) {
- /* Config HW to the specified mode. */
+ if (bActionAllowed) {
+ /* Config HW to the specified mode. */
SetRFPowerState(dev, StateToSet);
/* Turn on RF. */
- if (StateToSet == eRfOn) {
+ if (StateToSet == eRfOn) {
HalEnableRx8185Dummy(dev);
- if (bConnectBySSID) {
+ if (bConnectBySSID) {
/* by amy not supported */
}
}
@@ -1507,69 +1379,61 @@ MgntActSet_RF_State(
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
return bActionAllowed;
}
-void
-InactivePowerSave(
- struct net_device *dev
- )
+
+void InactivePowerSave(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
- is really scheduled.
- The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
- previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
- blocks the IPS procedure of switching RF.
- */
+ * This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
+ * is really scheduled.
+ * The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
+ * previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
+ * blocks the IPS procedure of switching RF.
+ */
priv->bSwRfProcessing = true;
MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS);
/*
- To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
- */
+ * To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
+ */
priv->bSwRfProcessing = false;
}
/*
- Description:
- Enter the inactive power save mode. RF will be off
-*/
-void
-IPSEnter(
- struct net_device *dev
- )
+ * Description:
+ * Enter the inactive power save mode. RF will be off
+ */
+void IPSEnter(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- if (priv->bInactivePs) {
+ if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
/*
- Do not enter IPS in the following conditions:
- (1) RF is already OFF or Sleep
- (2) bSwRfProcessing (indicates the IPS is still under going)
- (3) Connectted (only disconnected can trigger IPS)
- (4) IBSS (send Beacon)
- (5) AP mode (send Beacon)
- */
+ * Do not enter IPS in the following conditions:
+ * (1) RF is already OFF or Sleep
+ * (2) bSwRfProcessing (indicates the IPS is still under going)
+ * (3) Connected (only disconnected can trigger IPS)
+ * (4) IBSS (send Beacon)
+ * (5) AP mode (send Beacon)
+ */
if (rtState == eRfOn && !priv->bSwRfProcessing
- && (priv->ieee80211->state != IEEE80211_LINKED)) {
+ && (priv->ieee80211->state != IEEE80211_LINKED)) {
priv->eInactivePowerState = eRfOff;
InactivePowerSave(dev);
}
}
}
-void
-IPSLeave(
- struct net_device *dev
- )
+void IPSLeave(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- if (priv->bInactivePs) {
+ if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
- if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) {
+ if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) {
priv->eInactivePowerState = eRfOn;
InactivePowerSave(dev);
}
@@ -1582,8 +1446,8 @@ void rtl8185b_adapter_start(struct net_device *dev)
struct ieee80211_device *ieee = priv->ieee80211;
u8 SupportedWirelessMode;
- u8 InitWirelessMode;
- u8 bInvalidWirelessMode = 0;
+ u8 InitWirelessMode;
+ u8 bInvalidWirelessMode = 0;
u8 tmpu8;
u8 btCR9346;
u8 TmpU1b;
@@ -1598,89 +1462,89 @@ void rtl8185b_adapter_start(struct net_device *dev)
HwConfigureRTL8185(dev);
write_nic_dword(dev, MAC0, ((u32 *)dev->dev_addr)[0]);
write_nic_word(dev, MAC4, ((u32 *)dev->dev_addr)[1] & 0xffff);
- write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */
+ write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */
write_nic_word(dev, BcnItv, 100);
write_nic_word(dev, AtimWnd, 2);
PlatformIOWrite2Byte(dev, FEMR, 0xFFFF);
write_nic_byte(dev, WPA_CONFIG, 0);
MacConfig_85BASIC(dev);
- /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */
- /* BT_DEMO_BOARD type */
+ /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */
+ /* BT_DEMO_BOARD type */
PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a);
/*
- -----------------------------------------------------------------------------
- Set up PHY related.
- -----------------------------------------------------------------------------
- */
- /* Enable Config3.PARAM_En to revise AnaaParm. */
- write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */
+ *---------------------------------------------------------------------------
+ * Set up PHY related.
+ *---------------------------------------------------------------------------
+ */
+ /* Enable Config3.PARAM_En to revise AnaaParm. */
+ write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */
tmpu8 = read_nic_byte(dev, CONFIG3);
write_nic_byte(dev, CONFIG3, (tmpu8 | CONFIG3_PARM_En));
- /* Turn on Analog power. */
- /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */
+ /* Turn on Analog power. */
+ /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */
write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON);
write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON);
write_nic_word(dev, ANAPARAM3, 0x0010);
write_nic_byte(dev, CONFIG3, tmpu8);
write_nic_byte(dev, CR9346, 0x00);
- /* enable EEM0 and EEM1 in 9346CR */
+ /* enable EEM0 and EEM1 in 9346CR */
btCR9346 = read_nic_byte(dev, CR9346);
write_nic_byte(dev, CR9346, (btCR9346 | 0xC0));
- /* B cut use LED1 to control HW RF on/off */
+ /* B cut use LED1 to control HW RF on/off */
TmpU1b = read_nic_byte(dev, CONFIG5);
TmpU1b = TmpU1b & ~BIT3;
write_nic_byte(dev, CONFIG5, TmpU1b);
- /* disable EEM0 and EEM1 in 9346CR */
+ /* disable EEM0 and EEM1 in 9346CR */
btCR9346 &= ~(0xC0);
write_nic_byte(dev, CR9346, btCR9346);
- /* Enable Led (suggested by Jong) */
- /* B-cut RF Radio on/off 5e[3]=0 */
+ /* Enable Led (suggested by Jong) */
+ /* B-cut RF Radio on/off 5e[3]=0 */
btPSR = read_nic_byte(dev, PSR);
write_nic_byte(dev, PSR, (btPSR | BIT3));
- /* setup initial timing for RFE. */
+ /* setup initial timing for RFE. */
write_nic_word(dev, RFPinsOutput, 0x0480);
SetOutputEnableOfRfPins(dev);
write_nic_word(dev, RFPinsSelect, 0x2488);
- /* PHY config. */
+ /* PHY config. */
PhyConfig8185(dev);
/*
- We assume RegWirelessMode has already been initialized before,
- however, we has to validate the wireless mode here and provide a
- reasonable initialized value if necessary. 2005.01.13, by rcnjko.
- */
+ * We assume RegWirelessMode has already been initialized before,
+ * however, we has to validate the wireless mode here and provide a
+ * reasonable initialized value if necessary. 2005.01.13, by rcnjko.
+ */
SupportedWirelessMode = GetSupportedWirelessMode8185(dev);
if ((ieee->mode != WIRELESS_MODE_B) &&
(ieee->mode != WIRELESS_MODE_G) &&
(ieee->mode != WIRELESS_MODE_A) &&
- (ieee->mode != WIRELESS_MODE_AUTO)) {
- /* It should be one of B, G, A, or AUTO. */
+ (ieee->mode != WIRELESS_MODE_AUTO)) {
+ /* It should be one of B, G, A, or AUTO. */
bInvalidWirelessMode = 1;
- } else {
- /* One of B, G, A, or AUTO. */
- /* Check if the wireless mode is supported by RF. */
+ } else {
+ /* One of B, G, A, or AUTO. */
+ /* Check if the wireless mode is supported by RF. */
if ((ieee->mode != WIRELESS_MODE_AUTO) &&
- (ieee->mode & SupportedWirelessMode) == 0) {
+ (ieee->mode & SupportedWirelessMode) == 0) {
bInvalidWirelessMode = 1;
}
}
- if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) {
- /* Auto or other invalid value. */
- /* Assigne a wireless mode to initialize. */
- if ((SupportedWirelessMode & WIRELESS_MODE_A)) {
+ if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) {
+ /* Auto or other invalid value. */
+ /* Assigne a wireless mode to initialize. */
+ if ((SupportedWirelessMode & WIRELESS_MODE_A)) {
InitWirelessMode = WIRELESS_MODE_A;
- } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) {
+ } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) {
InitWirelessMode = WIRELESS_MODE_G;
- } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) {
+ } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) {
InitWirelessMode = WIRELESS_MODE_B;
- } else {
+ } else {
DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n",
SupportedWirelessMode);
InitWirelessMode = WIRELESS_MODE_B;
@@ -1690,24 +1554,21 @@ void rtl8185b_adapter_start(struct net_device *dev)
if (bInvalidWirelessMode)
ieee->mode = (WIRELESS_MODE)InitWirelessMode;
- } else {
- /* One of B, G, A. */
+ } else {
+ /* One of B, G, A. */
InitWirelessMode = ieee->mode;
}
-/* by amy for power save */
priv->eRFPowerState = eRfOff;
priv->RfOffReason = 0;
{
MgntActSet_RF_State(dev, eRfOn, 0);
}
/*
- If inactive power mode is enabled, disable rf while in disconnected state.
- */
+ * If inactive power mode is enabled, disable rf while in disconnected state.
+ */
if (priv->bInactivePs)
MgntActSet_RF_State(dev , eRfOff, RF_CHANGE_BY_IPS);
-/* by amy for power save */
-
ActSetWirelessMode8185(dev, (u8)(InitWirelessMode));
/* ----------------------------------------------------------------------------- */
@@ -1715,7 +1576,7 @@ void rtl8185b_adapter_start(struct net_device *dev)
rtl8185b_irq_enable(dev);
netif_start_queue(dev);
- }
+}
void rtl8185b_rx_enable(struct net_device *dev)
{
@@ -1728,7 +1589,7 @@ void rtl8185b_rx_enable(struct net_device *dev)
DMESG("NIC in promisc mode");
if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \
- dev->flags & IFF_PROMISC) {
+ dev->flags & IFF_PROMISC) {
priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM);
priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP;
}
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index f87e211..4602a47 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -14,6 +14,7 @@ if RTLLIB
config RTLLIB_CRYPTO_CCMP
tristate "Support for rtllib CCMP crypto"
depends on RTLLIB
+ select CRYPTO_AES
default y
---help---
CCMP crypto driver for rtllib.
@@ -23,6 +24,8 @@ config RTLLIB_CRYPTO_CCMP
config RTLLIB_CRYPTO_TKIP
tristate "Support for rtllib TKIP crypto"
depends on RTLLIB
+ select CRYPTO_ARC4
+ select CRYPTO_MICHAEL_MIC
default y
---help---
TKIP crypto driver for rtllib.
@@ -31,6 +34,7 @@ config RTLLIB_CRYPTO_TKIP
config RTLLIB_CRYPTO_WEP
tristate "Support for rtllib WEP crypto"
+ select CRYPTO_ARC4
depends on RTLLIB
default y
---help---
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
index 58d044e..ea91744 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
@@ -342,7 +342,6 @@ static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
u32 cmpk_message_handle_rx(struct net_device *dev,
struct rtllib_rx_stats *pstats)
{
- struct r8192_priv *priv = rtllib_priv(dev);
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
@@ -409,8 +408,6 @@ u32 cmpk_message_handle_rx(struct net_device *dev,
return 1;
}
- priv->stats.rxcmdpkt[element_id]++;
-
total_length -= cmd_length;
pcmd_buff += cmd_length;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
index 3771985..b526fa4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
@@ -216,7 +216,7 @@ static bool firmware_check_ready(struct net_device *dev,
break;
default:
rt_status = false;
- RT_TRACE(COMP_FIRMWARE, "Unknown firware status");
+ RT_TRACE(COMP_FIRMWARE, "Unknown firmware status");
break;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 3e705ef..9676c59 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -689,7 +689,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel)
case RF_8258:
break;
default:
- RT_TRACE(COMP_ERR, "unknown rf chip in funtion %s()\n",
+ RT_TRACE(COMP_ERR, "unknown rf chip in function %s()\n",
__func__);
break;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
index d5de279..970298b 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
@@ -306,7 +306,7 @@
#define bRFStart 0x0000f000
#define bBBStart 0x000000f0
#define bBBCCKStart 0x0000000f
-/* Reg)x814 */
+/* Reg x814 */
#define bPAEnd 0xf
#define bTREnd 0x0f000000
#define bRFEnd 0x000f0000
@@ -844,7 +844,7 @@
#define bRTL8258_RxLPFBW 0xc00
#define bRTL8258_RSSILPFBW 0xc0
-/* byte endable for sb_write */
+/* byte enable for sb_write */
#define bByte0 0x1
#define bByte1 0x2
#define bByte2 0x4
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 71adb6b..4f602b2 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -1025,7 +1025,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf)
break;
}
RT_TRACE(COMP_DBG, "===>%s():RF is in progress, need to wait "
- "until rf chang is done.\n", __func__);
+ "until rf change is done.\n", __func__);
mdelay(1);
RFInProgressTimeOut++;
spin_lock_irqsave(&priv->rf_ps_lock, flags);
@@ -1211,7 +1211,7 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
priv->AcmControl = 0;
priv->pFirmware = vzalloc(sizeof(struct rt_firmware));
if (!priv->pFirmware)
- printk(KERN_ERR "rtl8193e: Unable to allocate space "
+ printk(KERN_ERR "rtl8192e: Unable to allocate space "
"for firmware\n");
skb_queue_head_init(&priv->rx_queue);
@@ -2024,10 +2024,10 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
stype = WLAN_FC_GET_STYPE(fc);
pda_addr = header->addr1;
- if (is_multicast_ether_addr(pda_addr))
- multi_addr = true;
- else if (is_broadcast_ether_addr(pda_addr))
+ if (is_broadcast_ether_addr(pda_addr))
broad_addr = true;
+ else if (is_multicast_ether_addr(pda_addr))
+ multi_addr = true;
else
uni_addr = true;
@@ -2358,8 +2358,7 @@ static void rtl8192_rx_normal(struct net_device *dev)
stats.RxBufShift);
skb_trim(skb, skb->len - 4/*sCrcLng*/);
rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
- if (!is_broadcast_ether_addr(rtllib_hdr->addr1) &&
- !is_multicast_ether_addr(rtllib_hdr->addr1)) {
+ if (!is_multicast_ether_addr(rtllib_hdr->addr1)) {
/* unicast packet */
unicast_packet = true;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 2a2519c..320d5fc 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -353,7 +353,6 @@ struct rt_stats {
unsigned long rxrdu;
unsigned long rxok;
unsigned long rxframgment;
- unsigned long rxcmdpkt[8];
unsigned long rxurberr;
unsigned long rxstaterr;
unsigned long rxdatacrcerr;
@@ -944,7 +943,7 @@ struct r8192_priv {
bool bfsync_processing;
u32 rate_record;
u32 rateCountDiffRecord;
- u32 ContiuneDiffCount;
+ u32 ContinueDiffCount;
bool bswitch_fsync;
u8 framesync;
u32 framesyncC34;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index f026b71..481b1e4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -493,7 +493,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
if (priv->bResetInProgress) {
RT_TRACE(COMP_POWER_TRACKING,
- "we are in slient reset progress, so return\n");
+ "we are in silent reset progress, so return\n");
write_nic_byte(dev, Pw_Track_Flag, 0);
write_nic_byte(dev, FW_Busy_Flag, 0);
return;
@@ -2615,22 +2615,22 @@ void dm_fsync_timer_callback(unsigned long data)
rate_count_diff;
if (DiffNum >=
priv->rtllib->fsync_seconddiff_ratethreshold)
- priv->ContiuneDiffCount++;
+ priv->ContinueDiffCount++;
else
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
- if (priv->ContiuneDiffCount >= 2) {
+ if (priv->ContinueDiffCount >= 2) {
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
} else {
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
if (rate_count_diff <=
priv->rtllib->fsync_firstdiff_ratethreshold) {
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
@@ -2677,10 +2677,10 @@ void dm_fsync_timer_callback(unsigned long data)
write_nic_byte(dev, 0xC36, 0x5c);
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
- RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+ RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d "
"bSwitchFsync %d\n", priv->rate_record, rate_count,
rate_count_diff, priv->bswitch_fsync);
@@ -2723,7 +2723,7 @@ static void dm_EndSWFsync(struct net_device *dev)
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
@@ -2735,7 +2735,7 @@ static void dm_StartSWFsync(struct net_device *dev)
RT_TRACE(COMP_HALDM, "%s\n", __func__);
priv->rate_record = 0;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 4e93669..778d7ba 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -1322,9 +1322,9 @@ static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r8192_wx_handlers_def = {
.standard = r8192_wx_handlers,
- .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8192_wx_handlers),
.private = r8192_private_handler,
- .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8192_private_handler),
.num_private_args = sizeof(r8192_private_args) /
sizeof(struct iw_priv_args),
.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c
index 711a096..658e875 100644
--- a/drivers/staging/rtl8192e/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c
@@ -310,7 +310,7 @@ bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS,
u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
{
u8 UP = 0;
- if (is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) {
+ if (is_multicast_ether_addr(Addr)) {
RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR! get TS for Broadcast or "
"Multicast\n");
return false;
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index e26aec8..d7460ae 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -169,7 +169,7 @@ struct cb_desc {
u8 nStuckCount;
- /* Tx Firmware Relaged flags (10-11)*/
+ /* Tx Firmware Related flags (10-11)*/
u8 bCTSEnable:1;
u8 bRTSEnable:1;
u8 bUseShortGI:1;
@@ -1690,7 +1690,7 @@ enum rtllib_state {
/* the association procedure is sending AUTH request*/
RTLLIB_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
RTLLIB_ASSOCIATING_AUTHENTICATED,
@@ -2409,7 +2409,7 @@ struct rtllib_device {
/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
* if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+ * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
* then also management frames are sent via this callback.
* This function can't sleep.
*/
@@ -2422,12 +2422,12 @@ struct rtllib_device {
*/
void (*data_hard_stop)(struct net_device *dev);
- /* OK this is complementar to data_poll_hard_stop */
+ /* OK this is complementing to data_poll_hard_stop */
void (*data_hard_resume)(struct net_device *dev);
/* ask to the driver to retune the radio .
* This function can sleep. the driver should ensure
- * the radio has been swithced before return.
+ * the radio has been switched before return.
*/
void (*set_chan)(struct net_device *dev, short ch);
@@ -2438,7 +2438,7 @@ struct rtllib_device {
* The syncro version is similar to the start_scan but
* does not return until all channels has been scanned.
* this is called in user context and should sleep,
- * it is called in a work_queue when swithcing to ad-hoc mode
+ * it is called in a work_queue when switching to ad-hoc mode
* or in behalf of iwlist scan when the card is associated
* and root user ask for a scan.
* the fucntion stop_scan should stop both the syncro and
@@ -2481,7 +2481,7 @@ struct rtllib_device {
struct rtllib_network *network);
- /* check whether Tx hw resouce available */
+ /* check whether Tx hw resource available */
short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
short (*get_nic_desc_num)(struct net_device *dev, int queue_index);
void (*SetBWModeHandler)(struct net_device *dev,
@@ -2543,10 +2543,10 @@ struct rtllib_device {
/* Generate probe requests */
#define IEEE_SOFTMAC_PROBERQ (1<<4)
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
#define IEEE_SOFTMAC_PROBERS (1<<5)
-/* The ieee802.11 stack will manages the netif queue
+/* The ieee802.11 stack will manage the netif queue
* wake/stop for the driver, taking care of 802.11
* fragmentation. See softmac.c for details. */
#define IEEE_SOFTMAC_TX_QUEUE (1<<7)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 13979b5..8b8a5c6 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -496,7 +496,7 @@ void rtllib_indicate_packets(struct rtllib_device *ieee, struct rtllib_rxb **prx
memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN);
}
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
if (sub_skb) {
stats->rx_packets++;
stats->rx_bytes += sub_skb->len;
@@ -1000,7 +1000,7 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc,
return -1;
/* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) {
+ if (is_multicast_ether_addr(dst)) {
if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN))
return -1;
}
@@ -1233,7 +1233,7 @@ static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee,
if (is_multicast_ether_addr(dst))
ieee->stats.multicast++;
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
sub_skb->protocol = eth_type_trans(sub_skb, dev);
sub_skb->dev = dev;
@@ -1269,7 +1269,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
sc = le16_to_cpu(hdr->seq_ctl);
/*Filter pkt not to me*/
- multicast = is_multicast_ether_addr(hdr->addr1)|is_broadcast_ether_addr(hdr->addr1);
+ multicast = is_multicast_ether_addr(hdr->addr1);
unicast = !multicast;
if (unicast && (compare_ether_addr(dev->dev_addr, hdr->addr1) != 0)) {
if (ieee->bNetPromiscuousMode)
@@ -1350,7 +1350,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
/* Get TS for Rx Reorder */
hdr = (struct rtllib_hdr_4addr *) skb->data;
if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)
+ && !is_multicast_ether_addr(hdr->addr1)
&& (!bToOtherSTA)) {
TID = Frame_QoSTID(skb->data);
SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index c5a15db..a21b4d9 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -31,7 +31,7 @@ short rtllib_is_shortslot(const struct rtllib_network *net)
return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME;
}
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
* tag and the EXTENDED RATE MFIE tag if needed.
* It encludes two bytes per tag for the tag itself and its len
*/
@@ -49,7 +49,7 @@ static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee)
return rate_len;
}
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) pointed.
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
@@ -557,7 +557,7 @@ void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh)
* new network events, despite for updating the net list,
* but we are temporarly 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
- * So the only situation in witch are interested is to check
+ * So the only situation in which are interested is to check
* if the state become LINKED because of the #1 situation
*/
@@ -1681,7 +1681,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
/* if the user set the AP check if match.
* if the network does not broadcast essid we check the
- * user supplyed ANY essid
+ * user supplied ANY essid
* if the network does broadcast and the user does not set
* essid it is OK
* if the network does broadcast and the user did set essid
@@ -2444,16 +2444,16 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee,
/* following are for a simplier TX queue management.
* Instead of using netif_[stop/wake]_queue the driver
- * will uses these two function (plus a reset one), that
- * will internally uses the kernel netif_* and takes
+ * will use these two functions (plus a reset one), that
+ * will internally use the kernel netif_* and takes
* care of the ieee802.11 fragmentation.
* So the driver receives a fragment per time and might
- * call the stop function when it want without take care
- * to have enought room to TX an entire packet.
- * This might be useful if each fragment need it's own
+ * call the stop function when it wants to not
+ * have enough room to TX an entire packet.
+ * This might be useful if each fragment needs it's own
* descriptor, thus just keep a total free memory > than
- * the max fragmentation treshold is not enought.. If the
- * ieee802.11 stack passed a TXB struct then you needed
+ * the max fragmentation threshold is not enough.. If the
+ * ieee802.11 stack passed a TXB struct then you need
* to keep N free descriptors where
* N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
* In this way you need just one and the 802.11 stack
@@ -2696,15 +2696,15 @@ static void rtllib_start_ibss_wq(void *data)
rtllib_softmac_check_all_nets(ieee);
- /* if not then the state is not linked. Maybe the user swithced to
+ /* if not then the state is not linked. Maybe the user switched to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
* time to scan all the chans..) or we have just run up the iface
* after setting ad-hoc mode. So we have to give another try..
* Here, in ibss mode, should be safe to do this without extra care
- * (in bss mode we had to make sure no-one tryed to associate when
+ * (in bss mode we had to make sure no-one tried to associate when
* we had just checked the ieee->state and we was going to start the
- * scan) beacause in ibss mode the rtllib_new_net function, when
+ * scan) because in ibss mode the rtllib_new_net function, when
* finds a good net, just set the ieee->state to RTLLIB_LINKED,
* so, at worst, we waste a bit of time to initiate an unneeded syncro
* scan, that will stop at the first round because it sees the state
@@ -2819,7 +2819,7 @@ void rtllib_start_bss(struct rtllib_device *ieee)
/* ensure no-one start an associating process (thus setting
* the ieee->state to rtllib_ASSOCIATING) while we
- * have just cheked it and we are going to enable scan.
+ * have just checked it and we are going to enable scan.
* The rtllib_new_net function is always called with
* lock held (from both rtllib_softmac_check_all_nets and
* the rx path), so we cannot be in the middle of such function
@@ -2872,7 +2872,7 @@ static void rtllib_associate_retry_wq(void *data)
/* until we do not set the state to RTLLIB_NOLINK
* there are no possibility to have someone else trying
- * to start an association procdure (we get here with
+ * to start an association procedure (we get here with
* ieee->state = RTLLIB_ASSOCIATING).
* When we set the state to RTLLIB_NOLINK it is possible
* that the RX path run an attempt to associate, but
@@ -3679,8 +3679,7 @@ void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib, u8 *asSta,
RemovePeerTS(rtllib, asSta);
-
- if (memcpy(rtllib->current_network.bssid, asSta, 6) == NULL) {
+ if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) {
rtllib->state = RTLLIB_NOLINK;
for (i = 0; i < 6; i++)
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 1523bc7..1bb6b52e 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -479,7 +479,7 @@ int rtllib_wx_set_essid(struct rtllib_device *ieee,
/* this is just to be sure that the GET wx callback
- * has consisten infos. not needed otherwise
+ * has consistent infos. not needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
@@ -575,7 +575,7 @@ int rtllib_wx_set_power(struct rtllib_device *ieee,
if ((!ieee->sta_wake_up) ||
(!ieee->enter_sleep_state) ||
(!ieee->ps_is_queue_empty)) {
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use "
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use "
"but driver missed a callback\n\n", __func__);
return -1;
}
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index f451bfc..42900ee 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -59,7 +59,7 @@
802.11 Data Frame
-802.11 frame_contorl for data frames - 2 bytes
+802.11 frame_control for data frames - 2 bytes
,-----------------------------------------------------------------------------------------.
bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e |
|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
@@ -296,8 +296,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
return;
if (!IsQoSDataFrame(skb->data))
return;
- if (is_multicast_ether_addr(hdr->addr1) ||
- is_broadcast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
return;
if (tcb_desc->bdhcp || ieee->CntAfterLink < 2)
@@ -515,7 +514,7 @@ u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb,
{
u16 seqnum = 0;
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+ if (is_multicast_ether_addr(dst))
return 0;
if (IsQoSDataFrame(skb->data)) {
struct tx_ts_record *pTS = NULL;
@@ -576,7 +575,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&ieee->lock, flags);
- /* If there is no driver handler to take the TXB, dont' bother
+ /* If there is no driver handler to take the TXB, don't bother
* creating it... */
if ((!ieee->hard_start_xmit && !(ieee->softmac_features &
IEEE_SOFTMAC_TX_QUEUE)) ||
@@ -698,8 +697,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
ETH_ALEN);
}
- bIsMulticast = is_broadcast_ether_addr(header.addr1) ||
- is_multicast_ether_addr(header.addr1);
+ bIsMulticast = is_multicast_ether_addr(header.addr1);
header.frame_ctl = cpu_to_le16(fc);
@@ -738,7 +736,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
(CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
bytes_per_frag -= RTLLIB_FCS_LEN;
- /* Each fragment may need to have room for encryptiong
+ /* Each fragment may need to have room for encrypting
* pre/postfix */
if (encrypt) {
bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index c27ff7e..c7e8d4d8 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -88,7 +88,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
- for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
+ for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
if (network->mode&(1<<i)) {
sprintf(pname, rtllib_modes[i].mode_string,
rtllib_modes[i].mode_size);
@@ -408,7 +408,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
- * explicitely set */
+ * explicitly set */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
ieee->crypt_info.tx_keyidx = key;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index e3d47bc..82d4bf6 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -161,7 +161,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
if (ieee->pHTInfo == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
- return NULL;
+ goto failed;
}
HTUpdateDefaultSetting(ieee);
HTInitializeHTInfo(ieee); //may move to other place.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index be2a28c..e3cf7a4 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -671,7 +671,7 @@ void RxReorderIndicatePacket( struct ieee80211_device *ieee,
index = 1;
} else {
/* Current packet is going to be inserted into pending list.*/
- //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__);
+ //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to ordered list\n",__FUNCTION__);
if(!list_empty(&ieee->RxReorder_Unused_List)) {
pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List);
list_del_init(&pReorderEntry->List);
@@ -1285,7 +1285,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
*/
//added by amy for reorder
if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1))
+ && !is_multicast_ether_addr(hdr->addr1))
{
TID = Frame_QoSTID(skb->data);
SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index c2ab5fa..f6ff8cf 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -2062,7 +2062,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
- IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+ IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
ieee80211_associate_abort(ieee);
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 59c45a5..3f5ceeb 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -314,7 +314,7 @@ void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* s
if (!IsQoSDataFrame(skb->data))
return;
- if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
return;
//check packet and mode later
#ifdef TO_DO_LIST
@@ -575,7 +575,7 @@ void ieee80211_txrate_selectmode(struct ieee80211_device* ieee, cb_desc* tcb_des
void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst)
{
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+ if (is_multicast_ether_addr(dst))
return;
if (IsQoSDataFrame(skb->data)) //we deal qos data only
{
@@ -693,8 +693,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
- if (is_multicast_ether_addr(header.addr1) ||
- is_broadcast_ether_addr(header.addr1)) {
+ if (is_multicast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 957ce4e..06a9824 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -350,7 +350,7 @@ bool GetTs(
// We do not build any TS for Broadcast or Multicast stream.
// So reject these kinds of search here.
//
- if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
+ if (is_multicast_ether_addr(Addr))
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
return false;
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index 8878cfe..3c515b7 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -14,7 +14,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index fb3ac97..5cea51e 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thank the Authors of such projects and the Ndiswrapper project Authors.
*/
/*This files contains card eeprom (93c46 or 93c56) programming routines*/
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 9b81f26..57e3383 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -11,7 +11,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -98,7 +98,7 @@ do { if(rt_global_debug_component & component) \
#define COMP_INIT BIT2 // during driver initialization / halt / reset.
-#define COMP_RECV BIT3 // Reveive part data path.
+#define COMP_RECV BIT3 // Receive data path.
#define COMP_SEND BIT4 // Send part path.
#define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02.
#define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related.
@@ -322,7 +322,7 @@ typedef struct _tx_fwinfo_819x_usb {
u8 TxSubCarrier:2; // This is used for legacy OFDM rate only.
u8 STBC:2;
u8 AllowAggregation:1;
- u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate
+ u8 RtsHT:1; //Interpret RtsRate field as high throughput data rate
u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 RtsBandwidth:1; // This is used for HT MCS rate only.
u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only.
@@ -610,7 +610,6 @@ typedef struct Stats
// unsigned long rxnopointer;
unsigned long rxok;
unsigned long rxframgment;
- unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query
unsigned long rxurberr;
unsigned long rxstaterr;
unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa
@@ -1117,7 +1116,7 @@ typedef struct r8192_priv
bool bfsync_processing; // 500ms Fsync timer is active or not
u32 rate_record;
u32 rateCountDiffRecord;
- u32 ContiuneDiffCount;
+ u32 ContinueDiffCount;
bool bswitch_fsync;
u8 framesync;
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 9c00865..5981d66 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -203,7 +203,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv)
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
- //acturally 8225 & 8256 rf chip only support B,G,24N mode
+ //actually 8225 & 8256 rf chips only support B,G,24N mode
if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256))
{
min_chan = 1;
@@ -1103,7 +1103,7 @@ inline u16 rtl8192_rate2rate(short rate)
}
-/* The protype of rx_isr has changed since one verion of Linux Kernel */
+/* The prototype of rx_isr has changed since one version of Linux Kernel */
static void rtl8192_rx_isr(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
@@ -1476,7 +1476,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
if(tcb_desc->queue_index != TXCMD_QUEUE) {
if(tx_urb->status == 0) {
dev->trans_start = jiffies;
- // As act as station mode, destion shall be unicast address.
+ // Act as station mode, destination shall be unicast address.
//priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom);
//priv->ieee80211->stats.tx_packets++;
priv->stats.txoktotal++;
@@ -1522,13 +1522,13 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
else if ((skb_queue_len(&priv->ieee80211->skb_drv_aggQ[queue_index])!= 0)&&\
(!(priv->ieee80211->queue_stop))) {
// Tx Driver Aggregation process
- /* The driver will aggregation the packets according to the following stets
+ /* The driver will aggregation the packets according to the following stats
* 1. check whether there's tx irq available, for it's a completion return
* function, it should contain enough tx irq;
- * 2. check pakcet type;
+ * 2. check packet type;
* 3. initialize sendlist, check whether the to-be send packet no greater than 1
- * 4. aggregation the packets, and fill firmware info and tx desc to it, etc.
- * 5. check whehter the packet could be sent, otherwise just insert to wait head
+ * 4. aggregates the packets, and fill firmware info and tx desc into it, etc.
+ * 5. check whether the packet could be sent, otherwise just insert into wait head
* */
skb = skb_dequeue(&priv->ieee80211->skb_drv_aggQ[queue_index]);
if(!check_nic_enough_desc(dev, queue_index)) {
@@ -2447,7 +2447,7 @@ static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv,
return 0;
}
-/* handle manage frame frame beacon and probe response */
+/* handle and manage frame from beacon and probe response */
static int rtl8192_handle_beacon(struct net_device * dev,
struct ieee80211_beacon * beacon,
struct ieee80211_network * network)
@@ -2625,7 +2625,7 @@ bool GetHalfNmodeSupportByAPs819xUsb(struct net_device* dev)
void rtl8192_refresh_supportrate(struct r8192_priv* priv)
{
struct ieee80211_device* ieee = priv->ieee80211;
- //we donot consider set support rate for ABG mode, only HT MCS rate is set here.
+ //we do not consider set support rate for ABG mode, only HT MCS rate is set here.
if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G)
{
memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16);
@@ -2780,10 +2780,10 @@ static void rtl8192_init_priv_variable(struct net_device* dev)
priv->TransmitConfig =
// TCR_DurProcMode | //for RTL8185B, duration setting by HW
//? TCR_DISReqQsize |
- (TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)| // Max DMA Burst Size per Tx DMA Burst, 7: reservied.
+ (TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)| // Max DMA Burst Size per Tx DMA Burst, 7: reserved.
(priv->ShortRetryLimit<<TCR_SRL_OFFSET)| // Short retry limit
(priv->LongRetryLimit<<TCR_LRL_OFFSET) | // Long retry limit
- (false ? TCR_SAT: 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them
+ (false ? TCR_SAT: 0); // FALSE: HW provides PLCP length and LENGEXT, TRUE: SW provides them
#ifdef TO_DO_LIST
if(Adapter->bInHctTest)
pHalData->ReceiveConfig = pHalData->CSMethod |
@@ -3437,7 +3437,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET)
{ // User disable RF via registry.
RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n"));
MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW);
- // Those action will be discard in MgntActSet_RF_State because off the same state
+ // Those actions will be discard in MgntActSet_RF_State because of the same state
for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
}
@@ -3458,7 +3458,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET)
if(pHalData->eRFPowerState == eRfOff)
{
MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason);
- // Those action will be discard in MgntActSet_RF_State because off the same state
+ // Those actions will be discard in MgntActSet_RF_State because of the same state
for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
}
@@ -3586,7 +3586,7 @@ TxCheckStuck(struct net_device *dev)
//unsigned long flags;
//
- // Decide Stuch threshold according to current power save mode
+ // Decide such threshold according to current power save mode
//
// RT_TRACE(COMP_RESET, " ==> TxCheckStuck()\n");
@@ -3745,7 +3745,7 @@ rtl819x_ifcheck_resetornot(struct net_device *dev)
// Driver should not check RX stuck in IBSS mode because it is required to
// set Check BSSID in order to send beacon, however, if check BSSID is
- // set, STA cannot hear any packet a all. Emily, 2008.04.12
+ // set, STA cannot hear any packet at all. Emily, 2008.04.12
RxResetType = RxCheckStuck(dev);
}
if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL)
@@ -3962,7 +3962,7 @@ RESET_START:
up(&priv->wx_sem);
RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__);
//rtl8192_irq_disable(dev);
- RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__);
+ RT_TRACE(COMP_RESET,"%s():===========>start up the driver\n",__FUNCTION__);
reset_status = _rtl8192_up(dev);
RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__);
@@ -4155,7 +4155,7 @@ extern void rtl819x_watchdog_wqcallback(struct work_struct *work)
void watch_dog_timer_callback(unsigned long data)
{
struct r8192_priv *priv = ieee80211_priv((struct net_device *) data);
- //printk("===============>watch_dog timer\n");
+ //printk("===============>watch_dog timer\n");
queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq, 0);
mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME));
}
@@ -4170,7 +4170,7 @@ int _rtl8192_up(struct net_device *dev)
init_status = rtl8192_adapter_start(dev);
if(!init_status)
{
- RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n", __FUNCTION__);
+ RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization failed!\n", __FUNCTION__);
priv->up=priv->ieee80211->ieee_up = 0;
return -EAGAIN;
}
@@ -4256,7 +4256,7 @@ int rtl8192_down(struct net_device *dev)
skb_queue_purge(&priv->ieee80211->skb_drv_aggQ [i]);
}
- //as cancel_delayed_work will del work->timer, so if work is not definedas struct delayed_work, it will corrupt
+ //as cancel_delayed_work will del work->timer, so if work is not defined as struct delayed_work, it will corrupt
// flush_scheduled_work();
rtl8192_cancel_deferred_work(priv);
deinit_hal_dm(dev);
@@ -4516,7 +4516,7 @@ u8 HwRateToMRate90(bool bIsHT, u8 rate)
/**
* Function: UpdateRxPktTimeStamp
- * Overview: Recored down the TSF time stamp when receiving a packet
+ * Overview: Record the TSF time stamp when receiving a packet
*
* Input:
* PADAPTER Adapter
@@ -4556,10 +4556,10 @@ long rtl819x_translate_todbm(u8 signal_strength_index )// 0-100 index.
}
-/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to
+/* 2008/01/22 MH We can not declare RSSI/EVM total value of sliding window to
be a local static. Otherwise, it may increase when we return from S3/S4. The
- value will be kept in memory or disk. We must delcare the value in adapter
- and it will be reinitialized when return from S3/S4. */
+ value will be kept in memory or disk. Declare the value in the adaptor
+ and it will be reinitialized when returned from S3/S4. */
void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats)
{
bool bcheck = false;
@@ -5091,8 +5091,8 @@ static void rtl8192_query_rxphystatus(
tmp_rxevm = pofdm_buf->rxevm_X[i];
rx_evmX = (char)(tmp_rxevm);
- // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment
- // fill most significant bit to "zero" when doing shifting operation which may change a negative
+ // Do not use shift operation like "rx_evmX >>= 1" because the compiler of free build environment
+ // will set the most significant bit to "zero" when doing shifting operation which may change a negative
// value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore.
rx_evmX /= 2; //dbm
@@ -5171,7 +5171,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
type = WLAN_FC_GET_TYPE(fc);
praddr = hdr->addr1;
- /* Check if the received packet is acceptabe. */
+ /* Check if the received packet is acceptable. */
bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) &&
(eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3))
&& (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV));
@@ -5211,7 +5211,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
/**
* Function: UpdateReceivedRateHistogramStatistics
-* Overview: Recored down the received data rate
+* Overview: Record the received data rate
*
* Input:
* struct net_device *dev
@@ -5401,7 +5401,7 @@ void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats,
}
#ifdef USB_RX_AGGREGATION_SUPPORT
- /* for the rx aggregated sub frame, the redundant space truelly contained in the packet */
+ /* for the rx aggregated sub frame, the redundant space truly contained in the packet */
if(bIsRxAggrSubframe) {
skb_pull(skb, 8);
}
@@ -5480,7 +5480,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb)
PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, false);
}
#endif
- /* Process the MPDU recevied */
+ /* Process the MPDU received */
skb_trim(skb, skb->len - 4/*sCrcLng*/);
rx_pkt_len = skb->len;
@@ -5538,7 +5538,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb)
if(PacketLength > agg_skb->len) {
break;
}
- /* Process the MPDU recevied */
+ /* Process the MPDU received */
skb = dev_alloc_skb(PacketLength);
memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength);
skb_trim(skb, skb->len - 4/*sCrcLng*/);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 2dde9fa..cd8dc85 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -38,7 +38,7 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
/*------------------------Define global variable-----------------------------*/
// Debug variable ?
dig_t dm_digtable;
-// Store current shoftware write register content for MAC PHY.
+// Store current software write register content for MAC PHY.
u8 dm_shadow[16][256] = {{0}};
// For Dynamic Rx Path Selection by Signal Strength
DRxPathSel DM_RxPathSelTable;
@@ -119,7 +119,7 @@ static void dm_pd_th(struct net_device *dev);
static void dm_cs_ratio(struct net_device *dev);
static void dm_init_ctstoself(struct net_device *dev);
-// DM --> EDCA turboe mode control
+// DM --> EDCA turbo mode control
static void dm_check_edca_turbo(struct net_device *dev);
// DM --> HW RF control
@@ -348,7 +348,7 @@ extern void init_rate_adaptive(struct net_device * dev)
*
* Revised History:
* When Who Remark
- * 05/26/08 amy Create version 0 proting from windows code.
+ * 05/26/08 amy Create version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
static void dm_check_rate_adaptive(struct net_device * dev)
@@ -543,7 +543,7 @@ static u32 OFDMSwingTable[OFDM_Table_Length] = {
0x5a400169, // 3, +3db
0x50800142, // 4, +2db
0x47c0011f, // 5, +1db
- 0x40000100, // 6, +0db ===> default, upper for higher temprature, lower for low temprature
+ 0x40000100, // 6, +0db ===> default, upper for higher temperature, lower for low temperature
0x390000e4, // 7, -1db
0x32c000cb, // 8, -2db
0x2d4000b5, // 9, -3db
@@ -678,7 +678,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device * dev)
{
write_nic_byte(dev, 0x1ba, 0);
viviflag = FALSE;
- RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n");
+ RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
for(k = 0;k < 5; k++)
tmp_report[k] = 0;
break;
@@ -864,14 +864,14 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev)
RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA);
if(tmpRegA < 3 || tmpRegA > 13)
return;
- if(tmpRegA >= 12) // if over 12, TP will be bad when high temprature
+ if(tmpRegA >= 12) // if over 12, TP will be bad when high temperature
tmpRegA = 12;
RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA);
priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
- //Get current RF-A temprature index
- if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temprature
+ //Get current RF-A temperature index
+ if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temperature
{
tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
tmpCCK40Mindex = tmpCCK20Mindex - 6;
@@ -885,7 +885,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev)
else
{
tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
- if(tmpval >= 6) // higher temprature
+ if(tmpval >= 6) // higher temperature
tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB
else
tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
@@ -1457,9 +1457,9 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism
+ // Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
// can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
- // 3-wire by driver cause RF goes into wrong state.
+ // 3-wire by driver causes RF to go into a wrong state.
if(priv->ieee80211->FwRWRF)
priv->btxpower_tracking = TRUE;
else
@@ -1520,7 +1520,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
if(!TM_Trigger)
{
- //Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash
+ //Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
//actually write reg0x02 bit1=0, then bit1=1.
//DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
@@ -1744,7 +1744,7 @@ extern void dm_restore_dynamic_mechanism_state(struct net_device *dev)
write_nic_dword(dev, RATR0, ratr_value);
write_nic_byte(dev, UFWP, 1);
}
- //Resore TX Power Tracking Index
+ //Restore TX Power Tracking Index
if(priv->btxpower_trackingInit && priv->btxpower_tracking){
dm_txpower_reset_recovery(dev);
}
@@ -2031,7 +2031,7 @@ static void dm_dig_init(struct net_device *dev)
dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
dm_digtable.dig_algorithm_switch = 0;
- /* 2007/10/04 MH Define init gain threshol. */
+ /* 2007/10/04 MH Define init gain threshold. */
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
dm_digtable.initialgain_lowerbound_state = false;
@@ -2097,7 +2097,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi(
return;
//DbgPrint("Dig by Sw Rssi \n");
- if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig.
+ if(dm_digtable.dig_algorithm_switch) // if switched algorithm, we have to disable FW Dig.
fw_dig = 0;
if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled
{// FW DIG Off
@@ -2160,8 +2160,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
/*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d",
pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
- /* 1. When RSSI decrease, We have to judge if it is smaller than a treshold
- and then execute below step. */
+ /* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
+ and then execute the step below. */
if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
{
/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
@@ -2220,8 +2220,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
}
- /* 2. When RSSI increase, We have to judge if it is larger than a treshold
- and then execute below step. */
+ /* 2. When RSSI increase, We have to judge if it is larger than a threshold
+ and then execute the step below. */
if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) )
{
u8 reset_flag = 0;
@@ -2329,7 +2329,7 @@ static void dm_ctrl_initgain_byrssi_highpwr(
}
/* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
- it is larger than a treshold and then execute below step. */
+ it is larger than a threshold and then execute the step below. */
// 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
{
@@ -2841,8 +2841,8 @@ static void dm_check_rfctrl_gpio(struct net_device * dev)
{
//struct r8192_priv *priv = ieee80211_priv(dev);
- // Walk around for DTM test, we will not enable HW - radio on/off because r/w
- // page 1 register before Lextra bus is enabled cause system fails when resuming
+ // Work around for DTM test, we will not enable HW - radio on/off because r/w
+ // page 1 register before extra bus is enabled causing system failures when resuming
// from S4. 20080218, Emily
// Stop to execute workitem to prevent S3/S4 bug.
@@ -3377,30 +3377,30 @@ extern void dm_fsync_timer_callback(unsigned long data)
{
u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
- // Contiune count
+ // Continue count
if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
- priv->ContiuneDiffCount++;
+ priv->ContinueDiffCount++;
else
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
- // Contiune count over
- if(priv->ContiuneDiffCount >=2)
+ // Continue count over
+ if(priv->ContinueDiffCount >=2)
{
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
}
else
{
- // Stop contiune count
- priv->ContiuneDiffCount = 0;
+ // Stop the continued count
+ priv->ContinueDiffCount = 0;
}
//If Count diff <= FsyncRateCountThreshold
if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
{
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
@@ -3468,14 +3468,14 @@ extern void dm_fsync_timer_callback(unsigned long data)
#endif
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
#ifdef RTL8190P
write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd);
#else
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
#endif
}
- RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+ RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
}
@@ -3507,7 +3507,7 @@ static void dm_EndSWFsync(struct net_device *dev)
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
#ifndef RTL8190P
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
#endif
@@ -3523,8 +3523,8 @@ static void dm_StartSWFsync(struct net_device *dev)
RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__);
// Initial rate record to zero, start to record.
priv->rate_record = 0;
- // Initial contiune diff count to zero, start to record.
- priv->ContiuneDiffCount = 0;
+ // Initialize continue diff count to zero, start to record.
+ priv->ContinueDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
@@ -3875,7 +3875,7 @@ static void dm_send_rssi_tofw(struct net_device *dev)
// If we test chariot, we should stop the TX command ?
// Because 92E will always silent reset when we send tx command. We use register
- // 0x1e0(byte) to botify driver.
+ // 0x1e0(byte) to notify driver.
write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
return;
tx_cmd.Op = TXCMD_SET_RX_RSSI;
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index e89aaf7..1bfe871 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -10,7 +10,7 @@
Parts of this driver are based on the Intel Pro Wireless
2100 GPL driver.
- We want to tanks the Authors of those projects
+ We want to thank the Authors of those projects
and the Ndiswrapper project Authors.
*/
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index f6408f9..71f2d23 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -13,7 +13,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -256,7 +256,7 @@ static int r8192_wx_get_ap_status(struct net_device *dev,
//count the length of input ssid
for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++);
- //search for the correspoding info which is received
+ //search for the corresponding info which is received
list_for_each_entry(target, &ieee->network_list, list) {
if ( (target->ssid_len == name_len) &&
(strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){
@@ -419,7 +419,7 @@ static int rtl8180_wx_get_range(struct net_device *dev,
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + -98;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
@@ -1047,7 +1047,7 @@ static iw_handler r8192_wx_handlers[] =
#else
NULL,
#endif
- dummy, /* SIOCGIWAPLIST -- depricated */
+ dummy, /* SIOCGIWAPLIST -- deprecated */
r8192_wx_set_scan, /* SIOCSIWSCAN */
r8192_wx_get_scan, /* SIOCGIWSCAN */
r8192_wx_set_essid, /* SIOCSIWESSID */
@@ -1211,9 +1211,9 @@ struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r8192_wx_handlers_def={
.standard = r8192_wx_handlers,
- .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8192_wx_handlers),
.private = r8192_private_handler,
- .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8192_private_handler),
.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
#if WIRELESS_EXT >= 17
.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index f4cf280..9f6b105 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thank the Authors of such projects and the Ndiswrapper project Authors.
*/
/* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h
index 2ac4216..e07f8b1 100644
--- a/drivers/staging/rtl8192u/r819xU_HTType.h
+++ b/drivers/staging/rtl8192u/r819xU_HTType.h
@@ -211,7 +211,7 @@ typedef struct _RT_HIGH_THROUGHPUT{
u8 bEnableHT;
u8 bCurrentHTSupport;
- u8 bRegBW40MHz; // Tx 40MHz channel capablity
+ u8 bRegBW40MHz; // Tx 40MHz channel capability
u8 bCurBW40MHz; // Tx 40MHz channel capability
u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 0cb28c7..a8a6dc2 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -157,7 +157,7 @@ SendTxCommandPacket(
seg_ptr = skb_put(skb, buffer_len);
/*
* Transform from little endian to big endian
- * and pending zero
+ * and pending zero
*/
memcpy(seg_ptr,codevirtualaddress,buffer_len);
tcb_desc->txbuf_size= (u16)buffer_len;
@@ -697,7 +697,6 @@ cmpk_message_handle_rx(
struct ieee80211_rx_stats *pstats)
{
// u32 debug_level = DBG_LOUD;
- struct r8192_priv *priv = ieee80211_priv(dev);
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
@@ -719,15 +718,15 @@ cmpk_message_handle_rx(
/* 2. Read virtual address from RFD. */
pcmd_buff = pstats->virtual_address;
- /* 3. Read command pakcet element id and length. */
+ /* 3. Read command packet element id and length. */
element_id = pcmd_buff[0];
/*RT_TRACE(COMP_SEND, DebugLevel,
("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
- /* 4. Check every received command packet conent according to different
+ /* 4. Check every received command packet content according to different
element type. Because FW may aggregate RX command packet to minimize
transmit time between DRV and FW.*/
- // Add a counter to prevent to locked in the loop too long
+ // Add a counter to prevent the lock in the loop from being held too long
while (total_length > 0 || exe_cnt++ >100)
{
/* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
@@ -779,9 +778,6 @@ cmpk_message_handle_rx(
// 2007/01/22 MH Add to display tx statistic.
//cmpk_DisplayTxStatistic(pAdapter);
- /* 2007/03/09 MH Collect sidderent cmd element pkt num. */
- priv->stats.rxcmdpkt[element_id]++;
-
total_length -= cmd_length;
pcmd_buff += cmd_length;
} /* while (total_length > 0) */
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 4bb5fff..b12d190 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -275,11 +275,11 @@ bool init_firmware(struct net_device *dev)
/*
* Download boot, main, and data image for System reset.
- * Download data image for firmware reseta
+ * Download data image for firmware reset
*/
for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
/*
- * Open Image file, and map file to contineous memory if open file success.
+ * Open image file, and map file to continuous memory if open file success.
* or read image file from array. Default load from IMG file
*/
if(rst_opt == OPT_SYSTEM_RESET) {
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index c4586b0..dd1954d 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -40,7 +40,7 @@ static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
* and do register read/write
* input: u32 dwBitMask //taget bit pos in the addr to be modified
* output: none
- * return: u32 return the shift bit bit position of the mask
+ * return: u32 return the shift bit position of the mask
* ****************************************************************************/
u32 rtl8192_CalculateBitShift(u32 dwBitMask)
{
@@ -176,7 +176,7 @@ u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath,
rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1);
- // TODO: we should not delay such a long time. Ask help from SD3
+ // TODO: we should not delay such a long time. Ask for help from SD3
msleep(1);
ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
@@ -252,7 +252,7 @@ void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath
NewOffset = Offset;
}
- // Put write addr in [5:0] and write data in [31:16]
+ // Put write addr in [5:0] and write data in [31:16]
DataAndAddr = (Data<<16) | (NewOffset&0x3f);
// Write Operation
@@ -525,7 +525,7 @@ void rtl8192_phy_configmac(struct net_device* dev)
}
/******************************************************************************
- *function: This function do dirty work
+ *function: This function does dirty work
* input: dev
* output: none
* return: none
@@ -578,7 +578,7 @@ void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType)
void rtl8192_InitBBRFRegDef(struct net_device* dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
-// RF Interface Sowrtware Control
+// RF Interface Software Control
priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870
priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872)
priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874
@@ -602,7 +602,7 @@ void rtl8192_InitBBRFRegDef(struct net_device* dev)
priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A)
priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E)
- //Addr of LSSI. Wirte RF register by driver
+ //Addr of LSSI. Write RF register by driver
priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter
priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
@@ -1384,7 +1384,7 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u
}
/******************************************************************************
- *function: This function does acturally set channel work
+ *function: This function does actually set channel work
* input: struct net_device *dev
* u8 channel
* output: none
@@ -1425,7 +1425,7 @@ void rtl8192_SwChnl_WorkItem(struct net_device *dev)
}
/******************************************************************************
- *function: This function scheduled actural workitem to set channel
+ *function: This function scheduled actual work item to set channel
* input: net_device dev
* u8 channel //channel to set
* output: none
diff --git a/drivers/staging/rtl8192u/r819xU_phyreg.h b/drivers/staging/rtl8192u/r819xU_phyreg.h
index 06b0b53..50f24dc 100644
--- a/drivers/staging/rtl8192u/r819xU_phyreg.h
+++ b/drivers/staging/rtl8192u/r819xU_phyreg.h
@@ -443,7 +443,7 @@
#define bCCKRxIG 0x7f00
#define bCCKLNAPolarity 0x800000
#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity
+#define bCCKRFExtend 0x20000000 //CCK Rx inital gain polarity
#define bCCKRxAGCSatLevel 0x1f000000
#define bCCKRxAGCSatCount 0xe0
#define bCCKRxRFSettle 0x1f //AGCsamp_dly
diff --git a/drivers/staging/rtl8712/big_endian.h b/drivers/staging/rtl8712/big_endian.h
deleted file mode 100644
index b16f8ec..0000000
--- a/drivers/staging/rtl8712/big_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H
-#define _LINUX_BYTEORDER_BIG_ENDIAN_H
-
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#endif
-#ifndef __BIG_ENDIAN_BITFIELD
-#define __BIG_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ((__u32)(x))
-#define __constant_ntohl(x) ((__u32)(x))
-#define __constant_htons(x) ((__u16)(x))
-#define __constant_ntohs(x) ((__u16)(x))
-#define __constant_cpu_to_le64(x) ___constant_swab64((x))
-#define __constant_le64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_le32(x) ___constant_swab32((x))
-#define __constant_le32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_le16(x) ___constant_swab16((x))
-#define __constant_le16_to_cpu(x) ___constant_swab16((x))
-#define __constant_cpu_to_be64(x) ((__u64)(x))
-#define __constant_be64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_be32(x) ((__u32)(x))
-#define __constant_be32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_be16(x) ((__u16)(x))
-#define __constant_be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64(x) __swab64((x))
-#define __le64_to_cpu(x) __swab64((x))
-#define __cpu_to_le32(x) __swab32((x))
-#define __le32_to_cpu(x) __swab32((x))
-#define __cpu_to_le16(x) __swab16((x))
-#define __le16_to_cpu(x) __swab16((x))
-#define __cpu_to_be64(x) ((__u64)(x))
-#define __be64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_be32(x) ((__u32)(x))
-#define __be32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_be16(x) ((__u16)(x))
-#define __be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64p(x) __swab64p((x))
-#define __le64_to_cpup(x) __swab64p((x))
-#define __cpu_to_le32p(x) __swab32p((x))
-#define __le32_to_cpup(x) __swab32p((x))
-#define __cpu_to_le16p(x) __swab16p((x))
-#define __le16_to_cpup(x) __swab16p((x))
-#define __cpu_to_be64p(x) (*(__u64 *)(x))
-#define __be64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_be32p(x) (*(__u32 *)(x))
-#define __be32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_be16p(x) (*(__u16 *)(x))
-#define __be16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_le64s(x) __swab64s((x))
-#define __le64_to_cpus(x) __swab64s((x))
-#define __cpu_to_le32s(x) __swab32s((x))
-#define __le32_to_cpus(x) __swab32s((x))
-#define __cpu_to_le16s(x) __swab16s((x))
-#define __le16_to_cpus(x) __swab16s((x))
-#define __cpu_to_be64s(x) do {} while (0)
-#define __be64_to_cpus(x) do {} while (0)
-#define __cpu_to_be32s(x) do {} while (0)
-#define __be32_to_cpus(x) do {} while (0)
-#define __cpu_to_be16s(x) do {} while (0)
-#define __be16_to_cpus(x) do {} while (0)
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index e83665d..62b5566 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -146,7 +146,7 @@ struct dvobj_priv {
/**
* struct _adapter - the main adapter structure for this device.
*
- * bup: True indicates that the interface is Up.
+ * bup: True indicates that the interface is up.
*/
struct _adapter {
struct dvobj_priv dvobjpriv;
diff --git a/drivers/staging/rtl8712/generic.h b/drivers/staging/rtl8712/generic.h
deleted file mode 100644
index 8868c9f..0000000
--- a/drivers/staging/rtl8712/generic.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_GENERIC_H
-#define _LINUX_BYTEORDER_GENERIC_H
-
-/*
- * linux/byteorder_generic.h
- * Generic Byte-reordering support
- *
- * Francois-Rene Rideau <fare@tunes.org> 19970707
- * gathered all the good ideas from all asm-foo/byteorder.h into one file,
- * cleaned them up.
- * I hope it is compliant with non-GCC compilers.
- * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h,
- * because I wasn't sure it would be ok to put it in types.h
- * Upgraded it to 2.1.43
- * Francois-Rene Rideau <fare@tunes.org> 19971012
- * Upgraded it to 2.1.57
- * to please Linus T., replaced huge #ifdef's between little/big endian
- * by nestedly #include'd files.
- * Francois-Rene Rideau <fare@tunes.org> 19971205
- * Made it to 2.1.71; now a facelift:
- * Put files under include/linux/byteorder/
- * Split swab from generic support.
- *
- * TODO:
- * = Regular kernel maintainers could also replace all these manual
- * byteswap macros that remain, disseminated among drivers,
- * after some grep or the sources...
- * = Linus might want to rename all these macros and files to fit his taste,
- * to fit his personal naming scheme.
- * = it seems that a few drivers would also appreciate
- * nybble swapping support...
- * = every architecture could add their byteswap macro in asm/byteorder.h
- * see how some architectures already do (i386, alpha, ppc, etc)
- * = cpu_to_beXX and beXX_to_cpu might some day need to be well
- * distinguished throughout the kernel. This is not the case currently,
- * since little endian, big endian, and pdp endian machines needn't it.
- * But this might be the case for, say, a port of Linux to 20/21 bit
- * architectures (and F21 Linux addict around?).
- */
-
-/*
- * The following macros are to be defined by <asm/byteorder.h>:
- *
- * Conversion of long and short int between network and host format
- * ntohl(__u32 x)
- * ntohs(__u16 x)
- * htonl(__u32 x)
- * htons(__u16 x)
- * It seems that some programs (which? where? or perhaps a standard? POSIX?)
- * might like the above to be functions, not macros (why?).
- * if that's true, then detect them, and take measures.
- * Anyway, the measure is: define only ___ntohl as a macro instead,
- * and in a separate file, have
- * unsigned long inline ntohl(x){return ___ntohl(x);}
- *
- * The same for constant arguments
- * __constant_ntohl(__u32 x)
- * __constant_ntohs(__u16 x)
- * __constant_htonl(__u32 x)
- * __constant_htons(__u16 x)
- *
- * Conversion of XX-bit integers (16- 32- or 64-)
- * between native CPU format and little/big endian format
- * 64-bit stuff only defined for proper architectures
- * cpu_to_[bl]eXX(__uXX x)
- * [bl]eXX_to_cpu(__uXX x)
- *
- * The same, but takes a pointer to the value to convert
- * cpu_to_[bl]eXXp(__uXX x)
- * [bl]eXX_to_cpup(__uXX x)
- *
- * The same, but change in situ
- * cpu_to_[bl]eXXs(__uXX x)
- * [bl]eXX_to_cpus(__uXX x)
- *
- * See asm-foo/byteorder.h for examples of how to provide
- * architecture-optimized versions
- *
- */
-
-
-/*
- * inside the kernel, we can use nicknames;
- * outside of it, we must avoid POSIX namespace pollution...
- */
-#define cpu_to_le64 __cpu_to_le64
-#define le64_to_cpu __le64_to_cpu
-#define cpu_to_le32 __cpu_to_le32
-#define le32_to_cpu __le32_to_cpu
-#define cpu_to_le16 __cpu_to_le16
-#define le16_to_cpu __le16_to_cpu
-#define cpu_to_be64 __cpu_to_be64
-#define be64_to_cpu __be64_to_cpu
-#define cpu_to_be32 __cpu_to_be32
-#define be32_to_cpu __be32_to_cpu
-#define cpu_to_be16 __cpu_to_be16
-#define be16_to_cpu __be16_to_cpu
-#define cpu_to_le64p __cpu_to_le64p
-#define le64_to_cpup __le64_to_cpup
-#define cpu_to_le32p __cpu_to_le32p
-#define le32_to_cpup __le32_to_cpup
-#define cpu_to_le16p __cpu_to_le16p
-#define le16_to_cpup __le16_to_cpup
-#define cpu_to_be64p __cpu_to_be64p
-#define be64_to_cpup __be64_to_cpup
-#define cpu_to_be32p __cpu_to_be32p
-#define be32_to_cpup __be32_to_cpup
-#define cpu_to_be16p __cpu_to_be16p
-#define be16_to_cpup __be16_to_cpup
-#define cpu_to_le64s __cpu_to_le64s
-#define le64_to_cpus __le64_to_cpus
-#define cpu_to_le32s __cpu_to_le32s
-#define le32_to_cpus __le32_to_cpus
-#define cpu_to_le16s __cpu_to_le16s
-#define le16_to_cpus __le16_to_cpus
-#define cpu_to_be64s __cpu_to_be64s
-#define be64_to_cpus __be64_to_cpus
-#define cpu_to_be32s __cpu_to_be32s
-#define be32_to_cpus __be32_to_cpus
-#define cpu_to_be16s __cpu_to_be16s
-#define be16_to_cpus __be16_to_cpus
-
-
-/*
- * Handle ntohl and suches. These have various compatibility
- * issues - like we want to give the prototype even though we
- * also have a macro for them in case some strange program
- * wants to take the address of the thing or something..
- *
- * Note that these used to return a "long" in libc5, even though
- * long is often 64-bit these days.. Thus the casts.
- *
- * They have to be macros in order to do the constant folding
- * correctly - if the argument passed into a inline function
- * it is no longer constant according to gcc..
- */
-
-#undef ntohl
-#undef ntohs
-#undef htonl
-#undef htons
-
-/*
- * Do the prototypes. Somebody might want to take the
- * address or some such sick thing..
- */
-extern __u32 ntohl(__u32);
-extern __u32 htonl(__u32);
-extern unsigned short int ntohs(unsigned short int);
-extern unsigned short int htons(unsigned short int);
-
-#endif /* _LINUX_BYTEORDER_GENERIC_H */
-
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index cc893c0..cb9d4cf 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -36,7 +36,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "usb_osintf.h"
#define FWBUFF_ALIGN_SZ 512
diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h
index 3c0092b..21515c3 100644
--- a/drivers/staging/rtl8712/ieee80211.h
+++ b/drivers/staging/rtl8712/ieee80211.h
@@ -705,7 +705,7 @@ enum ieee80211_state {
IEEE80211_ASSOCIATING_RETRY,
/* the association procedure is sending AUTH request*/
IEEE80211_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
IEEE80211_ASSOCIATING_AUTHENTICATED,
diff --git a/drivers/staging/rtl8712/if_ether.h b/drivers/staging/rtl8712/if_ether.h
deleted file mode 100644
index 2bbe527..0000000
--- a/drivers/staging/rtl8712/if_ether.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Global definitions for the Ethernet IEEE 802.3 interface.
- *
- * Version: @(#)if_ether.h 1.0.1a 02/08/94
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
- * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_IF_ETHER_H
-#define _LINUX_IF_ETHER_H
-
-/*
- * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
- * and FCS/CRC (frame check sequence).
- */
-
-#define ETH_ALEN 6 /* Octets in one ethernet addr */
-#define ETH_HLEN 14 /* Total octets in header. */
-#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN 1500 /* Max. octets in payload */
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-/*
- * These are the defined Ethernet Protocol ID's.
- */
-
-#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
-#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
-#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_X25 0x0805 /* CCITT X.25 */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet
- * [ NOT AN OFFICIAL ID ] */
-#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
-#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr
- * Trans packet */
-#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
-#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
-#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
-#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
-#define ETH_P_LAT 0x6004 /* DEC LAT */
-#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
-#define ETH_P_CUST 0x6006 /* DEC Customer use */
-#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
-#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
-#define ETH_P_ATALK 0x809B /* Appletalk DDP */
-#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
-#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
-#define ETH_P_IPX 0x8137 /* IPX over DIX */
-#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
-#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
-#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
-#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
-#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
- * over Ethernet
- */
-
-/*
- * Non DIX types. Won't clash for 1500 types.
- */
-
-#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
-#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
-#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
-#define ETH_P_802_2 0x0004 /* 802.2 frames */
-#define ETH_P_SNAP 0x0005 /* Internal only */
-#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
-#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
-#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
-#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
-#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
-#define ETH_P_TR_802_2 0x0011i /* 802.2 frames */
-#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
-#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
-#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
-#define ETH_P_ECONET 0x0018 /* Acorn Econet */
-
-/*
- * This is an Ethernet frame header.
- */
-
-struct ethhdr {
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
-};
-
-struct _vlan {
- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID*/
- unsigned short h_vlan_encapsulated_proto;
-};
-
-
-
-#define get_vlan_id(pvlan) ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
-#define get_vlan_priority(pvlan) ((ntohs((unsigned short)\
- pvlan->h_vlan_TCI)) >> 13)
-#define get_vlan_encap_proto(pvlan) (ntohs((unsigned short)\
- pvlan->h_vlan_encapsulated_proto))
-
-
-#endif /* _LINUX_IF_ETHER_H */
-
diff --git a/drivers/staging/rtl8712/ip.h b/drivers/staging/rtl8712/ip.h
deleted file mode 100644
index f37b0f8..0000000
--- a/drivers/staging/rtl8712/ip.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the IP protocol.
- *
- * Version: @(#)ip.h 1.0.2 04/28/93
- *
- * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.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.
- */
-#ifndef _LINUX_IP_H
-#define _LINUX_IP_H
-
-#include "rtl871x_byteorder.h"
-
-/* SOL_IP socket options */
-
-#define IPTOS_TOS_MASK 0x1E
-#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-#define IPTOS_MINCOST 0x02
-
-#define IPTOS_PREC_MASK 0xE0
-#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
-#define IPTOS_PREC_NETCONTROL 0xe0
-#define IPTOS_PREC_INTERNETCONTROL 0xc0
-#define IPTOS_PREC_CRITIC_ECP 0xa0
-#define IPTOS_PREC_FLASHOVERRIDE 0x80
-#define IPTOS_PREC_FLASH 0x60
-#define IPTOS_PREC_IMMEDIATE 0x40
-#define IPTOS_PREC_PRIORITY 0x20
-#define IPTOS_PREC_ROUTINE 0x00
-
-/* IP options */
-#define IPOPT_COPY 0x80
-#define IPOPT_CLASS_MASK 0x60
-#define IPOPT_NUMBER_MASK 0x1f
-
-#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
-#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
-#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
-
-#define IPOPT_CONTROL 0x00
-#define IPOPT_RESERVED1 0x20
-#define IPOPT_MEASUREMENT 0x40
-#define IPOPT_RESERVED2 0x60
-
-#define IPOPT_END (0 | IPOPT_CONTROL)
-#define IPOPT_NOOP (1 | IPOPT_CONTROL)
-#define IPOPT_SEC (2 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_LSRR (3 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_TIMESTAMP (4 | IPOPT_MEASUREMENT)
-#define IPOPT_RR (7 | IPOPT_CONTROL)
-#define IPOPT_SID (8 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_SSRR (9 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_RA (20 | IPOPT_CONTROL | IPOPT_COPY)
-
-#define IPVERSION 4
-#define MAXTTL 255
-#define IPDEFTTL 64
-
-/* struct timestamp, struct route and MAX_ROUTES are removed.
- *
- * REASONS: it is clear that nobody used them because:
- * - MAX_ROUTES value was wrong.
- * - "struct route" was wrong.
- * - "struct timestamp" had fatally misaligned bitfields and was completely
- * unusable.
- */
-
-#define IPOPT_OPTVAL 0
-#define IPOPT_OLEN 1
-#define IPOPT_OFFSET 2
-#define IPOPT_MINOFF 4
-#define MAX_IPOPTLEN 40
-#define IPOPT_NOP IPOPT_NOOP
-#define IPOPT_EOL IPOPT_END
-#define IPOPT_TS IPOPT_TIMESTAMP
-
-#define IPOPT_TS_TSONLY 0 /* timestamps only */
-#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
-#define IPOPT_TS_PRESPEC 3 /* specified modules only */
-
-struct ip_options {
- __u32 faddr; /* Saved first hop address */
- unsigned char optlen;
- unsigned char srr;
- unsigned char rr;
- unsigned char ts;
- unsigned char is_setbyuser:1, /* Set by setsockopt? */
- is_data:1, /* Options in __data, rather than skb */
- is_strictroute:1, /* Strict source route */
- srr_is_hit:1, /* Packet destination addr was our one*/
- is_changed:1, /* IP checksum more not valid */
- rr_needaddr:1, /* Need to record addr of outgoing dev*/
- ts_needtime:1, /* Need to record timestamp */
- ts_needaddr:1; /* Need to record addr of outgoing dev*/
- unsigned char router_alert;
- unsigned char __pad1;
- unsigned char __pad2;
- unsigned char __data[0];
-};
-
-#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
-
-struct iphdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 ihl:4,
- version:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 version:4,
- ihl:4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __u8 tos;
- __u16 tot_len;
- __u16 id;
- __u16 frag_off;
- __u8 ttl;
- __u8 protocol;
- __u16 check;
- __u32 saddr;
- __u32 daddr;
- /*The options start here. */
-};
-
-#endif /* _LINUX_IP_H */
-
diff --git a/drivers/staging/rtl8712/little_endian.h b/drivers/staging/rtl8712/little_endian.h
deleted file mode 100644
index cd57d6c..0000000
--- a/drivers/staging/rtl8712/little_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN 1234
-#endif
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ___constant_swab32((x))
-#define __constant_ntohl(x) ___constant_swab32((x))
-#define __constant_htons(x) ___constant_swab16((x))
-#define __constant_ntohs(x) ___constant_swab16((x))
-#define __constant_cpu_to_le64(x) ((__u64)(x))
-#define __constant_le64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_le32(x) ((__u32)(x))
-#define __constant_le32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_le16(x) ((__u16)(x))
-#define __constant_le16_to_cpu(x) ((__u16)(x))
-#define __constant_cpu_to_be64(x) ___constant_swab64((x))
-#define __constant_be64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_be32(x) ___constant_swab32((x))
-#define __constant_be32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_be16(x) ___constant_swab16((x))
-#define __constant_be16_to_cpu(x) ___constant_swab16((x))
-#define __cpu_to_le64(x) ((__u64)(x))
-#define __le64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_le32(x) ((__u32)(x))
-#define __le32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_le16(x) ((__u16)(x))
-#define __le16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_be64(x) __swab64((x))
-#define __be64_to_cpu(x) __swab64((x))
-#define __cpu_to_be32(x) __swab32((x))
-#define __be32_to_cpu(x) __swab32((x))
-#define __cpu_to_be16(x) __swab16((x))
-#define __be16_to_cpu(x) __swab16((x))
-#define __cpu_to_le64p(x) (*(__u64 *)(x))
-#define __le64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_le32p(x) (*(__u32 *)(x))
-#define __le32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_le16p(x) (*(__u16 *)(x))
-#define __le16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_be64p(x) __swab64p((x))
-#define __be64_to_cpup(x) __swab64p((x))
-#define __cpu_to_be32p(x) __swab32p((x))
-#define __be32_to_cpup(x) __swab32p((x))
-#define __cpu_to_be16p(x) __swab16p((x))
-#define __be16_to_cpup(x) __swab16p((x))
-#define __cpu_to_le64s(x) do {} while (0)
-#define __le64_to_cpus(x) do {} while (0)
-#define __cpu_to_le32s(x) do {} while (0)
-#define __le32_to_cpus(x) do {} while (0)
-#define __cpu_to_le16s(x) do {} while (0)
-#define __le16_to_cpus(x) do {} while (0)
-#define __cpu_to_be64s(x) __swab64s((x))
-#define __be64_to_cpus(x) __swab64s((x))
-#define __cpu_to_be32s(x) __swab32s((x))
-#define __be32_to_cpus(x) __swab32s((x))
-#define __cpu_to_be16s(x) __swab16s((x))
-#define __be16_to_cpus(x) __swab16s((x))
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 7bbd53a..448f00d 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -52,7 +52,7 @@ static int lbkmode = RTL8712_AIR_TRX;
static int hci = RTL8712_USB;
static int ampdu_enable = 1;/*for enable tx_ampdu*/
-/* The video_mode variable is for vedio mode.*/
+/* The video_mode variable is for video mode.*/
/* It may be specify when inserting module with video_mode=1 parameter.*/
static int video_mode = 1; /* enable video mode*/
@@ -248,7 +248,7 @@ static u32 start_drv_threads(struct _adapter *padapter)
void r8712_stop_drv_threads(struct _adapter *padapter)
{
- /*Below is to termindate r8712_cmd_thread & event_thread...*/
+ /*Below is to terminate r8712_cmd_thread & event_thread...*/
up(&padapter->cmdpriv.cmd_queue_sema);
if (padapter->cmdThread)
_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema);
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 9ba6033..f1ccc7e 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -29,7 +29,6 @@
#define _SUCCESS 1
#define _FAIL 0
-#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -107,8 +106,6 @@ static inline void _set_workitem(_workitem *pwork)
schedule_work(pwork);
}
-#include "rtl871x_byteorder.h"
-
#ifndef BIT
#define BIT(x) (1 << (x))
#endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index 9f6ebc4..088647c 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -50,7 +50,6 @@
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
#include "rtl871x_ioctl_set.h"
static void check_hw_pbc(struct _adapter *padapter)
@@ -69,7 +68,7 @@ static void check_hw_pbc(struct _adapter *padapter)
* After trigger PBC, the variable will be set to false */
DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n");
/* 0 is the default value and it means the application monitors
- * the HW PBC doesn't privde its pid to driver. */
+ * the HW PBC doesn't provide its pid to driver. */
if (padapter->pid == 0)
return;
kill_pid(find_vpid(padapter->pid), SIGUSR1, 1);
@@ -382,7 +381,7 @@ _next:
*pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) |
(pcmd->cmdcode << 16) |
(pcmdpriv->cmd_seq << 24));
- pcmdbuf += 2 ; /* 8 bytes aligment */
+ pcmdbuf += 2 ; /* 8 bytes alignment */
memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
while (check_cmd_fifo(padapter, wr_sz) == _FAIL) {
if ((padapter->bDriverStopped == true) ||
@@ -471,7 +470,7 @@ void r8712_event_handle(struct _adapter *padapter, uint *peventbuf)
pevt_priv->event_seq++; /* update evt_seq */
if (pevt_priv->event_seq > 127)
pevt_priv->event_seq = 0;
- peventbuf = peventbuf + 2; /* move to event content, 8 bytes aligment */
+ peventbuf = peventbuf + 2; /* move to event content, 8 bytes alignment */
if (peventbuf) {
event_callback = wlanevents[evt_code].event_callback;
if (event_callback)
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 766a646..039ab3e 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -121,7 +121,7 @@ enum rtl8712_h2c_cmd {
GEN_CMD_CODE(_GetCurDataRate) ,
GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to
- * transmmit packet after association
+ * transmit packet after association
*/
GEN_CMD_CODE(_GetRxRetrycnt), /* to record total number of the
* received frame with ReTry bit set in
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index b08e9a2..377fca9 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -417,7 +417,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
} else { /* write header fail */
bResult = false;
if (0xFF == efuse_data)
- return bResult; /* not thing damaged. */
+ return bResult; /* nothing damaged. */
/* call rescue procedure */
if (fix_header(padapter, efuse_data, efuse_addr) ==
false)
diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
index 884a821..138ea45 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
@@ -70,7 +70,7 @@
#define GPIOSEL_BT 2 /* BT_coex*/
#define GPIOSEL_WLANDBG 3 /* WLANDBG*/
#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1)))
-/* HW Readio OFF switch (GPIO BIT) */
+/* HW Radio OFF switch (GPIO BIT) */
#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3)
#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4)
diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h
index d19865a..4c51fa3 100644
--- a/drivers/staging/rtl8712/rtl8712_hal.h
+++ b/drivers/staging/rtl8712/rtl8712_hal.h
@@ -83,7 +83,7 @@ struct fw_priv { /*8-bytes alignment required*/
unsigned char rfintfs; /* 0:SWSI, 1:HWSI, 2:HWPI*/
unsigned char def_nettype;
unsigned char turboMode;
- unsigned char lowPowerMode;/* 0: noral mode, 1: low power mode*/
+ unsigned char lowPowerMode;/* 0: normal mode, 1: low power mode*/
/*--- long word 2 ----*/
unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/
unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */
@@ -123,7 +123,7 @@ struct fw_priv { /*8-bytes alignment required*/
unsigned char rsvd053;
};
-struct fw_hdr {/*8-byte alinment required*/
+struct fw_hdr {/*8-byte alignment required*/
unsigned short signature;
unsigned short version; /*0x8000 ~ 0x8FFF for FPGA version,
*0x0000 ~ 0x7FFF for ASIC version,*/
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index bac56e5..c9eb4b7 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -60,7 +60,7 @@ enum _LED_STATE_871x {
* the # of times to blink is depend on time
* for scanning. */
LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */
- LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer
+ LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer
* Server case */
LED_BLINK_WPS = 9, /* LED is blinkg during WPS communication */
LED_TXRX_BLINK = 10,
@@ -826,7 +826,7 @@ static void BlinkTimerCallback(unsigned long data)
{
struct LED_871x *pLed = (struct LED_871x *)data;
- /* This fixed the crash problem on Fedora 12 when trying to do thei
+ /* This fixed the crash problem on Fedora 12 when trying to do the
* insmod;ifconfig up;rmmod commands. */
if ((pLed->padapter->bSurpriseRemoved == true) ||
(pLed->padapter->bDriverStopped == true))
@@ -836,7 +836,7 @@ static void BlinkTimerCallback(unsigned long data)
/* Description:
* Callback function of LED BlinkWorkItem.
- * We dispatch acture LED blink action according to LedStrategy.
+ * We dispatch actual LED blink action according to LedStrategy.
*/
static void BlinkWorkItemCallback(struct work_struct *work)
{
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index fa6dc9c..8e82ce2 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -28,12 +28,13 @@
#define _RTL8712_RECV_C_
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
#include "osdep_service.h"
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
#include "ethernet.h"
#include "usb_ops.h"
#include "wifi.h"
@@ -459,7 +460,7 @@ void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
cmd_seq = (u8)((le32_to_cpu(voffset) >> 24) & 0x7f);
eid = (u8)((le32_to_cpu(voffset) >> 16) & 0xff);
r8712_event_handle(padapter, (uint *)poffset);
- poffset += (cmd_len + 8);/*8 bytes aligment*/
+ poffset += (cmd_len + 8);/*8 bytes alignment*/
} while (le32_to_cpu(voffset) & BIT(31));
}
@@ -603,7 +604,7 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter,
}
}
spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
- /*s2. check if winstart_b(indicate_seq) needs to been updated*/
+ /*s2. check if winstart_b(indicate_seq) needs to be updated*/
if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num))
goto _err_exit;
/*s3. Insert all packet into Reorder Queue to maintain its ordering.*/
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 6933319..3d23514 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -30,7 +30,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "osdep_intf.h"
#include "usb_ops.h"
diff --git a/drivers/staging/rtl8712/rtl871x_byteorder.h b/drivers/staging/rtl8712/rtl871x_byteorder.h
deleted file mode 100644
index bd3703b..0000000
--- a/drivers/staging/rtl8712/rtl871x_byteorder.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
- ******************************************************************************/
-#ifndef _RTL871X_BYTEORDER_H_
-#define _RTL871X_BYTEORDER_H_
-
-#if defined(__LITTLE_ENDIAN)
-# include "little_endian.h"
-#elif defined(__BIG_ENDIAN)
-# include "big_endian.h"
-#else
-# error "Must be LITTLE/BIG Endian Host"
-#endif
-
-#endif /* _RTL871X_BYTEORDER_H_ */
-
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index d77388b..659683e 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -50,7 +50,6 @@
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
/*
Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 757ebf7..9d93189 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -720,7 +720,7 @@ struct DisconnectCtrlEx_param {
* Result:
* 0x00: success
* 0x01: success, and check Response.
- * 0x02: cmd ignored due to duplicated sequcne number
+ * 0x02: cmd ignored due to duplicated sequence number
* 0x03: cmd dropped due to invalid cmd code
* 0x04: reserved.
*/
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index d3d8727..dc23395 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -117,7 +117,7 @@ struct io_req {
u32 command;
u32 status;
u8 *pbuf;
- void (*_async_io_callback)(struct _adapter *padater,
+ void (*_async_io_callback)(struct _adapter *padapter,
struct io_req *pio_req, u8 *cnxt);
u8 *cnxt;
};
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index ef35bc29..35e781f 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -43,7 +43,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <net/iw_handler.h>
@@ -242,7 +241,7 @@ static inline char *translate_scan(struct _adapter *padapter,
/* Add frequency/channel */
iwe.cmd = SIOCGIWFREQ;
{
- /* check legel index */
+ /* check legal index */
u8 dsconfig = pnetwork->network.Configuration.DSConfig;
if (dsconfig >= 1 && dsconfig <= sizeof(
ieee80211_wlan_frequencies) / sizeof(long))
@@ -810,11 +809,11 @@ static int r871x_wx_set_pmkid(struct net_device *dev,
/*
There are the BSSID information in the bssid.sa_data array.
- If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear
- all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
- wpa_supplicant wants to add a PMKID/BSSID to driver.
+ If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
+ all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
+ wpa_supplicant wants to add a PMKID/BSSID to driver.
If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
- remove a PMKID/BSSID from driver.
+ remove a PMKID/BSSID from driver.
*/
if (pPMK == NULL)
return -EINVAL;
@@ -924,7 +923,7 @@ static int r8711_wx_get_range(struct net_device *dev,
range->max_qual.noise = 100;
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + -98;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
@@ -1071,7 +1070,7 @@ FREE_EXT:
* MAC# of a preferred Access Point.
* Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
*
- * For this operation to succeed, there is no need for the interface to be Up.
+ * For this operation to succeed, there is no need for the interface to be up.
*
*/
static int r8711_wx_set_wap(struct net_device *dev,
@@ -2389,10 +2388,10 @@ static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r871x_handlers_def = {
.standard = r8711_handlers,
- .num_standard = sizeof(r8711_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8711_handlers),
.private = r8711_private_handler,
.private_args = (struct iw_priv_args *)r8711_private_args,
- .num_private = sizeof(r8711_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8711_private_handler),
.num_private_args = sizeof(r8711_private_args) /
sizeof(struct iw_priv_args),
.get_wireless_stats = r871x_get_wireless_stats
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index fb29b42..f352b32 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -264,7 +264,7 @@ void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter,
(*pold_state == Ndis802_11Infrastructure) ||
(*pold_state == Ndis802_11IBSS)) {
/* will clr Linked_state before this function,
- * we must have chked whether issue dis-assoc_cmd or
+ * we must have checked whether issue dis-assoc_cmd or
* not */
r8712_ind_disconnect(padapter);
}
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 4277d03..dc7adc1 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -137,7 +137,7 @@ static void _free_network_nolock(struct mlme_priv *pmlmepriv,
/*
return the wlan_network with the matching addr
- Shall be calle under atomic context...
+ Shall be called under atomic context...
to avoid possible racing condition...
*/
static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue,
@@ -255,7 +255,7 @@ void r8712_free_network_queue(struct _adapter *dev)
/*
return the wlan_network with the matching addr
- Shall be calle under atomic context...
+ Shall be called under atomic context...
to avoid possible racing condition...
*/
static struct wlan_network *r8712_find_network(struct __queue *scanned_queue,
@@ -1037,7 +1037,7 @@ void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf)
* and the WiFi client will drop the data with seq number 0.
* So, the 8712 firmware has to inform driver with receiving the
* ADDBA-Req frame so that the driver can reset the
- * sequence value of Rx reorder contorl.
+ * sequence value of Rx reorder control.
*/
void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf)
{
@@ -1775,7 +1775,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len)
phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
}
/* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info
- * if A-MPDU Rx is enabled, reseting rx_ordering_ctrl
+ * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl
* wstart_b(indicate_seq) to default value=0xffff
* todo: check if AP can send A-MPDU packets
*/
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index 71ca013..42bd0bf 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -69,8 +69,8 @@ since mlme_priv is a shared resource between many threads,
like ISR/Call-Back functions, the OID handlers, and even timer functions.
Each _queue has its own locks, already.
Other items are protected by mlme_priv.lock.
-To avoid possible dead lock, any thread trying to modifiying mlme_priv
-SHALL not lock up more than one locks at a time!
+To avoid possible dead lock, any thread trying to modify mlme_priv
+SHALL not lock up more than one lock at a time!
*/
#define traffic_threshold 10
@@ -132,7 +132,7 @@ static inline sint get_fwstate(struct mlme_priv *pmlmepriv)
* therefore set it to be the critical section...
*
* ### NOTE:#### (!!!!)
- * TAKE CARE THAT BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
+ * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
*/
static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
{
diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
index 23532a7..8e25862 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
@@ -184,7 +184,7 @@
/*RxIQ DC offset, Rx digital filter, DC notch filter */
#define rOFDM0_XARxAFE 0xc10
-#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */
+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */
#define rOFDM0_XBRxAFE 0xc18
#define rOFDM0_XBRxIQImbalance 0xc1c
#define rOFDM0_XCRxAFE 0xc20
@@ -603,7 +603,7 @@
#define bCCKRxIG 0x7f00
#define bCCKLNAPolarity 0x800000
#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */
+#define bCCKRFExtend 0x20000000 /* CCK Rx inital gain polarity */
#define bCCKRxAGCSatLevel 0x1f000000
#define bCCKRxAGCSatCount 0xe0
#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 5b03b40..c9d1743 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -28,15 +28,15 @@
#define _RTL871X_RECV_C_
+#include <linux/ip.h>
#include <linux/slab.h>
+#include <linux/if_ether.h>
#include <linux/kmemleak.h>
#include "osdep_service.h"
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
#include "ethernet.h"
#include "usb_ops.h"
#include "wifi.h"
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index aa57e77..78f570b 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -30,7 +30,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "osdep_intf.h"
#include "usb_ops.h"
@@ -72,7 +71,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
spin_lock_init(&pxmitpriv->lock);
/*
- Please insert all the queue initializaiton using _init_queue below
+ Please insert all the queue initialization using _init_queue below
*/
pxmitpriv->adapter = padapter;
_init_queue(&pxmitpriv->be_pending);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 638b79b..ee90698 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -119,7 +119,7 @@ struct pkt_attrib {
u8 priority;
u8 encrypt; /* when 0 indicate no encrypt. when non-zero,
- * indicate the encrypt algorith*/
+ * indicate the encrypt algorithm*/
u8 iv_len;
u8 icv_len;
unsigned char iv[8];
diff --git a/drivers/staging/rtl8712/swab.h b/drivers/staging/rtl8712/swab.h
deleted file mode 100644
index f127818..0000000
--- a/drivers/staging/rtl8712/swab.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_SWAB_H
-#define _LINUX_BYTEORDER_SWAB_H
-
-#ifndef __u16
- #define __u16 unsigned short
-#endif
-
-#ifndef __u32
- #define __u32 unsigned int
-#endif
-
-#ifndef __u8
- #define __u8 unsigned char
-#endif
-
-#ifndef __u64
- #define __u64 unsigned long long
-#endif
-
-
-static inline __u16 ___swab16(__u16 x)
-{
- __u16 __x = x;
- return (__u16)(
- (((__u16)(__x) & (__u16)0x00ffU) << 8) |
- (((__u16)(__x) & (__u16)0xff00U) >> 8));
-
-}
-
-static inline __u32 ___swab32(__u32 x)
-{
- __u32 __x = (x);
- return (__u32)(
- (((__u32)(__x) & (__u32)0x000000ffUL) << 24) |
- (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) |
- (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) |
- (((__u32)(__x) & (__u32)0xff000000UL) >> 24));
-}
-
-static inline __u64 ___swab64(__u64 x)
-{
- __u64 __x = (x);
-
- return (__u64)( \
- (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
- (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56));
-}
-
-#ifndef __arch__swab16
-static inline __u16 __arch__swab16(__u16 x)
-{
- return ___swab16(x);
-}
-
-#endif
-
-#ifndef __arch__swab32
-static inline __u32 __arch__swab32(__u32 x)
-{
- __u32 __tmp = (x) ;
- return ___swab32(__tmp);
-}
-#endif
-
-#ifndef __arch__swab64
-
-static inline __u64 __arch__swab64(__u64 x)
-{
- __u64 __tmp = (x) ;
- return ___swab64(__tmp);
-}
-
-
-#endif
-
-#define __swab16(x) __fswab16(x)
-#define __swab32(x) __fswab32(x)
-#define __swab64(x) __fswab64(x)
-
-static inline const __u16 __fswab16(__u16 x)
-{
- return __arch__swab16(x);
-}
-static inline const __u32 __fswab32(__u32 x)
-{
- return __arch__swab32(x);
-}
-
-#define swab16 __swab16
-#define swab32 __swab32
-#define swab64 __swab64
-#define swab16p __swab16p
-#define swab32p __swab32p
-#define swab64p __swab64p
-#define swab16s __swab16s
-#define swab32s __swab32s
-#define swab64s __swab64s
-
-#endif /* _LINUX_BYTEORDER_SWAB_H */
-
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index 46287c1..b4ae11a 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -141,7 +141,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
/* Enable AFE PLL Macro Block */
val8 = r8712_read8(padapter, AFE_PLL_CTRL);
r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
- /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+ /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
val8 = r8712_read8(padapter, SYS_ISO_CTRL);
r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
@@ -234,7 +234,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
udelay(500);
r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
udelay(500);
- /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+ /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
val8 = r8712_read8(padapter, SYS_ISO_CTRL);
r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index e419b4f..9bd18e2 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -621,30 +621,28 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
struct usb_device *udev = interface_to_usbdev(pusb_intf);
usb_set_intfdata(pusb_intf, NULL);
- if (padapter) {
- if (padapter->fw_found)
- release_firmware(padapter->fw);
- /* never exit with a firmware callback pending */
- wait_for_completion(&padapter->rtl8712_fw_ready);
- if (drvpriv.drv_registered == true)
- padapter->bSurpriseRemoved = true;
- if (pnetdev != NULL) {
- /* will call netdev_close() */
- unregister_netdev(pnetdev);
- }
- flush_scheduled_work();
- udelay(1);
- /*Stop driver mlme relation timer */
- if (padapter->fw_found)
- r8712_stop_drv_timers(padapter);
- r871x_dev_unload(padapter);
- r8712_free_drv_sw(padapter);
+ if (padapter->fw_found)
+ release_firmware(padapter->fw);
+ /* never exit with a firmware callback pending */
+ wait_for_completion(&padapter->rtl8712_fw_ready);
+ if (drvpriv.drv_registered == true)
+ padapter->bSurpriseRemoved = true;
+ if (pnetdev != NULL) {
+ /* will call netdev_close() */
+ unregister_netdev(pnetdev);
}
+ flush_scheduled_work();
+ udelay(1);
+ /*Stop driver mlme relation timer */
+ if (padapter->fw_found)
+ r8712_stop_drv_timers(padapter);
+ r871x_dev_unload(padapter);
+ r8712_free_drv_sw(padapter);
usb_set_intfdata(pusb_intf, NULL);
/* decrease the reference count of the usb device structure
* when disconnect */
usb_put_dev(udev);
- /* If we didn't unplug usb dongle and remove/insert modlue, driver
+ /* If we didn't unplug usb dongle and remove/insert module, driver
* fails on sitesurvey for the first time when device is up.
* Reset usb port for sitesurvey fail issue. */
if (udev->state != USB_STATE_NOTATTACHED)
diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c
index 5a8b0eb..c03508d 100644
--- a/drivers/staging/rtl8712/usb_ops.c
+++ b/drivers/staging/rtl8712/usb_ops.c
@@ -33,7 +33,6 @@
#include "osdep_intf.h"
#include "usb_ops.h"
#include "recv_osdep.h"
-#include "rtl871x_byteorder.h"
static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
{
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 277398c..793443e 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -26,7 +26,6 @@
#ifndef _WIFI_H_
#define _WIFI_H_
-#include "rtl871x_byteorder.h"
#include <linux/compiler.h>
#ifdef BIT
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index c970362..65542cb 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -29,14 +29,12 @@
#define _XMIT_OSDEP_C_
#include <linux/usb.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
#include "osdep_service.h"
#include "drv_types.h"
-
-#include "if_ether.h"
-#include "ip.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "mlme_osdep.h"
#include "xmit_osdep.h"
diff --git a/drivers/staging/rts5139/ms.c b/drivers/staging/rts5139/ms.c
index b0e9071..6eef33b 100644
--- a/drivers/staging/rts5139/ms.c
+++ b/drivers/staging/rts5139/ms.c
@@ -2680,7 +2680,7 @@ static int mspro_set_rw_cmd(struct rts51x_chip *chip, u32 start_sec,
return STATUS_SUCCESS;
}
-void mspro_stop_seq_mode(struct rts51x_chip *chip)
+static void mspro_stop_seq_mode(struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
int retval;
@@ -3149,7 +3149,7 @@ Fail:
TRACE_RET(chip, STATUS_FAIL);
sec_cnt = chip->rsp_buf[0];
- RTS51X_DEBUGP("%d pages need be trasferred, %d pages remained\n",
+ RTS51X_DEBUGP("%d pages need be transferred, %d pages remained\n",
(int)page_cnt, (int)sec_cnt);
page_addr = start_page + (page_cnt - sec_cnt);
@@ -3864,7 +3864,7 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip,
log_blk = (u16) (start_sector >> ms_card->block_shift);
start_page = (u8) (start_sector & ms_card->page_off);
- for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+ for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) {
if (log_blk < ms_start_idx[seg_no + 1])
break;
}
@@ -4020,7 +4020,8 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip,
log_blk++;
- for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+ for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1;
+ seg_no++) {
if (log_blk < ms_start_idx[seg_no + 1])
break;
}
@@ -4134,7 +4135,7 @@ void ms_cleanup_work(struct rts51x_chip *chip)
}
}
-int ms_power_off_card3v3(struct rts51x_chip *chip)
+static int ms_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
diff --git a/drivers/staging/rts5139/ms.h b/drivers/staging/rts5139/ms.h
index 3ce1dc9..0321d06 100644
--- a/drivers/staging/rts5139/ms.h
+++ b/drivers/staging/rts5139/ms.h
@@ -234,7 +234,6 @@
void mspro_polling_format_status(struct rts51x_chip *chip);
void mspro_format_sense(struct rts51x_chip *chip, unsigned int lun);
-void mspro_stop_seq_mode(struct rts51x_chip *chip);
int reset_ms_card(struct rts51x_chip *chip);
int ms_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
@@ -242,7 +241,6 @@ int mspro_format(struct scsi_cmnd *srb, struct rts51x_chip *chip,
int short_data_len, int quick_format);
void ms_free_l2p_tbl(struct rts51x_chip *chip);
void ms_cleanup_work(struct rts51x_chip *chip);
-int ms_power_off_card3v3(struct rts51x_chip *chip);
int release_ms_card(struct rts51x_chip *chip);
int ms_delay_write(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/ms_mg.c b/drivers/staging/rts5139/ms_mg.c
index 154b523..057d96c 100644
--- a/drivers/staging/rts5139/ms_mg.c
+++ b/drivers/staging/rts5139/ms_mg.c
@@ -38,7 +38,7 @@
#ifdef SUPPORT_MAGIC_GATE
-int mg_check_int_error(struct rts51x_chip *chip)
+static int mg_check_int_error(struct rts51x_chip *chip)
{
u8 value;
@@ -444,7 +444,7 @@ int mg_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip)
*
* Since the extra 4 bytes data is just only a prefix to original data
* that read from medium, so that the 4-byte data pushed into Ring buffer
- * precedes data tramsinssion from medium to Ring buffer by DMA mechanisim
+ * precedes data transmission from medium to Ring buffer by DMA mechanism
* in order to get maximum performance and minimum code size simultaneously.
*/
int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip)
diff --git a/drivers/staging/rts5139/rts51x.c b/drivers/staging/rts5139/rts51x.c
index 2b9f785..c3fe7dd 100644
--- a/drivers/staging/rts5139/rts51x.c
+++ b/drivers/staging/rts5139/rts51x.c
@@ -56,12 +56,6 @@ MODULE_DESCRIPTION(RTS51X_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
-#ifdef SCSI_SCAN_DELAY
-static unsigned int delay_use = 5;
-module_param(delay_use, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-#endif
-
static int auto_delink_en;
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
@@ -114,7 +108,7 @@ static inline void usb_autopm_disable(struct usb_interface *intf)
usb_autopm_get_interface(intf);
}
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("Ready to enter SS state\n");
usb_autopm_enable(chip->usb->pusb_intf);
@@ -207,7 +201,7 @@ int rts51x_reset_resume(struct usb_interface *iface)
#else /* CONFIG_PM */
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
}
@@ -364,11 +358,6 @@ static int rts51x_polling_thread(void *__chip)
{
struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
-#ifdef SCSI_SCAN_DELAY
- /* Wait until SCSI scan finished */
- wait_timeout((delay_use + 5) * HZ);
-#endif
-
for (;;) {
wait_timeout(POLLING_INTERVAL);
@@ -432,38 +421,6 @@ static int rts51x_polling_thread(void *__chip)
return 0;
}
-#ifdef SCSI_SCAN_DELAY
-/* Thread to carry out delayed SCSI-device scanning */
-static int rts51x_scan_thread(void *__chip)
-{
- struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
-
- printk(KERN_DEBUG
- "rts51x: device found at %d\n", chip->usb->pusb_dev->devnum);
-
- set_freezable();
- /* Wait for the timeout to expire or for a disconnect */
- if (delay_use > 0) {
- printk(KERN_DEBUG "rts51x: waiting for device "
- "to settle before scanning\n");
- wait_event_freezable_timeout(chip->usb->delay_wait,
- test_bit(FLIDX_DONT_SCAN,
- &chip->usb->dflags),
- delay_use * HZ);
- }
-
- /* If the device is still connected, perform the scanning */
- if (!test_bit(FLIDX_DONT_SCAN, &chip->usb->dflags)) {
- scsi_scan_host(rts51x_to_host(chip));
- printk(KERN_DEBUG "rts51x: device scan complete\n");
-
- /* Should we unbind if no devices were detected? */
- }
-
- complete_and_exit(&chip->usb->scanning_done, 0);
-}
-#endif
-
/* Associate our private data with the USB device */
static int associate_dev(struct rts51x_chip *chip, struct usb_interface *intf)
{
@@ -521,7 +478,6 @@ static void rts51x_init_options(struct rts51x_chip *chip)
{
struct rts51x_option *option = &(chip->option);
- option->led_blink_speed = 7;
option->mspro_formatter_enable = 1;
option->fpga_sd_sdr104_clk = CLK_100;
@@ -549,7 +505,6 @@ static void rts51x_init_options(struct rts51x_chip *chip)
option->ss_en = ss_en;
option->ss_delay = ss_delay;
- option->needs_remote_wakeup = needs_remote_wakeup;
option->auto_delink_en = auto_delink_en;
@@ -561,10 +516,7 @@ static void rts51x_init_options(struct rts51x_chip *chip)
option->rts5129_D3318_off_enable = 0;
option->sd20_pad_drive = 0;
option->reset_or_rw_fail_set_pad_drive = 1;
- option->rcc_fail_flag = 0;
- option->rcc_bug_fix_en = 1;
option->debounce_num = 2;
- option->polling_time = 100;
option->led_toggle_interval = 6;
option->xd_rwn_step = 0;
option->sd_send_status_en = 0;
@@ -737,15 +689,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip)
if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED)
set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
-#ifdef SCSI_SCAN_DELAY
- /* Prevent SCSI-scanning (if it hasn't started yet)
- * and wait for the SCSI-scanning thread to stop.
- */
- set_bit(FLIDX_DONT_SCAN, &rts51x->dflags);
- wake_up(&rts51x->delay_wait);
- wait_for_completion(&rts51x->scanning_done);
-#endif
-
/* Removing the host will perform an orderly shutdown: caches
* synchronized, disks spun down, etc.
*/
@@ -757,9 +700,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip)
scsi_lock(host);
set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
scsi_unlock(host);
-#ifdef SCSI_SCAN_DELAY
- wake_up(&rts51x->delay_wait);
-#endif
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -818,10 +758,6 @@ static int rts51x_probe(struct usb_interface *intf,
init_completion(&rts51x->control_exit);
init_completion(&rts51x->polling_exit);
init_completion(&(rts51x->notify));
-#ifdef SCSI_SCAN_DELAY
- init_waitqueue_head(&rts51x->delay_wait);
- init_completion(&rts51x->scanning_done);
-#endif
chip->usb = rts51x;
@@ -855,22 +791,7 @@ static int rts51x_probe(struct usb_interface *intf,
printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n");
goto BadDevice;
}
-#ifdef SCSI_SCAN_DELAY
- /* Start up the thread for delayed SCSI-device scanning */
- th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD);
- if (IS_ERR(th)) {
- printk(KERN_WARNING RTS51X_TIP
- "Unable to start the device-scanning thread\n");
- complete(&rts51x->scanning_done);
- quiesce_and_remove_host(chip);
- result = PTR_ERR(th);
- goto BadDevice;
- }
-
- wake_up_process(th);
-#else
scsi_scan_host(rts51x_to_host(chip));
-#endif
/* Start up our polling thread */
th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD);
diff --git a/drivers/staging/rts5139/rts51x.h b/drivers/staging/rts5139/rts51x.h
index b2c5839..ecc0109 100644
--- a/drivers/staging/rts5139/rts51x.h
+++ b/drivers/staging/rts5139/rts51x.h
@@ -47,11 +47,9 @@
#define RTS51X_DESC "Realtek RTS5139/29 USB card reader driver"
#define RTS51X_NAME "rts5139"
#define RTS51X_CTL_THREAD "rts5139-control"
-#define RTS51X_SCAN_THREAD "rts5139-scan"
#define RTS51X_POLLING_THREAD "rts5139-polling"
#define POLLING_IN_THREAD
-/* #define SCSI_SCAN_DELAY */
#define SUPPORT_FILE_OP
#define wait_timeout_x(task_state, msecs) \
@@ -66,8 +64,6 @@ do { \
/* Size of the DMA-mapped I/O buffer */
#define RTS51X_IOBUF_SIZE 1024
-/* Size of the autosense data buffer */
-#define RTS51X_SENSE_SIZE 18
/* Dynamic bitflag definitions (dflags): used in set_bit() etc. */
#define FLIDX_URB_ACTIVE 0 /* current_urb is in use */
@@ -76,7 +72,6 @@ do { \
#define FLIDX_DISCONNECTING 3 /* disconnect in progress */
#define FLIDX_RESETTING 4 /* device reset in progress */
#define FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
-#define FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */
struct rts51x_chip;
@@ -116,10 +111,6 @@ struct rts51x_usb {
struct completion control_exit; /* control thread exit */
struct completion polling_exit; /* polling thread exit */
struct completion notify; /* thread begin/end */
-#ifdef SCSI_SCAN_DELAY
- wait_queue_head_t delay_wait; /* wait during scan, reset */
- struct completion scanning_done; /* wait for scan thread */
-#endif
};
extern struct usb_driver rts51x_driver;
@@ -188,7 +179,6 @@ enum xfer_buf_dir { TO_XFER_BUF, FROM_XFER_BUF };
/* General routines provided by the usb-storage standard core */
#ifdef CONFIG_PM
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip);
void rts51x_try_to_exit_ss(struct rts51x_chip *chip);
int rts51x_suspend(struct usb_interface *iface, pm_message_t message);
int rts51x_resume(struct usb_interface *iface);
diff --git a/drivers/staging/rts5139/rts51x_card.c b/drivers/staging/rts5139/rts51x_card.c
index 424a845..4192c3b 100644
--- a/drivers/staging/rts5139/rts51x_card.c
+++ b/drivers/staging/rts5139/rts51x_card.c
@@ -37,7 +37,6 @@
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "xd.h"
#include "sd.h"
#include "ms.h"
@@ -94,7 +93,7 @@ void do_remaining_work(struct rts51x_chip *chip)
ms_cleanup_work(chip);
}
-void do_reset_xd_card(struct rts51x_chip *chip)
+static void do_reset_xd_card(struct rts51x_chip *chip)
{
int retval;
@@ -148,7 +147,7 @@ void do_reset_sd_card(struct rts51x_chip *chip)
}
}
-void do_reset_ms_card(struct rts51x_chip *chip)
+static void do_reset_ms_card(struct rts51x_chip *chip)
{
int retval;
@@ -175,7 +174,7 @@ void do_reset_ms_card(struct rts51x_chip *chip)
}
}
-void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
+static void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
u8 *need_release)
{
int retval;
@@ -191,7 +190,6 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
goto Exit_Debounce;
if (chip->card_exist) {
- rts51x_clear_start_time(chip);
retval = rts51x_read_register(chip, CARD_INT_PEND, &value);
if (retval != STATUS_SUCCESS) {
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH,
@@ -214,17 +212,11 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
}
} else {
if (chip->card_status & XD_CD) {
- rts51x_clear_start_time(chip);
reset_map |= XD_CARD;
} else if (chip->card_status & SD_CD) {
- rts51x_clear_start_time(chip);
reset_map |= SD_CARD;
} else if (chip->card_status & MS_CD) {
- rts51x_clear_start_time(chip);
reset_map |= MS_CARD;
- } else {
- if (rts51x_check_start_time(chip))
- rts51x_set_start_time(chip);
}
}
@@ -709,7 +701,7 @@ u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun)
return 0;
}
-int card_share_mode(struct rts51x_chip *chip, int card)
+static int card_share_mode(struct rts51x_chip *chip, int card)
{
u8 value;
@@ -823,22 +815,6 @@ int enable_card_clock(struct rts51x_chip *chip, u8 card)
return STATUS_SUCCESS;
}
-int disable_card_clock(struct rts51x_chip *chip, u8 card)
-{
- u8 clk_en = 0;
-
- if (card & XD_CARD)
- clk_en |= XD_CLK_EN;
- if (card & SD_CARD)
- clk_en |= SD_CLK_EN;
- if (card & MS_CARD)
- clk_en |= MS_CLK_EN;
-
- RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0);
-
- return STATUS_SUCCESS;
-}
-
int card_power_on(struct rts51x_chip *chip, u8 card)
{
u8 mask, val1, val2;
@@ -851,16 +827,7 @@ int card_power_on(struct rts51x_chip *chip, u8 card)
if ((card == SD_CARD) || (card == XD_CARD)) {
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask | LDO3318_PWR_MASK,
val1 | LDO_SUSPEND);
- /* RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- LDO3318_PWR_MASK, LDO_SUSPEND); */
}
- /* else if(card==XD_CARD)
- {
- RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND);
- //RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- // LDO3318_PWR_MASK, LDO_SUSPEND);
- } */
else {
#endif
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1);
@@ -879,17 +846,6 @@ int card_power_on(struct rts51x_chip *chip, u8 card)
return STATUS_SUCCESS;
}
-int card_power_off(struct rts51x_chip *chip, u8 card)
-{
- u8 mask, val;
-
- mask = POWER_MASK;
- val = POWER_OFF;
- RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val);
-
- return STATUS_SUCCESS;
-}
-
int monitor_card_cd(struct rts51x_chip *chip, u8 card)
{
int retval;
diff --git a/drivers/staging/rts5139/rts51x_card.h b/drivers/staging/rts5139/rts51x_card.h
index ac3c1e7..c5c03cc 100644
--- a/drivers/staging/rts5139/rts51x_card.h
+++ b/drivers/staging/rts5139/rts51x_card.h
@@ -204,13 +204,7 @@
/* LDO_POWER_CFG */
#define TUNE_SD18_MASK 0x1C
-#define TUNE_SD18_1V7 0x00
#define TUNE_SD18_1V8 (0x01 << 2)
-#define TUNE_SD18_1V9 (0x02 << 2)
-#define TUNE_SD18_2V0 (0x03 << 2)
-#define TUNE_SD18_2V7 (0x04 << 2)
-#define TUNE_SD18_2V8 (0x05 << 2)
-#define TUNE_SD18_2V9 (0x06 << 2)
#define TUNE_SD18_3V3 (0x07 << 2)
/* XD_CP_WAITTIME */
@@ -744,9 +738,7 @@
int monitor_card_cd(struct rts51x_chip *chip, u8 card);
void do_remaining_work(struct rts51x_chip *chip);
-void do_reset_xd_card(struct rts51x_chip *chip);
void do_reset_sd_card(struct rts51x_chip *chip);
-void do_reset_ms_card(struct rts51x_chip *chip);
void rts51x_init_cards(struct rts51x_chip *chip);
void rts51x_release_cards(struct rts51x_chip *chip);
int switch_ssc_clock(struct rts51x_chip *chip, int clk);
@@ -754,15 +746,12 @@ int switch_normal_clock(struct rts51x_chip *chip, int clk);
int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr,
u16 sec_cnt);
u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun);
-int card_share_mode(struct rts51x_chip *chip, int card);
int rts51x_select_card(struct rts51x_chip *chip, int card);
void eject_card(struct rts51x_chip *chip, unsigned int lun);
void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip,
u32 byte_cnt, u8 pack_size);
int enable_card_clock(struct rts51x_chip *chip, u8 card);
-int disable_card_clock(struct rts51x_chip *chip, u8 card);
int card_power_on(struct rts51x_chip *chip, u8 card);
-int card_power_off(struct rts51x_chip *chip, u8 card);
int toggle_gpio(struct rts51x_chip *chip, u8 gpio);
int turn_on_led(struct rts51x_chip *chip, u8 gpio);
int turn_off_led(struct rts51x_chip *chip, u8 gpio);
diff --git a/drivers/staging/rts5139/rts51x_chip.c b/drivers/staging/rts5139/rts51x_chip.c
index b3e0bb2..db88d7a 100644
--- a/drivers/staging/rts5139/rts51x_chip.c
+++ b/drivers/staging/rts5139/rts51x_chip.c
@@ -34,7 +34,6 @@
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "xd.h"
#include "ms.h"
#include "sd.h"
@@ -79,20 +78,18 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
chip->option.sd20_pad_drive);
if (chip->rts5179)
rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01);
- if (!chip->option.ww_enable) {
- if (CHECK_PKG(chip, LQFP48)) {
- rts51x_write_register(chip, CARD_PULL_CTL3,
- 0x80, 0x80);
- rts51x_write_register(chip, CARD_PULL_CTL6,
- 0xf0, 0xA0);
- } else {
- rts51x_write_register(chip, CARD_PULL_CTL1,
- 0x30, 0x20);
- rts51x_write_register(chip, CARD_PULL_CTL3,
- 0x80, 0x80);
- rts51x_write_register(chip, CARD_PULL_CTL6,
- 0x0c, 0x08);
- }
+ if (CHECK_PKG(chip, LQFP48)) {
+ rts51x_write_register(chip, CARD_PULL_CTL3,
+ 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6,
+ 0xf0, 0xA0);
+ } else {
+ rts51x_write_register(chip, CARD_PULL_CTL1,
+ 0x30, 0x20);
+ rts51x_write_register(chip, CARD_PULL_CTL3,
+ 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6,
+ 0x0c, 0x08);
}
}
if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44) {
@@ -121,12 +118,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
/* GPIO OE */
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
-#ifdef LED_AUTO_BLINK
- /* LED autoblink */
- rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK,
- BLINK_ENABLE | BLINK_SPEED_MASK,
- BLINK_ENABLE | chip->option.led_blink_speed);
-#endif
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
@@ -144,7 +135,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
card_power_on(chip, SD_CARD | MS_CARD | XD_CARD);
wait_timeout(10);
}
- rts51x_clear_start_time(chip);
return STATUS_SUCCESS;
}
@@ -164,12 +154,6 @@ int rts51x_init_chip(struct rts51x_chip *chip)
chip->card_ejected = 0;
chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD;
-#if 0
- chip->option.sdr50_tx_phase = 0x01;
- chip->option.sdr50_rx_phase = 0x05;
- chip->option.ddr50_tx_phase = 0x09;
- chip->option.ddr50_rx_phase = 0x06; /* add for debug */
-#endif
#ifdef CLOSE_SSC_POWER
rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
udelay(100);
@@ -178,9 +162,6 @@ int rts51x_init_chip(struct rts51x_chip *chip)
RTS51X_SET_STAT(chip, STAT_RUN);
RTS51X_READ_REG(chip, HW_VERSION, &val);
- if ((val & 0x0f) >= 2)
- chip->option.rcc_bug_fix_en = 0;
- RTS51X_DEBUGP("rcc bug fix enable:%d\n", chip->option.rcc_bug_fix_en);
RTS51X_DEBUGP("HW_VERSION: 0x%x\n", val);
if (val & FPGA_VER) {
chip->asic_code = 0;
@@ -237,7 +218,6 @@ int rts51x_release_chip(struct rts51x_chip *chip)
return STATUS_SUCCESS;
}
-#ifndef LED_AUTO_BLINK
static inline void rts51x_blink_led(struct rts51x_chip *chip)
{
/* Read/Write */
@@ -251,20 +231,6 @@ static inline void rts51x_blink_led(struct rts51x_chip *chip)
}
}
}
-#endif
-
-int rts51x_check_start_time(struct rts51x_chip *chip)
-{
- return 0;
-}
-
-void rts51x_set_start_time(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_clear_start_time(struct rts51x_chip *chip)
-{
-}
static void rts51x_auto_delink_cmd(struct rts51x_chip *chip)
{
@@ -287,7 +253,6 @@ static void rts51x_auto_delink_polling_cycle(struct rts51x_chip *chip)
chip->option.delink_delay * 2) {
if (chip->auto_delink_counter ==
chip->option.delink_delay) {
- clear_first_install_mark(chip);
if (chip->card_exist) {
/* False card */
if (!chip->card_ejected) {
@@ -321,91 +286,13 @@ static void rts51x_auto_delink(struct rts51x_chip *chip)
}
#else
/* some of called funcs are not implemented, so comment it out */
-#if 0
-/* using precise time as delink time */
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
- int retvalue = 0;
-
- retvalue = rts51x_get_card_status(chip, &chip->card_status);
- /* get card CD status success and card CD not exist,
- * then check whether delink */
- if ((retvalue == STATUS_SUCCESS)
- && (!(chip->card_status & (SD_CD | MS_CD | XD_CD)))) {
- if (rts51x_count_delink_time(chip) >=
- chip->option.delink_delay) {
- clear_first_install_mark(chip);
- RTS51X_DEBUGP("No card inserted, do delink\n");
- /* sangdy2010-05-17:disable because there is error
- * after SSC clock closed and card power
- * has been closed before */
- /* rts51x_write_register(chip, CARD_PWR_CTL,
- DV3318_AUTO_PWR_OFF, 0); */
- rts51x_auto_delink_cmd(chip);
- }
- /* card CD exist and not ready, then do force delink */
- if ((retvalue == STATUS_SUCCESS)
- && (chip->card_status & (SD_CD | MS_CD | XD_CD))) {
- /* if card is not ejected or safely remove,
- * then do force delink */
- if (!chip->card_ejected) {
- /* sangdy2010-11-16:polling at least 2 cycles
- * then do force delink for card may force delink
- * if card is extracted and insert quickly
- * after ready. */
- if (chip->auto_delink_counter > 1) {
- if (rts51x_count_delink_time(chip) >
- chip->option.delink_delay * 2) {
- RTS51X_DEBUGP("Try to do force"
- "delink\n");
- rts51x_auto_delink_force_cmd(chip);
- }
- }
- }
- }
- chip->auto_delink_counter++;
-}
-#else
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
-}
-#endif
-
static void rts51x_auto_delink(struct rts51x_chip *chip)
{
- rts51x_auto_delink_precise_time(chip);
}
#endif
void rts51x_polling_func(struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-
- if (sd_card->sd_erase_status) {
- if (chip->card_exist & SD_CARD) {
- u8 val;
- rts51x_read_register(chip, SD_BUS_STAT, &val);
- if (val & SD_DAT0_STATUS) {
- /* Erase completed */
- sd_card->sd_erase_status = SD_NOT_ERASE;
- sd_card->sd_lock_notify = 1;
-
- /* SD card should be reinited,
- * so we release it here. */
- sd_cleanup_work(chip);
- release_sd_card(chip);
- chip->card_ready &= ~SD_CARD;
- chip->card_exist &= ~SD_CARD;
- chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
- clear_bit(chip->card2lun[SD_CARD],
- &(chip->lun_mc));
- }
- } else {
- sd_card->sd_erase_status = SD_NOT_ERASE;
- }
- }
-#endif
rts51x_init_cards(chip);
@@ -431,9 +318,7 @@ void rts51x_polling_func(struct rts51x_chip *chip)
if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) {
RTS51X_DEBUGP("Idle state!\n");
RTS51X_SET_STAT(chip, STAT_IDLE);
-#ifndef LED_AUTO_BLINK
chip->led_toggle_counter = 0;
-#endif
/* Idle state, turn off LED
* to reduce power consumption */
if (chip->option.led_always_on
@@ -467,9 +352,7 @@ void rts51x_polling_func(struct rts51x_chip *chip)
switch (RTS51X_GET_STAT(chip)) {
case STAT_RUN:
-#ifndef LED_AUTO_BLINK
rts51x_blink_led(chip);
-#endif
do_remaining_work(chip);
break;
@@ -484,7 +367,6 @@ void rts51x_polling_func(struct rts51x_chip *chip)
rts51x_auto_delink(chip);
} else {
chip->auto_delink_counter = 0;
- rts51x_clear_start_time(chip);
}
}
@@ -831,7 +713,7 @@ void rts51x_do_before_power_down(struct rts51x_chip *chip)
chip->cur_clk = 0;
chip->card_exist = 0;
chip->cur_card = 0;
- if (chip->asic_code && !chip->option.ww_enable) {
+ if (chip->asic_code) {
if (CHECK_PKG(chip, LQFP48)) {
rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50);
@@ -863,16 +745,6 @@ void rts51x_prepare_run(struct rts51x_chip *chip)
rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
}
#endif
-#if 0
- if (chip->option.ss_en && RTS51X_CHK_STAT(chip, STAT_SS)) {
- rts51x_try_to_exit_ss(chip);
- wait_timeout(100);
- rts51x_init_chip(chip);
- rts51x_init_cards(chip);
- }
-
- RTS51X_SET_STAT(chip, STAT_RUN);
-#endif
}
#ifdef _MSG_TRACE
@@ -1017,24 +889,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
status[0x0F] = 0x00;
}
}
-#ifdef SUPPORT_SD_LOCK
- /* SD Lock/Unlock */
- if (card == SD_CARD) {
- status[0x17] = 0x80;
- if (sd_card->sd_erase_status)
- status[0x17] |= 0x01; /* Under erasing */
- if (sd_card->sd_lock_status & SD_LOCKED) {
- status[0x17] |= 0x02; /* Locked */
- status[0x07] |= 0x40; /* Read protected */
- }
- if (sd_card->sd_lock_status & SD_PWD_EXIST)
- status[0x17] |= 0x04; /* Contain PWD */
- } else {
- status[0x17] = 0x00;
- }
-
- RTS51X_DEBUGP("status[0x17] = 0x%x\n", status[0x17]);
-#endif
/* Function 0
* Support Magic Gate, CPRM and PhyRegister R/W */
@@ -1044,12 +898,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
- /* Function 7 */
-#ifdef SUPPORT_SD_LOCK
- /* Support SD Lock/Unlock */
- status[0x1F] = 0x01;
-#endif
-
/* Function 2
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
diff --git a/drivers/staging/rts5139/rts51x_chip.h b/drivers/staging/rts5139/rts51x_chip.h
index 13fc2a4..6d395b6 100644
--- a/drivers/staging/rts5139/rts51x_chip.h
+++ b/drivers/staging/rts5139/rts51x_chip.h
@@ -39,12 +39,7 @@
#define SUPPORT_CPRM
#define SUPPORT_MAGIC_GATE
#define SUPPORT_MSXC
-/* #define LED_AUTO_BLINK */
-
-/* { wwang, 2010-07-26
- * Add support for SD lock/unlock */
-/* #define SUPPORT_SD_LOCK */
-/* } wwang, 2010-07-26 */
+#define USING_POLLING_CYCLE_DELINK
#ifdef SUPPORT_MAGIC_GA
/* Using NORMAL_WRITE instead of AUTO_WRITE to set ICVTE */
@@ -63,7 +58,6 @@
#define SUPPORT_OCP
#define MS_SPEEDUP
-/* #define XD_SPEEDUP */
#define SD_XD_IO_FOLLOW_PWR
@@ -81,7 +75,6 @@
#define MAX_ALLOWED_LUN_CNT 8
#define CMD_BUF_LEN 1024
-#define RSP_BUF_LEN 1024
#define POLLING_INTERVAL 50 /* 50ms */
#define XD_FREE_TABLE_CNT 1200
@@ -128,8 +121,6 @@
#endif
#define STATUS_FAIL 1
-#define STATUS_READ_FAIL 2
-#define STATUS_WRITE_FAIL 3
#define STATUS_TIMEDOUT 4
#define STATUS_NOMEM 5
#define STATUS_TRANS_SHORT 6
@@ -139,8 +130,6 @@
#define IDLE_MAX_COUNT 10
#define POLLING_WAIT_CNT 1
-#define DELINK_DELAY 100
-#define LED_TOGGLE_INTERVAL 6
#define LED_GPIO 0
/* package */
@@ -157,8 +146,6 @@
#define TRANSPORT_GOOD 0
/* Transport good, command failed */
#define TRANSPORT_FAILED 1
-/* Command failed, no auto-sense */
-#define TRANSPORT_NO_SENSE 2
/* Transport bad (i.e. device dead) */
#define TRANSPORT_ERROR 3
@@ -195,7 +182,6 @@ struct trace_msg_t {
#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6
#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7
#define SENSE_TYPE_MEDIA_WRITE_ERR 8
-#define SENSE_TYPE_FORMAT_IN_PROGRESS 9
#define SENSE_TYPE_FORMAT_CMD_FAILED 10
#ifdef SUPPORT_MAGIC_GATE
/* COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED */
@@ -207,83 +193,27 @@ struct trace_msg_t {
/* WRITE ERROR */
#define SENSE_TYPE_MG_WRITE_ERR 0x0e
#endif
-#ifdef SUPPORT_SD_LOCK
-/* FOR Locked SD card */
-#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10
-#endif
/*---- sense key ----*/
-#define ILI 0x20 /* ILI bit is on */
-
-#define NO_SENSE 0x00 /* not exist sense key */
-#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */
-#define NOT_READY 0x02 /* Logical unit is not ready */
-#define MEDIA_ERR 0x03 /* medium/data error */
-#define HARDWARE_ERR 0x04 /* hardware error */
#define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */
-#define UNIT_ATTENTION 0x06 /* unit attention condition occur */
-#define DAT_PRTCT 0x07 /* read/write is desable */
-#define BLNC_CHK 0x08 /* find blank/DOF in read */
- /* write to unblank area */
-#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illgal */
-#define ABRT_CMD 0x0b /* Target make the command in error */
-#define EQUAL 0x0c /* Search Data end with Equal */
-#define VLM_OVRFLW 0x0d /* Some data are left in buffer */
-#define MISCMP 0x0e /* find inequality */
/*-----------------------------------
SENSE_DATA
-----------------------------------*/
-/*---- valid ----*/
-#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */
-#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */
/*---- error code ----*/
#define CUR_ERR 0x70 /* current error */
-#define DEF_ERR 0x71 /* specific command error */
/*---- sense key Infomation ----*/
-#define SNSKEYINFO_LEN 3 /* length of sense key infomation */
#define SKSV 0x80
#define CDB_ILLEGAL 0x40
-#define DAT_ILLEGAL 0x00
-#define BPV 0x08
-#define BIT_ILLEGAL0 0 /* bit0 is illegal */
-#define BIT_ILLEGAL1 1 /* bit1 is illegal */
-#define BIT_ILLEGAL2 2 /* bit2 is illegal */
-#define BIT_ILLEGAL3 3 /* bit3 is illegal */
-#define BIT_ILLEGAL4 4 /* bit4 is illegal */
-#define BIT_ILLEGAL5 5 /* bit5 is illegal */
-#define BIT_ILLEGAL6 6 /* bit6 is illegal */
-#define BIT_ILLEGAL7 7 /* bit7 is illegal */
/*---- ASC ----*/
-#define ASC_NO_INFO 0x00
-#define ASC_MISCMP 0x1d
#define ASC_INVLD_CDB 0x24
-#define ASC_INVLD_PARA 0x26
-#define ASC_LU_NOT_READY 0x04
-#define ASC_WRITE_ERR 0x0c
-#define ASC_READ_ERR 0x11
-#define ASC_LOAD_EJCT_ERR 0x53
-#define ASC_MEDIA_NOT_PRESENT 0x3A
-#define ASC_MEDIA_CHANGED 0x28
-#define ASC_MEDIA_IN_PROCESS 0x04
-#define ASC_WRITE_PROTECT 0x27
-#define ASC_LUN_NOT_SUPPORTED 0x25
/*---- ASQC ----*/
-#define ASCQ_NO_INFO 0x00
-#define ASCQ_MEDIA_IN_PROCESS 0x01
-#define ASCQ_MISCMP 0x00
#define ASCQ_INVLD_CDB 0x00
-#define ASCQ_INVLD_PARA 0x02
-#define ASCQ_LU_NOT_READY 0x02
-#define ASCQ_WRITE_ERR 0x02
-#define ASCQ_READ_ERR 0x00
-#define ASCQ_LOAD_EJCT_ERR 0x00
-#define ASCQ_WRITE_PROTECT 0x00
struct sense_data_t {
unsigned char err_code; /* error code */
@@ -296,13 +226,13 @@ struct sense_data_t {
unsigned char seg_no; /* segment No. */
unsigned char sense_key; /* byte5 : ILI */
/* bit3-0 : sense key */
- unsigned char info[4]; /* infomation */
+ unsigned char info[4]; /* information */
unsigned char ad_sense_len; /* additional sense data length */
- unsigned char cmd_info[4]; /* command specific infomation */
+ unsigned char cmd_info[4]; /* command specific information */
unsigned char asc; /* ASC */
unsigned char ascq; /* ASCQ */
unsigned char rfu; /* FRU */
- unsigned char sns_key_info[3]; /* sense key specific infomation */
+ unsigned char sns_key_info[3]; /* sense key specific information */
};
/* sd_ctl bit map */
@@ -323,8 +253,6 @@ struct sense_data_t {
#define SUPPORT_UHS50_MMC44 0x40
struct rts51x_option {
- u8 led_blink_speed;
-
int mspro_formatter_enable;
/* card clock expected by user for fpga platform */
@@ -368,8 +296,6 @@ struct rts51x_option {
int ss_en;
/* Interval to enter SS from IDLE state (second) */
int ss_delay;
- int needs_remote_wakeup;
- u8 ww_enable; /* sangdy2010-08-03:add for remote wakeup */
/* Enable SSC clock */
int ssc_en;
@@ -392,10 +318,7 @@ struct rts51x_option {
/*if reset or rw fail,then set SD20 pad drive again */
u8 reset_or_rw_fail_set_pad_drive;
- u8 rcc_fail_flag; /* add to indicate whether rcc bug happen */
- u8 rcc_bug_fix_en; /* if set,then support fixing rcc bug */
u8 debounce_num; /* debounce number */
- int polling_time; /* polling delay time */
u8 led_toggle_interval; /* used to control led toggle speed */
int xd_rwn_step;
u8 sd_send_status_en;
@@ -405,7 +328,7 @@ struct rts51x_option {
u8 ddr50_rx_phase;
u8 sdr50_tx_phase;
u8 sdr50_rx_phase;
- /* used to enable select sdr50 tx phase according to proportion. */
+ /* used to enable select sdr50 tx phase according to proportion. */
u8 sdr50_phase_sel;
u8 ms_errreg_fix;
u8 reset_mmc_first;
@@ -614,11 +537,6 @@ struct sd_info {
u8 sd_reset_fail; /* sangdy2010-07-01 */
u8 sd_send_status_en;
-#ifdef SUPPORT_SD_LOCK
- u8 sd_lock_status;
- u8 sd_erase_status;
- u8 sd_lock_notify;
-#endif
};
#define MODE_512_SEQ 0x01
@@ -720,9 +638,8 @@ struct rts51x_chip {
struct scsi_cmnd *srb;
struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT];
-#ifndef LED_AUTO_BLINK
int led_toggle_counter;
-#endif
+
int ss_counter;
int idle_counter;
int auto_delink_counter;
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index 6eaebb6..ef893c8 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -234,12 +234,7 @@ ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
return 0;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-#endif
{
struct rts51x_chip *chip;
struct sd_direct_cmnd cmnd;
diff --git a/drivers/staging/rts5139/rts51x_fop.h b/drivers/staging/rts5139/rts51x_fop.h
index 94d75f0..eb45acf 100644
--- a/drivers/staging/rts5139/rts51x_fop.h
+++ b/drivers/staging/rts5139/rts51x_fop.h
@@ -50,12 +50,7 @@ ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos);
ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
-#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-#endif
#endif
diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c
index 87c9cdc..e07a1f4 100644
--- a/drivers/staging/rts5139/rts51x_scsi.c
+++ b/drivers/staging/rts5139/rts51x_scsi.c
@@ -40,7 +40,6 @@
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "sd_cprm.h"
#include "ms_mg.h"
#include "trace.h"
@@ -370,10 +369,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1);
break;
- case SENSE_TYPE_FORMAT_IN_PROGRESS:
- set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
- break;
-
case SENSE_TYPE_FORMAT_CMD_FAILED:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0);
break;
@@ -396,12 +391,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
break;
#endif
-#ifdef SUPPORT_SD_LOCK
- case SENSE_TYPE_MEDIA_READ_FORBIDDEN:
- set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0);
- break;
-#endif
-
case SENSE_TYPE_NO_SENSE:
default:
set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0);
@@ -448,20 +437,6 @@ static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
}
-#ifdef SUPPORT_SD_LOCK
- if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) {
- struct sd_info *sd_card = &(chip->sd_card);
- if (sd_card->sd_lock_notify) {
- sd_card->sd_lock_notify = 0;
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
- return TRANSPORT_FAILED;
- } else if (sd_card->sd_lock_status & SD_LOCKED) {
- set_sense_type(chip, lun,
- SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- return TRANSPORT_FAILED;
- }
- }
-#endif
return TRANSPORT_GOOD;
}
@@ -797,9 +772,6 @@ static int request_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-#endif
unsigned int lun = SCSI_LUN(srb);
int retval;
u32 start_sec;
@@ -819,25 +791,6 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_erase_status) {
- /* Accessing to any card is forbidden
- * until the erase procedure of SD is completed */
- RTS51X_DEBUGP("SD card being erased!\n");
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
-
- if (get_lun_card(chip, lun) == SD_CARD) {
- if (sd_card->sd_lock_status & SD_LOCKED) {
- RTS51X_DEBUGP("SD card locked!\n");
- set_sense_type(chip, lun,
- SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#endif
-
if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
start_sec =
((u32) srb->cmnd[2] << 24) |
@@ -883,20 +836,12 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
retval = card_rw(srb, chip, start_sec, sec_cnt);
if (retval != STATUS_SUCCESS) {
-#if 0
- if (chip->need_release & chip->lun2card[lun]) {
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
- } else {
-#endif
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
}
-#if 0
- }
-#endif
TRACE_RET(chip, TRANSPORT_FAILED);
}
@@ -1516,7 +1461,7 @@ static int ms_format_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
}
#ifdef SUPPORT_PCGL_1P18
-int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1677,7 +1622,7 @@ static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
#endif
#ifdef SUPPORT_MAGIC_GATE
-int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1764,7 +1709,7 @@ int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
return TRANSPORT_GOOD;
}
-int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1871,30 +1816,10 @@ int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-#endif
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int result = TRANSPORT_GOOD;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_erase_status) {
- /* Block all SCSI command except for REQUEST_SENSE
- * and rs_ppstatus */
- if (!
- ((srb->cmnd[0] == VENDOR_CMND)
- && (srb->cmnd[1] == SCSI_APP_CMD)
- && (srb->cmnd[2] == GET_DEV_STATUS))
- && (srb->cmnd[0] != REQUEST_SENSE)) {
- /* Logical Unit Not Ready Format in Progress */
- set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
- 0, 0);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#endif
-
if ((get_lun_card(chip, lun) == MS_CARD) &&
(ms_card->format_status == FORMAT_IN_PROGRESS)) {
if ((srb->cmnd[0] != REQUEST_SENSE)
@@ -1994,11 +1919,6 @@ int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
* Host functions
***********************************************************************/
-const char *host_info(struct Scsi_Host *host)
-{
- return "SCSI emulation for RTS51xx USB driver-based card reader";
-}
-
int slave_alloc(struct scsi_device *sdev)
{
/*
@@ -2111,14 +2031,7 @@ int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
return 0;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
-{
- return queuecommand_lck(srb, done);
-}
-#else
DEF_SCSI_QCMD(queuecommand)
-#endif
/***********************************************************************
* Error handling functions
***********************************************************************/
diff --git a/drivers/staging/rts5139/rts51x_scsi.h b/drivers/staging/rts5139/rts51x_scsi.h
index 3a8ca06..060d2c2 100644
--- a/drivers/staging/rts5139/rts51x_scsi.h
+++ b/drivers/staging/rts5139/rts51x_scsi.h
@@ -145,16 +145,11 @@ struct Scsi_Host;
struct scsi_device;
struct scsi_cmnd;
-const char *host_info(struct Scsi_Host *host);
int slave_alloc(struct scsi_device *sdev);
int slave_configure(struct scsi_device *sdev);
int proc_info(struct Scsi_Host *host, char *buffer,
char **start, off_t offset, int length, int inout);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *));
-#else
int queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-#endif
int command_abort(struct scsi_cmnd *srb);
int device_reset(struct scsi_cmnd *srb);
int bus_reset(struct scsi_cmnd *srb);
diff --git a/drivers/staging/rts5139/rts51x_sys.h b/drivers/staging/rts5139/rts51x_sys.h
deleted file mode 100644
index b09cd34..0000000
--- a/drivers/staging/rts5139/rts51x_sys.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Driver for Realtek USB RTS51xx card reader
- * Header file
- *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- * wwang (wei_wang@realsil.com.cn)
- * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- * Maintainer:
- * Edwin Rong (edwin_rong@realsil.com.cn)
- * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- */
-
-#ifndef __RTS51X_SYS_H
-#define __RTS51X_SYS_H
-
-#include "rts51x.h"
-#include "rts51x_chip.h"
-#include "rts51x_card.h"
-
-#define USING_POLLING_CYCLE_DELINK
-
-extern int rts51x_check_start_time(struct rts51x_chip *chip);
-extern void rts51x_set_start_time(struct rts51x_chip *chip);
-extern void rts51x_clear_start_time(struct rts51x_chip *chip);
-
-/* typedef dma_addr_t ULONG_PTR; */
-
-static inline void rts51x_reset_detected_cards(struct rts51x_chip *chip)
-{
-/* rts51x_reset_cards(chip); */
-}
-
-static inline void clear_first_install_mark(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_enter_ss(struct rts51x_chip *chip);
-void rts51x_exit_ss(struct rts51x_chip *chip);
-
-#endif /* __RTS51X_SYS_H */
diff --git a/drivers/staging/rts5139/rts51x_transport.c b/drivers/staging/rts5139/rts51x_transport.c
index da9c83b..89e4d80 100644
--- a/drivers/staging/rts5139/rts51x_transport.c
+++ b/drivers/staging/rts5139/rts51x_transport.c
@@ -120,7 +120,7 @@ unsigned int rts51x_access_sglist(unsigned char *buffer,
return cnt;
}
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
+static unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb,
struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
@@ -252,6 +252,8 @@ static int rts51x_msg_common(struct rts51x_chip *chip, struct urb *urb,
return status;
}
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
+
/*
* Interpret the results of a URB transfer
*/
@@ -359,7 +361,7 @@ int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
rts51x->current_urb->actual_length);
}
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe);
@@ -378,11 +380,6 @@ int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
return STATUS_SUCCESS;
}
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe)
-{
- return rts51x_clear_halt(chip, pipe);
-}
-
static void rts51x_sg_clean(struct usb_sg_request *io)
{
if (io->urbs) {
@@ -391,226 +388,17 @@ static void rts51x_sg_clean(struct usb_sg_request *io)
kfree(io->urbs);
io->urbs = NULL;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) */
- if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
- io->sg, io->nents);
-#endif
io->dev = NULL;
}
-#if 0
-static void rts51x_sg_complete(struct urb *urb)
-{
- struct usb_sg_request *io = urb->context;
- int status = urb->status;
-
- spin_lock(&io->lock);
-
- /* In 2.5 we require hcds' endpoint queues not to progress after fault
- * reports, until the completion callback (this!) returns. That lets
- * device driver code (like this routine) unlink queued urbs first,
- * if it needs to, since the HC won't work on them at all. So it's
- * not possible for page N+1 to overwrite page N, and so on.
- *
- * That's only for "hard" faults; "soft" faults (unlinks) sometimes
- * complete before the HCD can get requests away from hardware,
- * though never during cleanup after a hard fault.
- */
- if (io->status
- && (io->status != -ECONNRESET
- || status != -ECONNRESET)
- && urb->actual_length) {
- dev_err(io->dev->bus->controller,
- "dev %s ep%d%s scatterlist error %d/%d\n",
- io->dev->devpath,
- usb_endpoint_num(&urb->ep->desc),
- usb_urb_dir_in(urb) ? "in" : "out",
- status, io->status);
- /* BUG (); */
- }
-
- if (io->status == 0 && status && status != -ECONNRESET) {
- int i, found, retval;
-
- io->status = status;
-
- /* the previous urbs, and this one, completed already.
- * unlink pending urbs so they won't rx/tx bad data.
- * careful: unlink can sometimes be synchronous...
- */
- spin_unlock(&io->lock);
- for (i = 0, found = 0; i < io->entries; i++) {
- if (!io->urbs[i] || !io->urbs[i]->dev)
- continue;
- if (found) {
- retval = usb_unlink_urb(io->urbs[i]);
- if (retval != -EINPROGRESS &&
- retval != -ENODEV &&
- retval != -EBUSY)
- dev_err(&io->dev->dev,
- "%s, unlink --> %d\n",
- __func__, retval);
- } else if (urb == io->urbs[i])
- found = 1;
- }
- spin_lock(&io->lock);
- }
- urb->dev = NULL;
-
- /* on the last completion, signal usb_sg_wait() */
- io->bytes += urb->actual_length;
- io->count--;
- if (!io->count)
- complete(&io->complete);
-
- spin_unlock(&io->lock);
-}
-
-/* This function is ported from usb_sg_init, which can transfer
- * sg list partially */
-int rts51x_sg_init_partial(struct usb_sg_request *io, struct usb_device *dev,
- unsigned pipe, unsigned period, void *buf, struct scatterlist **sgptr,
- unsigned int *offset, int nents, size_t length, gfp_t mem_flags)
-{
- int i;
- int urb_flags;
- int dma;
- struct scatterlist *sg = *sgptr, *first_sg;
-
- first_sg = (struct scatterlist *)buf;
- if (!sg)
- sg = first_sg;
-
- if (!io || !dev || !sg
- || usb_pipecontrol(pipe)
- || usb_pipeisoc(pipe)
- || (nents <= 0))
- return -EINVAL;
-
- spin_lock_init(&io->lock);
- io->dev = dev;
- io->pipe = pipe;
- io->sg = first_sg; /* used by unmap */
- io->nents = nents;
-
- RTS51X_DEBUGP("Before map, sg address: 0x%x\n", (unsigned int)sg);
- RTS51X_DEBUGP("Before map, dev address: 0x%x\n", (unsigned int)dev);
-
- /* not all host controllers use DMA (like the mainstream pci ones);
- * they can use PIO (sl811) or be software over another transport.
- */
- dma = (dev->dev.dma_mask != NULL);
- if (dma) {
- /* map the whole sg list, because here we only know the
- * total nents */
- io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
- first_sg, nents);
- } else {
- io->entries = nents;
- }
-
- /* initialize all the urbs we'll use */
- if (io->entries <= 0)
- return io->entries;
-
- io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
- if (!io->urbs)
- goto nomem;
-
- urb_flags = URB_NO_INTERRUPT;
- if (dma)
- urb_flags |= URB_NO_TRANSFER_DMA_MAP;
- if (usb_pipein(pipe))
- urb_flags |= URB_SHORT_NOT_OK;
-
- RTS51X_DEBUGP("io->entries = %d\n", io->entries);
-
- for (i = 0; (sg != NULL) && (length > 0); i++) {
- unsigned len;
-
- RTS51X_DEBUGP("sg address: 0x%x\n", (unsigned int)sg);
- RTS51X_DEBUGP("length = %d, *offset = %d\n", length, *offset);
-
- io->urbs[i] = usb_alloc_urb(0, mem_flags);
- if (!io->urbs[i]) {
- io->entries = i;
- goto nomem;
- }
-
- io->urbs[i]->dev = NULL;
- io->urbs[i]->pipe = pipe;
- io->urbs[i]->interval = period;
- io->urbs[i]->transfer_flags = urb_flags;
-
- io->urbs[i]->complete = rts51x_sg_complete;
- io->urbs[i]->context = io;
-
- if (dma) {
- io->urbs[i]->transfer_dma =
- sg_dma_address(sg) + *offset;
- len = sg_dma_len(sg) - *offset;
- io->urbs[i]->transfer_buffer = NULL;
- RTS51X_DEBUGP(" -- sg entry dma length = %d\n",
- sg_dma_len(sg));
- } else {
- /* hc may use _only_ transfer_buffer */
- io->urbs[i]->transfer_buffer = sg_virt(sg) + *offset;
- len = sg->length - *offset;
- RTS51X_DEBUGP(" -- sg entry length = %d\n",
- sg->length);
- }
-
- if (length >= len) {
- *offset = 0;
- io->urbs[i]->transfer_buffer_length = len;
- length -= len;
- sg = sg_next(sg);
- } else {
- *offset += length;
- io->urbs[i]->transfer_buffer_length = length;
- length = 0;
- }
- if (length == 0)
- io->entries = i + 1;
-#if 0
- if (length) {
- len = min_t(unsigned, len, length);
- length -= len;
- if (length == 0) {
- io->entries = i + 1;
- *offset += len;
- } else {
- *offset = 0;
- }
- }
-#endif
- }
- RTS51X_DEBUGP("In %s, urb count: %d\n", __func__, i);
- io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
-
- RTS51X_DEBUGP("sg address stored in sgptr: 0x%x\n", (unsigned int)sg);
- *sgptr = sg;
-
- /* transaction state */
- io->count = io->entries;
- io->status = 0;
- io->bytes = 0;
- init_completion(&io->complete);
- return 0;
-nomem:
- rts51x_sg_clean(io);
- return -ENOMEM;
-}
-#endif
-int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+static int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
unsigned pipe, unsigned period, struct scatterlist *sg,
int nents, size_t length, gfp_t mem_flags)
{
return usb_sg_init(io, dev, pipe, period, sg, nents, length, mem_flags);
}
-int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
+static int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
{
long timeleft;
int i;
@@ -630,7 +418,7 @@ int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
*/
spin_unlock_irq(&io->lock);
switch (retval) {
- /* maybe we retrying will recover */
+ /* maybe the retry will recover */
case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
@@ -740,56 +528,9 @@ static int rts51x_bulk_transfer_sglist(struct rts51x_chip *chip,
return interpret_urb_result(chip, pipe, length, result,
chip->usb->current_sg.bytes);
}
-#if 0
-static int rts51x_bulk_transfer_sglist_partial(struct rts51x_chip *chip,
- unsigned int pipe, void *buf, struct scatterlist **sgptr,
- unsigned int *offset, int num_sg, unsigned int length,
- unsigned int *act_len, int timeout)
-{
- int result;
-
- /* don't submit s-g requests during abort processing */
- if (test_bit(FLIDX_ABORTING, &chip->usb->dflags))
- TRACE_RET(chip, STATUS_ERROR);
- /* initialize the scatter-gather request block */
- RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
- length, num_sg);
- result = rts51x_sg_init_partial(&chip->usb->current_sg,
- chip->usb->pusb_dev, pipe, 0, buf, sgptr, offset,
- num_sg, length, GFP_NOIO);
- if (result) {
- RTS51X_DEBUGP("rts51x_sg_init_partial returned %d\n", result);
- TRACE_RET(chip, STATUS_ERROR);
- }
-
- /* since the block has been initialized successfully, it's now
- * okay to cancel it */
- set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
- /* did an abort occur during the submission? */
- if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) {
-
- /* cancel the request, if it hasn't been cancelled already */
- if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) {
- RTS51X_DEBUGP("-- cancelling sg request\n");
- usb_sg_cancel(&chip->usb->current_sg);
- }
- }
-
- /* wait for the completion of the transfer */
- result = rts51x_sg_wait(&chip->usb->current_sg, timeout);
-
- clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
- /* result = us->current_sg.status; */
- if (act_len)
- *act_len = chip->usb->current_sg.bytes;
- return interpret_urb_result(chip, pipe, length, result,
- chip->usb->current_sg.bytes);
-}
-#endif
-int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, unsigned int pipe,
+static int rts51x_bulk_transfer_buf(struct rts51x_chip *chip,
+ unsigned int pipe,
void *buf, unsigned int length,
unsigned int *act_len, int timeout)
{
@@ -860,11 +601,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
}
kfree(tmp_buf);
-#if 0
- result = rts51x_bulk_transfer_sglist_partial(chip, pipe, buf,
- (struct scatterlist **)ptr, offset,
- use_sg, len, act_len, timeout);
-#endif
} else {
unsigned int step = 0;
if (offset)
diff --git a/drivers/staging/rts5139/rts51x_transport.h b/drivers/staging/rts5139/rts51x_transport.h
index 9dd556e..024f115 100644
--- a/drivers/staging/rts5139/rts51x_transport.h
+++ b/drivers/staging/rts5139/rts51x_transport.h
@@ -40,11 +40,6 @@ unsigned int rts51x_access_sglist(unsigned char *buffer,
unsigned int buflen, void *sglist,
void **sgptr, unsigned int *offset,
enum xfer_buf_dir dir);
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen,
- struct scsi_cmnd *srb,
- struct scatterlist **sgptr,
- unsigned int *offset,
- enum xfer_buf_dir dir);
void rts51x_set_xfer_buf(unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb);
void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
@@ -53,7 +48,6 @@ void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout);
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
@@ -62,12 +56,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
-/* whichPipe:
- * 0: bulk in pipe
- * 1: bulk out pipe
- * 2: intr in pipe */
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe);
-
#ifndef POLLING_IN_THREAD
int rts51x_start_epc_transfer(struct rts51x_chip *chip);
void rts51x_cancel_epc_transfer(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd.c b/drivers/staging/rts5139/sd.c
index d5dd2f9..b739f26 100644
--- a/drivers/staging/rts5139/sd.c
+++ b/drivers/staging/rts5139/sd.c
@@ -246,12 +246,7 @@ RTY_SEND_CMD:
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef SUPPORT_SD_LOCK
- /* exclude bit25 CARD_IS_LOCKED */
- if (buf[1] & 0x7D) {
-#else
if (buf[1] & 0x7F) {
-#endif
RTS51X_DEBUGP("buf[1]: 0x%02x\n", buf[1]);
TRACE_RET(chip, STATUS_FAIL);
}
@@ -709,37 +704,7 @@ int sd_select_card(struct rts51x_chip *chip, int select)
return STATUS_SUCCESS;
}
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip)
-{
- struct sd_info *sd_card = &(chip->sd_card);
- int retval;
- u8 rsp[5];
-
- retval =
- sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
- SD_RSP_TYPE_R1, rsp, 5);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-
- if (rsp[1] & 0x02)
- sd_card->sd_lock_status |= SD_LOCKED;
- else
- sd_card->sd_lock_status &= ~SD_LOCKED;
-
- RTS51X_DEBUGP("sd_card->sd_lock_status = 0x%x\n",
- sd_card->sd_lock_status);
-
- if (rsp[1] & 0x01) {
- /* LOCK_UNLOCK_FAILED */
- TRACE_RET(chip, STATUS_FAIL);
- }
-
- return STATUS_SUCCESS;
-}
-#endif
-
-int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
+static int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
u8 rdychk, u16 pollingcnt)
{
struct sd_info *sd_card = &(chip->sd_card);
@@ -1197,15 +1162,6 @@ static int sd_switch_function(struct rts51x_chip *chip, u8 bus_width)
RTS51X_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x",
func_to_switch);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_SDR_RST)
- && (DDR50_SUPPORT == func_to_switch)
- && (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) {
- func_to_switch = SDR50_SUPPORT;
- RTS51X_DEBUGP("Using SDR50 instead of DDR50 for SD Lock\n");
- }
-#endif
-
if (func_to_switch) {
retval =
sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch,
@@ -1562,7 +1518,7 @@ static u8 sd_search_final_phase(struct rts51x_chip *chip, u32 phase_map,
}
Search_Finish:
- RTS51X_DEBUGP("Final choosen phase: %d\n", final_phase);
+ RTS51X_DEBUGP("Final chosen phase: %d\n", final_phase);
return final_phase;
}
@@ -2024,10 +1980,6 @@ Switch_Fail:
k = 0;
hi_cap_flow = 0;
support_1v8 = 0;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
- goto SD_UNLOCK_ENTRY;
-#endif
retval = sd_prepare_reset(chip);
if (retval != STATUS_SUCCESS)
@@ -2182,7 +2134,7 @@ RTY_CMD55:
sd_card->sd_addr += (u32) rsp[2] << 16;
/* Get CSD register for Calculating Timing,Capacity,
- * Check CSD to determaine as if this is the SD ROM card */
+ * Check CSD to determine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
@@ -2190,20 +2142,6 @@ RTY_CMD55:
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-SD_UNLOCK_ENTRY:
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-
- if (sd_card->sd_lock_status & SD_LOCKED) {
- sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST);
- return STATUS_SUCCESS;
- } else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) {
- sd_card->sd_lock_status &= ~SD_PWD_EXIST;
- }
-#endif
/* ACMD42 */
retval =
@@ -2294,10 +2232,6 @@ SD_UNLOCK_ENTRY:
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
-#ifdef SUPPORT_SD_LOCK
- /* clear 1 bit mode status */
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
if (CHK_SD30_SPEED(sd_card)) {
rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
@@ -2380,19 +2314,6 @@ SD_UNLOCK_ENTRY:
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
- retval = rts51x_send_cmd(chip, MODE_C, 100);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
- }
-#endif
-
return STATUS_SUCCESS;
}
@@ -2587,17 +2508,10 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip)
sd_card->capacity =
((u32) buf[5] << 24) | ((u32) buf[4] << 16) |
((u32) buf[3] << 8) | ((u32) buf[2]);
-#ifdef SUPPORT_SD_LOCK
- if (!(sd_card->sd_lock_status & SD_SDR_RST) && CHECK_UHS50(chip))
- card_type_mask = 0x07;
- else
- card_type_mask = 0x03;
-#else
if (CHECK_UHS50(chip))
card_type_mask = 0x07;
else
card_type_mask = 0x03;
-#endif
card_type = buf[1] & card_type_mask;
if (card_type) {
@@ -2626,15 +2540,9 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip)
if (mmc_test_switch_bus(chip, MMC_8BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_8BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 8;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
} else if (mmc_test_switch_bus(chip, MMC_4BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_4BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
} else {
CLR_MMC_8BIT(sd_card);
CLR_MMC_4BIT(sd_card);
@@ -2652,11 +2560,6 @@ static int reset_mmc(struct rts51x_chip *chip)
u8 change_to_ddr52 = 1;
u8 cmd[5];
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
- goto MMC_UNLOCK_ENTRY;
-#endif
-
MMC_DDR_FAIL:
retval = sd_prepare_reset(chip);
@@ -2745,7 +2648,7 @@ RTY_MMC_RST:
TRACE_RET(chip, retval);
/* Get CSD register for Calculating Timing,Capacity
- * Check CSD to determaine as if this is the SD ROM card */
+ * Check CSD to determine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
@@ -2763,13 +2666,6 @@ RTY_MMC_RST:
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-MMC_UNLOCK_ENTRY:
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-#endif
RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
@@ -2842,18 +2738,6 @@ MMC_UNLOCK_ENTRY:
}
}
}
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
- retval = rts51x_send_cmd(chip, MODE_C, 100);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
- }
-#endif
retval = rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS)
@@ -2879,11 +2763,6 @@ int reset_sd_card(struct rts51x_chip *chip)
sd_card->capacity = 0;
sd_card->sd_switch_fail = 0;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status = 0;
- sd_card->sd_erase_status = 0;
-#endif
-
sd_clear_reset_fail(chip);
enable_card_clock(chip, SD_CARD);
@@ -3006,7 +2885,7 @@ static int wait_data_buf_ready(struct rts51x_chip *chip)
TRACE_RET(chip, STATUS_FAIL);
}
-void sd_stop_seq_mode(struct rts51x_chip *chip)
+static void sd_stop_seq_mode(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
@@ -3300,7 +3179,7 @@ void sd_cleanup_work(struct rts51x_chip *chip)
}
}
-inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
+static inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
{
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
@@ -3322,7 +3201,7 @@ inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
}
}
-int sd_power_off_card3v3(struct rts51x_chip *chip)
+static int sd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
@@ -3346,17 +3225,12 @@ int release_sd_card(struct rts51x_chip *chip)
struct sd_info *sd_card = &(chip->sd_card);
int retval;
- RTS51X_DEBUGP("elease_sd_card\n");
+ RTS51X_DEBUGP("release_sd_card\n");
chip->card_ready &= ~SD_CARD;
chip->card_fail &= ~SD_CARD;
chip->card_wp &= ~SD_CARD;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status = 0;
- sd_card->sd_erase_status = 0;
-#endif
-
memset(sd_card->raw_csd, 0, 16);
memset(sd_card->raw_scr, 0, 8);
diff --git a/drivers/staging/rts5139/sd.h b/drivers/staging/rts5139/sd.h
index 0805edc..de155d8 100644
--- a/drivers/staging/rts5139/sd.h
+++ b/drivers/staging/rts5139/sd.h
@@ -141,29 +141,6 @@
#define SWITCH_MODE_ERR 0x06
#define SWITCH_PASS 0x07
-#ifdef SUPPORT_SD_LOCK
-/* CMD42 Parameter */
-#define SD_ERASE 0x08
-#define SD_LOCK 0x04
-#define SD_UNLOCK 0x00
-#define SD_CLR_PWD 0x02
-#define SD_SET_PWD 0x01
-
-#define SD_PWD_LEN 0x10
-
-/* SD lock unlock Status */
-#define SD_LOCKED 0x80 /* Global lock status */
-#define SD_LOCK_1BIT_MODE 0x40 /**/
-#define SD_PWD_EXIST 0x20
-#define SD_UNLOCK_POW_ON 0x01 /**/
-#define SD_SDR_RST 0x02 /* Reset SD30 card with current DDR mode to SDR mode. */
-/* g_bySDEraseStatus */
-#define SD_NOT_ERASE 0x00
-#define SD_UNDER_ERASING 0x01
-#define SD_COMPLETE_ERASE 0x02
-/* SD_RW FAIL status */
-#define SD_RW_FORBIDDEN 0x0F /* read/write is forbidden (SD card) */
-#endif
/* Function Group Definition */
/* Function Group 1 */
#define HS_SUPPORT 0x01
@@ -282,17 +259,11 @@ struct timing_phase_path {
int sd_select_card(struct rts51x_chip *chip, int select);
int reset_sd_card(struct rts51x_chip *chip);
int sd_switch_clock(struct rts51x_chip *chip);
-void sd_stop_seq_mode(struct rts51x_chip *chip);
int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void sd_cleanup_work(struct rts51x_chip *chip);
-int sd_power_off_card3v3(struct rts51x_chip *chip);
int release_sd_card(struct rts51x_chip *chip);
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip);
-#endif
-
#ifdef SUPPORT_CPRM
extern int reset_sd(struct rts51x_chip *chip);
extern int sd_check_data0_status(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index d5969d9..f8c6071 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -77,12 +77,7 @@ static inline int get_rsp_type(u8 rsp_code, u8 *rsp_type, int *rsp_len)
return STATUS_SUCCESS;
}
-int soft_reset_sd_card(struct rts51x_chip *chip)
-{
- return reset_sd(chip);
-}
-
-int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
+static int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
int special_check)
{
@@ -206,11 +201,7 @@ RTY_SEND_CMD:
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef SUPPORT_SD_LOCK
- if (buf[1] & 0x7D) {
-#else
if (buf[1] & 0x7F) {
-#endif
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[2] & 0xF8)
@@ -233,7 +224,7 @@ RTY_SEND_CMD:
return STATUS_SUCCESS;
}
-int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
+static int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
{
int retval, rsp_len;
u16 reg_addr;
@@ -305,26 +296,8 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#else
/* Set H/W SD/MMC Bus Width */
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
if (standby) {
retval = sd_select_card(chip, 0);
@@ -350,12 +323,6 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
}
-#ifdef SUPPORT_SD_LOCK
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-#endif
return TRANSPORT_GOOD;
@@ -399,21 +366,7 @@ int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card))
- bus_width = SD_BUS_WIDTH_8;
- else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card))
- bus_width = SD_BUS_WIDTH_4;
- else
- bus_width = SD_BUS_WIDTH_1;
- } else {
- bus_width = SD_BUS_WIDTH_4;
- }
- RTS51X_DEBUGP("bus_width = %d\n", bus_width);
-#else
bus_width = SD_BUS_WIDTH_4;
-#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -599,11 +552,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
int cmd13_checkbit = 0, write_err = 0;
u8 rsp_type;
u32 i;
-#ifdef SUPPORT_SD_LOCK
- int lock_cmd_fail = 0;
- u8 sd_lock_state = 0;
- u8 lock_cmd_type = 0;
-#endif
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
@@ -614,12 +562,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- sd_lock_state = sd_card->sd_lock_status;
- sd_lock_state &= SD_LOCKED;
- }
-#endif
retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
if (retval != STATUS_SUCCESS) {
@@ -631,25 +573,7 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#else
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -692,10 +616,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
else
memcpy(buf, data_buf, data_len);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK)
- lock_cmd_type = buf[0] & 0x0F;
-#endif
if (data_len > 256) {
rts51x_init_cmd(chip);
@@ -802,29 +722,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- if (lock_cmd_type == SD_ERASE) {
- sd_card->sd_erase_status = SD_UNDER_ERASING;
- scsi_set_resid(srb, 0);
- return TRANSPORT_GOOD;
- }
-
- rts51x_init_cmd(chip);
- rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS,
- SD_DAT0_STATUS);
- retval = rts51x_send_cmd(chip, MODE_CR, 250);
- if (retval != STATUS_SUCCESS)
- TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
- rts51x_get_rsp(chip, 1, 200); /* Don't care return value */
-
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS) {
- RTS51X_DEBUGP("Lock command fail!\n");
- lock_cmd_fail = 1;
- }
- }
-#endif /* SUPPORT_SD_LOCK */
if (standby) {
retval = sd_select_card(chip, 1);
@@ -865,51 +762,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
}
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- if (!lock_cmd_fail) {
- RTS51X_DEBUGP("lock_cmd_type = 0x%x\n",
- lock_cmd_type);
- if (lock_cmd_type & SD_CLR_PWD)
- sd_card->sd_lock_status &= ~SD_PWD_EXIST;
- if (lock_cmd_type & SD_SET_PWD)
- sd_card->sd_lock_status |= SD_PWD_EXIST;
- }
-
- RTS51X_DEBUGP("sd_lock_state = 0x%x,"
- "sd_card->sd_lock_status = 0x%x\n",
- sd_lock_state, sd_card->sd_lock_status);
- if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
- sd_card->sd_lock_notify = 1;
- if (sd_lock_state) {
- if (sd_card->sd_lock_status &
- SD_LOCK_1BIT_MODE) {
- sd_card->sd_lock_status |=
- (SD_UNLOCK_POW_ON | SD_SDR_RST);
- if (CHK_SD(sd_card)) {
- retval = reset_sd(chip);
- if (retval != STATUS_SUCCESS) {
- sd_card->sd_lock_status
- &= ~(SD_UNLOCK_POW_ON |
- SD_SDR_RST);
- TRACE_GOTO(chip,
- SD_Execute_Write_Cmd_Failed);
- }
- }
-
- sd_card->sd_lock_status &=
- ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
- }
- }
- }
- }
-
- if (lock_cmd_fail) {
- scsi_set_resid(srb, 0);
- set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
-#endif /* SUPPORT_SD_LOCK */
return TRANSPORT_GOOD;
@@ -1173,30 +1025,18 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip)
switch (srb->cmnd[1] & 0x0F) {
case 0:
/* SD Card Power Off -> ON and Initialization */
-#ifdef SUPPORT_SD_LOCK
- if (0x64 == srb->cmnd[9]) {
- /* Command Mode */
- sd_card->sd_lock_status |= SD_SDR_RST;
- }
-#endif /* SUPPORT_SD_LOCK */
retval = reset_sd_card(chip);
if (retval != STATUS_SUCCESS) {
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
TRACE_RET(chip, TRANSPORT_FAILED);
}
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
break;
case 1:
/* reset CMD(CMD0) and Initialization
* (without SD Card Power Off -> ON) */
- retval = soft_reset_sd_card(chip);
+ retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
diff --git a/drivers/staging/rts5139/xd.c b/drivers/staging/rts5139/xd.c
index 5820605..58f8ba2 100644
--- a/drivers/staging/rts5139/xd.c
+++ b/drivers/staging/rts5139/xd.c
@@ -47,13 +47,6 @@ static inline void xd_set_err_code(struct rts51x_chip *chip, u8 err_code)
xd_card->err_code = err_code;
}
-static inline int xd_check_err_code(struct rts51x_chip *chip, u8 err_code)
-{
- struct xd_info *xd_card = &(chip->xd_card);
-
- return (xd_card->err_code == err_code);
-}
-
static int xd_set_init_para(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
@@ -862,6 +855,8 @@ static void xd_set_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off,
zone->l2p_table[log_off] = phy_off;
}
+static int xd_delay_write(struct rts51x_chip *chip);
+
static u32 xd_get_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off)
{
struct xd_info *xd_card = &(chip->xd_card);
@@ -1182,91 +1177,6 @@ static int xd_copy_page(struct rts51x_chip *chip,
return STATUS_SUCCESS;
}
-#ifdef XD_SPEEDUP
-static int xd_auto_copy_page(struct rts51x_chip *chip,
- u32 old_blk, u32 new_blk,
- u8 start_page, u8 end_page)
-{
- struct xd_info *xd_card = &(chip->xd_card);
- u32 old_page, new_page;
- int retval;
- u8 page_count;
-
- RTS51X_DEBUGP("Auto copy page from block 0x%x to block 0x%x\n",
- old_blk, new_blk);
-
- if (start_page > end_page)
- TRACE_RET(chip, STATUS_FAIL);
-
- page_count = end_page - start_page;
-
- if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
- TRACE_RET(chip, STATUS_FAIL);
-
- old_page = (old_blk << xd_card->block_shift) + start_page;
- new_page = (new_blk << xd_card->block_shift) + start_page;
-
- XD_CLR_BAD_NEWBLK(xd_card);
-
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WAITTIME, 0x03, WAIT_FF);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_PAGELEN, 0xFF, page_count);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR0, 0xFF, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR1, 0xFF,
- (u8) old_page);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR2, 0xFF,
- (u8) (old_page >> 8));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR3, 0xFF,
- (u8) (old_page >> 16));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR4, 0xFF, 0);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR0, 0xFF, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR1, 0xFF,
- (u8) new_page);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR2, 0xFF,
- (u8) (new_page >> 8));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR3, 0xFF,
- (u8) (new_page >> 16));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR4, 0xFF, 0);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
- PINGPONG_BUFFER);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG,
- XD_BA_TRANSFORM | XD_ADDR_MASK, 0 | xd_card->addr_cycle);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
- XD_AUTO_CHK_DATA_STATUS, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
- XD_TRANSFER_START | XD_COPY_PAGES);
- rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
- XD_TRANSFER_END);
-
- retval = rts51x_send_cmd(chip, MODE_CR, 100);
- if (retval != STATUS_SUCCESS) {
- rts51x_clear_xd_error(chip);
- TRACE_GOTO(chip, Copy_Fail);
- }
-
- retval = rts51x_get_rsp(chip, 1, 800);
- if (retval != STATUS_SUCCESS) {
- rts51x_clear_xd_error(chip);
- TRACE_GOTO(chip, Copy_Fail);
- }
-
- return STATUS_SUCCESS;
-
-Copy_Fail:
- retval = xd_copy_page(chip, old_blk, new_blk, start_page, end_page);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
-
- return STATUS_SUCCESS;
-}
-#endif
-
static int xd_reset_cmd(struct rts51x_chip *chip)
{
int retval;
@@ -1686,15 +1596,9 @@ Fail:
XD_CLR_BAD_OLDBLK(xd_card);
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef XD_SPEEDUP
- retval =
- xd_auto_copy_page(chip, phy_blk, new_blk, 0,
- xd_card->page_off + 1);
-#else
retval =
xd_copy_page(chip, phy_blk, new_blk, 0,
xd_card->page_off + 1);
-#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
@@ -1741,13 +1645,8 @@ static int xd_finish_write(struct rts51x_chip *chip,
TRACE_RET(chip, STATUS_FAIL);
}
} else {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip, old_blk, new_blk,
- page_off, xd_card->page_off + 1);
-#else
retval = xd_copy_page(chip, old_blk, new_blk,
page_off, xd_card->page_off + 1);
-#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
@@ -1789,11 +1688,7 @@ static int xd_prepare_write(struct rts51x_chip *chip,
old_blk, new_blk, log_blk, (int)page_off);
if (page_off) {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip, old_blk, new_blk, 0, page_off);
-#else
retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off);
-#endif
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
@@ -1922,7 +1817,7 @@ Fail:
TRACE_RET(chip, STATUS_FAIL);
}
-int xd_delay_write(struct rts51x_chip *chip)
+static int xd_delay_write(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
struct xd_delay_write_tag *delay_write = &(xd_card->delay_write);
@@ -1999,18 +1894,11 @@ int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
(start_page > delay_write->pageoff)) {
delay_write->delay_write_flag = 0;
if (delay_write->old_phyblock != BLK_NOT_FOUND) {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip,
- delay_write->old_phyblock,
- delay_write->new_phyblock,
- delay_write->pageoff, start_page);
-#else
retval = xd_copy_page(chip,
delay_write->old_phyblock,
delay_write->new_phyblock,
delay_write->pageoff,
start_page);
-#endif
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
@@ -2198,7 +2086,7 @@ void xd_cleanup_work(struct rts51x_chip *chip)
}
}
-int xd_power_off_card3v3(struct rts51x_chip *chip)
+static int xd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
@@ -2232,7 +2120,7 @@ int release_xd_card(struct rts51x_chip *chip)
struct xd_info *xd_card = &(chip->xd_card);
int retval;
- RTS51X_DEBUGP("elease_xd_card\n");
+ RTS51X_DEBUGP("release_xd_card\n");
chip->card_ready &= ~XD_CARD;
chip->card_fail &= ~XD_CARD;
diff --git a/drivers/staging/rts5139/xd.h b/drivers/staging/rts5139/xd.h
index fa69590..55e4205 100644
--- a/drivers/staging/rts5139/xd.h
+++ b/drivers/staging/rts5139/xd.h
@@ -182,12 +182,10 @@
#define CIS1_9 (256 + 9)
int reset_xd_card(struct rts51x_chip *chip);
-int xd_delay_write(struct rts51x_chip *chip);
int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void xd_free_l2p_tbl(struct rts51x_chip *chip);
void xd_cleanup_work(struct rts51x_chip *chip);
-int xd_power_off_card3v3(struct rts51x_chip *chip);
int release_xd_card(struct rts51x_chip *chip);
#endif /* __RTS51X_XD_H */
diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c
index f9a4498..0bf6d95 100644
--- a/drivers/staging/rts_pstor/ms.c
+++ b/drivers/staging/rts_pstor/ms.c
@@ -4136,7 +4136,7 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
#else
retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
2, WAIT_INT, 0, 0, buf + 4, 1024);
- if ((retval != STATUS_SUCCESS) || check_ms_err(chip) {
+ if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) {
rtsx_clear_ms_error(chip);
if (ms_card->mg_auth == 0) {
if ((buf[5] & 0xC0) != 0) {
diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c
index 9b2e5c9..54a4742 100644
--- a/drivers/staging/rts_pstor/rtsx_transport.c
+++ b/drivers/staging/rts_pstor/rtsx_transport.c
@@ -130,7 +130,7 @@ unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
/* Store the contents of buffer into srb's transfer buffer and set the
* SCSI residue. */
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb)
+ unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
@@ -141,7 +141,7 @@ void rtsx_stor_set_xfer_buf(unsigned char *buffer,
}
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb)
+ unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index fa7c0d0..9d9fc7c 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -68,11 +68,11 @@
#define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16
/* flag that signifies tah the lock is
-currently held by the proccess (struct file) */
+currently held by the process (struct file) */
#define SEP_DRIVER_OWN_LOCK_FLAG 1
/* flag that signifies tah the lock is currently NOT
-held by the proccess (struct file) */
+held by the process (struct file) */
#define SEP_DRIVER_DISOWN_LOCK_FLAG 0
/* indicates whether driver has mapped/unmapped shared area */
@@ -280,7 +280,7 @@ held by the proccess (struct file) */
/*
* Used to limit number of concurrent processes
- * allowed to allocte dynamic buffers in fastcall
+ * allowed to allocate dynamic buffers in fastcall
* interface.
*/
#define SEP_DOUBLEBUF_USERS_LIMIT 3
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index f1701bc..df1d13e 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -786,7 +786,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait)
"[PID%d] poll: send_ct is %lx reply ct is %lx\n",
current->pid, sep->send_ct, sep->reply_ct);
- /* Check if error occured during poll */
+ /* Check if error occurred during poll */
retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
if ((retval2 != 0x0) && (retval2 != 0x8)) {
dev_dbg(&sep->pdev->dev, "[PID%d] poll; poll error %x\n",
@@ -1160,7 +1160,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep,
/* Put mapped kernel sg into kernel resource array */
- /* Set output params acording to the in_out flag */
+ /* Set output params according to the in_out flag */
if (in_out_flag == SEP_DRIVER_IN_FLAG) {
*lli_array_ptr = lli_array;
dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -1358,7 +1358,7 @@ static int sep_lock_user_pages(struct sep_device *sep,
lli_array[num_pages - 1].block_size);
}
- /* Set output params acording to the in_out flag */
+ /* Set output params according to the in_out flag */
if (in_out_flag == SEP_DRIVER_IN_FLAG) {
*lli_array_ptr = lli_array;
dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -2038,7 +2038,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep,
/*
* If this is not the last table -
- * then allign it to the block size
+ * then align it to the block size
*/
if (!last_table_flag)
table_data_size =
@@ -3033,7 +3033,7 @@ static int sep_free_dcb_handler(struct sep_device *sep,
* @cmd: command
* @arg: pointer to argument structure
*
- * Implement the ioctl methods availble on the SEP device.
+ * Implement the ioctl methods available on the SEP device.
*/
static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -4460,7 +4460,7 @@ static int sep_pm_runtime_suspend(struct device *dev)
* @sep_pm_runtime_resume: resume- no communication with cpu & main memory
* @sep_pm_runtime_suspend: suspend- no communication with cpu & main memory
* @sep_pci_suspend: suspend - main memory is still ON
- * @sep_pci_resume: resume - main meory is still ON
+ * @sep_pci_resume: resume - main memory is still ON
*/
static const struct dev_pm_ops sep_pm = {
.runtime_resume = sep_pm_runtime_resume,
diff --git a/drivers/staging/serial/68360serial.c b/drivers/staging/serial/68360serial.c
deleted file mode 100644
index daf0b1d..0000000
--- a/drivers/staging/serial/68360serial.c
+++ /dev/null
@@ -1,2979 +0,0 @@
-/*
- * UART driver for 68360 CPM SCC or SMC
- * Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
- * Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
- * Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *
- * I used the serial.c driver as the framework for this driver.
- * Give credit to those guys.
- * The original code was written for the MBX860 board. I tried to make
- * it generic, but there may be some assumptions in the structures that
- * have to be fixed later.
- * To save porting time, I did not bother to change any object names
- * that are not accessed outside of this file.
- * It still needs lots of work........When it was easy, I included code
- * to support the SCCs, but this has never been tested, nor is it complete.
- * Only the SCCs support modem control, so that is not complete either.
- *
- * This module exports the following rs232 io functions:
- *
- * int rs_360_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int kgdb_output_string (const char* s, unsigned int count);
-#endif
-
-
-/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
-#include <linux/console.h>
-#include <linux/jiffies.h>
-
-/* this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */
-#endif
-/* #endif */
-
-#if 0
-/* SCC2 for console
- */
-#undef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT 2
-#endif
-
-
-#define TX_WAKEUP ASYNC_SHARE_IRQ
-
-static char *serial_name = "CPM UART driver";
-static char *serial_version = "0.03";
-
-static struct tty_driver *serial_driver;
-int serial_console_setup(struct console *co, char *options);
-
-/*
- * Serial driver configuration section. Here are the various options:
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
-#define _INLINE_ inline
-
-#define DBG_CNT(s)
-
-/* We overload some of the items in the data structure to meet our
- * needs. For example, the port address is the CPM parameter ram
- * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and
- * 2 SMCs. The "hub6" field is used to indicate the channel number, with
- * a flag indicating SCC or SMC, and the number is used as an index into
- * the CPM parameter area for this device.
- * The "type" field is currently set to 0, for PORT_UNKNOWN. It is
- * not currently used. I should probably use it to indicate the port
- * type of SMC or SCC.
- * The SMCs do not support any modem control signals.
- */
-#define smc_scc_num hub6
-#define NUM_IS_SCC ((int)0x00010000)
-#define PORT_NUM(P) ((P) & 0x0000ffff)
-
-
-#if defined (CONFIG_UCQUICC)
-
-volatile extern void *_periph_base;
-/* sipex transceiver
- * mode bits for are on pins
- *
- * SCC2 d16..19
- * SCC3 d20..23
- * SCC4 d24..27
- */
-#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
-
-static uint sipex_mode_bits = 0x00000000;
-
-#endif
-
-/* There is no `serial_state' defined back here in 2.0.
- * Try to get by with serial_struct
- */
-/* #define serial_state serial_struct */
-
-/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
- * extras: */
-
-#if 0
-struct async_icount_24 {
- __u32 cts, dsr, rng, dcd, tx, rx;
- __u32 frame, parity, overrun, brk;
- __u32 buf_overrun;
-} icount;
-#endif
-
-#if 0
-
-struct serial_state {
- int magic;
- int baud_base;
- unsigned long port;
- int irq;
- int flags;
- int hub6;
- int type;
- int line;
- int revision; /* Chip revision (950) */
- int xmit_fifo_size;
- int custom_divisor;
- int count;
- u8 *iomem_base;
- u16 iomem_reg_shift;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
- struct async_icount_24 icount;
- int io_type;
- struct async_struct *info;
-};
-#endif
-
-#define SSTATE_MAGIC 0x5302
-
-
-
-/* SMC2 is sometimes used for low performance TDM interfaces. Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-
-#if 0
-/* Define SCC to ttySx mapping. */
-#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port. These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE 1 /* table index */
-#endif
-
-
-/* Processors other than the 860 only get SMCs configured by default.
- * Either they don't have SCCs or they are allocated somewhere else.
- * Of course, there are now 860s without some SCCs, so we will need to
- * address that someday.
- * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
- * stereo codec parts, and we use SMC2 to help support that.
- */
-static struct serial_state rs_table[] = {
-/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */
- { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */
-#if USE_SMC2
- ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */
-#endif
-
-#if defined(CONFIG_SERIAL_68360_SCC)
- ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */
- ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */
- ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */
-#endif
-};
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
-
-/* The number of buffer descriptors and their sizes.
- */
-#define RX_NUM_FIFO 4
-#define RX_BUF_SIZE 32
-#define TX_NUM_FIFO 4
-#define TX_BUF_SIZE 32
-
-#define CONSOLE_NUM_FIFO 2
-#define CONSOLE_BUF_SIZE 4
-
-char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
-
-/* The async_struct in serial.h does not really give us what we
- * need, so define our own here.
- */
-typedef struct serial_info {
- int magic;
- int flags;
-
- struct serial_state *state;
- /* struct serial_struct *state; */
- /* struct async_struct *state; */
-
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int line;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int blocked_open; /* # of blocked opens */
- struct work_struct tqueue;
- struct work_struct tqueue_hangup;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
-
-/* CPM Buffer Descriptor pointers.
- */
- QUICC_BD *rx_bd_base;
- QUICC_BD *rx_cur;
- QUICC_BD *tx_bd_base;
- QUICC_BD *tx_cur;
-} ser_info_t;
-
-
-/* since kmalloc_init() does not get called until much after this initialization: */
-static ser_info_t quicc_ser_info[NR_PORTS];
-static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
-static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
-
-static void change_speed(ser_info_t *info);
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(ser_info_t *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "Warning: null async_struct for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts,
- * indexed by the termio value. The generic CPM functions are responsible
- * for setting and assigning baud rate generators for us.
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-/* This sucks. There is a better way: */
-#if defined(CONFIG_CONSOLE_9600)
- #define CONSOLE_BAUDRATE 9600
-#elif defined(CONFIG_CONSOLE_19200)
- #define CONSOLE_BAUDRATE 19200
-#elif defined(CONFIG_CONSOLE_115200)
- #define CONSOLE_BAUDRATE 115200
-#else
- #warning "console baud rate undefined"
- #define CONSOLE_BAUDRATE 9600
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_360_stop(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int idx;
- unsigned long flags;
- volatile struct scc_regs *sccp;
- volatile struct smc_regs *smcp;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm &= ~UART_SCCM_TX;
- } else {
- /* smcp = &cpmp->cp_smc[idx]; */
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm &= ~SMCM_TX;
- }
- local_irq_restore(flags);
-}
-
-
-static void rs_360_start(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int idx;
- unsigned long flags;
- volatile struct scc_regs *sccp;
- volatile struct smc_regs *smcp;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm |= UART_SCCM_TX;
- } else {
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm |= SMCM_TX;
- }
- local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off. People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible. After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static _INLINE_ void receive_chars(ser_info_t *info)
-{
- struct tty_struct *tty = info->port.tty;
- unsigned char ch, flag, *cp;
- /*int ignored = 0;*/
- int i;
- ushort status;
- struct async_icount *icount;
- /* struct async_icount_24 *icount; */
- volatile QUICC_BD *bdp;
-
- icount = &info->state->icount;
-
- /* Just loop through the closed BDs and copy the characters into
- * the buffer.
- */
- bdp = info->rx_cur;
- for (;;) {
- if (bdp->status & BD_SC_EMPTY) /* If this one is empty */
- break; /* we are all done */
-
- /* The read status mask tell us what we should do with
- * incoming characters, especially if errors occur.
- * One special case is the use of BD_SC_EMPTY. If
- * this is not set, we are supposed to be ignoring
- * inputs. In this case, just mark the buffer empty and
- * continue.
- */
- if (!(info->read_status_mask & BD_SC_EMPTY)) {
- bdp->status |= BD_SC_EMPTY;
- bdp->status &=
- ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
- if (bdp->status & BD_SC_WRAP)
- bdp = info->rx_bd_base;
- else
- bdp++;
- continue;
- }
-
- /* Get the number of characters and the buffer pointer.
- */
- i = bdp->length;
- /* cp = (unsigned char *)__va(bdp->buf); */
- cp = (char *)bdp->buf;
- status = bdp->status;
-
- while (i-- > 0) {
- ch = *cp++;
- icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
- printk("DR%02x:%02x...", ch, status);
-#endif
- flag = TTY_NORMAL;
-
- if (status & (BD_SC_BR | BD_SC_FR |
- BD_SC_PR | BD_SC_OV)) {
- /*
- * For statistics only
- */
- if (status & BD_SC_BR)
- icount->brk++;
- else if (status & BD_SC_PR)
- icount->parity++;
- else if (status & BD_SC_FR)
- icount->frame++;
- if (status & BD_SC_OV)
- icount->overrun++;
-
- /*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
- if (status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- continue;
- }
- */
- status &= info->read_status_mask;
-
- if (status & (BD_SC_BR)) {
-#ifdef SERIAL_DEBUG_INTR
- printk("handling break....");
-#endif
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- if (info->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (status & BD_SC_PR)
- flag = TTY_PARITY;
- else if (status & BD_SC_FR)
- flag = TTY_FRAME;
- }
- tty_insert_flip_char(tty, ch, flag);
- if (status & BD_SC_OV)
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- }
-
- /* This BD is ready to be used again. Clear status.
- * Get next BD.
- */
- bdp->status |= BD_SC_EMPTY;
- bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
- if (bdp->status & BD_SC_WRAP)
- bdp = info->rx_bd_base;
- else
- bdp++;
- }
-
- info->rx_cur = (QUICC_BD *)bdp;
-
- tty_schedule_flip(tty);
-}
-
-static _INLINE_ void receive_break(ser_info_t *info)
-{
- struct tty_struct *tty = info->port.tty;
-
- info->state->icount.brk++;
- /* Check to see if there is room in the tty buffer for
- * the break. If not, we exit now, losing the break. FIXME
- */
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
-}
-
-static _INLINE_ void transmit_chars(ser_info_t *info)
-{
-
- if ((info->flags & TX_WAKEUP) ||
- (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
- schedule_work(&info->tqueue);
- }
-
-#ifdef SERIAL_DEBUG_INTR
- printk("THRE...");
-#endif
-}
-
-#ifdef notdef
- /* I need to do this for the SCCs, so it is left as a reminder.
- */
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
- int status;
- /* struct async_icount *icount; */
- struct async_icount_24 *icount;
-
- status = serial_in(info, UART_MSR);
-
- if (status & UART_MSR_ANY_DELTA) {
- icount = &info->state->icount;
- /* update input line counters */
- if (status & UART_MSR_TERI)
- icount->rng++;
- if (status & UART_MSR_DDSR)
- icount->dsr++;
- if (status & UART_MSR_DDCD) {
- icount->dcd++;
-#ifdef CONFIG_HARD_PPS
- if ((info->flags & ASYNC_HARDPPS_CD) &&
- (status & UART_MSR_DCD))
- hardpps();
-#endif
- }
- if (status & UART_MSR_DCTS)
- icount->cts++;
- wake_up_interruptible(&info->delta_msr_wait);
- }
-
- if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
- printk("ttys%d CD now %s...", info->line,
- (status & UART_MSR_DCD) ? "on" : "off");
-#endif
- if (status & UART_MSR_DCD)
- wake_up_interruptible(&info->open_wait);
- else {
-#ifdef SERIAL_DEBUG_OPEN
- printk("scheduling hangup...");
-#endif
- queue_task(&info->tqueue_hangup,
- &tq_scheduler);
- }
- }
- if (info->flags & ASYNC_CTS_FLOW) {
- if (info->port.tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx start...");
-#endif
- info->port.tty->hw_stopped = 0;
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
- return;
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx stop...");
-#endif
- info->port.tty->hw_stopped = 1;
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- }
- }
-}
-#endif
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id)
-{
- u_char events;
- int idx;
- ser_info_t *info;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- info = dev_id;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- events = sccp->scc_scce;
- if (events & SCCM_RX)
- receive_chars(info);
- if (events & SCCM_TX)
- transmit_chars(info);
- sccp->scc_scce = events;
- } else {
- smcp = &pquicc->smc_regs[idx];
- events = smcp->smc_smce;
- if (events & SMCM_BRKE)
- receive_break(info);
- if (events & SMCM_RX)
- receive_chars(info);
- if (events & SMCM_TX)
- transmit_chars(info);
- smcp->smc_smce = events;
- }
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_single(%d, %x)...",
- info->state->smc_scc_num, events);
-#endif
-#ifdef modem_control
- check_modem_status(info);
-#endif
- info->last_active = jiffies;
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-
-static void do_softint(void *private_)
-{
- ser_info_t *info = (ser_info_t *) private_;
- struct tty_struct *tty;
-
- tty = info->port.tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_serial_hangup() -> tty->hangup() -> rs_hangup()
- *
- */
-static void do_serial_hangup(void *private_)
-{
- struct async_struct *info = (struct async_struct *) private_;
- struct tty_struct *tty;
-
- tty = info->port.tty;
- if (!tty)
- return;
-
- tty_hangup(tty);
-}
-
-
-static int startup(ser_info_t *info)
-{
- unsigned long flags;
- int retval=0;
- int idx;
- /*struct serial_state *state = info->state;*/
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
- volatile struct smc_uart_pram *up;
- volatile struct uart_pram *scup;
-
-
- local_irq_save(flags);
-
- if (info->flags & ASYNC_INITIALIZED) {
- goto errout;
- }
-
-#ifdef maybe
- if (!state->port || !state->type) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- goto errout;
- }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-
-#ifdef modem_control
- info->MCR = 0;
- if (info->port.tty->termios->c_cflag & CBAUD)
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#endif
-
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- /*
- * and set the speed of the serial port
- */
- change_speed(info);
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- scup = &pquicc->pram[info->state->port].scc.pscc.u;
-
- scup->mrblr = RX_BUF_SIZE;
- scup->max_idl = RX_BUF_SIZE;
-
- sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
- sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Enable interrupts and I/O.
- */
- smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
- smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
-
- /* We can tune the buffer length and idle characters
- * to take advantage of the entire incoming buffer size.
- * If mrblr is something other than 1, maxidl has to be
- * non-zero or we never get an interrupt. The maxidl
- * is the number of character times we wait after reception
- * of the last character before we decide no more characters
- * are coming.
- */
- /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
- /* holy unionized structures, Batman: */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
- up->mrblr = RX_BUF_SIZE;
- up->max_idl = RX_BUF_SIZE;
-
- up->brkcr = 1; /* number of break chars */
- }
-
- info->flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-
-errout:
- local_irq_restore(flags);
- return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(ser_info_t *info)
-{
- unsigned long flags;
- struct serial_state *state;
- int idx;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....", info->line,
- state->irq);
-#endif
-
- local_irq_save(flags);
-
- idx = PORT_NUM(state->smc_scc_num);
- if (state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#ifdef CONFIG_SERIAL_CONSOLE
- /* We can't disable the transmitter if this is the
- * system console.
- */
- if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
- sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Disable interrupts and I/O.
- */
- smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-#ifdef CONFIG_SERIAL_CONSOLE
- /* We can't disable the transmitter if this is the
- * system console.
- */
- if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
- smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- }
-
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- info->flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(ser_info_t *info)
-{
- int baud_rate;
- unsigned cflag, cval, scval, prev_mode;
- int i, bits, sbits, idx;
- unsigned long flags;
- struct serial_state *state;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!info->port.tty || !info->port.tty->termios)
- return;
- cflag = info->port.tty->termios->c_cflag;
-
- state = info->state;
-
- /* Character length programmed into the mode register is the
- * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
- * 1 or 2 stop bits, minus 1.
- * The value 'bits' counts this for us.
- */
- cval = 0;
- scval = 0;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: bits = 5; break;
- case CS6: bits = 6; break;
- case CS7: bits = 7; break;
- case CS8: bits = 8; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: bits = 8; break;
- }
- sbits = bits - 5;
-
- if (cflag & CSTOPB) {
- cval |= SMCMR_SL; /* Two stops */
- scval |= SCU_PMSR_SL;
- bits++;
- }
- if (cflag & PARENB) {
- cval |= SMCMR_PEN;
- scval |= SCU_PMSR_PEN;
- bits++;
- }
- if (!(cflag & PARODD)) {
- cval |= SMCMR_PM_EVEN;
- scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
- }
-
- /* Determine divisor based on baud rate */
- i = cflag & CBAUD;
- if (i >= (sizeof(baud_table)/sizeof(int)))
- baud_rate = 9600;
- else
- baud_rate = baud_table[i];
-
- info->timeout = (TX_BUF_SIZE*HZ*bits);
- info->timeout += HZ/50; /* Add .02 seconds of slop */
-
-#ifdef modem_control
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- if (info->flags & ASYNC_HARDPPS_CD)
- info->IER |= UART_IER_MSI;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- info->IER |= UART_IER_MSI;
- } else
- info->flags &= ~ASYNC_CTS_FLOW;
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
- }
- serial_out(info, UART_IER, info->IER);
-#endif
-
- /*
- * Set up parity check flag
- */
- info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
- if (I_INPCK(info->port.tty))
- info->read_status_mask |= BD_SC_FR | BD_SC_PR;
- if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
- info->read_status_mask |= BD_SC_BR;
-
- /*
- * Characters to ignore
- */
- info->ignore_status_mask = 0;
- if (I_IGNPAR(info->port.tty))
- info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
- if (I_IGNBRK(info->port.tty)) {
- info->ignore_status_mask |= BD_SC_BR;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->port.tty))
- info->ignore_status_mask |= BD_SC_OV;
- }
- /*
- * !!! ignore all characters if CREAD is not set
- */
- if ((cflag & CREAD) == 0)
- info->read_status_mask &= ~BD_SC_EMPTY;
- local_irq_save(flags);
-
- /* Start bit has not been added (so don't, because we would just
- * subtract it later), and we need to add one for the number of
- * stops bits (there is always at least one).
- */
- bits++;
- idx = PORT_NUM(state->smc_scc_num);
- if (state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_psmr = (sbits << 12) | scval;
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Set the mode register. We want to keep a copy of the
- * enables, because we want to put them back if they were
- * present.
- */
- prev_mode = smcp->smc_smcmr;
- smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
- smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
- }
-
- m360_cpm_setbrg((state - rs_table), baud_rate);
-
- local_irq_restore(flags);
-}
-
-static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- volatile QUICC_BD *bdp;
-
- if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return 0;
-
- if (!tty)
- return 0;
-
- bdp = info->tx_cur;
- while (bdp->status & BD_SC_READY);
-
- /* *((char *)__va(bdp->buf)) = ch; */
- *((char *)bdp->buf) = ch;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
-
- info->tx_cur = (QUICC_BD *)bdp;
- return 1;
-
-}
-
-static int rs_360_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, ret = 0;
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- volatile QUICC_BD *bdp;
-
-#ifdef CONFIG_KGDB
- /* Try to let stub handle output. Returns true if it did. */
- if (kgdb_output_string(buf, count))
- return ret;
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty)
- return 0;
-
- bdp = info->tx_cur;
-
- while (1) {
- c = min(count, TX_BUF_SIZE);
-
- if (c <= 0)
- break;
-
- if (bdp->status & BD_SC_READY) {
- info->flags |= TX_WAKEUP;
- break;
- }
-
- /* memcpy(__va(bdp->buf), buf, c); */
- memcpy((void *)bdp->buf, buf, c);
-
- bdp->length = c;
- bdp->status |= BD_SC_READY;
-
- buf += c;
- count -= c;
- ret += c;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
- info->tx_cur = (QUICC_BD *)bdp;
- }
- return ret;
-}
-
-static int rs_360_write_room(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
-
- if ((info->tx_cur->status & BD_SC_READY) == 0) {
- info->flags &= ~TX_WAKEUP;
- ret = TX_BUF_SIZE;
- }
- else {
- info->flags |= TX_WAKEUP;
- ret = 0;
- }
- return ret;
-}
-
-/* I could track this with transmit counters....maybe later.
-*/
-static int rs_360_chars_in_buffer(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return 0;
-}
-
-static void rs_360_flush_buffer(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
-
- /* There is nothing to "flush", whatever we gave the CPM
- * is on its way out.
- */
- tty_wakeup(tty);
- info->flags &= ~TX_WAKEUP;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_360_send_xchar(struct tty_struct *tty, char ch)
-{
- volatile QUICC_BD *bdp;
-
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_send_char"))
- return;
-
- bdp = info->tx_cur;
- while (bdp->status & BD_SC_READY);
-
- /* *((char *)__va(bdp->buf)) = ch; */
- *((char *)bdp->buf) = ch;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
-
- info->tx_cur = (QUICC_BD *)bdp;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_360_throttle(struct tty_struct * tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- rs_360_send_xchar(tty, STOP_CHAR(tty));
-
-#ifdef modem_control
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR &= ~UART_MCR_RTS;
-
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
-}
-
-static void rs_360_unthrottle(struct tty_struct * tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- rs_360_send_xchar(tty, START_CHAR(tty));
- }
-#ifdef modem_control
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR |= UART_MCR_RTS;
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#ifdef maybe
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
- unsigned char status;
- unsigned int result;
-
- local_irq_disable();
- status = serial_in(info, UART_LSR);
- local_irq_enable();
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
-}
-#endif
-
-static int rs_360_tiocmget(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned int result = 0;
-#ifdef modem_control
- unsigned char control, status;
-
- if (serial_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- control = info->MCR;
- local_irq_disable();
- status = serial_in(info, UART_MSR);
- local_irq_enable();
- result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
- | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
- | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-#endif
- return result;
-}
-
-static int rs_360_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
-#ifdef modem_control
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned int arg;
-
- if (serial_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- /* FIXME: locking on info->mcr */
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR)
- info->mcr |= UART_MCR_DTR;
- if (clear & TIOCM_RTS)
- info->MCR &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR)
- info->MCR &= ~UART_MCR_DTR;
-
-#ifdef TIOCM_OUT1
- if (set & TIOCM_OUT1)
- info->MCR |= UART_MCR_OUT1;
- if (set & TIOCM_OUT2)
- info->MCR |= UART_MCR_OUT2;
- if (clear & TIOCM_OUT1)
- info->MCR &= ~UART_MCR_OUT1;
- if (clear & TIOCM_OUT2)
- info->MCR &= ~UART_MCR_OUT2;
-#endif
-
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
- return 0;
-}
-
-/* Sending a break is a two step process on the SMC/SCC. It is accomplished
- * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
- * command. We take advantage of the begin/end functions to make this
- * happen.
- */
-static ushort smc_chan_map[] = {
- CPM_CR_CH_SMC1,
- CPM_CR_CH_SMC2
-};
-
-static ushort scc_chan_map[] = {
- CPM_CR_CH_SCC1,
- CPM_CR_CH_SCC2,
- CPM_CR_CH_SCC3,
- CPM_CR_CH_SCC4
-};
-
-static void begin_break(ser_info_t *info)
-{
- volatile QUICC *cp;
- ushort chan;
- int idx;
-
- cp = pquicc;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC)
- chan = scc_chan_map[idx];
- else
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-}
-
-static void end_break(ser_info_t *info)
-{
- volatile QUICC *cp;
- ushort chan;
- int idx;
-
- cp = pquicc;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC)
- chan = scc_chan_map[idx];
- else
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(ser_info_t *info, unsigned int duration)
-{
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
- begin_break(info);
- msleep_interruptible(duration);
- end_break(info);
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
-static int rs_360_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- struct async_icount cnow;
-
- local_irq_disable();
- cnow = info->state->icount;
- local_irq_enable();
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
-
- return 0;
-}
-
-static int rs_360_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- int error;
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int retval;
- struct async_icount cnow;
- /* struct async_icount_24 cnow;*/ /* kernel counter temps */
- struct serial_icounter_struct *p_cuser; /* user space */
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if (cmd != TIOCMIWAIT) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, 250); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*100 : 250);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCSBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- begin_break(info);
- return 0;
- case TIOCCBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- end_break(info);
- return 0;
-#ifdef maybe
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-#endif
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
-#ifdef modem_control
- local_irq_disable();
- /* note the counters on entry */
- cprev = info->state->icount;
- local_irq_enable();
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- local_irq_disable();
- cnow = info->state->icount; /* atomic copy */
- local_irq_enable();
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
-#else
- return 0;
-#endif
-
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-/* FIX UP modem control here someday......
-*/
-static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- change_speed(info);
-
-#ifdef modem_control
- /* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) &&
- !(tty->termios->c_cflag & CBAUD)) {
- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
- }
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- (tty->termios->c_cflag & CBAUD)) {
- info->MCR |= UART_MCR_DTR;
- if (!tty->hw_stopped ||
- !(tty->termios->c_cflag & CRTSCTS)) {
- info->MCR |= UART_MCR_RTS;
- }
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- rs_360_start(tty);
- }
-#endif
-
-#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_360_close(struct tty_struct *tty, struct file * filp)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- /* struct async_state *state; */
- struct serial_state *state;
- unsigned long flags;
- int idx;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- state = info->state;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- DBG_CNT("before DEC-hung");
- local_irq_restore(flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
- if ((tty->count == 1) && (state->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. state->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "state->count is %d\n", state->count);
- state->count = 1;
- }
- if (--state->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
- info->line, state->count);
- state->count = 0;
- }
- if (state->count) {
- DBG_CNT("before DEC-2");
- local_irq_restore(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- info->read_status_mask &= ~BD_SC_EMPTY;
- if (info->flags & ASYNC_INITIALIZED) {
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm &= ~UART_SCCM_RX;
- sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
- } else {
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm &= ~SMCM_RX;
- smcp->smc_smcmr &= ~SMCMR_REN;
- }
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- rs_360_wait_until_sent(tty, info->timeout);
- }
- shutdown(info);
- rs_360_flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->port.tty = NULL;
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
- local_irq_restore(flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned long orig_jiffies, char_time;
- /*int lsr;*/
- volatile QUICC_BD *bdp;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
-#ifdef maybe
- if (info->state->type == PORT_UNKNOWN)
- return;
-#endif
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- char_time = 1;
- if (timeout)
- char_time = min(char_time, (unsigned long)timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
-#endif
-
- /* We go through the loop at least once because we can't tell
- * exactly when the last character exits the shifter. There can
- * be at least two characters waiting to be sent after the buffers
- * are empty.
- */
- do {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-/* current->counter = 0; make us low-priority */
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
- break;
- /* The 'tx_cur' is really the next buffer to send. We
- * have to back up to the previous BD and wait for it
- * to go. This isn't perfect, because all this indicates
- * is the buffer is available. There are still characters
- * in the CPM FIFO.
- */
- bdp = info->tx_cur;
- if (bdp == info->tx_bd_base)
- bdp += (TX_NUM_FIFO-1);
- else
- bdp--;
- } while (bdp->status & BD_SC_READY);
- current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_360_hangup(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- struct serial_state *state = info->state;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- state = info->state;
-
- rs_360_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- state->count = 0;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->port.tty = NULL;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- ser_info_t *info)
-{
-#ifdef DO_THIS_LATER
- DECLARE_WAITQUEUE(wait, current);
-#endif
- struct serial_state *state = info->state;
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- * If this is an SMC port, we don't have modem control to wait
- * for, so just get out here.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR)) ||
- !(info->state->smc_scc_num & NUM_IS_SCC)) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, state->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
-#ifdef DO_THIS_LATER
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
- state->line, state->count);
-#endif
- local_irq_disable();
- if (!tty_hung_up_p(filp))
- state->count--;
- local_irq_enable();
- info->blocked_open++;
- while (1) {
- local_irq_disable();
- if (tty->termios->c_cflag & CBAUD)
- serial_out(info, UART_MCR,
- serial_inp(info, UART_MCR) |
- (UART_MCR_DTR | UART_MCR_RTS));
- local_irq_enable();
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ASYNC_CLOSING) &&
- (do_clocal || (serial_in(info, UART_MSR) &
- UART_MSR_DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
- tty_unlock();
- schedule();
- tty_lock();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- state->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
-#endif /* DO_THIS_LATER */
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-static int get_async_struct(int line, ser_info_t **ret_info)
-{
- struct serial_state *sstate;
-
- sstate = rs_table + line;
- if (sstate->info) {
- sstate->count++;
- *ret_info = (ser_info_t *)sstate->info;
- return 0;
- }
- else {
- return -ENOMEM;
- }
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_360_open(struct tty_struct *tty, struct file * filp)
-{
- ser_info_t *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= NR_PORTS))
- return -ENODEV;
- retval = get_async_struct(line, &info);
- if (retval)
- return retval;
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
- tty->driver_data = info;
- info->port.tty = tty;
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s successful...", tty->name);
-#endif
- return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
-#ifdef notdef
- struct async_struct *info = state->info, scr_info;
- char stat_buf[30], control, status;
-#endif
- int ret;
-
- ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
- state->line,
- (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
- (unsigned int)(state->port), state->irq);
-
- if (!state->port || (state->type == PORT_UNKNOWN)) {
- ret += sprintf(buf+ret, "\n");
- return ret;
- }
-
-#ifdef notdef
- /*
- * Figure out the current RS-232 lines
- */
- if (!info) {
- info = &scr_info; /* This is just for serial_{in,out} */
-
- info->magic = SERIAL_MAGIC;
- info->port = state->port;
- info->flags = state->flags;
- info->quot = 0;
- info->port.tty = NULL;
- }
- local_irq_disable();
- status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
- local_irq_enable();
-
- stat_buf[0] = 0;
- stat_buf[1] = 0;
- if (control & UART_MCR_RTS)
- strcat(stat_buf, "|RTS");
- if (status & UART_MSR_CTS)
- strcat(stat_buf, "|CTS");
- if (control & UART_MCR_DTR)
- strcat(stat_buf, "|DTR");
- if (status & UART_MSR_DSR)
- strcat(stat_buf, "|DSR");
- if (status & UART_MSR_DCD)
- strcat(stat_buf, "|CD");
- if (status & UART_MSR_RI)
- strcat(stat_buf, "|RI");
-
- if (info->quot) {
- ret += sprintf(buf+ret, " baud:%d",
- state->baud_base / info->quot);
- }
-
- ret += sprintf(buf+ret, " tx:%d rx:%d",
- state->icount.tx, state->icount.rx);
-
- if (state->icount.frame)
- ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-
- if (state->icount.parity)
- ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-
- if (state->icount.brk)
- ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
-
- if (state->icount.overrun)
- ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
- /*
- * Last thing is the RS-232 status lines
- */
- ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-#endif
- return ret;
-}
-
-int rs_360_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int i, len = 0;
- off_t begin = 0;
-
- len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
- for (i = 0; i < NR_PORTS && len < 4000; i++) {
- len += line_info(page + len, &rs_table[i]);
- if (len+begin > off+count)
- goto done;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- *eof = 1;
-done:
- if (off >= len+begin)
- return 0;
- *start = page + (begin-off);
- return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_serial_version(void)
-{
- printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
-/*
- * The serial console driver used during boot. Note that these names
- * clash with those found in "serial.c", so we currently can't support
- * the 16xxx uarts and these at the same time. I will fix this to become
- * an indirect function call from tty_io.c (or something).
- */
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
- */
-static void my_console_write(int idx, const char *s,
- unsigned count)
-{
- struct serial_state *ser;
- ser_info_t *info;
- unsigned i;
- QUICC_BD *bdp, *bdbase;
- volatile struct smc_uart_pram *up;
- volatile u_char *cp;
-
- ser = rs_table + idx;
-
-
- /* If the port has been initialized for general use, we have
- * to use the buffer descriptors allocated there. Otherwise,
- * we simply use the single buffer allocated.
- */
- if ((info = (ser_info_t *)ser->info) != NULL) {
- bdp = info->tx_cur;
- bdbase = info->tx_bd_base;
- }
- else {
- /* Pointer to UART in parameter ram.
- */
- /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
- up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
- /* Get the address of the host memory buffer.
- */
- bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
- }
-
- /*
- * We need to gracefully shut down the transmitter, disable
- * interrupts, then send our bytes out.
- */
-
- /*
- * Now, do each character. This is not as bad as it looks
- * since this is a holding FIFO and not a transmitting FIFO.
- * We could add the complexity of filling the entire transmit
- * buffer, but we would just wait longer between accesses......
- */
- for (i = 0; i < count; i++, s++) {
- /* Wait for transmitter fifo to empty.
- * Ready indicates output is ready, and xmt is doing
- * that, not that it is ready for us to send.
- */
- while (bdp->status & BD_SC_READY);
-
- /* Send the character out.
- */
- cp = bdp->buf;
- *cp = *s;
-
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- if (bdp->status & BD_SC_WRAP)
- bdp = bdbase;
- else
- bdp++;
-
- /* if a LF, also do CR... */
- if (*s == 10) {
- while (bdp->status & BD_SC_READY);
- /* cp = __va(bdp->buf); */
- cp = bdp->buf;
- *cp = 13;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- if (bdp->status & BD_SC_WRAP) {
- bdp = bdbase;
- }
- else {
- bdp++;
- }
- }
- }
-
- /*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
- */
- while (bdp->status & BD_SC_READY);
-
- if (info)
- info->tx_cur = (QUICC_BD *)bdp;
-}
-
-static void serial_console_write(struct console *c, const char *s,
- unsigned count)
-{
-#ifdef CONFIG_KGDB
- /* Try to let stub handle output. Returns true if it did. */
- if (kgdb_output_string(s, count))
- return;
-#endif
- my_console_write(c->index, s, count);
-}
-
-
-
-/*void console_print_68360(const char *p)
-{
- const char *cp = p;
- int i;
-
- for (i=0;cp[i]!=0;i++);
-
- serial_console_write (p, i);
-
- //Comment this if you want to have a strict interrupt-driven output
- //rs_fair_output();
-
- return;
-}*/
-
-
-
-
-
-
-#ifdef CONFIG_XMON
-int
-xmon_360_write(const char *s, unsigned count)
-{
- my_console_write(0, s, count);
- return(count);
-}
-#endif
-
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
- my_console_write(0, &ch, 1);
-}
-#endif
-
-/*
- * Receive character from the serial port. This only works well
- * before the port is initialized for real use.
- */
-static int my_console_wait_key(int idx, int xmon, char *obuf)
-{
- struct serial_state *ser;
- u_char c, *cp;
- ser_info_t *info;
- QUICC_BD *bdp;
- volatile struct smc_uart_pram *up;
- int i;
-
- ser = rs_table + idx;
-
- /* Get the address of the host memory buffer.
- * If the port has been initialized for general use, we must
- * use information from the port structure.
- */
- if ((info = (ser_info_t *)ser->info))
- bdp = info->rx_cur;
- else
- /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
- bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-
- /* Pointer to UART in parameter ram.
- */
- /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
- /*
- * We need to gracefully shut down the receiver, disable
- * interrupts, then read the input.
- * XMON just wants a poll. If no character, return -1, else
- * return the character.
- */
- if (!xmon) {
- while (bdp->status & BD_SC_EMPTY);
- }
- else {
- if (bdp->status & BD_SC_EMPTY)
- return -1;
- }
-
- cp = (char *)bdp->buf;
-
- if (obuf) {
- i = c = bdp->length;
- while (i-- > 0)
- *obuf++ = *cp++;
- }
- else {
- c = *cp;
- }
- bdp->status |= BD_SC_EMPTY;
-
- if (info) {
- if (bdp->status & BD_SC_WRAP) {
- bdp = info->rx_bd_base;
- }
- else {
- bdp++;
- }
- info->rx_cur = (QUICC_BD *)bdp;
- }
-
- return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
- return(my_console_wait_key(co->index, 0, NULL));
-}
-
-#ifdef CONFIG_XMON
-int
-xmon_360_read_poll(void)
-{
- return(my_console_wait_key(0, 1, NULL));
-}
-
-int
-xmon_360_read_char(void)
-{
- return(my_console_wait_key(0, 0, NULL));
-}
-#endif
-
-#ifdef CONFIG_KGDB
-static char kgdb_buf[RX_BUF_SIZE], *kgdp;
-static int kgdb_chars;
-
-unsigned char
-getDebugChar(void)
-{
- if (kgdb_chars <= 0) {
- kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
- kgdp = kgdb_buf;
- }
- kgdb_chars--;
-
- return(*kgdp++);
-}
-
-void kgdb_interruptible(int state)
-{
-}
-void kgdb_map_scc(void)
-{
- struct serial_state *ser;
- uint mem_addr;
- volatile QUICC_BD *bdp;
- volatile smc_uart_t *up;
-
- cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-
- /* To avoid data cache CPM DMA coherency problems, allocate a
- * buffer in the CPM DPRAM. This will work until the CPM and
- * serial ports are initialized. At that time a memory buffer
- * will be allocated.
- * The port is already initialized from the boot procedure, all
- * we do here is give it a different buffer and make it a FIFO.
- */
-
- ser = rs_table;
-
- /* Right now, assume we are using SMCs.
- */
- up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
-
- /* Allocate space for an input FIFO, plus a few bytes for output.
- * Allocate bytes to maintain word alignment.
- */
- mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
-
- /* Set the physical address of the host memory buffers in
- * the buffer descriptors.
- */
- bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
- bdp->buf = mem_addr;
-
- bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
- bdp->buf = mem_addr+RX_BUF_SIZE;
-
- up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */
- up->smc_maxidl = RX_BUF_SIZE;
-}
-#endif
-
-static struct tty_struct *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-
-struct console sercons = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .wait_key = serial_console_wait_key,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = CONFIG_SERIAL_CONSOLE_PORT,
-};
-
-
-
-/*
- * Register console.
- */
-long console_360_init(long kmem_start, long kmem_end)
-{
- register_console(&sercons);
- /*register_console (console_print_68360); - 2.0.38 only required a write
- function pointer. */
- return kmem_start;
-}
-
-#endif
-
-/* Index in baud rate table of the default console baud rate.
-*/
-static int baud_idx;
-
-static const struct tty_operations rs_360_ops = {
- .owner = THIS_MODULE,
- .open = rs_360_open,
- .close = rs_360_close,
- .write = rs_360_write,
- .put_char = rs_360_put_char,
- .write_room = rs_360_write_room,
- .chars_in_buffer = rs_360_chars_in_buffer,
- .flush_buffer = rs_360_flush_buffer,
- .ioctl = rs_360_ioctl,
- .throttle = rs_360_throttle,
- .unthrottle = rs_360_unthrottle,
- /* .send_xchar = rs_360_send_xchar, */
- .set_termios = rs_360_set_termios,
- .stop = rs_360_stop,
- .start = rs_360_start,
- .hangup = rs_360_hangup,
- /* .wait_until_sent = rs_360_wait_until_sent, */
- /* .read_proc = rs_360_read_proc, */
- .tiocmget = rs_360_tiocmget,
- .tiocmset = rs_360_tiocmset,
- .get_icount = rs_360_get_icount,
-};
-
-static int __init rs_360_init(void)
-{
- struct serial_state * state;
- ser_info_t *info;
- void *mem_addr;
- uint dp_addr, iobits;
- int i, j, idx;
- ushort chan;
- QUICC_BD *bdp;
- volatile QUICC *cp;
- volatile struct smc_regs *sp;
- volatile struct smc_uart_pram *up;
- volatile struct scc_regs *scp;
- volatile struct uart_pram *sup;
- /* volatile immap_t *immap; */
-
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -1;
-
- show_serial_version();
-
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &rs_360_ops);
-
- if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver\n");
-
- cp = pquicc; /* Get pointer to Communication Processor */
- /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */
-
-
- /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
- */
- /* The "standard" configuration through the 860.
- */
-/* immap->im_ioport.iop_papar |= 0x00fc; */
-/* immap->im_ioport.iop_padir &= ~0x00fc; */
-/* immap->im_ioport.iop_paodr &= ~0x00fc; */
- cp->pio_papar |= 0x00fc;
- cp->pio_padir &= ~0x00fc;
- /* cp->pio_paodr &= ~0x00fc; */
-
-
- /* Since we don't yet do modem control, connect the port C pins
- * as general purpose I/O. This will assert CTS and CD for the
- * SCC ports.
- */
- /* FIXME: see 360um p.7-365 and 860um p.34-12
- * I can't make sense of these bits - mleslie*/
-/* immap->im_ioport.iop_pcdir |= 0x03c6; */
-/* immap->im_ioport.iop_pcpar &= ~0x03c6; */
-
-/* cp->pio_pcdir |= 0x03c6; */
-/* cp->pio_pcpar &= ~0x03c6; */
-
-
-
- /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and
- * BRG4 to SCC3.
- */
- cp->si_sicr &= ~0x00ffff00;
- cp->si_sicr |= 0x001b1200;
-
-#ifdef CONFIG_PP04
- /* Frequentis PP04 forced to RS-232 until we know better.
- * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
- */
- immap->im_ioport.iop_pcdir |= 0x000c;
- immap->im_ioport.iop_pcpar &= ~0x000c;
- immap->im_ioport.iop_pcdat &= ~0x000c;
-
- /* This enables the TX driver.
- */
- cp->cp_pbpar &= ~0x6000;
- cp->cp_pbdat &= ~0x6000;
-#endif
-
- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
- state->magic = SSTATE_MAGIC;
- state->line = i;
- state->type = PORT_UNKNOWN;
- state->custom_divisor = 0;
- state->close_delay = 5*HZ/10;
- state->closing_wait = 30*HZ;
- state->icount.cts = state->icount.dsr =
- state->icount.rng = state->icount.dcd = 0;
- state->icount.rx = state->icount.tx = 0;
- state->icount.frame = state->icount.parity = 0;
- state->icount.overrun = state->icount.brk = 0;
- printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
- i, (unsigned int)(state->irq),
- (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
-
-#ifdef CONFIG_SERIAL_CONSOLE
- /* If we just printed the message on the console port, and
- * we are about to initialize it for general use, we have
- * to wait a couple of character times for the CR/NL to
- * make it out of the transmit buffer.
- */
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- mdelay(8);
-
-
-/* idx = PORT_NUM(info->state->smc_scc_num); */
-/* if (info->state->smc_scc_num & NUM_IS_SCC) */
-/* chan = scc_chan_map[idx]; */
-/* else */
-/* chan = smc_chan_map[idx]; */
-
-/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
-/* while (cp->cp_cr & CPM_CR_FLG); */
-
-#endif
- /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
- info = &quicc_ser_info[i];
- if (info) {
- memset (info, 0, sizeof(ser_info_t));
- info->magic = SERIAL_MAGIC;
- info->line = i;
- info->flags = state->flags;
- INIT_WORK(&info->tqueue, do_softint, info);
- INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- info->state = state;
- state->info = (struct async_struct *)info;
-
- /* We need to allocate a transmit and receive buffer
- * descriptors from dual port ram, and a character
- * buffer area from host mem.
- */
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
-
- /* Allocate space for FIFOs in the host memory.
- * (for now this is from a static array of buffers :(
- */
- /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
- /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
- mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- info->rx_cur = info->rx_bd_base = bdp;
-
- /* initialize rx buffer descriptors */
- for (j=0; j<(RX_NUM_FIFO-1); j++) {
- bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
- bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
- mem_addr += RX_BUF_SIZE;
- bdp++;
- }
- bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
- bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
-
-#if defined (CONFIG_UCQUICC) && 1
- /* set the transceiver mode to RS232 */
- sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
- sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
- *(uint *)_periph_base = sipex_mode_bits;
- /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
-#endif
- }
-
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
-
- /* Allocate space for FIFOs in the host memory.
- */
- /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
- /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
- mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
-
- /* initialize tx buffer descriptors */
- for (j=0; j<(TX_NUM_FIFO-1); j++) {
- bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
- bdp->status = BD_SC_INTRPT;
- mem_addr += TX_BUF_SIZE;
- bdp++;
- }
- bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
- bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
-
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- scp = &pquicc->scc_regs[idx];
- sup = &pquicc->pram[info->state->port].scc.pscc.u;
- sup->rbase = dp_addr;
- sup->tbase = dp_addr;
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- sup->rfcr = SMC_EB;
- sup->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- sup->mrblr = 1;
- sup->max_idl = 0;
- sup->brkcr = 1;
- sup->parec = 0;
- sup->frmer = 0;
- sup->nosec = 0;
- sup->brkec = 0;
- sup->uaddr1 = 0;
- sup->uaddr2 = 0;
- sup->toseq = 0;
- {
- int i;
- for (i=0;i<8;i++)
- sup->cc[i] = 0x8000;
- }
- sup->rccm = 0xc0ff;
-
- /* Send the CPM an initialize command.
- */
- chan = scc_chan_map[idx];
-
- /* execute the INIT RX & TX PARAMS command for this channel. */
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- scp->scc_gsmr.w.high = 0;
- scp->scc_gsmr.w.low =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
-
- /* If the port is the console, enable Rx and Tx.
- */
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
- }
- else {
- /* Configure SMCs Tx/Rx instead of port B
- * parallel I/O.
- */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
- up->rbase = dp_addr;
-
- iobits = 0xc0 << (idx * 4);
- cp->pip_pbpar |= iobits;
- cp->pip_pbdir &= ~iobits;
- cp->pip_pbodr &= ~iobits;
-
-
- /* Connect the baud rate generator to the
- * SMC based upon index in rs_table. Also
- * make sure it is connected to NMSI.
- */
- cp->si_simode &= ~(0xffff << (idx * 16));
- cp->si_simode |= (i << ((idx * 16) + 12));
-
- up->tbase = dp_addr;
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- up->rfcr = SMC_EB;
- up->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- up->mrblr = 1;
- up->max_idl = 0;
- up->brkcr = 1;
-
- /* Send the CPM an initialize command.
- */
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan,
- CPM_CR_INIT_TRX) | CPM_CR_FLG;
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- printk("");
-#endif
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- sp = &cp->smc_regs[idx];
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- sp->smc_smcm = 0;
- sp->smc_smce = 0xff;
-
- /* If the port is the console, enable Rx and Tx.
- */
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-#endif
- }
-
- /* Install interrupt handler.
- */
- /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */
- /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
- request_irq(state->irq, rs_360_interrupt, 0, "ttyS",
- (void *)info);
-
- /* Set up the baud rate generator.
- */
- m360_cpm_setbrg(i, baud_table[baud_idx]);
-
- }
- }
-
- return 0;
-}
-module_init(rs_360_init);
-
-/* This must always be called before the rs_360_init() function, otherwise
- * it blows away the port control information.
- */
-//static int __init serial_console_setup( struct console *co, char *options)
-int serial_console_setup( struct console *co, char *options)
-{
- struct serial_state *ser;
- uint mem_addr, dp_addr, bidx, idx, iobits;
- ushort chan;
- QUICC_BD *bdp;
- volatile QUICC *cp;
- volatile struct smc_regs *sp;
- volatile struct scc_regs *scp;
- volatile struct smc_uart_pram *up;
- volatile struct uart_pram *sup;
-
-/* mleslie TODO:
- * add something to the 68k bootloader to store a desired initial console baud rate */
-
-/* bd_t *bd; */ /* a board info struct used by EPPC-bug */
-/* bd = (bd_t *)__res; */
-
- for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
- /* if (bd->bi_baudrate == baud_table[bidx]) */
- if (CONSOLE_BAUDRATE == baud_table[bidx])
- break;
-
- /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
- baud_idx = bidx;
-
- ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
-
- cp = pquicc; /* Get pointer to Communication Processor */
-
- idx = PORT_NUM(ser->smc_scc_num);
- if (ser->smc_scc_num & NUM_IS_SCC) {
-
- /* TODO: need to set up SCC pin assignment etc. here */
-
- }
- else {
- iobits = 0xc0 << (idx * 4);
- cp->pip_pbpar |= iobits;
- cp->pip_pbdir &= ~iobits;
- cp->pip_pbodr &= ~iobits;
-
- /* Connect the baud rate generator to the
- * SMC based upon index in rs_table. Also
- * make sure it is connected to NMSI.
- */
- cp->si_simode &= ~(0xffff << (idx * 16));
- cp->si_simode |= (idx << ((idx * 16) + 12));
- }
-
- /* When we get here, the CPM has been reset, so we need
- * to configure the port.
- * We need to allocate a transmit and receive buffer descriptor
- * from dual port ram, and a character buffer area from host mem.
- */
-
- /* Allocate space for two buffer descriptors in the DP ram.
- */
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
-
- /* Allocate space for two 2 byte FIFOs in the host memory.
- */
- /* mem_addr = m360_cpm_hostalloc(8); */
- mem_addr = (uint)console_fifos;
-
-
- /* Set the physical address of the host memory buffers in
- * the buffer descriptors.
- */
- /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- bdp->buf = (char *)mem_addr;
- (bdp+1)->buf = (char *)(mem_addr+4);
-
- /* For the receive, set empty and wrap.
- * For transmit, set wrap.
- */
- bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
- (bdp+1)->status = BD_SC_WRAP;
-
- /* Set up the uart parameters in the parameter ram.
- */
- if (ser->smc_scc_num & NUM_IS_SCC) {
- scp = &cp->scc_regs[idx];
- /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
- sup = &pquicc->pram[ser->port].scc.pscc.u;
-
- sup->rbase = dp_addr;
- sup->tbase = dp_addr + sizeof(QUICC_BD);
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- sup->rfcr = SMC_EB;
- sup->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- sup->mrblr = 1;
- sup->max_idl = 0;
- sup->brkcr = 1;
- sup->parec = 0;
- sup->frmer = 0;
- sup->nosec = 0;
- sup->brkec = 0;
- sup->uaddr1 = 0;
- sup->uaddr2 = 0;
- sup->toseq = 0;
- {
- int i;
- for (i=0;i<8;i++)
- sup->cc[i] = 0x8000;
- }
- sup->rccm = 0xc0ff;
-
- /* Send the CPM an initialize command.
- */
- chan = scc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- scp->scc_gsmr.w.high = 0;
- scp->scc_gsmr.w.low =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
-
- scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
- }
- else {
- /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
- up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
- up->rbase = dp_addr; /* Base of receive buffer desc. */
- up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */
- up->rfcr = SMC_EB;
- up->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single character interrupts.
- */
- up->mrblr = 1; /* receive buffer length */
- up->max_idl = 0; /* wait forever for next char */
-
- /* Send the CPM an initialize command.
- */
- chan = smc_chan_map[idx];
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- sp = &cp->smc_regs[idx];
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
- /* And finally, enable Rx and Tx.
- */
- sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
- }
-
- /* Set up the baud rate generator.
- */
- /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
- m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
-
- return 0;
-}
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/drivers/staging/serial/Kconfig b/drivers/staging/serial/Kconfig
deleted file mode 100644
index 9489688..0000000
--- a/drivers/staging/serial/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-config SERIAL_68360_SMC
- bool "68360 SMC uart support"
- depends on M68360
- help
- This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
- bool "68360 SCC uart support"
- depends on M68360
- help
- This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
- bool
- depends on SERIAL_68360_SMC || SERIAL_68360_SCC
- default y
diff --git a/drivers/staging/serial/Makefile b/drivers/staging/serial/Makefile
deleted file mode 100644
index 37a6a0b3..0000000
--- a/drivers/staging/serial/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
diff --git a/drivers/staging/serial/TODO b/drivers/staging/serial/TODO
deleted file mode 100644
index a19cda8..0000000
--- a/drivers/staging/serial/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-These are a few serial drivers that either do not build, or do not work if they
-do build, or if they seem to work, are for obsolete hardware, or are full of
-unfixable races and no one uses them anymore.
-
-If no one steps up to adopt any of these drivers, they will be removed
-in the 3.4 release.
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index ae1d815..43045db 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -41,13 +41,6 @@ static bool debug;
#define QUATECH_HSU200B 0xC0B1 /* HSU200B */
#define QUATECH_HSU200C 0xC0B2 /* HSU200C */
#define QUATECH_HSU200D 0xC0B3 /* HSU200D */
-#define QUATECH_SSU100_2 0xC120 /* SSU100_2 */
-#define QUATECH_DSU100_2 0xC140 /* DSU100_2 */
-#define QUATECH_DSU400_2 0xC150 /* DSU400_2 */
-#define QUATECH_QSU100_2 0xC160 /* QSU100_2 */
-#define QUATECH_QSU400_2 0xC170 /* QSU400_2 */
-#define QUATECH_ESU400_2 0xC180 /* ESU400_2 */
-#define QUATECH_ESU100_2 0xC1A0 /* ESU100_2 */
#define QT_SET_GET_DEVICE 0xc2
#define QT_OPEN_CLOSE_CHANNEL 0xca
@@ -125,7 +118,7 @@ static bool debug;
#define MODEM_CTRL 0x40
#define RS232_MODE 0x00
-static const struct usb_device_id serqt_id_table[] = {
+static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)},
@@ -143,17 +136,9 @@ static const struct usb_device_id serqt_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200B)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200C)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200D)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100_2)},
{} /* Terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, serqt_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
struct qt_get_device_data {
__u8 porta;
@@ -195,13 +180,6 @@ struct quatech_port {
char closePending;
};
-static struct usb_driver serqt_usb_driver = {
- .name = "quatech-usb-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = serqt_id_table,
-};
-
static int port_paranoia_check(struct usb_serial_port *port,
const char *function)
{
@@ -304,8 +282,6 @@ static void qt_write_bulk_callback(struct urb *urb)
quatech_port = urb->context;
- dbg("%s - port %d\n", __func__, quatech_port->port_num);
-
tty = tty_port_tty_get(&quatech_port->port->port);
if (tty)
@@ -351,7 +327,6 @@ static void qt_read_bulk_callback(struct urb *urb)
/* index = MINOR(port->tty->device) - serial->minor; */
index = tty->index - serial->minor;
- dbg("%s - port %d\n", __func__, port->number);
dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
if (port_paranoia_check(port, __func__) != 0) {
@@ -726,8 +701,6 @@ static int qt_startup(struct usb_serial *serial)
int i;
int status;
- dbg("enterting %s", __func__);
-
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -855,8 +828,6 @@ static void qt_release(struct usb_serial *serial)
struct quatech_port *qt_port;
int i;
- dbg("enterting %s", __func__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (!port)
@@ -882,8 +853,6 @@ static int qt_open(struct tty_struct *tty,
if (port_paranoia_check(port, __func__))
return -ENODEV;
- dbg("%s - port %d\n", __func__, port->number);
-
serial = port->serial;
if (serial_paranoia_check(serial, __func__))
@@ -1006,8 +975,6 @@ static int qt_chars_in_buffer(struct tty_struct *tty)
serial = get_usb_serial(port, __func__);
- dbg("%s - port %d\n", __func__, port->number);
-
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS)
chars = port->write_urb->transfer_buffer_length;
@@ -1054,8 +1021,6 @@ static void qt_close(struct usb_serial_port *port)
unsigned int index;
status = 0;
- dbg("%s - port %d\n", __func__, port->number);
-
tty = tty_port_tty_get(&port->port);
index = tty->index - serial->minor;
@@ -1109,8 +1074,6 @@ static int qt_write(struct tty_struct *tty, struct usb_serial_port *port,
if (serial == NULL)
return -ENODEV;
- dbg("%s - port %d\n", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes\n", __func__);
return 0;
@@ -1173,8 +1136,6 @@ static int qt_write_room(struct tty_struct *tty)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
if (serial->num_bulk_out) {
if (port->write_urb->status != -EINPROGRESS)
retval = port->bulk_out_size;
@@ -1241,8 +1202,6 @@ static void qt_set_termios(struct tty_struct *tty,
int baud, divisor, remainder;
int status;
- dbg("%s", __func__);
-
index = tty->index - port->serial->minor;
switch (cflag) {
@@ -1365,8 +1324,6 @@ static void qt_break(struct tty_struct *tty, int break_state)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
result =
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300);
@@ -1385,8 +1342,6 @@ static inline int qt_real_tiocmget(struct tty_struct *tty,
int status;
unsigned int index;
- dbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty);
-
index = tty->index - serial->minor;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1426,8 +1381,6 @@ static inline int qt_real_tiocmset(struct tty_struct *tty,
int status;
unsigned int index;
- dbg("%s - port %d\n", __func__, port->number);
-
index = tty->index - serial->minor;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1461,18 +1414,11 @@ static int qt_tiocmget(struct tty_struct *tty)
struct quatech_port *qt_port = qt_get_port_private(port);
int retval = -ENODEV;
- dbg("In %s\n", __func__);
-
if (!serial)
return -ENODEV;
mutex_lock(&qt_port->lock);
-
- dbg("%s - port %d\n", __func__, port->number);
- dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
retval = qt_real_tiocmget(tty, port, serial);
-
mutex_unlock(&qt_port->lock);
return retval;
}
@@ -1486,18 +1432,11 @@ static int qt_tiocmset(struct tty_struct *tty,
struct quatech_port *qt_port = qt_get_port_private(port);
int retval = -ENODEV;
- dbg("In %s\n", __func__);
-
if (!serial)
return -ENODEV;
mutex_lock(&qt_port->lock);
-
- dbg("%s - port %d\n", __func__, port->number);
- dbg("%s - qt_port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
retval = qt_real_tiocmset(tty, port, serial, set);
-
mutex_unlock(&qt_port->lock);
return retval;
}
@@ -1508,8 +1447,6 @@ static void qt_throttle(struct tty_struct *tty)
struct usb_serial *serial = get_usb_serial(port, __func__);
struct quatech_port *qt_port;
- dbg("%s - port %d\n", __func__, port->number);
-
if (!serial)
return;
@@ -1519,7 +1456,6 @@ static void qt_throttle(struct tty_struct *tty)
/* pass on to the driver specific version of this function */
qt_port->RxHolding = 1;
- dbg("%s - port->RxHolding = 1\n", __func__);
mutex_unlock(&qt_port->lock);
return;
@@ -1539,8 +1475,6 @@ static void qt_unthrottle(struct tty_struct *tty)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
if (qt_port->RxHolding == 1) {
dbg("%s -qt_port->RxHolding == 1\n", __func__);
@@ -1559,8 +1493,9 @@ static void qt_unthrottle(struct tty_struct *tty)
qt_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed restarting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed restarting read urb, error %d\n",
+ __func__, result);
}
}
mutex_unlock(&qt_port->lock);
@@ -1589,7 +1524,7 @@ static struct usb_serial_driver quatech_device = {
.name = "serqt",
},
.description = DRIVER_DESC,
- .id_table = serqt_id_table,
+ .id_table = id_table,
.num_ports = 8,
.open = qt_open,
.close = qt_close,
@@ -1612,7 +1547,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&quatech_device, NULL
};
-module_usb_serial_driver(serqt_usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 83c582e..746c4cd5 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -2,31 +2,19 @@
* Silicon Motion SM7XX frame buffer device
*
* Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors: Ge Wang, gewang@siliconmotion.com
- * Boyod boyod.yang@siliconmotion.com.cn
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
*
* Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* Copyright (C) 2011 Igalia, S.L.
- * Author: Javier M. Mellid <jmunhoz@igalia.com>
+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
*
- * 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.
+ * 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.
*
- * Version 0.10.26192.21.01
- * - Add PowerPC/Big endian support
- * - Verified on 2.6.19.2
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09.2621.00.01
- * - Only support Linux Kernel's version 2.6.21
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09
- * - Only support Linux Kernel's version 2.6.12
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
*/
#include <linux/io.h>
@@ -45,40 +33,19 @@
#include "smtcfb.h"
-#ifdef DEBUG
-#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
-#else
-#define smdbg(format, arg...)
-#endif
-
struct screen_info smtc_screen_info;
/*
* Private structure
*/
struct smtcfb_info {
- /*
- * The following is a pointer to be passed into the
- * functions below. The modules outside the main
- * voyager.c driver have no knowledge as to what
- * is within this structure.
- */
struct fb_info fb;
- struct display_switch *dispsw;
- struct pci_dev *dev;
- signed int currcon;
-
+ struct pci_dev *pdev;
struct {
u8 red, green, blue;
} palette[NR_RGB];
-
u_int palette_size;
-};
-struct par_info {
- /*
- * Hardware
- */
u16 chipID;
unsigned char __iomem *m_pMMIO;
char __iomem *m_pLFB;
@@ -121,15 +88,6 @@ char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */
static u32 colreg[17];
-static struct par_info hw; /* hardware information */
-
-u16 smtc_ChipIDs[] = {
- 0x710,
- 0x712,
- 0x720
-};
-
-#define numSMTCchipIDs ARRAY_SIZE(smtc_ChipIDs)
static struct fb_var_screeninfo smtcfb_var = {
.xres = 1024,
@@ -154,30 +112,29 @@ static struct fb_fix_screeninfo smtcfb_fix = {
.accel = FB_ACCEL_SMI_LYNX,
};
-static void sm712_set_timing(struct smtcfb_info *sfb,
- struct par_info *ppar_info)
+static void sm712_set_timing(struct smtcfb_info *sfb)
{
int i = 0, j = 0;
u32 m_nScreenStride;
- smdbg("\nppar_info->width = %d ppar_info->height = %d"
- "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
- ppar_info->width, ppar_info->height,
- sfb->fb.var.bits_per_pixel, ppar_info->hz);
+ dev_dbg(&sfb->pdev->dev,
+ "sfb->width=%d sfb->height=%d "
+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
for (j = 0; j < numVGAModes; j++) {
- if (VGAMode[j].mmSizeX == ppar_info->width &&
- VGAMode[j].mmSizeY == ppar_info->height &&
+ if (VGAMode[j].mmSizeX == sfb->width &&
+ VGAMode[j].mmSizeY == sfb->height &&
VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
- VGAMode[j].hz == ppar_info->hz) {
+ VGAMode[j].hz == sfb->hz) {
- smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY ="
- "%d VGAMode[j].bpp = %d"
- "VGAMode[j].hz=%d\n",
- VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
- VGAMode[j].bpp, VGAMode[j].hz);
+ dev_dbg(&sfb->pdev->dev,
+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+ VGAMode[j].bpp, VGAMode[j].hz);
- smdbg("VGAMode index=%d\n", j);
+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
smtc_mmiowb(0x0, 0x3c6);
@@ -238,37 +195,37 @@ static void sm712_set_timing(struct smtcfb_info *sfb,
smtc_mmiowb(0x67, 0x3c2);
/* set VPR registers */
- writel(0x0, ppar_info->m_pVPR + 0x0C);
- writel(0x0, ppar_info->m_pVPR + 0x40);
+ writel(0x0, sfb->m_pVPR + 0x0C);
+ writel(0x0, sfb->m_pVPR + 0x40);
/* set data width */
m_nScreenStride =
- (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
+ (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
switch (sfb->fb.var.bits_per_pixel) {
case 8:
- writel(0x0, ppar_info->m_pVPR + 0x0);
+ writel(0x0, sfb->m_pVPR + 0x0);
break;
case 16:
- writel(0x00020000, ppar_info->m_pVPR + 0x0);
+ writel(0x00020000, sfb->m_pVPR + 0x0);
break;
case 24:
- writel(0x00040000, ppar_info->m_pVPR + 0x0);
+ writel(0x00040000, sfb->m_pVPR + 0x0);
break;
case 32:
- writel(0x00030000, ppar_info->m_pVPR + 0x0);
+ writel(0x00030000, sfb->m_pVPR + 0x0);
break;
}
writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
- ppar_info->m_pVPR + 0x10);
+ sfb->m_pVPR + 0x10);
}
static void sm712_setpalette(int regno, unsigned red, unsigned green,
unsigned blue, struct fb_info *info)
{
- struct par_info *cur_par = (struct par_info *)info->par;
+ struct smtcfb_info *sfb = info->par;
- if (cur_par->BaseAddressInVRAM)
+ if (sfb->BaseAddressInVRAM)
/*
* second display palette for dual head. Enable CRT RAM, 6-bit
* RAM
@@ -283,14 +240,13 @@ static void sm712_setpalette(int regno, unsigned red, unsigned green,
smtc_mmiowb(blue >> 10, dac_val);
}
-static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
- *ppar_info)
+static void smtc_set_timing(struct smtcfb_info *sfb)
{
- switch (ppar_info->chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
case 0x720:
- sm712_set_timing(sfb, ppar_info);
+ sm712_set_timing(sfb);
break;
}
}
@@ -310,7 +266,7 @@ static inline unsigned int chan_to_field(unsigned int chan,
return chan << bf->offset;
}
-static int cfb_blank(int blank_mode, struct fb_info *info)
+static int smtc_blank(int blank_mode, struct fb_info *info)
{
/* clear DPMS setting */
switch (blank_mode) {
@@ -660,10 +616,10 @@ void smtcfb_setmode(struct smtcfb_info *sfb)
break;
}
- hw.width = sfb->fb.var.xres;
- hw.height = sfb->fb.var.yres;
- hw.hz = 60;
- smtc_set_timing(sfb, &hw);
+ sfb->width = sfb->fb.var.xres;
+ sfb->height = sfb->fb.var.yres;
+ sfb->hz = 60;
+ smtc_set_timing(sfb);
}
static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -697,7 +653,7 @@ static struct fb_ops smtcfb_ops = {
.fb_check_var = smtc_check_var,
.fb_set_par = smtc_set_par,
.fb_setcolreg = smtc_setcolreg,
- .fb_blank = cfb_blank,
+ .fb_blank = smtc_blank,
.fb_fillrect = cfb_fillrect,
.fb_imageblit = cfb_imageblit,
.fb_copyarea = cfb_copyarea,
@@ -710,8 +666,7 @@ static struct fb_ops smtcfb_ops = {
/*
* Alloc struct smtcfb_info and assign the default value
*/
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
- char *name)
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
{
struct smtcfb_info *sfb;
@@ -720,8 +675,7 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
if (!sfb)
return NULL;
- sfb->currcon = -1;
- sfb->dev = dev;
+ sfb->pdev = pdev;
/*** Init sfb->fb with default value ***/
sfb->fb.flags = FBINFO_FLAG_DEFAULT;
@@ -745,7 +699,9 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
/* text mode acceleration */
sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
- sfb->fb.par = &hw;
+
+ sfb->fb.par = sfb;
+
sfb->fb.pseudo_palette = colreg;
return sfb;
@@ -766,17 +722,17 @@ static void smtc_unmap_mmio(struct smtcfb_info *sfb)
*/
static int smtc_map_smem(struct smtcfb_info *sfb,
- struct pci_dev *dev, u_long smem_len)
+ struct pci_dev *pdev, u_long smem_len)
{
if (sfb->fb.var.bits_per_pixel == 32) {
#ifdef __BIG_ENDIAN
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0)
+ 0x800000;
#else
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
#endif
} else {
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
}
sfb->fb.fix.smem_len = smem_len;
@@ -784,8 +740,8 @@ static int smtc_map_smem(struct smtcfb_info *sfb,
sfb->fb.screen_base = smtc_VRAMBaseAddress;
if (!sfb->fb.screen_base) {
- printk(KERN_ERR "%s: unable to map screen memory\n",
- sfb->fb.fix.id);
+ dev_err(&pdev->dev,
+ "%s: unable to map screen memory\n", sfb->fb.fix.id);
return -ENOMEM;
}
@@ -831,16 +787,14 @@ static int __init sm712vga_setup(char *options)
{
int index;
- if (!options || !*options) {
- smdbg("\n No vga parameter\n");
+ if (!options || !*options)
return -EINVAL;
- }
smtc_screen_info.lfb_width = 0;
smtc_screen_info.lfb_height = 0;
smtc_screen_info.lfb_depth = 0;
- smdbg("\nsm712vga_setup = %s\n", options);
+ pr_debug("sm712vga_setup = %s\n", options);
for (index = 0;
index < ARRAY_SIZE(vesa_mode);
@@ -858,10 +812,6 @@ static int __init sm712vga_setup(char *options)
}
__setup("vga=", sm712vga_setup);
-/* Jason (08/13/2009)
- * Original init function changed to probe method to be used by pci_drv
- * process used to detect chips replaced with kernel process in pci_drv
- */
static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -871,23 +821,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
int err;
unsigned long pFramebufferPhysical;
- printk(KERN_INFO
- "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
+ dev_info(&pdev->dev, "Silicon Motion display driver.");
err = pci_enable_device(pdev); /* enable SMTC chip */
if (err)
return err;
- hw.chipID = ent->device;
- sprintf(name, "sm%Xfb", hw.chipID);
-
sfb = smtc_alloc_fb_info(pdev, name);
if (!sfb)
goto failed_free;
- /* Jason (08/13/2009)
- * Store fb_info to be further used when suspending and resuming
- */
+
+ sfb->chipID = ent->device;
+ sprintf(name, "sm%Xfb", sfb->chipID);
+
pci_set_drvdata(pdev, sfb);
sm7xx_init_hw();
@@ -910,37 +857,37 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
#endif
/* Map address and memory detection */
pFramebufferPhysical = pci_resource_start(pdev, 0);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID);
- switch (hw.chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
sfb->fb.fix.mmio_len = 0x00400000;
smem_size = SM712_VIDEOMEMORYSIZE;
#ifdef __BIG_ENDIAN
- hw.m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
ioremap(pFramebufferPhysical, 0x00c00000));
#else
- hw.m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
ioremap(pFramebufferPhysical, 0x00800000));
#endif
- hw.m_pMMIO = (smtc_RegBaseAddress =
+ sfb->m_pMMIO = (smtc_RegBaseAddress =
smtc_VRAMBaseAddress + 0x00700000);
- hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
- hw.m_pVPR = hw.m_pLFB + 0x0040c000;
+ sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
+ sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
#ifdef __BIG_ENDIAN
if (sfb->fb.var.bits_per_pixel == 32) {
smtc_VRAMBaseAddress += 0x800000;
- hw.m_pLFB += 0x800000;
- printk(KERN_INFO
- "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
- smtc_VRAMBaseAddress, hw.m_pLFB);
+ sfb->m_pLFB += 0x800000;
+ dev_info(&pdev->dev,
+ "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
+ smtc_VRAMBaseAddress, sfb->m_pLFB);
}
#endif
if (!smtc_RegBaseAddress) {
- printk(KERN_ERR
- "%s: unable to map memory mapped IO\n",
+ dev_err(&pdev->dev,
+ "%s: unable to map memory mapped IO!",
sfb->fb.fix.id);
err = -ENOMEM;
goto failed_fb;
@@ -962,20 +909,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
sfb->fb.fix.mmio_start = pFramebufferPhysical;
sfb->fb.fix.mmio_len = 0x00200000;
smem_size = SM722_VIDEOMEMORYSIZE;
- hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
- hw.m_pLFB = (smtc_VRAMBaseAddress =
- hw.m_pDPR + 0x00200000);
- hw.m_pMMIO = (smtc_RegBaseAddress =
- hw.m_pDPR + 0x000c0000);
- hw.m_pVPR = hw.m_pDPR + 0x800;
+ sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pDPR + 0x00200000);
+ sfb->m_pMMIO = (smtc_RegBaseAddress =
+ sfb->m_pDPR + 0x000c0000);
+ sfb->m_pVPR = sfb->m_pDPR + 0x800;
smtc_seqw(0x62, 0xff);
smtc_seqw(0x6a, 0x0d);
smtc_seqw(0x6b, 0x02);
break;
default:
- printk(KERN_ERR
- "No valid Silicon Motion display chip was detected!\n");
+ dev_err(&pdev->dev,
+ "No valid Silicon Motion display chip was detected!");
goto failed_fb;
}
@@ -992,22 +939,21 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
smtcfb_setmode(sfb);
/* Primary display starting from 0 position */
- hw.BaseAddressInVRAM = 0;
- sfb->fb.par = &hw;
+ sfb->BaseAddressInVRAM = 0;
err = register_framebuffer(&sfb->fb);
if (err < 0)
goto failed;
- printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
- "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
- sfb->fb.var.xres, sfb->fb.var.yres,
- sfb->fb.var.bits_per_pixel);
+ dev_info(&pdev->dev,
+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+ sfb->chipID, sfb->chipRevID, sfb->fb.var.xres,
+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
return 0;
failed:
- printk(KERN_ERR "Silicon Motion, Inc. primary display init fail\n");
+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
smtc_unmap_smem(sfb);
smtc_unmap_mmio(sfb);
@@ -1021,7 +967,6 @@ failed_free:
}
-/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
{ PCI_DEVICE(0x126f, 0x710), },
{ PCI_DEVICE(0x126f, 0x712), },
@@ -1030,9 +975,6 @@ static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
};
-/* Jason (08/14/2009)
- * do some clean up when the driver module is removed
- */
static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
{
struct smtcfb_info *sfb;
@@ -1078,7 +1020,7 @@ static int smtcfb_pci_resume(struct device *device)
/* reinit hardware */
sm7xx_init_hw();
- switch (hw.chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
/* set MCLK = 14.31818 * (0x16 / 0x2) */
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
index ab95af2..43d86f8 100644
--- a/drivers/staging/sm7xx/smtcfb.h
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -13,19 +13,11 @@
* more details.
*/
-#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008"
-
#define NR_PALETTE 256
#define NR_RGB 2
#define FB_ACCEL_SMI_LYNX 88
-#ifdef __BIG_ENDIAN
-#define PC_VGA 0
-#else
-#define PC_VGA 1
-#endif
-
#define SCREEN_X_RES 1024
#define SCREEN_Y_RES 600
#define SCREEN_BPP 16
diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c
index f960279..fd7757a 100644
--- a/drivers/staging/telephony/ixj.c
+++ b/drivers/staging/telephony/ixj.c
@@ -19,20 +19,20 @@
* David W. Erhart, <derhart@quicknet.net>
* John Sellers, <jsellers@quicknet.net>
* Mike Preston, <mpreston@quicknet.net>
- *
+ *
* Fixes: David Huggins-Daines, <dhd@cepstral.com>
* Fabio Ferrari, <fabio.ferrari@digitro.com.br>
* Artis Kugevics, <artis@mt.lv>
* Daniele Bellucci, <bellucda@tiscali.it>
*
- * More information about the hardware related to this driver can be found
+ * More information about the hardware related to this driver can be found
* at our website: http://www.quicknet.net
*
* IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET
* TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
@@ -317,7 +317,7 @@ static IXJ *ixj[IXJMAX];
/*
* Allocate a free IXJ device
*/
-
+
static IXJ *ixj_alloc()
{
for(cnt=0; cnt<IXJMAX; cnt++)
@@ -366,7 +366,7 @@ static IXJ ixj[IXJMAX];
/*
* Allocate a free IXJ device
*/
-
+
static IXJ *ixj_alloc(void)
{
int cnt;
@@ -1084,7 +1084,7 @@ static void ixj_pstn_state(IXJ *j)
printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
j->cadence_f[4].on3, j->cadence_f[4].on3min, j->cadence_f[4].on3dot, j->cadence_f[4].on3max);
break;
- case 6:
+ case 6:
printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
j->cadence_f[4].off3, j->cadence_f[4].off3min, j->cadence_f[4].off3dot, j->cadence_f[4].off3max);
break;
@@ -1109,7 +1109,7 @@ static void ixj_pstn_state(IXJ *j)
}
j->pstn_ring_stop = j->pstn_ring_int = 0;
daa_set_mode(j, SOP_PU_SLEEP);
- }
+ }
outb_p(j->pld_scrw.byte, j->XILINXbase);
if (j->pstn_cid_intr && time_after(jiffies, j->pstn_cid_received + hertz)) {
ixj_daa_cid_read(j);
@@ -1133,7 +1133,7 @@ static void ixj_pstn_state(IXJ *j)
printk("IXJ DAA possible wink /dev/phone%d %ld\n", j->board, jiffies);
}
j->pstn_winkstart = jiffies;
- }
+ }
} else {
if (j->pstn_winkstart) {
if(ixjdebug & 0x0008) {
@@ -1524,7 +1524,7 @@ static inline void LED_SetState(int state, IXJ *j)
/*********************************************************************
* GPIO Pins are configured as follows on the Quicknet Internet
* PhoneJACK Telephony Cards
-*
+*
* POTS Select GPIO_6=0 GPIO_7=0
* Mic/Speaker Select GPIO_6=0 GPIO_7=1
* Handset Select GPIO_6=1 GPIO_7=0
@@ -1932,7 +1932,7 @@ static int ixj_hookstate(IXJ *j)
if(fOffHook != j->p_hook) {
if(!j->checkwait) {
j->checkwait = jiffies;
- }
+ }
if(time_before(jiffies, j->checkwait + 2)) {
fOffHook ^= 1;
} else {
@@ -2342,8 +2342,8 @@ static int ixj_release(struct inode *inode, struct file *file_p)
j->ixj_signals[cnt] = SIGIO;
/* Set the excetion signal enable flags */
- j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
- j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
+ j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+ j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
file_p->private_data = NULL;
@@ -2506,7 +2506,7 @@ static int read_filters(IXJ *j)
j->cadence_f[cnt].on1, j->cadence_f[cnt].on1min, j->cadence_f[cnt].on1dot, j->cadence_f[cnt].on1max);
break;
case 2:
- printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min,
+ printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min,
j->cadence_f[cnt].off1max);
break;
case 3:
@@ -2521,12 +2521,12 @@ static int read_filters(IXJ *j)
printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].on3min,
j->cadence_f[cnt].on3max);
break;
- case 6:
+ case 6:
printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off3min,
j->cadence_f[cnt].off3max);
break;
}
- }
+ }
}
if (j->cadence_f[cnt].state == 7) {
j->cadence_f[cnt].state = 0;
@@ -2656,37 +2656,37 @@ static void ulaw2alaw(unsigned char *buff, unsigned long len)
{
static unsigned char table_ulaw2alaw[] =
{
- 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D,
- 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
- 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D,
- 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
- 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02,
- 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A,
- 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12,
- 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B,
- 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63,
- 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79,
- 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71,
- 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D,
- 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
- 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D,
- 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
- 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5,
- 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD,
- 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5,
- 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD,
- 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5,
- 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82,
- 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A,
- 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92,
- 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB,
- 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3,
- 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9,
- 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1,
- 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD,
- 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5,
- 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD,
- 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1,
+ 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D,
+ 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+ 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D,
+ 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+ 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02,
+ 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A,
+ 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12,
+ 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B,
+ 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63,
+ 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79,
+ 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71,
+ 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D,
+ 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+ 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D,
+ 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+ 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5,
+ 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD,
+ 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5,
+ 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD,
+ 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5,
+ 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82,
+ 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A,
+ 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92,
+ 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB,
+ 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3,
+ 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9,
+ 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1,
+ 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD,
+ 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5,
+ 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD,
+ 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1,
0xD6, 0xD6, 0xD7, 0xD7, 0xD4, 0xD4, 0xD5, 0xD5
};
@@ -2701,37 +2701,37 @@ static void alaw2ulaw(unsigned char *buff, unsigned long len)
{
static unsigned char table_alaw2ulaw[] =
{
- 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C,
- 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24,
- 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C,
- 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34,
- 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D,
- 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
- 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D,
- 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
- 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
- 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E,
- 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A,
- 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D,
- 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B,
- 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43,
- 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59,
- 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51,
- 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC,
- 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4,
- 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC,
- 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4,
- 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D,
- 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
- 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D,
- 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
- 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5,
- 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE,
- 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA,
- 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED,
- 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB,
- 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3,
- 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9,
+ 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C,
+ 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24,
+ 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C,
+ 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34,
+ 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D,
+ 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+ 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D,
+ 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+ 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+ 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E,
+ 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A,
+ 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D,
+ 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B,
+ 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43,
+ 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59,
+ 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51,
+ 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC,
+ 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4,
+ 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC,
+ 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4,
+ 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D,
+ 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+ 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D,
+ 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+ 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5,
+ 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE,
+ 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA,
+ 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED,
+ 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB,
+ 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3,
+ 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9,
0xCF, 0xCF, 0xCE, 0xCE, 0xD2, 0xD3, 0xD0, 0xD1
};
@@ -3090,7 +3090,7 @@ static int ixj_write_cid_string(IXJ *j, char *s, int checksum)
static void ixj_pad_fsk(IXJ *j, int pad)
{
- int cnt;
+ int cnt;
for (cnt = 0; cnt < pad; cnt++) {
if(j->fskdcnt < (j->fsksize - 1))
@@ -3474,7 +3474,7 @@ static void ixj_write_frame(IXJ *j)
ixj_post_cid(j);
}
/* This may seem rude, but if we just played one frame of FSK data for CallerID
- and there is real audio data in the buffer, we need to throw it away because
+ and there is real audio data in the buffer, we need to throw it away because
we just used it's time slot */
if (j->write_buffer_rp > j->write_buffer_wp) {
j->write_buffer_rp += j->cid_play_frame_size * 2;
@@ -3486,7 +3486,7 @@ static void ixj_write_frame(IXJ *j)
wake_up_interruptible(&j->poll_q); /* Wake any blocked selects */
}
- } else if (j->write_buffer && j->write_buffers_empty < 1) {
+ } else if (j->write_buffer && j->write_buffers_empty < 1) {
if (j->write_buffer_wp > j->write_buffer_rp) {
frame_count =
(j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
@@ -4150,7 +4150,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_MED:
@@ -4161,7 +4161,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_HIGH:
@@ -4172,7 +4172,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_AGC:
@@ -4197,28 +4197,28 @@ static void ixj_aec_start(IXJ *j, int level)
/* Now we can set the AGC initial parameters and turn it on */
ixj_WriteDSPCommand(0xCF90, j); /* Set AGC Minimum gain */
ixj_WriteDSPCommand(0x0020, j); /* to 0.125 (-18dB) */
-
+
ixj_WriteDSPCommand(0xCF91, j); /* Set AGC Maximum gain */
ixj_WriteDSPCommand(0x1000, j); /* to 16 (24dB) */
-
+
ixj_WriteDSPCommand(0xCF92, j); /* Set AGC start gain */
ixj_WriteDSPCommand(0x0800, j); /* to 8 (+18dB) */
-
+
ixj_WriteDSPCommand(0xCF93, j); /* Set AGC hold time */
ixj_WriteDSPCommand(0x1F40, j); /* to 2 seconds (units are 250us) */
-
+
ixj_WriteDSPCommand(0xCF94, j); /* Set AGC Attack Time Constant */
ixj_WriteDSPCommand(0x0005, j); /* to 8ms */
-
+
ixj_WriteDSPCommand(0xCF95, j); /* Set AGC Decay Time Constant */
ixj_WriteDSPCommand(0x000D, j); /* to 4096ms */
-
+
ixj_WriteDSPCommand(0xCF96, j); /* Set AGC Attack Threshold */
ixj_WriteDSPCommand(0x1200, j); /* to 25% */
-
+
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0001, j); /* to on */
-
+
break;
case AEC_AUTO:
@@ -4495,7 +4495,7 @@ static int ixj_play_start(IXJ *j)
return -ENOMEM;
}
/* j->write_buffers_empty = 2; */
- j->write_buffers_empty = 1;
+ j->write_buffers_empty = 1;
j->write_buffer_size = j->play_frame_size * 2;
j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
@@ -6465,9 +6465,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
ixj_ringback(j);
break;
case PHONE_WINK:
- if(j->cardtype == QTI_PHONEJACK)
+ if(j->cardtype == QTI_PHONEJACK)
retval = -1;
- else
+ else
retval = ixj_wink(j);
break;
case PHONE_CPT_STOP:
@@ -6553,7 +6553,7 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
ixj_write_vmwi(j, arg);
break;
case IXJCTL_CID:
- if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID)))
+ if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID)))
retval = -EFAULT;
j->ex.bits.caller_id = 0;
break;
@@ -6575,13 +6575,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
break;
case PHONE_CAPABILITIES_LIST:
add_caps(j);
- if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps))
+ if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps))
retval = -EFAULT;
break;
case PHONE_CAPABILITIES_CHECK:
{
struct phone_capability cap;
- if (copy_from_user(&cap, argp, sizeof(cap)))
+ if (copy_from_user(&cap, argp, sizeof(cap)))
retval = -EFAULT;
else {
add_caps(j);
@@ -6597,13 +6597,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
j->ex.bits.pstn_ring = 0;
break;
case IXJCTL_SET_FILTER:
- if (copy_from_user(&jf, argp, sizeof(jf)))
+ if (copy_from_user(&jf, argp, sizeof(jf)))
retval = -EFAULT;
else
retval = ixj_init_filter(j, &jf);
break;
case IXJCTL_SET_FILTER_RAW:
- if (copy_from_user(&jfr, argp, sizeof(jfr)))
+ if (copy_from_user(&jfr, argp, sizeof(jfr)))
retval = -EFAULT;
else
retval = ixj_init_filter_raw(j, &jfr);
@@ -6638,9 +6638,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
raise *= 2;
}
if(j->sigdef.signal)
- j->ex_sig.bytes |= raise;
+ j->ex_sig.bytes |= raise;
else
- j->ex_sig.bytes &= (raise^0xffff);
+ j->ex_sig.bytes &= (raise^0xffff);
}
break;
case IXJCTL_INTERCOM_STOP:
@@ -7040,9 +7040,9 @@ static int ixj_selfprobe(IXJ *j)
/* initialise the DTMF prescale to a sensible value */
if (j->cardtype == QTI_LINEJACK) {
- set_dtmf_prescale(j, 0x10);
+ set_dtmf_prescale(j, 0x10);
} else {
- set_dtmf_prescale(j, 0x40);
+ set_dtmf_prescale(j, 0x40);
}
set_play_volume(j, 0x100);
set_rec_volume(j, 0x100);
@@ -7095,15 +7095,15 @@ static int ixj_selfprobe(IXJ *j)
j->ixj_signals[cnt] = SIGIO;
/* Set the excetion signal enable flags */
- j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
- j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
+ j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+ j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
#ifdef IXJ_DYN_ALLOC
j->fskdata = NULL;
#endif
j->fskdcnt = 0;
j->cidcw_wait = 0;
-
+
/* Register with the Telephony for Linux subsystem */
j->p.f_op = &ixj_fops;
j->p.open = ixj_open;
@@ -7118,7 +7118,7 @@ static int ixj_selfprobe(IXJ *j)
/*
* Exported service for pcmcia card handling
*/
-
+
IXJ *ixj_pcmcia_probe(unsigned long dsp, unsigned long xilinx)
{
IXJ *j = ixj_alloc();
@@ -7320,7 +7320,7 @@ static int ixj_get_status_proc(char *buf)
len += sprintf(buf + len, "\nRec volume 0x%x", get_rec_volume(j));
len += sprintf(buf + len, "\nPlay volume 0x%x", get_play_volume(j));
len += sprintf(buf + len, "\nDTMF prescale 0x%x", get_dtmf_prescale(j));
-
+
len += sprintf(buf + len, "\nHook state %d", j->hookstate); /* j->r_hook); */
if (j->cardtype == QTI_LINEJACK) {
@@ -7417,7 +7417,7 @@ static int ixj_get_status_proc(char *buf)
len += sprintf(buf + len, "\nPControl Wait Fails %ld", j->pcontrolwaitfail);
len += sprintf(buf + len, "\nIs Control Ready Checks %ld", j->iscontrolready);
len += sprintf(buf + len, "\nIs Control Ready Check failures %ld", j->iscontrolreadyfail);
-
+
#endif
len += sprintf(buf + len, "\n");
}
@@ -7608,7 +7608,7 @@ static IXJ *new_ixj(unsigned long port)
}
static int __init ixj_probe_isapnp(int *cnt)
-{
+{
int probe = 0;
int func = 0x110;
struct pnp_dev *dev = NULL, *old_dev = NULL;
@@ -7686,7 +7686,7 @@ static int __init ixj_probe_isapnp(int *cnt)
}
return probe;
}
-
+
static int __init ixj_probe_isa(int *cnt)
{
int i, probe;
@@ -7713,7 +7713,7 @@ static int __init ixj_probe_isa(int *cnt)
static int __init ixj_probe_pci(int *cnt)
{
- struct pci_dev *pci = NULL;
+ struct pci_dev *pci = NULL;
int i, probe = 0;
IXJ *j = NULL;
@@ -7745,7 +7745,7 @@ static int __init ixj_probe_pci(int *cnt)
static int __init ixj_init(void)
{
int cnt = 0;
- int probe = 0;
+ int probe = 0;
cnt = 0;
@@ -7887,7 +7887,7 @@ static void DAA_Coeff_US(IXJ *j)
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x2D; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0x62; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x2D; */
- /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */
+ /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x2D; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x62; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6; */
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 9b50b5b..c51f651 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -2212,7 +2212,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context)
if (status) {
pr_debug(
- "%s: Failed to read dll_module stuct for 0x%x.\n",
+ "%s: Failed to read dll_module struct for 0x%x.\n",
__func__, module_dsp_addr);
break;
}
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
index 006ffd7..3d28b23 100644
--- a/drivers/staging/tidspbridge/core/ue_deh.c
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -215,7 +215,7 @@ static inline const char *event_to_string(int event)
case DSP_MMUFAULT: return "DSP_MMUFAULT"; break;
case DSP_PWRERROR: return "DSP_PWRERROR"; break;
case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break;
- default: return "unkown event"; break;
+ default: return "unknown event"; break;
}
}
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index fa870e3..92ced35 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -113,8 +113,8 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
spin_unlock(&sdev->ud.lock);
- sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx");
- sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx");
+ sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx");
+ sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx");
spin_lock(&sdev->ud.lock);
sdev->ud.status = SDEV_ST_USED;
@@ -187,10 +187,10 @@ static void stub_shutdown_connection(struct usbip_device *ud)
}
/* 1. stop threads */
- if (ud->tcp_rx && !task_is_dead(ud->tcp_rx))
- kthread_stop(ud->tcp_rx);
- if (ud->tcp_tx && !task_is_dead(ud->tcp_tx))
- kthread_stop(ud->tcp_tx);
+ if (ud->tcp_rx)
+ kthread_stop_put(ud->tcp_rx);
+ if (ud->tcp_tx)
+ kthread_stop_put(ud->tcp_tx);
/*
* 2. close the socket
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index c7b888c..5d89c0f 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -292,6 +292,23 @@ struct usbip_device {
} eh_ops;
};
+#define kthread_get_run(threadfn, data, namefmt, ...) \
+({ \
+ struct task_struct *__k \
+ = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+ if (!IS_ERR(__k)) { \
+ get_task_struct(__k); \
+ wake_up_process(__k); \
+ } \
+ __k; \
+})
+
+#define kthread_stop_put(k) \
+ do { \
+ kthread_stop(k); \
+ put_task_struct(k); \
+ } while (0)
+
/* usbip_common.c */
void usbip_dump_urb(struct urb *purb);
void usbip_dump_header(struct usbip_header *pdu);
diff --git a/drivers/staging/usbip/usbip_protocol.txt b/drivers/staging/usbip/usbip_protocol.txt
index 0f10208..16b6fe2 100644
--- a/drivers/staging/usbip/usbip_protocol.txt
+++ b/drivers/staging/usbip/usbip_protocol.txt
@@ -27,7 +27,7 @@ Once the client knows the list of exported USB devices it may decide to use one
of them. First the client opens a TCP/IP connection towards the server and
sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
import was successful the TCP/IP connection remains open and will be used
-to trasfer the URB traffic between the client and the server. The client may
+to transfer the URB traffic between the client and the server. The client may
send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 2697877..0958ba5 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -59,7 +59,10 @@ static int parse_status(char *value)
/* skip a header line */
- c = strchr(value, '\n') + 1;
+ c = strchr(value, '\n');
+ if (!c)
+ return -1;
+ c++;
while (*c != '\0') {
int port, status, speed, devid;
@@ -109,7 +112,10 @@ static int parse_status(char *value)
/* go to the next line */
- c = strchr(c, '\n') + 1;
+ c = strchr(c, '\n');
+ if (!c)
+ break;
+ c++;
}
dbg("exit");
@@ -264,11 +270,17 @@ static int get_nports(void)
attr_status->method, attr_status->value);
/* skip a header line */
- c = strchr(attr_status->value, '\n') + 1;
+ c = strchr(attr_status->value, '\n');
+ if (!c)
+ return 0;
+ c++;
while (*c != '\0') {
/* go to the next line */
- c = strchr(c, '\n') + 1;
+ c = strchr(c, '\n');
+ if (!c)
+ return nports;
+ c++;
nports += 1;
}
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index dca9bf1..f708cba 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -821,10 +821,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
}
/* kill threads related to this sdev, if v.c. exists */
- if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx))
- kthread_stop(vdev->ud.tcp_rx);
- if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx))
- kthread_stop(vdev->ud.tcp_tx);
+ if (vdev->ud.tcp_rx)
+ kthread_stop_put(vdev->ud.tcp_rx);
+ if (vdev->ud.tcp_tx)
+ kthread_stop_put(vdev->ud.tcp_tx);
pr_info("stop threads\n");
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index f5fba732..f0eaf04f 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -162,7 +162,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
* already received the result of its submit result and gave
* back the URB.
*/
- pr_info("the urb (seqnum %d) was already given backed\n",
+ pr_info("the urb (seqnum %d) was already given back\n",
pdu->base.seqnum);
} else {
usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index 0cd039b..7ce9c2f 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -222,8 +222,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
spin_unlock(&the_controller->lock);
/* end the lock */
- vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
- vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+ vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+ vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
rh_port_connect(rhport, speed);
diff --git a/drivers/staging/vme/Makefile b/drivers/staging/vme/Makefile
index b4ea3f8..accdb72 100644
--- a/drivers/staging/vme/Makefile
+++ b/drivers/staging/vme/Makefile
@@ -1,8 +1 @@
-#
-# Makefile for the VME bridge device drivers.
-#
-obj-$(CONFIG_VME_BUS) += vme.o
-
-obj-y += bridges/
obj-y += devices/
-obj-y += boards/
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
deleted file mode 100644
index 79f0033..0000000
--- a/drivers/staging/vme/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
- TODO
- ====
-
-- Add one or more device drivers which use the VME framework.
-
diff --git a/drivers/staging/vme/devices/Kconfig b/drivers/staging/vme/devices/Kconfig
index 55ec30c..d0cab17 100644
--- a/drivers/staging/vme/devices/Kconfig
+++ b/drivers/staging/vme/devices/Kconfig
@@ -2,6 +2,7 @@ comment "VME Device Drivers"
config VME_USER
tristate "VME user space access driver"
+ depends on STAGING
help
If you say Y here you want to be able to access a limited number of
VME windows in a manner at least semi-compatible with the interface
@@ -9,7 +10,7 @@ config VME_USER
config VME_PIO2
tristate "GE PIO2 VME"
- depends on GPIOLIB
+ depends on STAGING && GPIOLIB
help
Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME
slave card, implementing 32 solid-state relay switched IO lines, in
diff --git a/drivers/staging/vme/devices/vme_pio2_cntr.c b/drivers/staging/vme/devices/vme_pio2_cntr.c
index 08e0d59..6335471 100644
--- a/drivers/staging/vme/devices/vme_pio2_cntr.c
+++ b/drivers/staging/vme/devices/vme_pio2_cntr.c
@@ -17,8 +17,8 @@
#include <linux/device.h>
#include <linux/types.h>
#include <linux/gpio.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
static int pio2_cntr_irq_set(struct pio2_card *card, int id)
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c
index 573c800..4bf8e05 100644
--- a/drivers/staging/vme/devices/vme_pio2_core.c
+++ b/drivers/staging/vme/devices/vme_pio2_core.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -20,8 +19,8 @@
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index 8584849..ad76a47 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -21,8 +20,8 @@
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
static const char driver_name[] = "pio2_gpio";
@@ -79,7 +78,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset,
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
- dev_err(&card->vdev->dev, "Channel not availabe as output\n");
+ dev_err(&card->vdev->dev, "Channel not available as output\n");
return;
}
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 7dcd162..e24a6f9 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pci.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
@@ -36,8 +36,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_user.h"
static DEFINE_MUTEX(vme_user_mutex);
@@ -95,7 +95,7 @@ struct image_desc {
void *kern_buf; /* Buffer address in kernel space */
dma_addr_t pci_buf; /* Buffer address in PCI address space */
unsigned long long size_buf; /* Buffer size */
- struct semaphore sem; /* Semaphore for locking image */
+ struct mutex mutex; /* Mutex for locking image */
struct device *device; /* Sysfs device */
struct vme_resource *resource; /* VME resource */
int users; /* Number of current users */
@@ -168,7 +168,7 @@ static int vme_user_open(struct inode *inode, struct file *file)
int err;
unsigned int minor = MINOR(inode->i_rdev);
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* Allow device to be opened if a resource is needed and allocated. */
if (minor < CONTROL_MINOR && image[minor].resource == NULL) {
printk(KERN_ERR "No resources allocated for device\n");
@@ -179,12 +179,12 @@ static int vme_user_open(struct inode *inode, struct file *file)
/* Increment user count */
image[minor].users++;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
err_res:
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return err;
}
@@ -193,12 +193,12 @@ static int vme_user_release(struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* Decrement user count */
image[minor].users--;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -325,14 +325,14 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count,
if (minor == CONTROL_MINOR)
return 0;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* XXX Do we *really* want this helper - we can use vme_*_get ? */
image_size = vme_get_size(image[minor].resource);
/* Ensure we are starting at a valid location */
if ((*ppos < 0) || (*ppos > (image_size - 1))) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -353,8 +353,7 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count,
retval = -EINVAL;
}
- up(&image[minor].sem);
-
+ mutex_unlock(&image[minor].mutex);
if (retval > 0)
*ppos += retval;
@@ -372,13 +371,13 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf,
if (minor == CONTROL_MINOR)
return 0;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
image_size = vme_get_size(image[minor].resource);
/* Ensure we are starting at a valid location */
if ((*ppos < 0) || (*ppos > (image_size - 1))) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -398,8 +397,8 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf,
default:
retval = -EINVAL;
}
-
- up(&image[minor].sem);
+
+ mutex_unlock(&image[minor].mutex);
if (retval > 0)
*ppos += retval;
@@ -416,7 +415,7 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
if (minor == CONTROL_MINOR)
return -EINVAL;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
image_size = vme_get_size(image[minor].resource);
switch (whence) {
@@ -430,19 +429,19 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
absolute = image_size + off;
break;
default:
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return -EINVAL;
break;
}
if ((absolute < 0) || (absolute >= image_size)) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return -EINVAL;
}
file->f_pos = absolute;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return absolute;
}
@@ -696,7 +695,7 @@ static int __devinit vme_user_probe(struct vme_dev *vdev)
for (i = 0; i < VME_DEVS; i++) {
image[i].kern_buf = NULL;
image[i].pci_buf = 0;
- sema_init(&image[i].sem, 1);
+ mutex_init(&image[i].mutex);
image[i].device = NULL;
image[i].resource = NULL;
image[i].users = 0;
@@ -858,8 +857,10 @@ static int __devexit vme_user_remove(struct vme_dev *dev)
int i;
/* Remove sysfs Entries */
- for (i = 0; i < VME_DEVS; i++)
+ for (i = 0; i < VME_DEVS; i++) {
+ mutex_destroy(&image[i].mutex);
device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
+ }
class_destroy(vme_user_sysfs_class);
for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h
deleted file mode 100644
index c9d65bf..0000000
--- a/drivers/staging/vme/vme.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef _VME_H_
-#define _VME_H_
-
-/* Resource Type */
-enum vme_resource_type {
- VME_MASTER,
- VME_SLAVE,
- VME_DMA,
- VME_LM
-};
-
-/* VME Address Spaces */
-#define VME_A16 0x1
-#define VME_A24 0x2
-#define VME_A32 0x4
-#define VME_A64 0x8
-#define VME_CRCSR 0x10
-#define VME_USER1 0x20
-#define VME_USER2 0x40
-#define VME_USER3 0x80
-#define VME_USER4 0x100
-
-#define VME_A16_MAX 0x10000ULL
-#define VME_A24_MAX 0x1000000ULL
-#define VME_A32_MAX 0x100000000ULL
-#define VME_A64_MAX 0x10000000000000000ULL
-#define VME_CRCSR_MAX 0x1000000ULL
-
-
-/* VME Cycle Types */
-#define VME_SCT 0x1
-#define VME_BLT 0x2
-#define VME_MBLT 0x4
-#define VME_2eVME 0x8
-#define VME_2eSST 0x10
-#define VME_2eSSTB 0x20
-
-#define VME_2eSST160 0x100
-#define VME_2eSST267 0x200
-#define VME_2eSST320 0x400
-
-#define VME_SUPER 0x1000
-#define VME_USER 0x2000
-#define VME_PROG 0x4000
-#define VME_DATA 0x8000
-
-/* VME Data Widths */
-#define VME_D8 0x1
-#define VME_D16 0x2
-#define VME_D32 0x4
-#define VME_D64 0x8
-
-/* Arbitration Scheduling Modes */
-#define VME_R_ROBIN_MODE 0x1
-#define VME_PRIORITY_MODE 0x2
-
-#define VME_DMA_PATTERN (1<<0)
-#define VME_DMA_PCI (1<<1)
-#define VME_DMA_VME (1<<2)
-
-#define VME_DMA_PATTERN_BYTE (1<<0)
-#define VME_DMA_PATTERN_WORD (1<<1)
-#define VME_DMA_PATTERN_INCREMENT (1<<2)
-
-#define VME_DMA_VME_TO_MEM (1<<0)
-#define VME_DMA_MEM_TO_VME (1<<1)
-#define VME_DMA_VME_TO_VME (1<<2)
-#define VME_DMA_MEM_TO_MEM (1<<3)
-#define VME_DMA_PATTERN_TO_VME (1<<4)
-#define VME_DMA_PATTERN_TO_MEM (1<<5)
-
-struct vme_dma_attr {
- u32 type;
- void *private;
-};
-
-struct vme_resource {
- enum vme_resource_type type;
- struct list_head *entry;
-};
-
-extern struct bus_type vme_bus_type;
-
-/* VME_MAX_BRIDGES comes from the type of vme_bus_numbers */
-#define VME_MAX_BRIDGES (sizeof(unsigned int)*8)
-#define VME_MAX_SLOTS 32
-
-#define VME_SLOT_CURRENT -1
-#define VME_SLOT_ALL -2
-
-/**
- * Structure representing a VME device
- * @num: The device number
- * @bridge: Pointer to the bridge device this device is on
- * @dev: Internal device structure
- * @drv_list: List of devices (per driver)
- * @bridge_list: List of devices (per bridge)
- */
-struct vme_dev {
- int num;
- struct vme_bridge *bridge;
- struct device dev;
- struct list_head drv_list;
- struct list_head bridge_list;
-};
-
-struct vme_driver {
- struct list_head node;
- const char *name;
- int (*match)(struct vme_dev *);
- int (*probe)(struct vme_dev *);
- int (*remove)(struct vme_dev *);
- void (*shutdown)(void);
- struct device_driver driver;
- struct list_head devices;
-};
-
-void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *);
-void vme_free_consistent(struct vme_resource *, size_t, void *,
- dma_addr_t);
-
-size_t vme_get_size(struct vme_resource *);
-
-struct vme_resource *vme_slave_request(struct vme_dev *, u32, u32);
-int vme_slave_set(struct vme_resource *, int, unsigned long long,
- unsigned long long, dma_addr_t, u32, u32);
-int vme_slave_get(struct vme_resource *, int *, unsigned long long *,
- unsigned long long *, dma_addr_t *, u32 *, u32 *);
-void vme_slave_free(struct vme_resource *);
-
-struct vme_resource *vme_master_request(struct vme_dev *, u32, u32, u32);
-int vme_master_set(struct vme_resource *, int, unsigned long long,
- unsigned long long, u32, u32, u32);
-int vme_master_get(struct vme_resource *, int *, unsigned long long *,
- unsigned long long *, u32 *, u32 *, u32 *);
-ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t);
-ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t);
-unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int,
- unsigned int, loff_t);
-void vme_master_free(struct vme_resource *);
-
-struct vme_resource *vme_dma_request(struct vme_dev *, u32);
-struct vme_dma_list *vme_new_dma_list(struct vme_resource *);
-struct vme_dma_attr *vme_dma_pattern_attribute(u32, u32);
-struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t);
-struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, u32, u32, u32);
-void vme_dma_free_attribute(struct vme_dma_attr *);
-int vme_dma_list_add(struct vme_dma_list *, struct vme_dma_attr *,
- struct vme_dma_attr *, size_t);
-int vme_dma_list_exec(struct vme_dma_list *);
-int vme_dma_list_free(struct vme_dma_list *);
-int vme_dma_free(struct vme_resource *);
-
-int vme_irq_request(struct vme_dev *, int, int,
- void (*callback)(int, int, void *), void *);
-void vme_irq_free(struct vme_dev *, int, int);
-int vme_irq_generate(struct vme_dev *, int, int);
-
-struct vme_resource *vme_lm_request(struct vme_dev *);
-int vme_lm_count(struct vme_resource *);
-int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32);
-int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *);
-int vme_lm_attach(struct vme_resource *, int, void (*callback)(int));
-int vme_lm_detach(struct vme_resource *, int);
-void vme_lm_free(struct vme_resource *);
-
-int vme_slot_get(struct vme_dev *);
-
-int vme_register_driver(struct vme_driver *, unsigned int);
-void vme_unregister_driver(struct vme_driver *);
-
-
-#endif /* _VME_H_ */
-
diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt
deleted file mode 100644
index 856efa3..0000000
--- a/drivers/staging/vme/vme_api.txt
+++ /dev/null
@@ -1,396 +0,0 @@
- VME Device Driver API
- =====================
-
-Driver registration
-===================
-
-As with other subsystems within the Linux kernel, VME device drivers register
-with the VME subsystem, typically called from the devices init routine. This is
-achieved via a call to the following function:
-
- int vme_register_driver (struct vme_driver *driver);
-
-If driver registration is successful this function returns zero, if an error
-occurred a negative error code will be returned.
-
-A pointer to a structure of type 'vme_driver' must be provided to the
-registration function. The structure is as follows:
-
- struct vme_driver {
- struct list_head node;
- const char *name;
- int (*match)(struct vme_dev *);
- int (*probe)(struct vme_dev *);
- int (*remove)(struct vme_dev *);
- void (*shutdown)(void);
- struct device_driver driver;
- struct list_head devices;
- unsigned int ndev;
- };
-
-At the minimum, the '.name', '.match' and '.probe' elements of this structure
-should be correctly set. The '.name' element is a pointer to a string holding
-the device driver's name.
-
-The '.match' function allows controlling the number of devices that need to
-be registered. The match function should return 1 if a device should be
-probed and 0 otherwise. This example match function (from vme_user.c) limits
-the number of devices probed to one:
-
- #define USER_BUS_MAX 1
- ...
- static int vme_user_match(struct vme_dev *vdev)
- {
- if (vdev->id.num >= USER_BUS_MAX)
- return 0;
- return 1;
- }
-
-The '.probe' element should contain a pointer to the probe routine. The
-probe routine is passed a 'struct vme_dev' pointer as an argument. The
-'struct vme_dev' structure looks like the following:
-
- struct vme_dev {
- int num;
- struct vme_bridge *bridge;
- struct device dev;
- struct list_head drv_list;
- struct list_head bridge_list;
- };
-
-Here, the 'num' field refers to the sequential device ID for this specific
-driver. The bridge number (or bus number) can be accessed using
-dev->bridge->num.
-
-A function is also provided to unregister the driver from the VME core and is
-usually called from the device driver's exit routine:
-
- void vme_unregister_driver (struct vme_driver *driver);
-
-
-Resource management
-===================
-
-Once a driver has registered with the VME core the provided match routine will
-be called the number of times specified during the registration. If a match
-succeeds, a non-zero value should be returned. A zero return value indicates
-failure. For all successful matches, the probe routine of the corresponding
-driver is called. The probe routine is passed a pointer to the devices
-device structure. This pointer should be saved, it will be required for
-requesting VME resources.
-
-The driver can request ownership of one or more master windows, slave windows
-and/or dma channels. Rather than allowing the device driver to request a
-specific window or DMA channel (which may be used by a different driver) this
-driver allows a resource to be assigned based on the required attributes of the
-driver in question:
-
- struct vme_resource * vme_master_request(struct vme_dev *dev,
- u32 aspace, u32 cycle, u32 width);
-
- struct vme_resource * vme_slave_request(struct vme_dev *dev, u32 aspace,
- u32 cycle);
-
- struct vme_resource *vme_dma_request(struct vme_dev *dev, u32 route);
-
-For slave windows these attributes are split into the VME address spaces that
-need to be accessed in 'aspace' and VME bus cycle types required in 'cycle'.
-Master windows add a further set of attributes in 'width' specifying the
-required data transfer widths. These attributes are defined as bitmasks and as
-such any combination of the attributes can be requested for a single window,
-the core will assign a window that meets the requirements, returning a pointer
-of type vme_resource that should be used to identify the allocated resource
-when it is used. For DMA controllers, the request function requires the
-potential direction of any transfers to be provided in the route attributes.
-This is typically VME-to-MEM and/or MEM-to-VME, though some hardware can
-support VME-to-VME and MEM-to-MEM transfers as well as test pattern generation.
-If an unallocated window fitting the requirements can not be found a NULL
-pointer will be returned.
-
-Functions are also provided to free window allocations once they are no longer
-required. These functions should be passed the pointer to the resource provided
-during resource allocation:
-
- void vme_master_free(struct vme_resource *res);
-
- void vme_slave_free(struct vme_resource *res);
-
- void vme_dma_free(struct vme_resource *res);
-
-
-Master windows
-==============
-
-Master windows provide access from the local processor[s] out onto the VME bus.
-The number of windows available and the available access modes is dependent on
-the underlying chipset. A window must be configured before it can be used.
-
-
-Master window configuration
----------------------------
-
-Once a master window has been assigned the following functions can be used to
-configure it and retrieve the current settings:
-
- int vme_master_set (struct vme_resource *res, int enabled,
- unsigned long long base, unsigned long long size, u32 aspace,
- u32 cycle, u32 width);
-
- int vme_master_get (struct vme_resource *res, int *enabled,
- unsigned long long *base, unsigned long long *size, u32 *aspace,
- u32 *cycle, u32 *width);
-
-The address spaces, transfer widths and cycle types are the same as described
-under resource management, however some of the options are mutually exclusive.
-For example, only one address space may be specified.
-
-These functions return 0 on success or an error code should the call fail.
-
-
-Master window access
---------------------
-
-The following functions can be used to read from and write to configured master
-windows. These functions return the number of bytes copied:
-
- ssize_t vme_master_read(struct vme_resource *res, void *buf,
- size_t count, loff_t offset);
-
- ssize_t vme_master_write(struct vme_resource *res, void *buf,
- size_t count, loff_t offset);
-
-In addition to simple reads and writes, a function is provided to do a
-read-modify-write transaction. This function returns the original value of the
-VME bus location :
-
- unsigned int vme_master_rmw (struct vme_resource *res,
- unsigned int mask, unsigned int compare, unsigned int swap,
- loff_t offset);
-
-This functions by reading the offset, applying the mask. If the bits selected in
-the mask match with the values of the corresponding bits in the compare field,
-the value of swap is written the specified offset.
-
-
-Slave windows
-=============
-
-Slave windows provide devices on the VME bus access into mapped portions of the
-local memory. The number of windows available and the access modes that can be
-used is dependent on the underlying chipset. A window must be configured before
-it can be used.
-
-
-Slave window configuration
---------------------------
-
-Once a slave window has been assigned the following functions can be used to
-configure it and retrieve the current settings:
-
- int vme_slave_set (struct vme_resource *res, int enabled,
- unsigned long long base, unsigned long long size,
- dma_addr_t mem, u32 aspace, u32 cycle);
-
- int vme_slave_get (struct vme_resource *res, int *enabled,
- unsigned long long *base, unsigned long long *size,
- dma_addr_t *mem, u32 *aspace, u32 *cycle);
-
-The address spaces, transfer widths and cycle types are the same as described
-under resource management, however some of the options are mutually exclusive.
-For example, only one address space may be specified.
-
-These functions return 0 on success or an error code should the call fail.
-
-
-Slave window buffer allocation
-------------------------------
-
-Functions are provided to allow the user to allocate and free a contiguous
-buffers which will be accessible by the VME bridge. These functions do not have
-to be used, other methods can be used to allocate a buffer, though care must be
-taken to ensure that they are contiguous and accessible by the VME bridge:
-
- void * vme_alloc_consistent(struct vme_resource *res, size_t size,
- dma_addr_t *mem);
-
- void vme_free_consistent(struct vme_resource *res, size_t size,
- void *virt, dma_addr_t mem);
-
-
-Slave window access
--------------------
-
-Slave windows map local memory onto the VME bus, the standard methods for
-accessing memory should be used.
-
-
-DMA channels
-============
-
-The VME DMA transfer provides the ability to run link-list DMA transfers. The
-API introduces the concept of DMA lists. Each DMA list is a link-list which can
-be passed to a DMA controller. Multiple lists can be created, extended,
-executed, reused and destroyed.
-
-
-List Management
----------------
-
-The following functions are provided to create and destroy DMA lists. Execution
-of a list will not automatically destroy the list, thus enabling a list to be
-reused for repetitive tasks:
-
- struct vme_dma_list *vme_new_dma_list(struct vme_resource *res);
-
- int vme_dma_list_free(struct vme_dma_list *list);
-
-
-List Population
----------------
-
-An item can be added to a list using the following function ( the source and
-destination attributes need to be created before calling this function, this is
-covered under "Transfer Attributes"):
-
- int vme_dma_list_add(struct vme_dma_list *list,
- struct vme_dma_attr *src, struct vme_dma_attr *dest,
- size_t count);
-
-NOTE: The detailed attributes of the transfers source and destination
- are not checked until an entry is added to a DMA list, the request
- for a DMA channel purely checks the directions in which the
- controller is expected to transfer data. As a result it is
- possible for this call to return an error, for example if the
- source or destination is in an unsupported VME address space.
-
-Transfer Attributes
--------------------
-
-The attributes for the source and destination are handled separately from adding
-an item to a list. This is due to the diverse attributes required for each type
-of source and destination. There are functions to create attributes for PCI, VME
-and pattern sources and destinations (where appropriate):
-
-Pattern source:
-
- struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type);
-
-PCI source or destination:
-
- struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t mem);
-
-VME source or destination:
-
- struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long base,
- u32 aspace, u32 cycle, u32 width);
-
-The following function should be used to free an attribute:
-
- void vme_dma_free_attribute(struct vme_dma_attr *attr);
-
-
-List Execution
---------------
-
-The following function queues a list for execution. The function will return
-once the list has been executed:
-
- int vme_dma_list_exec(struct vme_dma_list *list);
-
-
-Interrupts
-==========
-
-The VME API provides functions to attach and detach callbacks to specific VME
-level and status ID combinations and for the generation of VME interrupts with
-specific VME level and status IDs.
-
-
-Attaching Interrupt Handlers
-----------------------------
-
-The following functions can be used to attach and free a specific VME level and
-status ID combination. Any given combination can only be assigned a single
-callback function. A void pointer parameter is provided, the value of which is
-passed to the callback function, the use of this pointer is user undefined:
-
- int vme_irq_request(struct vme_dev *dev, int level, int statid,
- void (*callback)(int, int, void *), void *priv);
-
- void vme_irq_free(struct vme_dev *dev, int level, int statid);
-
-The callback parameters are as follows. Care must be taken in writing a callback
-function, callback functions run in interrupt context:
-
- void callback(int level, int statid, void *priv);
-
-
-Interrupt Generation
---------------------
-
-The following function can be used to generate a VME interrupt at a given VME
-level and VME status ID:
-
- int vme_irq_generate(struct vme_dev *dev, int level, int statid);
-
-
-Location monitors
-=================
-
-The VME API provides the following functionality to configure the location
-monitor.
-
-
-Location Monitor Management
----------------------------
-
-The following functions are provided to request the use of a block of location
-monitors and to free them after they are no longer required:
-
- struct vme_resource * vme_lm_request(struct vme_dev *dev);
-
- void vme_lm_free(struct vme_resource * res);
-
-Each block may provide a number of location monitors, monitoring adjacent
-locations. The following function can be used to determine how many locations
-are provided:
-
- int vme_lm_count(struct vme_resource * res);
-
-
-Location Monitor Configuration
-------------------------------
-
-Once a bank of location monitors has been allocated, the following functions
-are provided to configure the location and mode of the location monitor:
-
- int vme_lm_set(struct vme_resource *res, unsigned long long base,
- u32 aspace, u32 cycle);
-
- int vme_lm_get(struct vme_resource *res, unsigned long long *base,
- u32 *aspace, u32 *cycle);
-
-
-Location Monitor Use
---------------------
-
-The following functions allow a callback to be attached and detached from each
-location monitor location. Each location monitor can monitor a number of
-adjacent locations:
-
- int vme_lm_attach(struct vme_resource *res, int num,
- void (*callback)(int));
-
- int vme_lm_detach(struct vme_resource *res, int num);
-
-The callback function is declared as follows.
-
- void callback(int num);
-
-
-Slot Detection
-==============
-
-This function returns the slot ID of the provided bridge.
-
- int vme_slot_get(struct vme_dev *dev);
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index 61ac46f..0afb9fe 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -148,7 +148,7 @@ WPA_ParseRSN (
{
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
- for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(unsigned char)); i++) {
+ for(i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -180,7 +180,7 @@ WPA_ParseRSN (
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
- for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(unsigned char)); i++) {
+ for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index c0edf97..e4bdf2a 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -452,7 +452,7 @@ RXbBulkInProcessData (
}
}
- if (!is_multicast_ether_addr(pMACHeader->abyAddr1) && !is_broadcast_ether_addr(pMACHeader->abyAddr1)) {
+ if (!is_multicast_ether_addr(pMACHeader->abyAddr1)) {
if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) {
pDevice->s802_11Counter.FrameDuplicateCount++;
return FALSE;
diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c
index d59456c..5b9a84f 100644
--- a/drivers/staging/vt6656/ioctl.c
+++ b/drivers/staging/vt6656/ioctl.c
@@ -90,18 +90,17 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
spin_lock_irq(&pDevice->lock);
if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0)
- BSSvClearBSSList((void *)pDevice, FALSE);
+ BSSvClearBSSList(pDevice, FALSE);
else
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ BSSvClearBSSList(pDevice, pDevice->bLinkPass);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_BSS_SCAN..begin\n");
if (pItemSSID->len != 0)
- bScheduleCommand((void *)pDevice,
- WLAN_CMD_BSSID_SCAN,
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
abyScanSSID);
else
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -150,6 +149,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
}
}
break;
+
case WLAN_CMD_BSS_JOIN:
if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) {
result = -EFAULT;
@@ -190,10 +190,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
pMgmt->eCurrState = WMAC_STATE_IDLE;
- bScheduleCommand((void *) pDevice,
- WLAN_CMD_BSSID_SCAN,
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_SSID, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -299,7 +298,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
result = -EINVAL;
break;
}
- pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC);
+ pList = kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), GFP_ATOMIC);
if (pList == NULL) {
result = -ENOMEM;
break;
@@ -313,7 +312,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval;
pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo;
RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
- pList->sBSSIDList[ii].uRSSI = (unsigned int) ldBm;
+ pList->sBSSIDList[ii].uRSSI = (unsigned int)ldBm;
/* pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI; */
memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN);
pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
@@ -356,6 +355,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
break;
}
break;
+
case WLAN_CMD_STOP_MAC:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_STOP_MAC\n");
/* Todo xxxxxx */
@@ -534,7 +534,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
- bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_RUN_AP, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -565,7 +565,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
result = -ENOMEM;
break;
}
- pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC);
+ pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), GFP_ATOMIC);
if (pNodeList == NULL) {
result = -ENOMEM;
break;
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 763e028..ee5261a 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1257,9 +1257,7 @@ static void __devexit vt6656_disconnect(struct usb_interface *intf)
}
device_release_WPADEV(device);
-
- if (device->firmware)
- release_firmware(device->firmware);
+ release_firmware(device->firmware);
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index 7dde3d6..b16d4dd 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -149,7 +149,7 @@ WPA_ParseRSN(
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
for (i = 0; (i < pRSN->wPKCount) &&
- (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
+ (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -182,7 +182,7 @@ WPA_ParseRSN(
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
for (i = 0; (i < pIE_RSN_Auth->wAuthCount) &&
- (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
+ (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu
index edee8b9..5f1cfb8f 100644
--- a/drivers/staging/wlags49_h2/README.ubuntu
+++ b/drivers/staging/wlags49_h2/README.ubuntu
@@ -87,7 +87,7 @@ The linux driver files (wl_xxxx.c) are changed in the following ways:
-- Recovery actions added
The major problem was the order in which calls can be made. The original
-looks like a traditonal UNIX driver. To call an "ioctl" function you
+looks like a traditional UNIX driver. To call an "ioctl" function you
have to "open" the device first to get a handle and after "close" no
"ioctl" function can be called anymore. With the 2.6 driver this all
changed; the former ioctl functions are now called before "open" and
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 5957c3a..366e4a4 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -2871,8 +2871,8 @@ or
* The Assert validates the HCF assumption about Hermes implementation upon which the range of
* Pseudo-RIDs is based.
* Then the control fields up to the start of the 802.3 frame are read from the NIC into the lookahead buffer.
-* The status field is converted to native Endianess.
-* The length is, after implicit Endianess conversion if needed, and adjustment for the 14 bytes of the
+* The status field is converted to native Endianness.
+* The length is, after implicit Endianness conversion if needed, and adjustment for the 14 bytes of the
* 802.3 MAC header, stored in IFB_RxLen.
* In MAC Monitor mode, 802.11 control frames with a TOTAL length of 14 are received, so without this
* length adjustment, IFB_RxLen could not be used to distinguish these frames from "no frame".
@@ -2894,7 +2894,7 @@ or
* - the Hermes reported Tunnel encapsulation or
* - the Hermes reported 1042 Encapsulation and hcf_encap reports that the HCF would not have used
* 1042 as the encapsulation mechanism
-* Note that the first field of the RxFS in bufp has Native Endianess due to the conversion done by the
+* Note that the first field of the RxFS in bufp has Native Endianness due to the conversion done by the
* BE_PAR in get_frag.
*36: The Type field is the only word kept (after moving) of the just read 8 bytes, it is moved to the
* L-field. The original L-field and 6 byte SNAP header are discarded, so IFB_RxLen and buf_addr must
@@ -3831,7 +3831,7 @@ get_fid( IFBP ifbp )
*.DESCRIPTION
* process the single byte (if applicable) read by the previous get_frag and copy len (or len-1) bytes from
* NIC to bufp.
- * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianess is
+ * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianness is
* converted (i.e. byte swapped)
*
*
@@ -3980,7 +3980,7 @@ get_frag( IFBP ifbp, wci_bufp bufp, int len BE_PAR( int word_len ) )
* appropriate means on H-I: always
* and on H-II if F/W supplier reflects a primary (i.e. only after an Hermes Reset or Init
* command).
- * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianess is converted to native Endianess.
+ * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianness is converted to native Endianness.
* Only the return code of the first hcf_get_info is used. All hcf_get_info calls are made, regardless of
* the success or failure of the 1st hcf_get_info. The assumptions are:
* - if any call fails, they all fail, so remembering the result of the 1st call is adequate
diff --git a/drivers/staging/wlags49_h2/hcf.h b/drivers/staging/wlags49_h2/hcf.h
index 95527b5..68e2330 100644
--- a/drivers/staging/wlags49_h2/hcf.h
+++ b/drivers/staging/wlags49_h2/hcf.h
@@ -90,7 +90,7 @@
#define LOF(x) (sizeof(x)/sizeof(hcf_16)-1)
-/* Endianess
+/* Endianness
* Little Endian (a.k.a. Intel), least significant byte first
* Big Endian (a.k.a. Motorola), most significant byte first
*
@@ -101,7 +101,7 @@
*/
/* To increase portability, use unsigned char and unsigned char * when accessing parts of larger
- * types to convert their Endianess
+ * types to convert their Endianness
*/
#define CNV_END_SHORT(w) (hcf_16)( ((hcf_16)(w) & 0x00FF) << 8 | ((hcf_16)(w) & 0xFF00) >> 8 )
@@ -109,14 +109,14 @@
#if HCF_BIG_ENDIAN
//******************************************** B I G E N D I A N *******************************************
-#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed
-#define CNV_BIG_TO_SHORT(w) (w) // no endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed
+#define CNV_BIG_TO_SHORT(w) (w) // no endianness conversion needed
#define CNV_LITTLE_TO_LONG(dw) CNV_END_LONG(dw)
#define CNV_LONG_TO_LITTLE(dw) CNV_END_LONG(dw)
#else
//****************************************** L I T T L E E N D I A N ****************************************
-#define CNV_LITTLE_TO_SHORT(w) (w) // no endianess conversion needed
-#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w) (w) // no endianness conversion needed
+#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed
#define CNV_LITTLE_TO_LONG(dw) (dw)
#define CNV_LONG_TO_LITTLE(dw) (dw)
diff --git a/drivers/staging/wlags49_h2/mmd.c b/drivers/staging/wlags49_h2/mmd.c
index c8f5210..7204a37 100644
--- a/drivers/staging/wlags49_h2/mmd.c
+++ b/drivers/staging/wlags49_h2/mmd.c
@@ -101,10 +101,10 @@
* supp address of the supplier specification
*
* Description: mmd_check_comp is a support routine to check the compatibility between an actor and a
-* supplier. mmd_check_comp is independent of the endianess of the actp and supp structures. This is
+* supplier. mmd_check_comp is independent of the endianness of the actp and supp structures. This is
* achieved by checking the "bottom" or "role" fields of these structures. Since these fields are restricted
* to a limited range, comparing the contents to a value with a known endian-ess gives a clue to their actual
-* endianess.
+* endianness.
*
*.DIAGRAM
*1a: The role-field of the actor structure has a known non-zero, not "byte symmetric" value (namely
@@ -114,16 +114,16 @@
* for a supplier. A supplier has always exactly 1 variant,top,bottom record with (officially, but see the
* note below) each of these 3 values in the range 1 through 99, so one byte of the word value of variant,
* top and bottom words is 0x00 and the other byte is non-zero. Whether the lowest address byte or the
-* highest address byte is non-zero depends on the Endianess of the LTV. If and only if the word value of
+* highest address byte is non-zero depends on the Endianness of the LTV. If and only if the word value of
* bottom is less than 0x0100, the supplier is Native Endian.
* NOTE: the variant field of the supplier structure can not be used for the Endian Detection Algorithm,
* because a a zero-valued variant has been used as Controlled Deployment indication in the past.
* Note: An actor may have multiple sets of variant,top,bottom records, including dummy sets with variant,
-* top and bottom fields with a zero-value. As a consequence the endianess of the actor can not be determined
+* top and bottom fields with a zero-value. As a consequence the endianness of the actor can not be determined
* based on its variant,top,bottom values.
*
* Note: the L and T field of the structures are always in Native Endian format, so you can not draw
-* conclusions concerning the Endianess of the structure based on these two fields.
+* conclusions concerning the Endianness of the structure based on these two fields.
*
*1b/2b
* The only purpose of the CFG_RANGE_SPEC_BYTE_STRCT is to give easy access to the non-zero byte of the word
@@ -149,7 +149,7 @@
*
* This is implemented as:
* #if HCF_BIG_ENDIAN == 0 //platform is LE
-* sup/act_endian becomes reverse of structure-endianess as determined in 1a/1b
+* sup/act_endian becomes reverse of structure-endianness as determined in 1a/1b
* #endif
*6: Each of the actor variant-bottom-top records is checked against the (single) supplier variant-bottom-top
* range till either an acceptable match is found or all actor records are tried. As explained above, due to
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index 7084f41..7c7c77f 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -177,10 +177,9 @@ static void wl_adapter_detach(struct pcmcia_device *link)
if (dev) {
unregister_wlags_sysfs(dev);
unregister_netdev(dev);
+ wl_device_dealloc(dev);
}
- wl_device_dealloc(dev);
-
DBG_LEAVE(DbgInfo);
} /* wl_adapter_detach */
/*============================================================================*/
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 90820ff..824b852 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -1063,7 +1063,7 @@ void wl_multicast( struct net_device *dev )
#if DBG
if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
DBG_PRINT(" flags: %s%s%s\n",
- ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "",
+ ( dev->flags & IFF_PROMISC ) ? "Promiscuous " : "",
( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
@@ -1510,8 +1510,11 @@ void wl_wds_device_alloc( struct wl_private *lp )
for( count = 0; count < NUM_WDS_PORTS; count++ ) {
struct net_device *dev_wds = NULL;
- dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL );
- memset( dev_wds, 0, sizeof( struct net_device ));
+ dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (!dev_wds) {
+ DBG_LEAVE(DbgInfo);
+ return;
+ }
ether_setup( dev_wds );
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 3df990c..0b31b01 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -524,6 +524,7 @@ int wl_pci_setup( struct pci_dev *pdev )
/* Make sure that space was allocated for our private adapter struct */
if( dev->priv == NULL ) {
DBG_ERROR( DbgInfo, "Private adapter struct was not allocated!!!\n" );
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return -ENOMEM;
}
@@ -532,6 +533,7 @@ int wl_pci_setup( struct pci_dev *pdev )
/* Allocate DMA Descriptors */
if( wl_pci_dma_alloc( pdev, dev->priv ) < 0 ) {
DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" );
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return -ENOMEM;
}
@@ -561,6 +563,8 @@ int wl_pci_setup( struct pci_dev *pdev )
result = request_irq(dev->irq, wl_isr, SA_SHIRQ, dev->name, dev);
if( result ) {
DBG_WARNING( DbgInfo, "Could not register ISR!!!\n" );
+ wl_remove(dev);
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return result;
}
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index b8c96cf..0e49272 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -401,7 +401,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
lp->brsc[0] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
} else if (strcmp(key, PARM_NAME_BRSC_5GHZ) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_5GHZ, value);
@@ -409,7 +409,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
lp->brsc[1] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
} else if ((strcmp(key, PARM_NAME_DESIRED_SSID) == 0) || (strcmp(key, PARM_NAME_OWN_SSID) == 0)) {
DBG_TRACE(DbgInfo, "SSID, value: %s\n", value);
@@ -556,7 +556,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
lp->srsc[0] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
} else if (strcmp(key, PARM_NAME_SRSC_5GHZ) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_5GHZ, value);
@@ -564,7 +564,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
lp->srsc[1] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
} else if (strcmp(key, PARM_NAME_SYSTEM_SCALE) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value);
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index f104e6f..404ec7d 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -98,8 +98,7 @@
******************************************************************************/
/* A matrix which maps channels to frequencies */
-#define MAX_CHAN_FREQ_MAP_ENTRIES 50
-static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
+static const long chan_freq_list[][2] =
{
{1,2412},
{2,2417},
@@ -846,7 +845,7 @@ int wl_is_a_valid_chan( int channel )
}
/* Iterate through the matrix and retrieve the frequency */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][0] == channel ) {
return 1;
}
@@ -884,7 +883,7 @@ int wl_is_a_valid_freq( long frequency )
/* Iterate through the matrix and retrieve the channel */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][1] == frequency ) {
return 1;
}
@@ -927,7 +926,7 @@ long wl_get_freq_from_chan( int channel )
}
/* Iterate through the matrix and retrieve the frequency */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][0] == channel ) {
return chan_freq_list[i][1];
}
@@ -965,7 +964,7 @@ int wl_get_chan_from_freq( long frequency )
/* Iterate through the matrix and retrieve the channel */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][1] == frequency ) {
return chan_freq_list[i][0];
}
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 4cd3ba5..8bc562b 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -332,6 +332,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
wlandevice_t *wlandev = dev->ml_priv;
struct p80211msg_dot11req_scan msg1;
struct p80211msg_dot11req_scan_results msg2;
+ struct cfg80211_bss *bss;
int result;
int err = 0;
int numbss = 0;
@@ -401,7 +402,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
ie_buf[1] = msg2.ssid.data.len;
ie_len = ie_buf[1] + 2;
memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
- cfg80211_inform_bss(wiphy,
+ bss = cfg80211_inform_bss(wiphy,
ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
(const u8 *) &(msg2.bssid.data.data),
msg2.timestamp.data, msg2.capinfo.data,
@@ -411,6 +412,13 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
(msg2.signal.data - 65536) * 100, /* Conversion to signed type */
GFP_KERNEL
);
+
+ if (!bss) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ cfg80211_put_bss(bss);
}
if (result)
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index c3bb05d..4efa9bc 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -380,8 +380,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
}
count = (hw->scanresults->framelen - 3) / 32;
- if (count > 32)
- count = 32;
+ if (count > HFA384x_SCANRESULT_MAX)
+ count = HFA384x_SCANRESULT_MAX;
if (req->bssindex.data >= count) {
pr_debug("requested index (%d) out of range (%d)\n",
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index e828fd4..9c62aeb 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -12,9 +12,6 @@
#define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-#ifndef PCI_DEVICE_ID_XGI_41
-#define PCI_DEVICE_ID_XGI_41 0x041
-#endif
#ifndef PCI_DEVICE_ID_XGI_42
#define PCI_DEVICE_ID_XGI_42 0x042
#endif
@@ -82,177 +79,79 @@ static int XGIfb_tvplug = -1;
/* TW: For ioctl XGIFB_GET_INFO */
/* XGIfb_info XGIfbinfo; */
-#define MD_XGI300 1
-#define MD_XGI315 2
+#define MD_XGI315 1
/* mode table */
static const struct _XGIbios_mode {
- char name[15];
u8 mode_no;
u16 vesa_mode_no_1; /* "XGI defined" VESA mode number */
u16 vesa_mode_no_2; /* Real VESA mode numbers */
u16 xres;
u16 yres;
u16 bpp;
- u16 rate_idx;
- u16 cols;
- u16 rows;
u8 chipset;
} XGIbios_mode[] = {
- {"320x240x16", 0x56, 0x0000, 0x0000, 320, 240, 16, 1, 40, 15,
- MD_XGI315},
- {"320x480x8", 0x5A, 0x0000, 0x0000, 320, 480, 8, 1, 40, 30,
- MD_XGI315}, /* TW: FSTN */
- {"320x480x16", 0x5B, 0x0000, 0x0000, 320, 480, 16, 1, 40, 30,
- MD_XGI315}, /* TW: FSTN */
- {"640x480x8", 0x2E, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"640x480x16", 0x44, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"640x480x24", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30,
- MD_XGI300|MD_XGI315}, /* TW: That's for people who mix up color-
- and fb depth */
- {"640x480x32", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x8", 0x31, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x16", 0x33, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x24", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x32", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x576x8", 0x32, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x16", 0x34, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x24", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x32", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"800x480x8", 0x70, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x16", 0x7a, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x24", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x32", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x600x8", 0x30, 0x0103, 0x0103, 800, 600, 8, 1, 100, 37,
- MD_XGI300|MD_XGI315},
-#define DEFAULT_MODE 20 /* index for 800x600x16 */
- {"800x600x16", 0x47, 0x0114, 0x0114, 800, 600, 16, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"800x600x24", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"800x600x32", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"1024x576x8", 0x71, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x16", 0x74, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x24", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x32", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x600x8", 0x20, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37,
- MD_XGI300 }, /* TW: 300 series only */
- {"1024x600x16", 0x21, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37,
- MD_XGI300 },
- {"1024x600x24", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37,
- MD_XGI300 },
- {"1024x600x32", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37,
- MD_XGI300 },
- {"1024x768x8", 0x38, 0x0105, 0x0105, 1024, 768, 8, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x16", 0x4A, 0x0117, 0x0117, 1024, 768, 16, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x24", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x32", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1152x768x8", 0x23, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48,
- MD_XGI300 }, /* TW: 300 series only */
- {"1152x768x16", 0x24, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48,
- MD_XGI300 },
- {"1152x768x24", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48,
- MD_XGI300 },
- {"1152x768x32", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48,
- MD_XGI300 },
- {"1280x720x8", 0x79, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x16", 0x75, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x24", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x32", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x768x8", 0x23, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48,
- MD_XGI315}, /* TW: 310/325 series only */
- {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48,
- MD_XGI315},
- {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48,
- MD_XGI315},
- {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48,
- MD_XGI315},
- {"1280x960x8", 0x7C, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x16", 0x7D, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x24", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x32", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x1024x8", 0x3A, 0x0107, 0x0107, 1280, 1024, 8, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1400x1050x8", 0x26, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65,
- MD_XGI315}, /* TW: 310/325 series only */
- {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,
- MD_XGI315},
- {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
- MD_XGI315},
- {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
- MD_XGI315},
- {"1600x1200x8", 0x3C, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"2048x1536x8", 0x6c, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96,
- MD_XGI315}, /* TW: 310/325 series only */
- {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,
- MD_XGI315},
- {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
- MD_XGI315},
- {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
- MD_XGI315},
- {"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
+ { 0x56, 0x0000, 0x0000, 320, 240, 16, MD_XGI315 },
+ { 0x5A, 0x0000, 0x0000, 320, 480, 8, MD_XGI315 },
+ { 0x5B, 0x0000, 0x0000, 320, 480, 16, MD_XGI315 },
+ { 0x2E, 0x0101, 0x0101, 640, 480, 8, MD_XGI315 },
+ { 0x44, 0x0111, 0x0111, 640, 480, 16, MD_XGI315 },
+ { 0x62, 0x013a, 0x0112, 640, 480, 32, MD_XGI315 },
+ { 0x31, 0x0000, 0x0000, 720, 480, 8, MD_XGI315 },
+ { 0x33, 0x0000, 0x0000, 720, 480, 16, MD_XGI315 },
+ { 0x35, 0x0000, 0x0000, 720, 480, 32, MD_XGI315 },
+ { 0x32, 0x0000, 0x0000, 720, 576, 8, MD_XGI315 },
+ { 0x34, 0x0000, 0x0000, 720, 576, 16, MD_XGI315 },
+ { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 },
+ { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 },
+ { 0x70, 0x0000, 0x0000, 800, 480, 8, MD_XGI315 },
+ { 0x7a, 0x0000, 0x0000, 800, 480, 16, MD_XGI315 },
+ { 0x76, 0x0000, 0x0000, 800, 480, 32, MD_XGI315 },
+ { 0x30, 0x0103, 0x0103, 800, 600, 8, MD_XGI315 },
+#define DEFAULT_MODE 17 /* index for 800x600x16 */
+ { 0x47, 0x0114, 0x0114, 800, 600, 16, MD_XGI315 },
+ { 0x63, 0x013b, 0x0115, 800, 600, 32, MD_XGI315 },
+ { 0x71, 0x0000, 0x0000, 1024, 576, 8, MD_XGI315 },
+ { 0x74, 0x0000, 0x0000, 1024, 576, 16, MD_XGI315 },
+ { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 },
+ { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 },
+ { 0x20, 0x0000, 0x0000, 1024, 600, 8, },
+ { 0x21, 0x0000, 0x0000, 1024, 600, 16, },
+ { 0x22, 0x0000, 0x0000, 1024, 600, 32, },
+ { 0x38, 0x0105, 0x0105, 1024, 768, 8, MD_XGI315 },
+ { 0x4A, 0x0117, 0x0117, 1024, 768, 16, MD_XGI315 },
+ { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 },
+ { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 },
+ { 0x23, 0x0000, 0x0000, 1152, 768, 8, },
+ { 0x24, 0x0000, 0x0000, 1152, 768, 16, },
+ { 0x25, 0x0000, 0x0000, 1152, 768, 32, },
+ { 0x79, 0x0000, 0x0000, 1280, 720, 8, MD_XGI315 },
+ { 0x75, 0x0000, 0x0000, 1280, 720, 16, MD_XGI315 },
+ { 0x78, 0x0000, 0x0000, 1280, 720, 32, MD_XGI315 },
+ { 0x23, 0x0000, 0x0000, 1280, 768, 8, MD_XGI315 },
+ { 0x24, 0x0000, 0x0000, 1280, 768, 16, MD_XGI315 },
+ { 0x25, 0x0000, 0x0000, 1280, 768, 32, MD_XGI315 },
+ { 0x7C, 0x0000, 0x0000, 1280, 960, 8, MD_XGI315 },
+ { 0x7D, 0x0000, 0x0000, 1280, 960, 16, MD_XGI315 },
+ { 0x7E, 0x0000, 0x0000, 1280, 960, 32, MD_XGI315 },
+ { 0x3A, 0x0107, 0x0107, 1280, 1024, 8, MD_XGI315 },
+ { 0x4D, 0x011a, 0x011a, 1280, 1024, 16, MD_XGI315 },
+ { 0x65, 0x013d, 0x011b, 1280, 1024, 32, MD_XGI315 },
+ { 0x26, 0x0000, 0x0000, 1400, 1050, 8, MD_XGI315 },
+ { 0x27, 0x0000, 0x0000, 1400, 1050, 16, MD_XGI315 },
+ { 0x28, 0x0000, 0x0000, 1400, 1050, 32, MD_XGI315 },
+ { 0x3C, 0x0130, 0x011c, 1600, 1200, 8, MD_XGI315 },
+ { 0x3D, 0x0131, 0x011e, 1600, 1200, 16, MD_XGI315 },
+ { 0x66, 0x013e, 0x011f, 1600, 1200, 32, MD_XGI315 },
+ { 0x68, 0x013f, 0x0000, 1920, 1440, 8, MD_XGI315 },
+ { 0x69, 0x0140, 0x0000, 1920, 1440, 16, MD_XGI315 },
+ { 0x6B, 0x0141, 0x0000, 1920, 1440, 32, MD_XGI315 },
+ { 0x6c, 0x0000, 0x0000, 2048, 1536, 8, MD_XGI315 },
+ { 0x6d, 0x0000, 0x0000, 2048, 1536, 16, MD_XGI315 },
+ { 0x6e, 0x0000, 0x0000, 2048, 1536, 32, MD_XGI315 },
+ { 0 },
};
-/* TW: CR36 evaluation */
-static const unsigned short XGI300paneltype[] = {
- LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
- LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768,
- LCD_1024x768, LCD_1024x768, LCD_1024x768,
- LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768};
-
static const unsigned short XGI310paneltype[] = {
LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960,
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 21c0378..85dbf32 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -156,25 +156,14 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
unsigned short ModeNo = modeno;
unsigned short ModeIdIndex = 0, ClockIndex = 0;
unsigned short RefreshRateTableIndex = 0;
-
- /* unsigned long temp = 0; */
int Clock;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
+ XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
+
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
- /*
- temp = XGI_SearchModeID(ModeNo , &ModeIdIndex, XGI_Pr) ;
- if (!temp) {
- printk(KERN_ERR "Could not find mode %x\n", ModeNo);
- return 65000;
- }
-
- RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
- RefreshRateTableIndex += (rateindex - 1);
-
- */
ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000;
@@ -190,7 +179,7 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
u32 *vmode)
{
unsigned short ModeNo = modeno;
- unsigned short ModeIdIndex = 0, index = 0;
+ unsigned short ModeIdIndex, index = 0;
unsigned short RefreshRateTableIndex = 0;
unsigned short VRE, VBE, VRS, VBS, VDE, VT;
@@ -199,16 +188,10 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
unsigned long cr_data3;
int A, B, C, D, E, F, temp, j;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
+ if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr))
+ return 0;
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
- /*
- temp = XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
- if (!temp)
- return 0;
-
- RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
- RefreshRateTableIndex += (rateindex - 1);
- */
index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5];
@@ -219,12 +202,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
HT = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8);
A = HT + 5;
- /*
- cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
-
- Horizontal display enable end
- HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6);
- */
HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) - 1;
E = HDE + 1;
@@ -358,7 +335,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr)
{
- XGI_Pr->RelIO = BaseAddr;
XGI_Pr->P3c4 = BaseAddr + 0x14;
XGI_Pr->P3d4 = BaseAddr + 0x24;
XGI_Pr->P3c0 = BaseAddr + 0x10;
@@ -414,19 +390,26 @@ static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info)
static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info,
const char *name)
{
- int i = 0, j = 0, l;
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int bpp;
+ int i;
- while (XGIbios_mode[i].mode_no != 0) {
- l = min(strlen(name), strlen(XGIbios_mode[i].name));
- if (!strncmp(name, XGIbios_mode[i].name, l)) {
+ if (sscanf(name, "%ux%ux%u", &xres, &yres, &bpp) != 3)
+ goto invalid_mode;
+
+ if (bpp == 24)
+ bpp = 32; /* That's for people who mix up color and fb depth. */
+
+ for (i = 0; XGIbios_mode[i].mode_no != 0; i++)
+ if (XGIbios_mode[i].xres == xres &&
+ XGIbios_mode[i].yres == yres &&
+ XGIbios_mode[i].bpp == bpp) {
xgifb_info->mode_idx = i;
- j = 1;
- break;
+ return;
}
- i++;
- }
- if (!j)
- pr_info("Invalid mode '%s'\n", name);
+invalid_mode:
+ pr_info("Invalid mode '%s'\n", name);
}
static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info,
@@ -1088,7 +1071,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
+ var->vsync_len;
#if defined(__powerpc__)
- u8 sr_data, cr_data;
+ u8 cr_data;
#endif
unsigned int drate = 0, hrate = 0;
int found_mode = 0;
@@ -1162,8 +1145,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
if (XGIfb_search_refresh_rate(xgifb_info,
xgifb_info->refresh_rate) == 0) {
- xgifb_info->rate_idx =
- XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+ xgifb_info->rate_idx = 1;
xgifb_info->refresh_rate = 60;
}
@@ -1680,17 +1662,6 @@ static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info)
ChannelNum = 1;
break;
- case XG45:
- if (tmp == 1)
- ChannelNum = 2;
- else if (tmp == 2)
- ChannelNum = 3;
- else if (tmp == 3)
- ChannelNum = 4;
- else
- ChannelNum = 1;
- break;
-
case XG40:
default:
if (tmp == 2)
@@ -1911,11 +1882,9 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->mmio_base = pci_resource_start(pdev, 1);
xgifb_info->mmio_size = pci_resource_len(pdev, 1);
xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
- hw_info->pjIOAddress = (unsigned char *)xgifb_info->vga_base;
- /* XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; */
- pr_info("Relocate IO address: %lx [%08lx]\n",
- (unsigned long)pci_resource_start(pdev, 2),
- xgifb_info->dev_info.RelIO);
+ pr_info("Relocate IO address: %Lx [%08lx]\n",
+ (u64) pci_resource_start(pdev, 2),
+ xgifb_info->vga_base);
if (pci_enable_device(pdev)) {
ret = -EIO;
@@ -1927,7 +1896,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->display2_force = true;
}
- XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress);
+ XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base);
xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
@@ -1950,9 +1919,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
case PCI_DEVICE_ID_XGI_40:
xgifb_info->chip = XG40;
break;
- case PCI_DEVICE_ID_XGI_41:
- xgifb_info->chip = XG41;
- break;
case PCI_DEVICE_ID_XGI_42:
xgifb_info->chip = XG42;
break;
@@ -2006,13 +1972,13 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
xgifb_info->mmio_size);
- pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
- xgifb_info->video_base,
+ pr_info("Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n",
+ (u64) xgifb_info->video_base,
xgifb_info->video_vbase,
xgifb_info->video_size / 1024);
- pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
- xgifb_info->mmio_base, xgifb_info->mmio_vbase,
+ pr_info("MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n",
+ (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase,
xgifb_info->mmio_size / 1024);
pci_set_drvdata(pdev, xgifb_info);
@@ -2174,8 +2140,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->refresh_rate = 60;
if (XGIfb_search_refresh_rate(xgifb_info,
xgifb_info->refresh_rate) == 0) {
- xgifb_info->rate_idx =
- XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+ xgifb_info->rate_idx = 1;
xgifb_info->refresh_rate = 60;
}
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 37bb730..9068c5a 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -23,9 +23,7 @@ enum xgifb_display_type {
enum XGI_CHIP_TYPE {
XG40 = 32,
- XG41,
XG42,
- XG45,
XG20 = 48,
XG21,
XG27,
@@ -66,9 +64,9 @@ struct xgifb_video_info {
int chip_id;
unsigned int video_size;
- unsigned long video_base;
+ phys_addr_t video_base;
void __iomem *video_vbase;
- unsigned long mmio_base;
+ phys_addr_t mmio_base;
unsigned long mmio_size;
void __iomem *mmio_vbase;
unsigned long vga_base;
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 3650bbf..c222d61 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -353,7 +353,6 @@ static void XGINew_DDR1x_DefaultRegister(
XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
switch (HwDeviceExtension->jChipType) {
- case XG41:
case XG42:
/* CR82 */
xgifb_reg_set(P3d4,
@@ -556,8 +555,7 @@ static void XGINew_SetDRAMDefaultRegister340(
xgifb_reg_set(P3d4, (0x8A + j),
pVBInfo->CR40[1 + j][pVBInfo->ram_type]);
- if ((HwDeviceExtension->jChipType == XG41) ||
- (HwDeviceExtension->jChipType == XG42))
+ if (HwDeviceExtension->jChipType == XG42)
xgifb_reg_set(P3d4, 0x8C, 0x87);
xgifb_reg_set(P3d4,
@@ -854,78 +852,6 @@ static void XGINew_CheckChannel(struct xgi_hw_device_info *HwDeviceExtension,
pVBInfo->ram_channel = 1; /* Single channel */
xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x51); /* 32Mx16 bit*/
break;
- case XG41:
- if (XGINew_CheckFrequence(pVBInfo) == 1) {
- pVBInfo->ram_bus = 32; /* 32 bits */
- pVBInfo->ram_channel = 3; /* Quad Channel */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4C);
-
- if (XGINew_ReadWriteRest(25, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x48);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x49);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 3;
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x3C);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x38);
-
- if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
- return;
- else
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x39);
- } else { /* DDR */
- pVBInfo->ram_bus = 64; /* 64 bits */
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x5A);
-
- if (XGINew_ReadWriteRest(25, 24, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 1; /* Single channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x52);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x53);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4A);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 1; /* Single channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x42);
-
- if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
- return;
- else
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x43);
- }
-
- break;
-
case XG42:
/*
XG42 SR14 D[3] Reserve
@@ -1478,7 +1404,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress;
- pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+ pVBInfo->BaseAddr = xgifb_info->vga_base;
/* Newdebugcode(0x99); */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index 60d4adf..b2f4338 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -16,36 +16,6 @@
#define IndexMask 0xff
-static const unsigned short XGINew_MDA_DAC[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
-
-static const unsigned short XGINew_CGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
-static const unsigned short XGINew_EGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
- 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
- 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
- 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
- 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
- 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
- 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
static const unsigned short XGINew_VGA_DAC[] = {
0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
@@ -60,8 +30,7 @@ static const unsigned short XGINew_VGA_DAC[] = {
void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
{
- pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable;
- pVBInfo->StandTable = (struct SiS_StandTable_S *) XGI330_StandTable;
+ pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable;
pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable;
pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex;
pVBInfo->XGINEWUB_CRT1Table
@@ -182,38 +151,17 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
}
-static unsigned char XGI_GetModePtr(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
-{
- unsigned char index;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].St_StTableIndex;
- else {
- if (pVBInfo->ModeType <= 0x02)
- index = 0x1B; /* 02 -> ModeEGA */
- else
- index = 0x0F;
- }
- return index; /* Get pVBInfo->StandTable index */
-}
-
static void XGI_SetSeqRegs(unsigned short ModeNo,
- unsigned short StandTableIndex,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned char tempah, SRdata;
unsigned short i, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
xgifb_reg_set(pVBInfo->P3c4, 0x00, 0x03); /* Set SR0 */
- tempah = pVBInfo->StandTable[StandTableIndex].SR[0];
+ tempah = pVBInfo->StandTable->SR[0];
i = XGI_SetCRT2ToLCDA;
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -230,13 +178,12 @@ static void XGI_SetSeqRegs(unsigned short ModeNo,
for (i = 02; i <= 04; i++) {
/* Get SR2,3,4 from file */
- SRdata = pVBInfo->StandTable[StandTableIndex].SR[i - 1];
+ SRdata = pVBInfo->StandTable->SR[i - 1];
xgifb_reg_set(pVBInfo->P3c4, i, SRdata); /* Set SR2 3 4 */
}
}
static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short StandTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned char CRTCdata;
@@ -248,26 +195,22 @@ static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
for (i = 0; i <= 0x18; i++) {
/* Get CRTC from file */
- CRTCdata = pVBInfo->StandTable[StandTableIndex].CRTC[i];
+ CRTCdata = pVBInfo->StandTable->CRTC[i];
xgifb_reg_set(pVBInfo->P3d4, i, CRTCdata); /* Set CRTC(3d4) */
}
}
static void XGI_SetATTRegs(unsigned short ModeNo,
- unsigned short StandTableIndex,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned char ARdata;
unsigned short i, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
for (i = 0; i <= 0x13; i++) {
- ARdata = pVBInfo->StandTable[StandTableIndex].ATTR[i];
+ ARdata = pVBInfo->StandTable->ATTR[i];
if (modeflag & Charx8Dot) { /* ifndef Dot9 */
if (i == 0x13) {
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -295,15 +238,14 @@ static void XGI_SetATTRegs(unsigned short ModeNo,
outb(0x20, pVBInfo->P3c0);
}
-static void XGI_SetGRCRegs(unsigned short StandTableIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetGRCRegs(struct vb_device_info *pVBInfo)
{
unsigned char GRdata;
unsigned short i;
for (i = 0; i <= 0x08; i++) {
/* Get GR from file */
- GRdata = pVBInfo->StandTable[StandTableIndex].GRC[i];
+ GRdata = pVBInfo->StandTable->GRC[i];
xgifb_reg_set(pVBInfo->P3ce, i, GRdata); /* Set GR(3ce) */
}
@@ -344,12 +286,7 @@ static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo,
{
unsigned short tempax, tempbx, resinfo, modeflag, infoflag;
- if (ModeNo <= 0x13)
- /* si+St_ModeFlag */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
tempbx = pVBInfo->RefIndex[RefreshRateTableIndex + (*i)].ModeID;
tempax = 0;
@@ -584,11 +521,7 @@ static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
data &= 0x80;
data = data >> 2;
- if (ModeNo <= 0x13)
- i = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
i &= DoubleScanMode;
if (i)
data |= 0x80;
@@ -641,158 +574,97 @@ static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
- unsigned char StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
+ unsigned char index, Tempax, Tempbx, Tempcx, Tempdx;
unsigned short Temp1, Temp2, Temp3;
- if (ModeNo <= 0x13) {
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- /* CR04 HRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
- /* SR2E [7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
- /* Tempbx: CR05 HRE */
- Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
- Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
- Tempcx = Tempax;
- Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
- Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
- if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
- Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
- Tempdx <<= 2; /* Tempdx << 2 */
- /* SR2F [7:2]->HRE */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* Tempax: CR16 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
- Tempbx = Tempax; /* Tempbx=Tempax */
- Tempax &= 0x01; /* Tempax: VRS[0] */
- xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS */
-
- /* Tempax: CR7 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- Tempdx = Tempbx >> 1; /* Tempdx: VRS[7:1] */
- Tempcx = Tempax & 0x04; /* Tempcx: CR7[2] */
- Tempcx <<= 5; /* Tempcx[7]: VRS[8] */
- Tempdx |= Tempcx; /* Tempdx: VRS[8:1] */
- /* SR34[7:0]: VRS[8:1] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempdx);
-
- /* Temp1[8]: VRS[8] unsigned char -> unsigned short */
- Temp1 = Tempcx << 1;
- Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
- Tempax &= 0x80; /* Tempax[7]: CR7[7] */
- Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
- Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
-
- /* CR16 VRE */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- Temp2 = Temp1 & 0x3F0; /* Temp2[9:4]: VRS[9:4] */
- Temp2 |= Tempax; /* Temp2[9:0]: VRE[9:0] */
- Temp3 = Temp1 & 0x0F; /* Temp3[3:0]: VRS[3:0] */
- if (Tempax < Temp3) /* VRE[3:0]<VRS[3:0] */
- Temp2 |= 0x10; /* Temp2: VRE + 0x10 */
- Temp2 &= 0xFF; /* Temp2[7:0]: VRE[7:0] */
- Tempax = (unsigned char) Temp2; /* Tempax[7:0]: VRE[7:0] */
- Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
- Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
- Temp1 >>= 9; /* [10:9]->[1:0] */
- Tempbx = (unsigned char) Temp1; /* Tempbx[1:0]: VRS[10:9] */
- Tempax |= Tempbx; /* VRE[5:0]VRS[10:9] */
- Tempax &= 0x7F;
- /* SR3F D[7:2]->VRE D[1:0]->VRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
- } else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempcx = Tempax; /* Tempcx: HRS */
- /* SR2E[7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-
- Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
- Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
- Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
- Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
- Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
- Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
-
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
- Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
- Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
- Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
-
- Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
- Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
-
- Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
- if (Tempax < Tempcx) /* HRE < HRS */
- Temp2 |= 0x40; /* Temp2 + 0x40 */
-
- Temp2 &= 0xFF;
- Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
- Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
- Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
- Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
- /* SR2F D[7:2]->HRE, D[1:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* CR10 VRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
- Tempbx = Tempax; /* Tempbx: VRS */
- Tempax &= 0x01; /* Tempax[0]: VRS[0] */
- xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
- /* CR7[2][7] VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
- Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
- Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
- Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
- Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
-
- Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
- Temp1 <<= 1; /* Temp1[8]: VRS[8] */
- Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
- Tempax &= 0x80;
- Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
- Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
- /* Tempax: SRA */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempax &= 0x08; /* Tempax[3]: VRS[3] */
- Temp2 = Tempax;
- Temp2 <<= 7; /* Temp2[10]: VRS[10] */
- Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
-
- /* Tempax: CR11 VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- /* Tempbx: SRA */
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
- Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
- Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
- Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
- Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
-
- Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
- if (Tempax < Temp3) /* VRE < VRS */
- Temp2 |= 0x20; /* VRE + 0x20 */
-
- Temp2 &= 0xFF;
- Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
- Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
- Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
- Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
- Tempbx = (unsigned char) Temp1;
- Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
- Tempax &= 0x7F;
- /* SR3F D[7:2]->VRE D[1:0]->VRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
- }
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempcx = Tempax; /* Tempcx: HRS */
+ /* SR2E[7:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+
+ Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
+ Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
+ Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
+ Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
+ Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+ Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+ Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
+ Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
+ Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
+
+ Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
+ Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
+
+ Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
+ if (Tempax < Tempcx) /* HRE < HRS */
+ Temp2 |= 0x40; /* Temp2 + 0x40 */
+
+ Temp2 &= 0xFF;
+ Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
+ Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
+ Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
+ Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
+ /* SR2F D[7:2]->HRE, D[1:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+
+ /* CR10 VRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+ Tempbx = Tempax; /* Tempbx: VRS */
+ Tempax &= 0x01; /* Tempax[0]: VRS[0] */
+ xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
+ /* CR7[2][7] VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+ Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
+ Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
+ Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
+ Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
+
+ Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
+ Temp1 <<= 1; /* Temp1[8]: VRS[8] */
+ Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
+ Tempax &= 0x80;
+ Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
+ Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
+ /* Tempax: SRA */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempax &= 0x08; /* Tempax[3]: VRS[3] */
+ Temp2 = Tempax;
+ Temp2 <<= 7; /* Temp2[10]: VRS[10] */
+ Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
+
+ /* Tempax: CR11 VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+ Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+ /* Tempbx: SRA */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
+ Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+ Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
+ Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
+
+ Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
+ if (Tempax < Temp3) /* VRE < VRS */
+ Temp2 |= 0x20; /* VRE + 0x20 */
+
+ Temp2 &= 0xFF;
+ Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
+ Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
+ Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
+ Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
+ Tempbx = (unsigned char) Temp1;
+ Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
+ Tempax &= 0x7F;
+ /* SR3F D[7:2]->VRE D[1:0]->VRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
}
static void XGI_SetXG27CRTC(unsigned short ModeNo,
@@ -800,139 +672,88 @@ static void XGI_SetXG27CRTC(unsigned short ModeNo,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
-
- if (ModeNo <= 0x13) {
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- /* CR04 HRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
- /* SR2E [7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
- /* Tempbx: CR05 HRE */
- Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
- Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
- Tempcx = Tempax;
- Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
- Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
- if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
- Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
- Tempdx <<= 2; /* Tempdx << 2 */
- /* SR2F [7:2]->HRE */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* Tempax: CR10 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); /* SR34[7:0]->VRS */
- Tempcx = Tempax; /* Tempcx=Tempax=VRS[7:0] */
- /* Tempax[7][2]: CR7[7][2] VRS[9][8] */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- Tempbx = Tempax; /* Tempbx=CR07 */
- Tempax &= 0x04; /* Tempax[2]: CR07[2] VRS[8] */
- Tempax >>= 2;
- /* SR35 D[0]->VRS D[8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
- Tempcx |= (Tempax << 8); /* Tempcx[8] |= VRS[8] */
- Tempcx |= (Tempbx & 0x80) << 2; /* Tempcx[9] |= VRS[9] */
-
- /* CR11 VRE */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
- Tempax &= 0x0F; /* Tempax: VRE[3:0] */
- Tempbx = Tempcx; /* Tempbx=Tempcx=VRS[9:0] */
- Tempbx &= 0x3F0; /* Tempbx[9:4]: VRS[9:4] */
- Tempbx |= Tempax; /* Tempbx[9:0]: VRE[9:0] */
- if (Tempax <= (Tempcx & 0x0F)) /* VRE[3:0]<=VRS[3:0] */
- Tempbx |= 0x10; /* Tempbx: VRE + 0x10 */
- /* Tempax[7:0]: VRE[7:0] */
- Tempax = (unsigned char) Tempbx & 0xFF;
- Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
- Tempcx = (Tempcx & 0x600) >> 8; /* Tempcx VRS[10:9] */
- /* SR3F D[7:2]->VRE D[5:0] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
- /* SR35 D[2:1]->VRS[10:9] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x06, Tempcx);
- } else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempbx = Tempax; /* Tempbx: HRS[7:0] */
- /* SR2E[7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-
- /* SR0B */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
- Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
- Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
- Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
- Tempcx = Tempax; /* Tempcx: HRE[4:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
- Tempax &= 0x04; /* Tempax[2]: HRE[5] */
- Tempax <<= 3; /* Tempax[5]: HRE[5] */
- Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
-
- Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
- Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
-
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempax &= 0x3F; /* Tempax: HRS[5:0] */
- if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
- Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
- Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
- Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
- Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
- /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* CR10 VRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
- /* SR34[7:0]->VRS[7:0] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
-
- Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
- /* CR7[7][2] VRS[9][8] */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
- Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
- Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
- Tempax >>= 2; /* Tempax[0]: VRS[8] */
- /* SR35[0]: VRS[8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
- Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
- Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
- /* Tempax: SR0A */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempax &= 0x08; /* SR0A[3] VRS[10] */
- Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
-
- /* Tempax: CR11 VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- /* Tempbx: SR0A */
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
- Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
- Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
- Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
- Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
- Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
-
- if (Tempbx <= Tempcx) /* VRE <= VRS */
- Tempbx |= 0x20; /* VRE + 0x20 */
-
- /* Tempax: Tempax[7:0]; VRE[5:0]00 */
- Tempax = (Tempbx << 2) & 0xFF;
- /* SR3F[7:2]:VRE[5:0] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
- Tempax = Tempcx >> 8;
- /* SR35[2:0]:VRS[10:8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
- }
+ unsigned short index, Tempax, Tempbx, Tempcx;
+
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempbx = Tempax; /* Tempbx: HRS[7:0] */
+ /* SR2E[7:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+
+ /* SR0B */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
+ Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+ Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+ Tempcx = Tempax; /* Tempcx: HRE[4:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+ Tempax &= 0x04; /* Tempax[2]: HRE[5] */
+ Tempax <<= 3; /* Tempax[5]: HRE[5] */
+ Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
+
+ Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
+ Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
+
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempax &= 0x3F; /* Tempax: HRS[5:0] */
+ if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
+ Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
+ Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
+ Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
+ /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+
+ /* CR10 VRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+ /* SR34[7:0]->VRS[7:0] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
+
+ Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
+ /* CR7[7][2] VRS[9][8] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+ Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
+ Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
+ Tempax >>= 2; /* Tempax[0]: VRS[8] */
+ /* SR35[0]: VRS[8] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
+ Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
+ Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
+ /* Tempax: SR0A */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempax &= 0x08; /* SR0A[3] VRS[10] */
+ Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
+
+ /* Tempax: CR11 VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+ Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+ /* Tempbx: SR0A */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
+ Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+ Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
+ Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
+ Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
+
+ if (Tempbx <= Tempcx) /* VRE <= VRS */
+ Tempbx |= 0x20; /* VRE + 0x20 */
+
+ /* Tempax: Tempax[7:0]; VRE[5:0]00 */
+ Tempax = (Tempbx << 2) & 0xFF;
+ /* SR3F[7:2]:VRE[5:0] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
+ Tempax = Tempcx >> 8;
+ /* SR35[2:0]:VRS[10:8] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
}
static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo)
@@ -954,7 +775,7 @@ static void xgifb_set_lcd(int chip_id,
unsigned short RefreshRateTableIndex,
unsigned short ModeNo)
{
- unsigned short Data, Temp, b3CC;
+ unsigned short Data, Temp;
unsigned short XGI_P3cc;
XGI_P3cc = pVBInfo->P3cc;
@@ -995,23 +816,13 @@ static void xgifb_set_lcd(int chip_id,
xgifb_reg_and(pVBInfo->P3c4, 0x30, ~0x20); /* Hsync polarity */
xgifb_reg_and(pVBInfo->P3c4, 0x35, ~0x80); /* Vsync polarity */
- if (ModeNo <= 0x13) {
- b3CC = (unsigned char) inb(XGI_P3cc);
- if (b3CC & 0x40)
- /* Hsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
- if (b3CC & 0x80)
- /* Vsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
- } else {
- Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
- if (Data & 0x4000)
- /* Hsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
- if (Data & 0x8000)
- /* Vsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
- }
+ Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ if (Data & 0x4000)
+ /* Hsync polarity */
+ xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
+ if (Data & 0x8000)
+ /* Vsync polarity */
+ xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
}
/* --------------------------------------------------------------------- */
@@ -1024,30 +835,22 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo,
struct vb_device_info *pVBInfo,
unsigned short RefreshRateTableIndex)
{
- int i, index = -1;
+ int index = -1;
xgifb_reg_and(pVBInfo->P3d4, 0x11, 0x7F); /* Unlock CR0~7 */
- if (ModeNo <= 0x13) {
- for (i = 0; i < 12; i++) {
- if (ModeNo == pVBInfo->UpdateCRT1[i].ModeID)
- index = i;
- }
- } else {
- if (ModeNo == 0x2E &&
- (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
- RES640x480x60))
- index = 12;
- else if (ModeNo == 0x2E &&
- (pVBInfo->RefIndex[RefreshRateTableIndex].
+ if (ModeNo == 0x2E &&
+ (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
+ RES640x480x60))
+ index = 12;
+ else if (ModeNo == 0x2E && (pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRT1CRTC == RES640x480x72))
- index = 13;
- else if (ModeNo == 0x2F)
- index = 14;
- else if (ModeNo == 0x50)
- index = 15;
- else if (ModeNo == 0x59)
- index = 16;
- }
+ index = 13;
+ else if (ModeNo == 0x2F)
+ index = 14;
+ else if (ModeNo == 0x50)
+ index = 15;
+ else if (ModeNo == 0x59)
+ index = 16;
if (index != -1) {
xgifb_reg_set(pVBInfo->P3d4, 0x02,
@@ -1061,20 +864,6 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo,
}
}
-static unsigned short XGI_GetResInfo(unsigned short ModeNo,
- unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
-{
- unsigned short resindex;
-
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- return resindex;
-}
-
static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
@@ -1084,33 +873,25 @@ static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
unsigned char data;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempax = pVBInfo->StResInfo[resindex].HTotal;
- tempbx = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempax = pVBInfo->ModeResInfo[resindex].HTotal;
- tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempax = pVBInfo->ModeResInfo[resindex].HTotal;
+ tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
if (modeflag & HalfDCLK)
tempax = tempax >> 1;
- if (ModeNo > 0x13) {
- if (modeflag & HalfDCLK)
- tempax = tempax << 1;
+ if (modeflag & HalfDCLK)
+ tempax = tempax << 1;
- temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
- if (temp & InterlaceMode)
- tempbx = tempbx >> 1;
+ if (temp & InterlaceMode)
+ tempbx = tempbx >> 1;
- if (modeflag & DoubleScanMode)
- tempbx = tempbx << 1;
- }
+ if (modeflag & DoubleScanMode)
+ tempbx = tempbx << 1;
tempcx = 8;
@@ -1258,18 +1039,10 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
unsigned short CRT2Index, VCLKIndex;
unsigned short modeflag, resinfo;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- CRT2Index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
if (pVBInfo->IF_DEF_LVDS == 0) {
CRT2Index = CRT2Index >> 6; /* for LCD */
@@ -1318,23 +1091,13 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
VCLKIndex += 25;
}
} else { /* for CRT2 */
- /* Port 3cch */
- VCLKIndex = (unsigned char) inb((pVBInfo->P3ca + 0x02));
- VCLKIndex = ((VCLKIndex >> 2) & 0x03);
- if (ModeNo > 0x13) {
- /* di+Ext_CRTVCLK */
- VCLKIndex = pVBInfo->RefIndex[
- RefreshRateTableIndex].
+ /* di+Ext_CRTVCLK */
+ VCLKIndex = pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRTVCLK;
- VCLKIndex &= IndexMask;
- }
+ VCLKIndex &= IndexMask;
}
} else { /* LVDS */
- if (ModeNo <= 0x13)
- VCLKIndex = CRT2Index;
- else
- VCLKIndex = CRT2Index;
-
+ VCLKIndex = CRT2Index;
VCLKIndex = VCLKIndex >> 6;
if ((pVBInfo->LCDResInfo == Panel_800x600) ||
(pVBInfo->LCDResInfo == Panel_320x480))
@@ -1431,27 +1194,13 @@ static void XGI_SetCRT1FIFO(unsigned short ModeNo,
data &= 0xfe;
xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); /* diable auto-threshold */
- if (ModeNo > 0x13) {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xC0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
- data |= 0x01;
- xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
- } else {
- if (HwDeviceExtension->jChipType == XG27) {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x0E);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xC0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x20);
- } else {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0xAE);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xF0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data);
- }
- }
+ xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
+ data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
+ data &= 0xC0;
+ xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
+ data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
+ data |= 0x01;
+ xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
if (HwDeviceExtension->jChipType == XG21)
XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */
@@ -1466,13 +1215,9 @@ static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
unsigned char index;
- if (ModeNo <= 0x13)
- VCLK = 0;
- else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
- index &= IndexMask;
- VCLK = pVBInfo->VCLKData[index].CLOCK;
- }
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+ index &= IndexMask;
+ VCLK = pVBInfo->VCLKData[index].CLOCK;
data = xgifb_reg_get(pVBInfo->P3c4, 0x32);
data &= 0xf3;
@@ -1508,44 +1253,26 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
unsigned short data, data2, data3, infoflag = 0, modeflag, resindex,
xres;
- if (ModeNo > 0x13) {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_InfoFlag;
- } else
- /* si+St_ModeFlag */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
if (xgifb_reg_get(pVBInfo->P3d4, 0x31) & 0x01)
xgifb_reg_and_or(pVBInfo->P3c4, 0x1F, 0x3F, 0x00);
- if (ModeNo > 0x13)
- data = infoflag;
- else
- data = 0;
-
+ data = infoflag;
data2 = 0;
-
- if (ModeNo > 0x13) {
- if (pVBInfo->ModeType > 0x02) {
- data2 |= 0x02;
- data3 = pVBInfo->ModeType - ModeVGA;
- data3 = data3 << 2;
- data2 |= data3;
- }
- }
-
+ data2 |= 0x02;
+ data3 = pVBInfo->ModeType - ModeVGA;
+ data3 = data3 << 2;
+ data2 |= data3;
data &= InterlaceMode;
if (data)
data2 |= 0x20;
xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x3F, data2);
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13)
- xres = pVBInfo->StResInfo[resindex].HTotal;
- else
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
data = 0x0000;
if (infoflag & InterlaceMode) {
@@ -1568,18 +1295,10 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
if (modeflag & LineCompareOff)
data2 |= 0x08;
- if (ModeNo > 0x13) {
- if (pVBInfo->ModeType == ModeEGA)
- data2 |= 0x40;
- }
-
xgifb_reg_and_or(pVBInfo->P3c4, 0x0F, ~0x48, data2);
data = 0x60;
- if (pVBInfo->ModeType != ModeText) {
- data = data ^ 0x60;
- if (pVBInfo->ModeType != ModeEGA)
- data = data ^ 0xA0;
- }
+ data = data ^ 0x60;
+ data = data ^ 0xA0;
xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data);
XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex,
@@ -1644,38 +1363,13 @@ static void XGI_WriteDAC(unsigned short dl,
static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short data, data2, time, i, j, k, m, n, o, si, di, bx, dl, al,
- ah, dh;
- const unsigned short *table = NULL;
-
- if (ModeNo <= 0x13)
- data = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- data = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
- data &= DACInfoFlag;
- time = 64;
-
- if (data == 0x00)
- table = XGINew_MDA_DAC;
- else if (data == 0x08)
- table = XGINew_CGA_DAC;
- else if (data == 0x10)
- table = XGINew_EGA_DAC;
- else if (data == 0x18) {
- time = 256;
- table = XGINew_VGA_DAC;
- }
-
- if (time == 256)
- j = 16;
- else
- j = time;
+ unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh;
+ const unsigned short *table = XGINew_VGA_DAC;
outb(0xFF, pVBInfo->P3c6);
outb(0x00, pVBInfo->P3c8);
- for (i = 0; i < j; i++) {
+ for (i = 0; i < 16; i++) {
data = table[i];
for (k = 0; k < 3; k++) {
@@ -1692,45 +1386,43 @@ static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
- if (time == 256) {
- for (i = 16; i < 32; i++) {
- data = table[i];
-
- for (k = 0; k < 3; k++)
- outb(data, pVBInfo->P3c9);
- }
+ for (i = 16; i < 32; i++) {
+ data = table[i];
- si = 32;
+ for (k = 0; k < 3; k++)
+ outb(data, pVBInfo->P3c9);
+ }
- for (m = 0; m < 9; m++) {
- di = si;
- bx = si + 0x04;
- dl = 0;
+ si = 32;
- for (n = 0; n < 3; n++) {
- for (o = 0; o < 5; o++) {
- dh = table[si];
- ah = table[di];
- al = table[bx];
- si++;
- XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
- }
+ for (m = 0; m < 9; m++) {
+ di = si;
+ bx = si + 0x04;
+ dl = 0;
- si -= 2;
+ for (n = 0; n < 3; n++) {
+ for (o = 0; o < 5; o++) {
+ dh = table[si];
+ ah = table[di];
+ al = table[bx];
+ si++;
+ XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
+ }
- for (o = 0; o < 3; o++) {
- dh = table[bx];
- ah = table[di];
- al = table[si];
- si--;
- XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
- }
+ si -= 2;
- dl++;
+ for (o = 0; o < 3; o++) {
+ dh = table[bx];
+ ah = table[di];
+ al = table[si];
+ si--;
+ XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
}
- si += 5;
+ dl++;
}
+
+ si += 5;
}
}
@@ -1740,34 +1432,20 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo,
{
unsigned short resindex, xres, yres, modeflag;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ /* si+Ext_ResInfo */
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal;
- yres = pVBInfo->ModeResInfo[resindex].VTotal;
- }
- if (ModeNo > 0x13) {
- if (modeflag & HalfDCLK)
- xres = xres << 1;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal;
+ yres = pVBInfo->ModeResInfo[resindex].VTotal;
- if (modeflag & DoubleScanMode)
- yres = yres << 1;
- }
+ if (modeflag & HalfDCLK)
+ xres = xres << 1;
+
+ if (modeflag & DoubleScanMode)
+ yres = yres << 1;
if (xres == 720)
xres = 640;
@@ -1789,32 +1467,16 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo,
tempbx = BX;
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempal = tempal & 0x0f;
if (tempbx <= 1) { /* ExpLink */
- if (ModeNo <= 0x13) {
- /* find no Ext_CRT2CRTC2 */
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
- if (ModeNo <= 0x13)
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].
- St_CRT2CRTC2;
- else
- tempal = pVBInfo->RefIndex[
- RefreshRateTableIndex].
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRT2CRTC2;
}
@@ -1882,9 +1544,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo,
tempbx = tempdi[i].MASK;
tempdx = pVBInfo->LCDInfo;
- if (ModeNo <= 0x13) /* alan 09/10/2003 */
- tempdx |= SetLCDStdMode;
-
if (modeflag & HalfDCLK)
tempdx |= SetLCDLowResolution;
@@ -2238,15 +1897,8 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo,
struct XGI330_TVDataTablStruct *tempdi = NULL;
tempbx = BX;
-
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
- }
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempal = tempal & 0x3f;
table = tempbx;
@@ -2413,11 +2065,7 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
struct XGI_LVDSCRT1HDataStruct *LCDPtr = NULL;
struct XGI_LVDSCRT1VDataStruct *LCDPtr1 = NULL;
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- else
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
index = index & IndexMask;
tempbx = 0;
@@ -2530,14 +2178,10 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag;
unsigned long temp, temp1, temp2, temp3, push3;
- struct XGI330_LCDDataDesStruct *LCDPtr = NULL;
+ struct XGI_LCDDesStruct *LCDPtr = NULL;
struct XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL;
- if (ModeNo > 0x13)
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- else
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
tempbx = 3;
if (pVBInfo->LCDInfo & EnableScalingLCD)
LCDPtr1 =
@@ -2550,7 +2194,7 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo);
else
LCDPtr =
- (struct XGI330_LCDDataDesStruct *)
+ (struct XGI_LCDDesStruct *)
XGI_GetLcdPtr(
tempbx,
ModeNo,
@@ -2829,12 +2473,8 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
unsigned short index, modeflag;
unsigned char tempal;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if ((pVBInfo->SetFlag & ProgrammingCRT2) &&
(!(pVBInfo->LCDInfo & EnableScalingLCD))) { /* {LCDA/LCDB} */
@@ -2895,9 +2535,6 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
if ((pVBInfo->LCDInfo & EnableScalingLCD) && (modeflag & Charx8Dot))
tempal = tempal ^ tempal; /* ; set to VCLK25MHz always */
- if (ModeNo <= 0x13)
- return tempal;
-
tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
return tempal;
}
@@ -3079,11 +2716,7 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempax, push, tempbx, temp, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
pVBInfo->SetFlag = 0;
pVBInfo->ModeType = modeflag & ModeTypeMask;
tempbx = 0;
@@ -3283,17 +2916,8 @@ static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
resinfo = 0;
if (pVBInfo->VBInfo & SetCRT2ToTV) {
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ModeFlag; /* si+St_ModeFlag */
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ResInfo; /* si+St_ResInfo */
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].
- Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].
- Ext_RESINFO; /* si+Ext_ResInfo */
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
if (pVBInfo->VBInfo & SetCRT2ToTV) {
temp = xgifb_reg_get(pVBInfo->P3d4, 0x35);
@@ -3380,15 +3004,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
pVBInfo->LCDTypeInfo = 0;
pVBInfo->LCDInfo = 0;
- if (ModeNo <= 0x13) {
- /* si+St_ModeFlag // */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- /* si+Ext_ResInfo // */
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo // */
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
temp = xgifb_reg_get(pVBInfo->P3d4, 0x36); /* Get LCD Res.Info */
tempbx = temp & 0x0F;
@@ -3442,8 +3060,8 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
if (pVBInfo->IF_DEF_LVDS == 0) {
if ((pVBInfo->LCDResInfo == Panel_1400x1050) && (pVBInfo->VBInfo
- & SetCRT2ToLCD) && (ModeNo > 0x13) && (resinfo
- == 9) && (!(tempbx & EnableScalingLCD)))
+ & SetCRT2ToLCD) && (resinfo == 9) &&
+ (!(tempbx & EnableScalingLCD)))
/* set to center in 1280x1024 LCDB for Panel_1400x1050 */
tempbx |= SetLCDtoNonExpanding;
}
@@ -3453,12 +3071,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
if (!(tempbx & SetLCDtoNonExpanding)) {
tempbx |= XGI_EnableLVDSDDA;
} else {
- if (ModeNo > 0x13) {
- if (pVBInfo->LCDResInfo
- == Panel_1024x768) {
- if (resinfo == 4) {/* 512x384 */
- tempbx |= XGI_EnableLVDSDDA;
- }
+ if (pVBInfo->LCDResInfo == Panel_1024x768) {
+ if (resinfo == 4) {/* 512x384 */
+ tempbx |= XGI_EnableLVDSDDA;
}
}
}
@@ -3474,56 +3089,17 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
pVBInfo->LCDInfo = tempbx;
- if (pVBInfo->IF_DEF_LVDS == 0) {
- if (tempax & (LockLCDBToA | StLCDBToA)) {
- if (pVBInfo->VBInfo & SetInSlaveMode) {
- if (!(tempax & LockLCDBToA)) {
- if (ModeNo <= 0x13) {
- pVBInfo->VBInfo &=
- ~(SetSimuScanMode |
- SetInSlaveMode |
- SetCRT2ToLCD);
- pVBInfo->VBInfo |=
- XGI_SetCRT2ToLCDA |
- SetCRT2ToDualEdge;
- }
- }
- }
- }
- }
-
return 1;
}
unsigned char XGI_SearchModeID(unsigned short ModeNo,
unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo)
{
- if (ModeNo <= 5)
- ModeNo |= 1;
- if (ModeNo <= 0x13) {
- for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
- ModeNo)
- break;
- if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
- 0xFF)
- return 0;
- }
-
- if (ModeNo == 0x07)
- (*ModeIdIndex)++; /* 400 lines */
- if (ModeNo <= 3)
- (*ModeIdIndex) += 2; /* 400 lines */
- /* else 350 lines */
- } else {
- for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
- ModeNo)
- break;
- if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
- 0xFF)
- return 0;
- }
+ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
+ break;
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ return 0;
}
return 1;
@@ -3789,22 +3365,17 @@ static void XGI_GetCRT2ResInfo(unsigned short ModeNo,
{
unsigned short xres, yres, modeflag, resindex;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- if (modeflag & HalfDCLK)
- xres *= 2;
+ if (modeflag & HalfDCLK)
+ xres *= 2;
- if (modeflag & DoubleScanMode)
- yres *= 2;
- }
+ if (modeflag & DoubleScanMode)
+ yres *= 2;
if (pVBInfo->VBInfo & SetCRT2ToLCD) {
if (pVBInfo->IF_DEF_LVDS == 0) {
@@ -3868,37 +3439,23 @@ static void XGI_GetRAMDAC2DATA(unsigned short ModeNo,
struct vb_device_info *pVBInfo)
{
unsigned short tempax, tempbx, temp1, temp2, modeflag = 0, tempcx,
- StandTableIndex, CRT1Index;
+ CRT1Index;
pVBInfo->RVBHCMAX = 1;
pVBInfo->RVBHCFACT = 1;
-
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- tempax = pVBInfo->StandTable[StandTableIndex].CRTC[0];
- tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[6];
- temp1 = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- temp1 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[0];
- temp2 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[5];
- tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
- tempbx = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[8];
- tempcx = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
- tempcx &= 0x0100;
- tempcx = tempcx << 2;
- tempbx |= tempcx;
- temp1 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[9];
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[0];
+ temp2 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[5];
+ tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+ tempbx = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[8];
+ tempcx = (unsigned short)
+ pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
+ tempcx &= 0x0100;
+ tempcx = tempcx << 2;
+ tempbx |= tempcx;
+ temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[9];
if (temp1 & 0x01)
tempbx |= 0x0100;
@@ -3928,16 +3485,9 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
struct SiS_LCDData *LCDPtr = NULL;
struct SiS_TVData *TVPtr = NULL;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
pVBInfo->NewFlickerMode = 0;
pVBInfo->RVBHRS = 50;
@@ -4141,11 +3691,7 @@ static unsigned short XGI_GetColorDepth(unsigned short ModeNo,
short index;
unsigned short modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = (modeflag & ModeTypeMask) - ModeEGA;
if (index < 0)
@@ -4164,11 +3710,7 @@ static unsigned short XGI_GetOffset(unsigned short ModeNo,
ColorDepth[] = { 0x01, 0x02, 0x04 };
modeinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeInfo;
- if (ModeNo <= 0x14)
- infoflag = 0;
- else
- infoflag = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
index = (modeinfo >> 8) & 0xFF;
@@ -4228,12 +3770,9 @@ static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempcx = 0, CRT1Index = 0, resinfo = 0;
- if (ModeNo > 0x13) {
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
HwDeviceExtension, pVBInfo);
@@ -4254,17 +3793,10 @@ static void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short temp = 0, tempax = 0, tempbx = 0, tempcx = 0,
pushbx = 0, CRT1Index = 0, modeflag, resinfo = 0;
- if (ModeNo > 0x13) {
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
/* bainy change table name */
if (modeflag & HalfDCLK) {
@@ -4422,18 +3954,11 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo,
modeflag, CRT1Index;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
if (!(pVBInfo->VBInfo & SetInSlaveMode))
return;
@@ -4500,8 +4025,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
temp -= 6;
if (pVBInfo->TVInfo & TVSimuMode) {
temp -= 4;
- if (ModeNo > 0x13)
- temp -= 10;
+ temp -= 10;
}
}
} else {
@@ -4523,14 +4047,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
if (pVBInfo->LCDResInfo != Panel_1280x960 &&
pVBInfo->VGAHDE >= 800) {
temp -= 7;
- if (pVBInfo->ModeType == ModeEGA &&
- pVBInfo->VGAVDE == 1024) {
- temp += 15;
- if (pVBInfo->LCDResInfo !=
- Panel_1280x1024)
- temp += 7;
- }
-
if (pVBInfo->VGAHDE >= 1280 &&
pVBInfo->LCDResInfo != Panel_1280x960 &&
(pVBInfo->LCDInfo & LCDNonExpanding))
@@ -4546,48 +4062,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
if (pVBInfo->VBInfo & SetCRT2ToTV) {
if (pVBInfo->TVInfo & TVSimuMode) {
- if ((ModeNo == 0x06) || (ModeNo == 0x10) || (ModeNo
- == 0x11) || (ModeNo == 0x13) || (ModeNo
- == 0x0F)) {
- xgifb_reg_set(pVBInfo->Part1Port, 0x07, 0x5b);
- xgifb_reg_set(pVBInfo->Part1Port, 0x08, 0x03);
- }
-
- if ((ModeNo == 0x00) || (ModeNo == 0x01)) {
- if (pVBInfo->TVInfo & SetNTSCTV) {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x2A);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x61);
- } else {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x2A);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x41);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x0C, 0xF0);
- }
- }
-
- if ((ModeNo == 0x02) || (ModeNo == 0x03) || (ModeNo
- == 0x07)) {
- if (pVBInfo->TVInfo & SetNTSCTV) {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x54);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x00);
- } else {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x55);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x00);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x0C, 0xF0);
- }
- }
-
- if ((ModeNo == 0x04) || (ModeNo == 0x05) || (ModeNo
- == 0x0D) || (ModeNo == 0x50)) {
+ if (ModeNo == 0x50) {
if (pVBInfo->TVInfo & SetNTSCTV) {
xgifb_reg_set(pVBInfo->Part1Port,
0x07, 0x30);
@@ -4796,18 +4271,10 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned long longtemp, tempeax, tempebx, temp2, tempecx;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- crt2crtc = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempax = 0;
@@ -5245,18 +4712,11 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
struct XGI_LCDDesStruct *LCDBDesPtr = NULL;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
if (!(pVBInfo->VBInfo & SetCRT2ToLCD))
return;
@@ -5274,16 +4734,6 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
xgifb_reg_and_or(pVBInfo->Part2Port, 0x2B, 0x0F, temp);
temp = 0x01;
- if (pVBInfo->LCDResInfo == Panel_1280x1024) {
- if (pVBInfo->ModeType == ModeEGA) {
- if (pVBInfo->VGAHDE >= 1024) {
- temp = 0x02;
- if (pVBInfo->LCDInfo & XGI_LCDVESATiming)
- temp = 0x01;
- }
- }
- }
-
xgifb_reg_set(pVBInfo->Part2Port, 0x0B, temp);
tempbx = pVBInfo->VDE; /* RTVACTEO=(VDE-1)&0xFF */
push1 = tempbx;
@@ -5542,12 +4992,8 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned char *tempdi;
unsigned short modeflag;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
xgifb_reg_set(pVBInfo->Part3Port, 0x00, 0x00);
if (pVBInfo->TVInfo & TVSetPAL) {
@@ -5605,13 +5051,8 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned long tempebx, tempeax, templong;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
temp = pVBInfo->RVBHCFACT;
xgifb_reg_set(pVBInfo->Part4Port, 0x13, temp);
@@ -5818,32 +5259,22 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
{
unsigned short xres, yres, colordepth, modeflag, resindex;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- }
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if (!(modeflag & Charx8Dot)) {
xres /= 9;
xres *= 8;
}
- if (ModeNo > 0x13) {
- if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
- xres *= 2;
-
- if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
- yres *= 2;
+ if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
+ xres *= 2;
- }
+ if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+ yres *= 2;
if (xres > xgifb_info->lvds_data.LVDSHDE)
return 0;
@@ -5851,16 +5282,11 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
if (yres > xgifb_info->lvds_data.LVDSVDE)
return 0;
- if (ModeNo > 0x13) {
- if (xres != xgifb_info->lvds_data.LVDSHDE ||
- yres != xgifb_info->lvds_data.LVDSVDE) {
- colordepth = XGI_GetColorDepth(ModeNo,
- ModeIdIndex,
- pVBInfo);
- if (colordepth > 2)
- return 0;
-
- }
+ if (xres != xgifb_info->lvds_data.LVDSHDE ||
+ yres != xgifb_info->lvds_data.LVDSVDE) {
+ colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+ if (colordepth > 2)
+ return 0;
}
return 1;
}
@@ -5895,18 +5321,11 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
else
XGI_SetXG21FPBits(pVBInfo);
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- }
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if (!(modeflag & Charx8Dot))
xres = xres * 8 / 9;
@@ -5914,8 +5333,6 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
LVDSHT = xgifb_info->lvds_data.LVDSHT;
LVDSHBS = xres + (xgifb_info->lvds_data.LVDSHDE - xres) / 2;
- if ((ModeNo <= 0x13) && (modeflag & HalfDCLK))
- LVDSHBS -= xres / 4;
if (LVDSHBS > LVDSHT)
LVDSHBS -= LVDSHT;
@@ -5933,7 +5350,7 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
LVDSVT = xgifb_info->lvds_data.LVDSVT;
LVDSVBS = yres + (xgifb_info->lvds_data.LVDSVDE - yres) / 2;
- if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+ if (modeflag & DoubleScanMode)
LVDSVBS += yres / 2;
if (LVDSVBS > LVDSVT)
@@ -6527,7 +5944,7 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short tempbx, index;
+ unsigned short tempbx;
unsigned char tempah;
@@ -6536,13 +5953,6 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo,
tempbx = XGI_GetTVPtrIndex(pVBInfo);
tempbx &= 0xFE;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
- else
- index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
-
- tempbx += index;
tempah = TVAntiFlickList[tempbx];
tempah = tempah << 4;
@@ -6553,19 +5963,12 @@ static void XGI_SetEdgeEnhance(unsigned short ModeNo,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short tempbx, index;
+ unsigned short tempbx;
unsigned char tempah;
tempbx = XGI_GetTVPtrIndex(pVBInfo);
tempbx &= 0xFE;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
- else
- index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
-
- tempbx += index;
tempah = TVEdgeList[tempbx];
tempah = tempah << 5;
@@ -6631,13 +6034,7 @@ static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
return;
}
- if (ModeNo <= 0x13)
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].
- VB_StTVYFilterIndex;
- else
- tempal = pVBInfo->EModeIDTable[ModeIdIndex].
- VB_ExtTVYFilterIndex;
-
+ tempal = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
if (tempcl == 0)
index = tempal * 4;
else
@@ -6712,16 +6109,14 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV
| SetCRT2ToLCD)) {
tempah = 0x40; /* BTDRAM */
- if (ModeNo > 0x13) {
- tempcl = pVBInfo->ModeType;
- tempcl -= ModeVGA;
- if (tempcl >= 0) {
- /* BT Color */
- tempah = (0x008 >> tempcl);
- if (tempah == 0)
- tempah = 1;
- tempah |= 0x040;
- }
+ tempcl = pVBInfo->ModeType;
+ tempcl -= ModeVGA;
+ if (tempcl >= 0) {
+ /* BT Color */
+ tempah = (0x008 >> tempcl);
+ if (tempah == 0)
+ tempah = 1;
+ tempah |= 0x040;
}
if (pVBInfo->VBInfo & SetInSlaveMode)
tempah ^= 0x50; /* BTDAC */
@@ -6797,10 +6192,8 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
if (pVBInfo->VBInfo & SetCRT2ToTV) {
tempah |= 0x020;
- if (ModeNo > 0x13) {
- if (pVBInfo->VBInfo & DriverMode)
- tempah = tempah ^ 0x20;
- }
+ if (pVBInfo->VBInfo & DriverMode)
+ tempah = tempah ^ 0x20;
}
xgifb_reg_and_or(pVBInfo->Part4Port, 0x0D, ~0x0BF, tempah);
@@ -6925,13 +6318,7 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
unsigned short RefreshRateTableIndex, i, modeflag, index, temp;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
- if (ModeNo < 0x14)
- return 0xFFFF;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = xgifb_reg_get(pVBInfo->P3d4, 0x33);
index = index >> pVBInfo->SelectCRT2Rate;
@@ -7297,16 +6684,13 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
unsigned short ModeNo, unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short StandTableIndex, RefreshRateTableIndex, b3CC, temp;
+ unsigned short RefreshRateTableIndex, temp;
- unsigned short XGINew_P3cc = pVBInfo->P3cc;
-
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- XGI_SetSeqRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
- outb(pVBInfo->StandTable[StandTableIndex].MISC, pVBInfo->P3c2);
- XGI_SetCRTCRegs(HwDeviceExtension, StandTableIndex, pVBInfo);
- XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
- XGI_SetGRCRegs(StandTableIndex, pVBInfo);
+ XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo);
+ outb(pVBInfo->StandTable->MISC, pVBInfo->P3c2);
+ XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo);
+ XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetGRCRegs(pVBInfo);
XGI_ClearExt1Regs(pVBInfo);
if (HwDeviceExtension->jChipType == XG27) {
@@ -7340,22 +6724,6 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
RefreshRateTableIndex, pVBInfo);
}
- if ((HwDeviceExtension->jChipType >= XG20) &&
- (HwDeviceExtension->jChipType < XG27)) { /* fix H/W DCLK/2 bug */
- if ((ModeNo == 0x00) | (ModeNo == 0x01)) {
- xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x4E);
- xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE9);
- b3CC = (unsigned char) inb(XGINew_P3cc);
- outb((b3CC |= 0x0C), XGINew_P3cc);
- } else if ((ModeNo == 0x04) | (ModeNo == 0x05) | (ModeNo
- == 0x0D)) {
- xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x1B);
- xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE3);
- b3CC = (unsigned char) inb(XGINew_P3cc);
- outb((b3CC |= 0x0C), XGINew_P3cc);
- }
- }
-
if (HwDeviceExtension->jChipType >= XG21) {
temp = xgifb_reg_get(pVBInfo->P3d4, 0x38);
if (temp & 0xA0) {
@@ -7394,7 +6762,7 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
unsigned short ModeIdIndex;
struct vb_device_info VBINF;
struct vb_device_info *pVBInfo = &VBINF;
- pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+ pVBInfo->BaseAddr = xgifb_info->vga_base;
pVBInfo->IF_DEF_LVDS = 0;
pVBInfo->IF_DEF_LCDA = 1;
@@ -7509,13 +6877,8 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
pVBInfo))
return 0;
- if (ModeNo <= 0x13) {
- pVBInfo->ModeType = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ModeFlag & ModeTypeMask;
- } else {
- pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
+ pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
Ext_ModeFlag & ModeTypeMask;
- }
pVBInfo->SetFlag = 0;
pVBInfo->VBInfo = DisableCRT2Display;
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index a5bd56a..38f47ff 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -10,28 +10,11 @@ struct XGI_LVDSCRT1VDataStruct {
unsigned char Reg[7];
};
-struct XGI_StStruct {
- unsigned char St_ModeID;
- unsigned short St_ModeFlag;
- unsigned char St_StTableIndex;
- unsigned char St_CRT2CRTC;
- unsigned char St_CRT2CRTC2;
- unsigned char St_ResInfo;
- unsigned char VB_StTVFlickerIndex;
- unsigned char VB_StTVEdgeIndex;
- unsigned char VB_StTVYFilterIndex;
-};
-
struct XGI_ExtStruct {
unsigned char Ext_ModeID;
unsigned short Ext_ModeFlag;
unsigned short Ext_ModeInfo;
- unsigned short Ext_Point;
- unsigned short Ext_VESAID;
- unsigned char Ext_VESAMEMSize;
unsigned char Ext_RESINFO;
- unsigned char VB_ExtTVFlickerIndex;
- unsigned char VB_ExtTVEdgeIndex;
unsigned char VB_ExtTVYFilterIndex;
unsigned char REFindex;
};
@@ -68,14 +51,6 @@ struct XGI_LCDDataTablStruct {
unsigned short DATAPTR;
};
-struct XGI330_LCDDataDesStruct {
- unsigned short LCDHDES;
- unsigned short LCDHRS;
- unsigned short LCDVDES;
- unsigned short LCDVRS;
-};
-
-
struct XGI330_LVDSDataStruct {
unsigned short VGAHT;
unsigned short VGAVT;
@@ -236,7 +211,6 @@ struct vb_device_info {
void __iomem *FBAddr;
unsigned long BaseAddr;
- unsigned long RelIO;
unsigned char (*CR6B)[4];
unsigned char (*CR6E)[4];
@@ -314,7 +288,6 @@ struct vb_device_info {
struct XGI_TimingHStruct *TimingH;
struct XGI_TimingVStruct *TimingV;
- struct XGI_StStruct *SModeIDTable;
struct SiS_StandTable_S *StandTable;
struct XGI_ExtStruct *EModeIDTable;
struct XGI_Ext2Struct *RefIndex;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index e8d6f67..d22e599 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -135,609 +135,92 @@ static unsigned char XGI330_SR33;
static unsigned char XG40_CRCF = 0x13;
static unsigned char XG40_DRAMTypeDefinition = 0xFF ;
-static struct XGI_StStruct XGI330_SModeIDTable[] = {
- {0x01, 0x9208, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00},
- {0x01, 0x1210, 0x14, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00},
- {0x01, 0x1010, 0x17, 0x02, 0x11, 0x00, 0x00, 0x01, 0x01},
- {0x03, 0x8208, 0x03, 0x00, 0x14, 0x00, 0x00, 0x01, 0x02},
- {0x03, 0x0210, 0x16, 0x01, 0x04, 0x01, 0x00, 0x01, 0x02},
- {0x03, 0x0010, 0x18, 0x02, 0x15, 0x00, 0x00, 0x01, 0x03},
- {0x05, 0x9209, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
- {0x06, 0x8209, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
- {0x07, 0x0000, 0x07, 0x03, 0x05, 0x03, 0x00, 0x01, 0x03},
- {0x07, 0x0000, 0x19, 0x02, 0x15, 0x02, 0x00, 0x01, 0x03},
- {0x0d, 0x920a, 0x0d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
- {0x0e, 0x820a, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
- {0x0f, 0x0202, 0x11, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
- {0x10, 0x0212, 0x12, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
- {0x11, 0x0212, 0x1a, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
- {0x12, 0x0212, 0x1b, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
- {0x13, 0x021b, 0x1c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04},
- {0x12, 0x0010, 0x18, 0x02, 0x24, 0x02, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
- not sure */
- {0x12, 0x0210, 0x18, 0x01, 0x24, 0x01, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
- not sure */
- {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
-
static struct XGI_ExtStruct XGI330_EModeIDTable[] = {
- {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08,
- 0x05, 0x00, 0x00, 0x05, 0x05},
- {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x3c, 0x0e3b, 0x070a, 0x3af2, 0x0130, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x2e, 0x0a1b, 0x0306, 0x06, 0x05, 0x06},
+ {0x2f, 0x0a1b, 0x0305, 0x05, 0x05, 0x05},
+ {0x30, 0x2a1b, 0x0407, 0x07, 0x07, 0x0e},
+ {0x31, 0x0a1b, 0x030d, 0x0d, 0x06, 0x3d},
+ {0x32, 0x0a1b, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x33, 0x0a1d, 0x0a0d, 0x0d, 0x06, 0x3d},
+ {0x34, 0x2a1d, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x35, 0x0a1f, 0x0a0d, 0x0d, 0x06, 0x3d},
+ {0x36, 0x2a1f, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x38, 0x0a1b, 0x0508, 0x08, 0x00, 0x16},
+ {0x3a, 0x0e3b, 0x0609, 0x09, 0x00, 0x1e},
+ {0x3c, 0x0e3b, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE [2003/10/07] */
- {0x3d, 0x0e7d, 0x070a, 0x3af2, 0x0131, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x3d, 0x0e7d, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE */
- {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00},
- {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00}, /* ModeIdIndex = 0x10 */
- {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x02},
- {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08,
- 0x03, 0x00, 0x00, 0x07, 0x03},
- {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08,
- 0x04, 0x00, 0x00, 0x00, 0x04},
- {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x02},
- {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08,
- 0x03, 0x00, 0x00, 0x07, 0x03},
- {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08,
- 0x04, 0x00, 0x00, 0x00, 0x04},
- {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00},
- {0x5A, 0x021b, 0x0014, 0x3b83, 0x0138, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x3f}, /* ModeIdIndex = 0x20 */
- {0x5B, 0x0a1d, 0x0014, 0x3b83, 0x0135, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x3f},
- {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08,
- 0x05, 0x00, 0x00, 0x07, 0x05},
- {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x66, 0x0eff, 0x070a, 0x3af2, 0x013e, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x40, 0x9a1c, 0x0000, 0x00, 0x04, 0x00},
+ {0x41, 0x9a1d, 0x0000, 0x00, 0x04, 0x00},
+ {0x43, 0x0a1c, 0x0306, 0x06, 0x05, 0x06},
+ {0x44, 0x0a1d, 0x0306, 0x06, 0x05, 0x06},
+ {0x46, 0x2a1c, 0x0407, 0x07, 0x07, 0x0e},
+ {0x47, 0x2a1d, 0x0407, 0x07, 0x07, 0x0e},
+ {0x49, 0x0a3c, 0x0508, 0x08, 0x00, 0x16},
+ {0x4a, 0x0a3d, 0x0508, 0x08, 0x00, 0x16},
+ {0x4c, 0x0e7c, 0x0609, 0x09, 0x00, 0x1e},
+ {0x4d, 0x0e7d, 0x0609, 0x09, 0x00, 0x1e},
+ {0x50, 0x9a1b, 0x0001, 0x01, 0x04, 0x02},
+ {0x51, 0xba1b, 0x0103, 0x03, 0x07, 0x03},
+ {0x52, 0x9a1b, 0x0204, 0x04, 0x00, 0x04},
+ {0x56, 0x9a1d, 0x0001, 0x01, 0x04, 0x02},
+ {0x57, 0xba1d, 0x0103, 0x03, 0x07, 0x03},
+ {0x58, 0x9a1d, 0x0204, 0x04, 0x00, 0x04},
+ {0x59, 0x9a1b, 0x0000, 0x00, 0x04, 0x00},
+ {0x5A, 0x021b, 0x0014, 0x01, 0x04, 0x3f},
+ {0x5B, 0x0a1d, 0x0014, 0x01, 0x04, 0x3f},
+ {0x5d, 0x0a1d, 0x0305, 0x05, 0x07, 0x05},
+ {0x62, 0x0a3f, 0x0306, 0x06, 0x05, 0x06},
+ {0x63, 0x2a3f, 0x0407, 0x07, 0x07, 0x0e},
+ {0x64, 0x0a7f, 0x0508, 0x08, 0x00, 0x16},
+ {0x65, 0x0eff, 0x0609, 0x09, 0x00, 0x1e},
+ {0x66, 0x0eff, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE */
- {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37},
- {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37}, /* ModeIdIndex = 0x30 */
- {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37},
- {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x20, 0x0e3b, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x21, 0x0e7d, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x22, 0x0eff, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x23, 0x0e3b, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x24, 0x0e7d, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x25, 0x0eff, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x26, 0x063b, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42}, /* ModeIdIndex = 0x40 */
- {0x27, 0x067d, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42},
- {0x28, 0x06ff, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42},
- {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
-static struct SiS_StandTable_S XGI330_StandTable[] = {
-/* MD_0_200 */
- {
- 0x28, 0x18, 0x08, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_1_200 */
- {
- 0x28, 0x18, 0x08, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_200 */
- {
- 0x50, 0x18, 0x08, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_3_200 */
- {
- 0x50, 0x18, 0x08, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_4 */
- {
- 0x28, 0x18, 0x08, 0x4000,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
- 0xff},
- {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x03, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
- 0xff}
- },
-/* MD_5 */
- {
- 0x28, 0x18, 0x08, 0x4000,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
- 0xff},
- {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x03, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
- 0xff}
- },
-/* MD_6 */
- {
- 0x50, 0x18, 0x08, 0x4000,
- {0x01, 0x01, 0x00, 0x06},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
- 0xff},
- {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x01, 0x00, 0x01, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
- 0xff}
- },
-/* MD_7 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x00, 0x03, 0x00, 0x03},
- 0xa6,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x0e, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
- 0xff}
- },
-/* MDA_DAC */
- {
- 0x00, 0x00, 0x00, 0x0000,
- {0x00, 0x00, 0x00, 0x15},
- 0x15,
- {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f,
- 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00,
- 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15},
- {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x3f}
- },
-/* CGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x09, 0x15, 0x00},
- 0x10,
- {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a,
- 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a,
- 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10,
- 0x04},
- {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04,
- 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e,
- 0x3e, 0x2b, 0x3b, 0x2f},
- {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
- 0x3f}
- },
-/* EGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x05, 0x15, 0x20},
- 0x30,
- {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18,
- 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38,
- 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12,
- 0x06},
- {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26,
- 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e,
- 0x1e, 0x0b, 0x1b, 0x0f},
- {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
- 0x3f}
- },
-/* VGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x09, 0x15, 0x2a},
- 0x3a,
- {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05,
- 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20,
- 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10,
- 0x1f},
- {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d,
- 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15,
- 0x1c, 0x0e, 0x11, 0x15},
- {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00,
- 0x04}
- },
- {
- 0x08, 0x0c, 0x10, 0x0a08,
- {0x0c, 0x0e, 0x10, 0x0b},
- 0x0c,
- {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00,
- 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00,
- 0x06},
- {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08,
- 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00}
- },
-/* MD_D */
- {
- 0x28, 0x18, 0x08, 0x2000,
- {0x09, 0x0f, 0x00, 0x06},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_E */
- {
- 0x50, 0x18, 0x08, 0x4000,
- {0x01, 0x0f, 0x00, 0x06},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
+ {0x68, 0x067b, 0x080b, 0x0b, 0x00, 0x29},
+ {0x69, 0x06fd, 0x080b, 0x0b, 0x00, 0x29},
+ {0x6b, 0x07ff, 0x080b, 0x0b, 0x00, 0x29},
+ {0x6c, 0x067b, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x6d, 0x06fd, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x6e, 0x07ff, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x70, 0x2a1b, 0x0410, 0x10, 0x07, 0x34},
+ {0x71, 0x0a1b, 0x0511, 0x11, 0x00, 0x37},
+ {0x74, 0x0a1d, 0x0511, 0x11, 0x00, 0x37},
+ {0x75, 0x0a3d, 0x0612, 0x12, 0x00, 0x3a},
+ {0x76, 0x2a1f, 0x0410, 0x10, 0x07, 0x34},
+ {0x77, 0x0a1f, 0x0511, 0x11, 0x00, 0x37},
+ {0x78, 0x0a3f, 0x0612, 0x12, 0x00, 0x3a},
+ {0x79, 0x0a3b, 0x0612, 0x12, 0x00, 0x3a},
+ {0x7a, 0x2a1d, 0x0410, 0x10, 0x07, 0x34},
+ {0x7b, 0x0e3b, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x7c, 0x0e7d, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x7d, 0x0eff, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x20, 0x0e3b, 0x0D16, 0x16, 0x00, 0x43},
+ {0x21, 0x0e7d, 0x0D16, 0x16, 0x00, 0x43},
+ {0x22, 0x0eff, 0x0D16, 0x16, 0x00, 0x43},
+ {0x23, 0x0e3b, 0x0614, 0x14, 0x00, 0x41},
+ {0x24, 0x0e7d, 0x0614, 0x14, 0x00, 0x41},
+ {0x25, 0x0eff, 0x0614, 0x14, 0x00, 0x41},
+ {0x26, 0x063b, 0x0c15, 0x15, 0x00, 0x42},
+ {0x27, 0x067d, 0x0c15, 0x15, 0x00, 0x42},
+ {0x28, 0x06ff, 0x0c15, 0x15, 0x00, 0x42},
+ {0xff, 0x0000, 0x0000, 0x00, 0x00, 0x00}
+};
+
+static struct SiS_StandTable_S XGI330_StandTable = {
/* ExtVGATable */
- {
- 0x00, 0x00, 0x00, 0x0000,
- {0x01, 0x0f, 0x00, 0x0e},
- 0x23,
- {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x01, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
- 0xff}
- },
-/* ROM_SAVEPTR */
- {
- 0x9f, 0x3b, 0x00, 0x00c0,
- {0x00, 0x00, 0x00, 0x00},
- 0x00,
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0,
- 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00}
- },
-/* MD_F */
- {
- 0x50, 0x18, 0x0e, 0x8000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xa2,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
- 0xff},
- {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
- 0x0b, 0x00, 0x05, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05,
- 0xff}
- },
-/* MD_10 */
- {
- 0x50, 0x18, 0x0e, 0x8000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_0_350 */
- {
- 0x28, 0x18, 0x0e, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0xa3,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_1_350 */
- {
- 0x28, 0x18, 0x0e, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0xa3,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_350 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_3_350 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_0_1_400 */
- {
- 0x28, 0x18, 0x10, 0x0800,
- {0x08, 0x03, 0x00, 0x02},
- 0x67,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x0c, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_3_400 */
- {
- 0x50, 0x18, 0x10, 0x1000,
- {0x00, 0x03, 0x00, 0x02},
- 0x67,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x0c, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_7_400 */
- {
- 0x50, 0x18, 0x10, 0x1000,
- {0x00, 0x03, 0x00, 0x02},
- 0x66,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x0e, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
- 0xff}
- },
-/* MD_11 */
- {
- 0x50, 0x1d, 0x10, 0xa000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xe3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3,
- 0xff},
- {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01,
- 0xff}
- },
-/* ExtEGATable */
- {
- 0x50, 0x1d, 0x10, 0xa000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xe3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_13 */
- {
- 0x28, 0x18, 0x08, 0x2000,
- {0x01, 0x0f, 0x00, 0x0e},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x41, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
- 0xff}
- }
+ 0x00, 0x00, 0x00, 0x0000,
+ {0x01, 0x0f, 0x00, 0x0e},
+ 0x23,
+ {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
+ 0xff}
};
static struct XGI_TimingHStruct XGI_TimingH[1];
@@ -1143,7 +626,7 @@ static struct XGI330_LCDDataStruct XGI_NoScalingDatax75[] = {
{1, 1, 1688, 806, 1688, 806} /* ; 0A (1280x768x75Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1024x768Data[] = {
{9, 1057, 0, 771}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1057, 0, 771}, /* ; 01 (320x350,640x350) */
{9, 1057, 0, 771}, /* ; 02 (360x400,720x400) */
@@ -1153,7 +636,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = {
{9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1024x768Data[] = {
{9, 1057, 737, 703}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1057, 686, 651}, /* ; 01 (320x350,640x350) */
{9, 1057, 737, 703}, /* ; 02 (360x400,720x400) */
@@ -1163,7 +646,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = {
{9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768Data[] = {
{1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */
{1152, 856, 622, 587}, /* ; 02 (360x400,720x400) */
@@ -1173,7 +656,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = {
{0, 1048, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
{18, 1346, 981, 940}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1346, 926, 865}, /* 01 (320x350,640x350) */
{18, 1346, 981, 940}, /* 02 (360x400,720x400) */
@@ -1184,7 +667,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1280x1024Data[] = {
{18, 1346, 970, 907}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1346, 917, 854}, /* 01 (320x350,640x350) */
{18, 1346, 970, 907}, /* 02 (360x400,720x400) */
@@ -1195,7 +678,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
{1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* 01 (320x350,640x350) */
{1368, 1008, 752, 711}, /* 02 (360x400,720x400) */
@@ -1206,7 +689,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1280x1024Data[] = {
{9, 1337, 981, 940}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1337, 926, 884}, /* ; 01 (320x350,640x350) alan, 2003/09/30 */
{9, 1337, 981, 940}, /* ; 02 (360x400,720x400) */
@@ -1217,7 +700,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1280x1024Data[] = {
{9, 1337, 970, 907}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1337, 917, 854}, /* ; 01 (320x350,640x350) */
{9, 1337, 970, 907}, /* ; 02 (360x400,720x400) */
@@ -1228,7 +711,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024Data[] = {
{1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* 01 (320x350,640x350) */
{1368, 1008, 752, 711}, /* 02 (360x400,720x400) */
@@ -1239,7 +722,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1400x1050[] = {
{18, 1464, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1464, 0, 1051}, /* 01 (320x350,640x350) */
{18, 1464, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1251,7 +734,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = {
{18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1400x1050[] = {
{9, 1455, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1455, 0, 1051}, /* 01 (320x350,640x350) */
{9, 1455, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1263,7 +746,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = {
{9, 1455, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data[] = {
{1308, 1068, 781, 766}, /* 00 (320x200,320x400,640x200,640x400) */
{1308, 1068, 781, 766}, /* 01 (320x350,640x350) */
{1308, 1068, 781, 766}, /* 02 (360x400,720x400) */
@@ -1275,7 +758,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = {
{18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data2[] = {
{0, 1448, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{0, 1448, 0, 1051}, /* 01 (320x350,640x350) */
{0, 1448, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1283,7 +766,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = {
{0, 1448, 0, 1051} /* 04 (640x480x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1682, 0, 1201}, /* 01 (320x350,640x350) */
{18, 1682, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1296,7 +779,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1600x1200Data[] = {
{18, 1682, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1682, 1083, 1034}, /* 01 (320x350,640x350) */
{18, 1682, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1309,7 +792,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1600x1200Data[] = {
{9, 1673, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1673, 0, 1201}, /* 01 (320x350,640x350) */
{9, 1673, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1322,7 +805,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = {
{9, 1673, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1600x1200Data[] = {
{9, 1673, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1673, 1083, 1034}, /* 01 (320x350,640x350) */
{9, 1673, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1352,7 +835,7 @@ static struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[] = {
};
/* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1024x768x75[] = {
{9, 1049, 0, 769}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1049, 0, 769}, /* ; 01 (320x350,640x350) */
{9, 1049, 0, 769}, /* ; 02 (360x400,720x400) */
@@ -1363,7 +846,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = {
};
/* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768x75Data[] = {
{1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */
{1192, 896, 622, 587}, /* ; 02 (360x400,720x400) */
@@ -1374,7 +857,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = {
};
/* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1280x1024x75[] = {
{18, 1314, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
{18, 1314, 0, 1025}, /* ; 01 (320x350,640x350) */
{18, 1314, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1386,7 +869,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = {
};
/* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
@@ -1398,7 +881,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
};
/* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1280x1024x75[] = {
{9, 1305, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1305, 0, 1025}, /* ; 01 (320x350,640x350) */
{9, 1305, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1410,7 +893,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = {
};
/* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024x75Data[] = {
{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index a7208e3..30cdd1a 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -66,8 +66,6 @@ struct xgi_hw_device_info {
unsigned long ulVideoMemorySize; /* size, in bytes, of the
memory on the board */
- unsigned char *pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
-
unsigned char jChipType; /* Used to Identify Graphics Chip */
/* defined in the data structure type */
/* "XGI_CHIP_TYPE" */
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c..4496737 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -45,12 +45,12 @@ static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
static int is_first_page(struct page *page)
{
- return test_bit(PG_private, &page->flags);
+ return PagePrivate(page);
}
static int is_last_page(struct page *page)
{
- return test_bit(PG_private_2, &page->flags);
+ return PagePrivate2(page);
}
static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +180,7 @@ out:
* link together 3 PAGE_SIZE sized pages to form a zspage
* since then we can perfectly fit in 8 such objects.
*/
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
{
int i, max_usedpc = 0;
/* zspage order which gives maximum used size per KB */
@@ -368,7 +368,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
* identify the last page.
*/
error = -ENOMEM;
- for (i = 0; i < class->zspage_order; i++) {
+ for (i = 0; i < class->pages_per_zspage; i++) {
struct page *page, *prev_page;
page = alloc_page(flags);
@@ -377,7 +377,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
INIT_LIST_HEAD(&page->lru);
if (i == 0) { /* first page */
- set_bit(PG_private, &page->flags);
+ SetPagePrivate(page);
set_page_private(page, 0);
first_page = page;
first_page->inuse = 0;
@@ -388,9 +388,8 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
page->first_page = first_page;
if (i >= 2)
list_add(&page->lru, &prev_page->lru);
- if (i == class->zspage_order - 1) /* last page */
- set_bit(PG_private_2, &page->flags);
-
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
prev_page = page;
}
@@ -398,7 +397,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
first_page->freelist = obj_location_to_handle(first_page, 0);
/* Maximum number of objects we can store in this zspage */
- first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
error = 0; /* Success */
@@ -513,7 +512,7 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
class->size = size;
class->index = i;
spin_lock_init(&class->lock);
- class->zspage_order = get_zspage_order(size);
+ class->pages_per_zspage = get_pages_per_zspage(size);
}
@@ -567,13 +566,9 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool);
* zs_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
- *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
*
+ * On success, handle to the allocated object is returned,
+ * otherwise NULL.
* Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
*/
void *zs_malloc(struct zs_pool *pool, size_t size)
@@ -604,7 +599,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
set_zspage_mapping(first_page, class->index, ZS_EMPTY);
spin_lock(&class->lock);
- class->pages_allocated += class->zspage_order;
+ class->pages_allocated += class->pages_per_zspage;
}
obj = first_page->freelist;
@@ -659,7 +654,7 @@ void zs_free(struct zs_pool *pool, void *obj)
fullness = fix_fullness_group(pool, first_page);
if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->zspage_order;
+ class->pages_allocated -= class->pages_per_zspage;
spin_unlock(&class->lock);
@@ -668,6 +663,15 @@ void zs_free(struct zs_pool *pool, void *obj)
}
EXPORT_SYMBOL_GPL(zs_free);
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object
+*/
void *zs_map_object(struct zs_pool *pool, void *handle)
{
struct page *page;
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
index 92eefc6..6fd32a9 100644
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ b/drivers/staging/zsmalloc/zsmalloc_int.h
@@ -124,7 +124,7 @@ struct size_class {
unsigned int index;
/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int zspage_order;
+ int pages_per_zspage;
spinlock_t lock;
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index b28794b..1830368 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -32,5 +32,6 @@ config TCM_PSCSI
source "drivers/target/loopback/Kconfig"
source "drivers/target/tcm_fc/Kconfig"
source "drivers/target/iscsi/Kconfig"
+source "drivers/target/sbp/Kconfig"
endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 62e5405..61648d8 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
obj-$(CONFIG_TCM_FC) += tcm_fc/
obj-$(CONFIG_ISCSI_TARGET) += iscsi/
+obj-$(CONFIG_SBP_TARGET) += sbp/
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 8b1d5e6..d57d10c 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -27,8 +27,10 @@
#include <asm/unaligned.h>
#include <scsi/scsi_device.h>
#include <scsi/iscsi_proto.h>
+#include <scsi/scsi_tcq.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -593,7 +595,7 @@ static void __exit iscsi_target_cleanup_module(void)
kfree(iscsit_global);
}
-int iscsit_add_reject(
+static int iscsit_add_reject(
u8 reason,
int fail_conn,
unsigned char *buf,
@@ -622,7 +624,7 @@ int iscsit_add_reject(
}
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
cmd->i_state = ISTATE_SEND_REJECT;
@@ -669,7 +671,7 @@ int iscsit_add_reject_from_cmd(
if (add_to_conn) {
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
}
@@ -685,9 +687,7 @@ int iscsit_add_reject_from_cmd(
/*
* Map some portion of the allocated scatterlist to an iovec, suitable for
- * kernel sockets to copy data in/out. This handles both pages and slab-allocated
- * buffers, since we have been tricky and mapped t_mem_sg to the buffer in
- * either case (see iscsit_alloc_buffs)
+ * kernel sockets to copy data in/out.
*/
static int iscsit_map_iovec(
struct iscsi_cmd *cmd,
@@ -700,10 +700,9 @@ static int iscsit_map_iovec(
unsigned int page_off;
/*
- * We have a private mapping of the allocated pages in t_mem_sg.
- * At this point, we also know each contains a page.
+ * We know each entry in t_data_sg contains a page.
*/
- sg = &cmd->t_mem_sg[data_offset / PAGE_SIZE];
+ sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE];
page_off = (data_offset % PAGE_SIZE);
cmd->first_data_sg = sg;
@@ -744,7 +743,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
conn->exp_statsn = exp_statsn;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
spin_lock(&cmd->istate_lock);
if ((cmd->i_state == ISTATE_SENT_STATUS) &&
(cmd->stat_sn < exp_statsn)) {
@@ -761,8 +760,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
{
- u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
- cmd->se_cmd.t_data_nents;
+ u32 iov_count = max(1UL, DIV_ROUND_UP(cmd->se_cmd.data_length, PAGE_SIZE));
iov_count += ISCSI_IOV_DATA_BUFFER;
@@ -776,64 +774,6 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
return 0;
}
-static int iscsit_alloc_buffs(struct iscsi_cmd *cmd)
-{
- struct scatterlist *sgl;
- u32 length = cmd->se_cmd.data_length;
- int nents = DIV_ROUND_UP(length, PAGE_SIZE);
- int i = 0, j = 0, ret;
- /*
- * If no SCSI payload is present, allocate the default iovecs used for
- * iSCSI PDU Header
- */
- if (!length)
- return iscsit_allocate_iovecs(cmd);
-
- sgl = kzalloc(sizeof(*sgl) * nents, GFP_KERNEL);
- if (!sgl)
- return -ENOMEM;
-
- sg_init_table(sgl, nents);
-
- while (length) {
- int buf_size = min_t(int, length, PAGE_SIZE);
- struct page *page;
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!page)
- goto page_alloc_failed;
-
- sg_set_page(&sgl[i], page, buf_size, 0);
-
- length -= buf_size;
- i++;
- }
-
- cmd->t_mem_sg = sgl;
- cmd->t_mem_sg_nents = nents;
-
- /* BIDI ops not supported */
-
- /* Tell the core about our preallocated memory */
- transport_generic_map_mem_to_cmd(&cmd->se_cmd, sgl, nents, NULL, 0);
- /*
- * Allocate iovecs for SCSI payload after transport_generic_map_mem_to_cmd
- * so that cmd->se_cmd.t_tasks_se_num has been set.
- */
- ret = iscsit_allocate_iovecs(cmd);
- if (ret < 0)
- return -ENOMEM;
-
- return 0;
-
-page_alloc_failed:
- while (j < i)
- __free_page(sg_page(&sgl[j++]));
-
- kfree(sgl);
- return -ENOMEM;
-}
-
static int iscsit_handle_scsi_cmd(
struct iscsi_conn *conn,
unsigned char *buf)
@@ -842,6 +782,8 @@ static int iscsit_handle_scsi_cmd(
int dump_immediate_data = 0, send_check_condition = 0, payload_length;
struct iscsi_cmd *cmd = NULL;
struct iscsi_scsi_req *hdr;
+ int iscsi_task_attr;
+ int sam_task_attr;
spin_lock_bh(&conn->sess->session_stats_lock);
conn->sess->cmd_pdus++;
@@ -958,15 +900,30 @@ done:
(hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
DMA_NONE;
- cmd = iscsit_allocate_se_cmd(conn, hdr->data_length, data_direction,
- (hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK));
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
- buf, conn);
+ buf, conn);
- pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
- " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
- hdr->cmdsn, hdr->data_length, payload_length, conn->cid);
+ cmd->data_direction = data_direction;
+ iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK;
+ /*
+ * Figure out the SAM Task Attribute for the incoming SCSI CDB
+ */
+ if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) ||
+ (iscsi_task_attr == ISCSI_ATTR_SIMPLE))
+ sam_task_attr = MSG_SIMPLE_TAG;
+ else if (iscsi_task_attr == ISCSI_ATTR_ORDERED)
+ sam_task_attr = MSG_ORDERED_TAG;
+ else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE)
+ sam_task_attr = MSG_HEAD_TAG;
+ else if (iscsi_task_attr == ISCSI_ATTR_ACA)
+ sam_task_attr = MSG_ACA_TAG;
+ else {
+ pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using"
+ " MSG_SIMPLE_TAG\n", iscsi_task_attr);
+ sam_task_attr = MSG_SIMPLE_TAG;
+ }
cmd->iscsi_opcode = ISCSI_OP_SCSI_CMD;
cmd->i_state = ISTATE_NEW_CMD;
@@ -1003,6 +960,17 @@ done:
}
/*
+ * Initialize struct se_cmd descriptor from target_core_mod infrastructure
+ */
+ transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
+ conn->sess->se_sess, hdr->data_length, cmd->data_direction,
+ sam_task_attr, &cmd->sense_buffer[0]);
+
+ pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
+ " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
+ hdr->cmdsn, hdr->data_length, payload_length, conn->cid);
+
+ /*
* The CDB is going to an se_device_t.
*/
ret = transport_lookup_cmd_lun(&cmd->se_cmd,
@@ -1016,13 +984,8 @@ done:
send_check_condition = 1;
goto attach_cmd;
}
- /*
- * The Initiator Node has access to the LUN (the addressing method
- * is handled inside of iscsit_get_lun_for_cmd()). Now it's time to
- * allocate 1->N transport tasks (depending on sector count and
- * maximum request size the physical HBA(s) can handle.
- */
- transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb);
+
+ transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
if (transport_ret == -ENOMEM) {
return iscsit_add_reject_from_cmd(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
@@ -1035,9 +998,7 @@ done:
*/
send_check_condition = 1;
} else {
- cmd->data_length = cmd->se_cmd.data_length;
-
- if (iscsit_decide_list_to_build(cmd, payload_length) < 0)
+ if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
1, 1, buf, cmd);
@@ -1045,18 +1006,15 @@ done:
attach_cmd:
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
/*
* Check if we need to delay processing because of ALUA
* Active/NonOptimized primary access state..
*/
core_alua_check_nonop_delay(&cmd->se_cmd);
- /*
- * Allocate and setup SGL used with transport_generic_map_mem_to_cmd().
- * also call iscsit_allocate_iovecs()
- */
- ret = iscsit_alloc_buffs(cmd);
+
+ ret = iscsit_allocate_iovecs(cmd);
if (ret < 0)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
@@ -1303,10 +1261,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
se_cmd = &cmd->se_cmd;
iscsit_mod_dataout_timer(cmd);
- if ((hdr->offset + payload_length) > cmd->data_length) {
+ if ((hdr->offset + payload_length) > cmd->se_cmd.data_length) {
pr_err("DataOut Offset: %u, Length %u greater than"
" iSCSI Command EDTL %u, protocol error.\n",
- hdr->offset, payload_length, cmd->data_length);
+ hdr->offset, payload_length, cmd->se_cmd.data_length);
return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
1, 0, buf, cmd);
}
@@ -1442,7 +1400,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
return 0;
else if (ret == DATAOUT_SEND_R2T) {
iscsit_set_dataout_sequence_values(cmd);
- iscsit_build_r2ts_for_cmd(cmd, conn, 0);
+ iscsit_build_r2ts_for_cmd(cmd, conn, false);
} else if (ret == DATAOUT_SEND_TO_TRANSPORT) {
/*
* Handle extra special case for out of order
@@ -1617,7 +1575,7 @@ static int iscsit_handle_nop_out(
* Initiator is expecting a NopIN ping reply,
*/
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
@@ -1723,10 +1681,75 @@ static int iscsit_handle_task_mgt_cmd(
(hdr->refcmdsn != ISCSI_RESERVED_TAG))
hdr->refcmdsn = ISCSI_RESERVED_TAG;
- cmd = iscsit_allocate_se_cmd_for_tmr(conn, function);
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
+ 1, buf, conn);
+
+ cmd->data_direction = DMA_NONE;
+
+ cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
+ if (!cmd->tmr_req) {
+ pr_err("Unable to allocate memory for"
+ " Task Management command!\n");
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, 1, buf, cmd);
+ }
+
+ /*
+ * TASK_REASSIGN for ERL=2 / connection stays inside of
+ * LIO-Target $FABRIC_MOD
+ */
+ if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
+
+ u8 tcm_function;
+ int ret;
+
+ transport_init_se_cmd(&cmd->se_cmd,
+ &lio_target_fabric_configfs->tf_ops,
+ conn->sess->se_sess, 0, DMA_NONE,
+ MSG_SIMPLE_TAG, &cmd->sense_buffer[0]);
+
+ switch (function) {
+ case ISCSI_TM_FUNC_ABORT_TASK:
+ tcm_function = TMR_ABORT_TASK;
+ break;
+ case ISCSI_TM_FUNC_ABORT_TASK_SET:
+ tcm_function = TMR_ABORT_TASK_SET;
+ break;
+ case ISCSI_TM_FUNC_CLEAR_ACA:
+ tcm_function = TMR_CLEAR_ACA;
+ break;
+ case ISCSI_TM_FUNC_CLEAR_TASK_SET:
+ tcm_function = TMR_CLEAR_TASK_SET;
+ break;
+ case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+ tcm_function = TMR_LUN_RESET;
+ break;
+ case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+ tcm_function = TMR_TARGET_WARM_RESET;
+ break;
+ case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+ tcm_function = TMR_TARGET_COLD_RESET;
+ break;
+ default:
+ pr_err("Unknown iSCSI TMR Function:"
+ " 0x%02x\n", function);
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, 1, buf, cmd);
+ }
+
+ ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
+ tcm_function, GFP_KERNEL);
+ if (ret < 0)
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, 1, buf, cmd);
+
+ cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
+ }
cmd->iscsi_opcode = ISCSI_OP_SCSI_TMFUNC;
cmd->i_state = ISTATE_SEND_TASKMGTRSP;
@@ -1804,7 +1827,7 @@ static int iscsit_handle_task_mgt_cmd(
se_tmr->call_transport = 1;
attach:
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
@@ -1980,7 +2003,7 @@ static int iscsit_handle_text_cmd(
cmd->data_direction = DMA_NONE;
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
@@ -2168,7 +2191,7 @@ static int iscsit_handle_logout_cmd(
logout_remove = 1;
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY)
@@ -2178,7 +2201,7 @@ static int iscsit_handle_logout_cmd(
* Immediate commands are executed, well, immediately.
* Non-Immediate Logout Commands are executed in CmdSN order.
*/
- if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+ if (cmd->immediate_cmd) {
int ret = iscsit_execute_cmd(cmd, 0);
if (ret < 0)
@@ -2336,7 +2359,7 @@ static int iscsit_handle_immediate_data(
cmd->write_data_done += length;
- if (cmd->write_data_done == cmd->data_length) {
+ if (cmd->write_data_done == cmd->se_cmd.data_length) {
spin_lock_bh(&cmd->istate_lock);
cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
@@ -2381,7 +2404,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
cmd->i_state = ISTATE_SEND_ASYNCMSG;
spin_lock_bh(&conn_p->cmd_lock);
- list_add_tail(&cmd->i_list, &conn_p->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn_p->conn_cmd_list);
spin_unlock_bh(&conn_p->cmd_lock);
iscsit_add_cmd_to_response_queue(cmd, conn_p, cmd->i_state);
@@ -2434,10 +2457,19 @@ static int iscsit_send_conn_drop_async_message(
return 0;
}
+static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
+{
+ if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
+ (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
+ wait_for_completion_interruptible_timeout(
+ &conn->tx_half_close_comp,
+ ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
+ }
+}
+
static int iscsit_send_data_in(
struct iscsi_cmd *cmd,
- struct iscsi_conn *conn,
- int *eodr)
+ struct iscsi_conn *conn)
{
int iov_ret = 0, set_statsn = 0;
u32 iov_count = 0, tx_size = 0;
@@ -2445,6 +2477,8 @@ static int iscsit_send_data_in(
struct iscsi_datain_req *dr;
struct iscsi_data_rsp *hdr;
struct kvec *iov;
+ int eodr = 0;
+ int ret;
memset(&datain, 0, sizeof(struct iscsi_datain));
dr = iscsit_get_datain_values(cmd, &datain);
@@ -2457,11 +2491,11 @@ static int iscsit_send_data_in(
/*
* Be paranoid and double check the logic for now.
*/
- if ((datain.offset + datain.length) > cmd->data_length) {
+ if ((datain.offset + datain.length) > cmd->se_cmd.data_length) {
pr_err("Command ITT: 0x%08x, datain.offset: %u and"
" datain.length: %u exceeds cmd->data_length: %u\n",
cmd->init_task_tag, datain.offset, datain.length,
- cmd->data_length);
+ cmd->se_cmd.data_length);
return -1;
}
@@ -2577,13 +2611,26 @@ static int iscsit_send_data_in(
cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
ntohl(hdr->offset), datain.length, conn->cid);
+ /* sendpage is preferred but can't insert markers */
+ if (!conn->conn_ops->IFMarker)
+ ret = iscsit_fe_sendpage_sg(cmd, conn);
+ else
+ ret = iscsit_send_tx_data(cmd, conn, 0);
+
+ iscsit_unmap_iovec(cmd);
+
+ if (ret < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ return ret;
+ }
+
if (dr->dr_complete) {
- *eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
+ eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
2 : 1;
iscsit_free_datain_req(cmd, dr);
}
- return 0;
+ return eodr;
}
static int iscsit_send_logout_response(
@@ -2715,6 +2762,7 @@ static int iscsit_send_unsolicited_nopin(
{
int tx_size = ISCSI_HDR_LEN;
struct iscsi_nopin *hdr;
+ int ret;
hdr = (struct iscsi_nopin *) cmd->pdu;
memset(hdr, 0, ISCSI_HDR_LEN);
@@ -2747,6 +2795,17 @@ static int iscsit_send_unsolicited_nopin(
pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:"
" 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid);
+ ret = iscsit_send_tx_data(cmd, conn, 1);
+ if (ret < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ return ret;
+ }
+
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = want_response ?
+ ISTATE_SENT_NOPIN_WANT_RESPONSE : ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+
return 0;
}
@@ -2837,13 +2896,14 @@ static int iscsit_send_nopin_response(
return 0;
}
-int iscsit_send_r2t(
+static int iscsit_send_r2t(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
{
int tx_size = 0;
struct iscsi_r2t *r2t;
struct iscsi_r2t_rsp *hdr;
+ int ret;
r2t = iscsit_get_r2t_from_list(cmd);
if (!r2t)
@@ -2899,19 +2959,27 @@ int iscsit_send_r2t(
r2t->sent_r2t = 1;
spin_unlock_bh(&cmd->r2t_lock);
+ ret = iscsit_send_tx_data(cmd, conn, 1);
+ if (ret < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ return ret;
+ }
+
+ spin_lock_bh(&cmd->dataout_timeout_lock);
+ iscsit_start_dataout_timer(cmd, conn);
+ spin_unlock_bh(&cmd->dataout_timeout_lock);
+
return 0;
}
/*
- * type 0: Normal Operation.
- * type 1: Called from Storage Transport.
- * type 2: Called from iscsi_task_reassign_complete_write() for
- * connection recovery.
+ * @recovery: If called from iscsi_task_reassign_complete_write() for
+ * connection recovery.
*/
int iscsit_build_r2ts_for_cmd(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn,
- int type)
+ bool recovery)
{
int first_r2t = 1;
u32 offset = 0, xfer_len = 0;
@@ -2922,32 +2990,37 @@ int iscsit_build_r2ts_for_cmd(
return 0;
}
- if (conn->sess->sess_ops->DataSequenceInOrder && (type != 2))
- if (cmd->r2t_offset < cmd->write_data_done)
- cmd->r2t_offset = cmd->write_data_done;
+ if (conn->sess->sess_ops->DataSequenceInOrder &&
+ !recovery)
+ cmd->r2t_offset = max(cmd->r2t_offset, cmd->write_data_done);
while (cmd->outstanding_r2ts < conn->sess->sess_ops->MaxOutstandingR2T) {
if (conn->sess->sess_ops->DataSequenceInOrder) {
offset = cmd->r2t_offset;
- if (first_r2t && (type == 2)) {
- xfer_len = ((offset +
- (conn->sess->sess_ops->MaxBurstLength -
- cmd->next_burst_len) >
- cmd->data_length) ?
- (cmd->data_length - offset) :
- (conn->sess->sess_ops->MaxBurstLength -
- cmd->next_burst_len));
+ if (first_r2t && recovery) {
+ int new_data_end = offset +
+ conn->sess->sess_ops->MaxBurstLength -
+ cmd->next_burst_len;
+
+ if (new_data_end > cmd->se_cmd.data_length)
+ xfer_len = cmd->se_cmd.data_length - offset;
+ else
+ xfer_len =
+ conn->sess->sess_ops->MaxBurstLength -
+ cmd->next_burst_len;
} else {
- xfer_len = ((offset +
- conn->sess->sess_ops->MaxBurstLength) >
- cmd->data_length) ?
- (cmd->data_length - offset) :
- conn->sess->sess_ops->MaxBurstLength;
+ int new_data_end = offset +
+ conn->sess->sess_ops->MaxBurstLength;
+
+ if (new_data_end > cmd->se_cmd.data_length)
+ xfer_len = cmd->se_cmd.data_length - offset;
+ else
+ xfer_len = conn->sess->sess_ops->MaxBurstLength;
}
cmd->r2t_offset += xfer_len;
- if (cmd->r2t_offset == cmd->data_length)
+ if (cmd->r2t_offset == cmd->se_cmd.data_length)
cmd->cmd_flags |= ICF_SENT_LAST_R2T;
} else {
struct iscsi_seq *seq;
@@ -3179,6 +3252,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
return ret;
}
+#define SENDTARGETS_BUF_LIMIT 32768U
+
static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
{
char *payload = NULL;
@@ -3187,12 +3262,10 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
struct iscsi_tiqn *tiqn;
struct iscsi_tpg_np *tpg_np;
int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;
- unsigned char buf[256];
+ unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
- buffer_len = (conn->conn_ops->MaxRecvDataSegmentLength > 32768) ?
- 32768 : conn->conn_ops->MaxRecvDataSegmentLength;
-
- memset(buf, 0, 256);
+ buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,
+ SENDTARGETS_BUF_LIMIT);
payload = kzalloc(buffer_len, GFP_KERNEL);
if (!payload) {
@@ -3408,18 +3481,6 @@ static int iscsit_send_reject(
return 0;
}
-static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
-{
- if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
- (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
- wait_for_completion_interruptible_timeout(
- &conn->tx_half_close_comp,
- ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
- }
-}
-
-#ifdef CONFIG_SMP
-
void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
{
struct iscsi_thread_set *ts = conn->thread_set;
@@ -3433,10 +3494,6 @@ void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
* execute upon.
*/
ord = ts->thread_id % cpumask_weight(cpu_online_mask);
-#if 0
- pr_debug(">>>>>>>>>>>>>>>>>>>> Generated ord: %d from"
- " thread_id: %d\n", ord, ts->thread_id);
-#endif
for_each_online_cpu(cpu) {
if (ord-- == 0) {
cpumask_set_cpu(cpu, conn->conn_cpumask);
@@ -3476,34 +3533,196 @@ static inline void iscsit_thread_check_cpumask(
*/
memset(buf, 0, 128);
cpumask_scnprintf(buf, 128, conn->conn_cpumask);
-#if 0
- pr_debug(">>>>>>>>>>>>>> Calling set_cpus_allowed_ptr():"
- " %s for %s\n", buf, p->comm);
-#endif
set_cpus_allowed_ptr(p, conn->conn_cpumask);
}
-#else
-
-void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
+static int handle_immediate_queue(struct iscsi_conn *conn)
{
- return;
+ struct iscsi_queue_req *qr;
+ struct iscsi_cmd *cmd;
+ u8 state;
+ int ret;
+
+ while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
+ atomic_set(&conn->check_immediate_queue, 0);
+ cmd = qr->cmd;
+ state = qr->state;
+ kmem_cache_free(lio_qr_cache, qr);
+
+ switch (state) {
+ case ISTATE_SEND_R2T:
+ ret = iscsit_send_r2t(cmd, conn);
+ if (ret < 0)
+ goto err;
+ break;
+ case ISTATE_REMOVE:
+ if (cmd->data_direction == DMA_TO_DEVICE)
+ iscsit_stop_dataout_timer(cmd);
+
+ spin_lock_bh(&conn->cmd_lock);
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ iscsit_free_cmd(cmd);
+ continue;
+ case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+ iscsit_mod_nopin_response_timer(conn);
+ ret = iscsit_send_unsolicited_nopin(cmd,
+ conn, 1);
+ if (ret < 0)
+ goto err;
+ break;
+ case ISTATE_SEND_NOPIN_NO_RESPONSE:
+ ret = iscsit_send_unsolicited_nopin(cmd,
+ conn, 0);
+ if (ret < 0)
+ goto err;
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag, state,
+ conn->cid);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ return -1;
}
-#define iscsit_thread_check_cpumask(X, Y, Z) ({})
-#endif /* CONFIG_SMP */
+static int handle_response_queue(struct iscsi_conn *conn)
+{
+ struct iscsi_queue_req *qr;
+ struct iscsi_cmd *cmd;
+ u8 state;
+ int ret;
+
+ while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
+ cmd = qr->cmd;
+ state = qr->state;
+ kmem_cache_free(lio_qr_cache, qr);
+
+check_rsp_state:
+ switch (state) {
+ case ISTATE_SEND_DATAIN:
+ ret = iscsit_send_data_in(cmd, conn);
+ if (ret < 0)
+ goto err;
+ else if (!ret)
+ /* more drs */
+ goto check_rsp_state;
+ else if (ret == 1) {
+ /* all done */
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ continue;
+ } else if (ret == 2) {
+ /* Still must send status,
+ SCF_TRANSPORT_TASK_SENSE was set */
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SEND_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ state = ISTATE_SEND_STATUS;
+ goto check_rsp_state;
+ }
+
+ break;
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ ret = iscsit_send_status(cmd, conn);
+ break;
+ case ISTATE_SEND_LOGOUTRSP:
+ ret = iscsit_send_logout_response(cmd, conn);
+ break;
+ case ISTATE_SEND_ASYNCMSG:
+ ret = iscsit_send_conn_drop_async_message(
+ cmd, conn);
+ break;
+ case ISTATE_SEND_NOPIN:
+ ret = iscsit_send_nopin_response(cmd, conn);
+ break;
+ case ISTATE_SEND_REJECT:
+ ret = iscsit_send_reject(cmd, conn);
+ break;
+ case ISTATE_SEND_TASKMGTRSP:
+ ret = iscsit_send_task_mgt_rsp(cmd, conn);
+ if (ret != 0)
+ break;
+ ret = iscsit_tmr_post_handler(cmd, conn);
+ if (ret != 0)
+ iscsit_fall_back_to_erl0(conn->sess);
+ break;
+ case ISTATE_SEND_TEXTRSP:
+ ret = iscsit_send_text_rsp(cmd, conn);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ state, conn->cid);
+ goto err;
+ }
+ if (ret < 0)
+ goto err;
+
+ if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ iscsit_unmap_iovec(cmd);
+ goto err;
+ }
+ iscsit_unmap_iovec(cmd);
+
+ switch (state) {
+ case ISTATE_SEND_LOGOUTRSP:
+ if (!iscsit_logout_post_handler(cmd, conn))
+ goto restart;
+ /* fall through */
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_ASYNCMSG:
+ case ISTATE_SEND_NOPIN:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ case ISTATE_SEND_TEXTRSP:
+ case ISTATE_SEND_TASKMGTRSP:
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ break;
+ case ISTATE_SEND_REJECT:
+ if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
+ cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
+ complete(&cmd->reject_comp);
+ goto err;
+ }
+ complete(&cmd->reject_comp);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ cmd->i_state, conn->cid);
+ goto err;
+ }
+
+ if (atomic_read(&conn->check_immediate_queue))
+ break;
+ }
+
+ return 0;
+
+err:
+ return -1;
+restart:
+ return -EAGAIN;
+}
int iscsi_target_tx_thread(void *arg)
{
- u8 state;
- int eodr = 0;
int ret = 0;
- int sent_status = 0;
- int use_misc = 0;
- int map_sg = 0;
- struct iscsi_cmd *cmd = NULL;
struct iscsi_conn *conn;
- struct iscsi_queue_req *qr = NULL;
struct iscsi_thread_set *ts = arg;
/*
* Allow ourselves to be interrupted by SIGINT so that a
@@ -3516,7 +3735,7 @@ restart:
if (!conn)
goto out;
- eodr = map_sg = ret = sent_status = use_misc = 0;
+ ret = 0;
while (!kthread_should_stop()) {
/*
@@ -3531,251 +3750,15 @@ restart:
signal_pending(current))
goto transport_err;
-get_immediate:
- qr = iscsit_get_cmd_from_immediate_queue(conn);
- if (qr) {
- atomic_set(&conn->check_immediate_queue, 0);
- cmd = qr->cmd;
- state = qr->state;
- kmem_cache_free(lio_qr_cache, qr);
-
- spin_lock_bh(&cmd->istate_lock);
- switch (state) {
- case ISTATE_SEND_R2T:
- spin_unlock_bh(&cmd->istate_lock);
- ret = iscsit_send_r2t(cmd, conn);
- break;
- case ISTATE_REMOVE:
- spin_unlock_bh(&cmd->istate_lock);
-
- if (cmd->data_direction == DMA_TO_DEVICE)
- iscsit_stop_dataout_timer(cmd);
-
- spin_lock_bh(&conn->cmd_lock);
- list_del(&cmd->i_list);
- spin_unlock_bh(&conn->cmd_lock);
-
- iscsit_free_cmd(cmd);
- goto get_immediate;
- case ISTATE_SEND_NOPIN_WANT_RESPONSE:
- spin_unlock_bh(&cmd->istate_lock);
- iscsit_mod_nopin_response_timer(conn);
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 1);
- break;
- case ISTATE_SEND_NOPIN_NO_RESPONSE:
- spin_unlock_bh(&cmd->istate_lock);
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 0);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag, state,
- conn->cid);
- spin_unlock_bh(&cmd->istate_lock);
- goto transport_err;
- }
- if (ret < 0) {
- conn->tx_immediate_queue = 0;
- goto transport_err;
- }
-
- if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
- conn->tx_immediate_queue = 0;
- iscsit_tx_thread_wait_for_tcp(conn);
- goto transport_err;
- }
-
- spin_lock_bh(&cmd->istate_lock);
- switch (state) {
- case ISTATE_SEND_R2T:
- spin_unlock_bh(&cmd->istate_lock);
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
- break;
- case ISTATE_SEND_NOPIN_WANT_RESPONSE:
- cmd->i_state = ISTATE_SENT_NOPIN_WANT_RESPONSE;
- spin_unlock_bh(&cmd->istate_lock);
- break;
- case ISTATE_SEND_NOPIN_NO_RESPONSE:
- cmd->i_state = ISTATE_SENT_STATUS;
- spin_unlock_bh(&cmd->istate_lock);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- state, conn->cid);
- spin_unlock_bh(&cmd->istate_lock);
- goto transport_err;
- }
- goto get_immediate;
- } else
- conn->tx_immediate_queue = 0;
-
-get_response:
- qr = iscsit_get_cmd_from_response_queue(conn);
- if (qr) {
- cmd = qr->cmd;
- state = qr->state;
- kmem_cache_free(lio_qr_cache, qr);
-
- spin_lock_bh(&cmd->istate_lock);
-check_rsp_state:
- switch (state) {
- case ISTATE_SEND_DATAIN:
- spin_unlock_bh(&cmd->istate_lock);
- ret = iscsit_send_data_in(cmd, conn,
- &eodr);
- map_sg = 1;
- break;
- case ISTATE_SEND_STATUS:
- case ISTATE_SEND_STATUS_RECOVERY:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_status(cmd, conn);
- break;
- case ISTATE_SEND_LOGOUTRSP:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_logout_response(cmd, conn);
- break;
- case ISTATE_SEND_ASYNCMSG:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_conn_drop_async_message(
- cmd, conn);
- break;
- case ISTATE_SEND_NOPIN:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_nopin_response(cmd, conn);
- break;
- case ISTATE_SEND_REJECT:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_reject(cmd, conn);
- break;
- case ISTATE_SEND_TASKMGTRSP:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_task_mgt_rsp(cmd, conn);
- if (ret != 0)
- break;
- ret = iscsit_tmr_post_handler(cmd, conn);
- if (ret != 0)
- iscsit_fall_back_to_erl0(conn->sess);
- break;
- case ISTATE_SEND_TEXTRSP:
- spin_unlock_bh(&cmd->istate_lock);
- use_misc = 1;
- ret = iscsit_send_text_rsp(cmd, conn);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- state, conn->cid);
- spin_unlock_bh(&cmd->istate_lock);
- goto transport_err;
- }
- if (ret < 0) {
- conn->tx_response_queue = 0;
- goto transport_err;
- }
-
- if (map_sg && !conn->conn_ops->IFMarker) {
- if (iscsit_fe_sendpage_sg(cmd, conn) < 0) {
- conn->tx_response_queue = 0;
- iscsit_tx_thread_wait_for_tcp(conn);
- iscsit_unmap_iovec(cmd);
- goto transport_err;
- }
- } else {
- if (iscsit_send_tx_data(cmd, conn, use_misc) < 0) {
- conn->tx_response_queue = 0;
- iscsit_tx_thread_wait_for_tcp(conn);
- iscsit_unmap_iovec(cmd);
- goto transport_err;
- }
- }
- map_sg = 0;
- iscsit_unmap_iovec(cmd);
-
- spin_lock_bh(&cmd->istate_lock);
- switch (state) {
- case ISTATE_SEND_DATAIN:
- if (!eodr)
- goto check_rsp_state;
-
- if (eodr == 1) {
- cmd->i_state = ISTATE_SENT_LAST_DATAIN;
- sent_status = 1;
- eodr = use_misc = 0;
- } else if (eodr == 2) {
- cmd->i_state = state =
- ISTATE_SEND_STATUS;
- sent_status = 0;
- eodr = use_misc = 0;
- goto check_rsp_state;
- }
- break;
- case ISTATE_SEND_STATUS:
- use_misc = 0;
- sent_status = 1;
- break;
- case ISTATE_SEND_ASYNCMSG:
- case ISTATE_SEND_NOPIN:
- case ISTATE_SEND_STATUS_RECOVERY:
- case ISTATE_SEND_TEXTRSP:
- use_misc = 0;
- sent_status = 1;
- break;
- case ISTATE_SEND_REJECT:
- use_misc = 0;
- if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
- cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
- spin_unlock_bh(&cmd->istate_lock);
- complete(&cmd->reject_comp);
- goto transport_err;
- }
- complete(&cmd->reject_comp);
- break;
- case ISTATE_SEND_TASKMGTRSP:
- use_misc = 0;
- sent_status = 1;
- break;
- case ISTATE_SEND_LOGOUTRSP:
- spin_unlock_bh(&cmd->istate_lock);
- if (!iscsit_logout_post_handler(cmd, conn))
- goto restart;
- spin_lock_bh(&cmd->istate_lock);
- use_misc = 0;
- sent_status = 1;
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- cmd->i_state, conn->cid);
- spin_unlock_bh(&cmd->istate_lock);
- goto transport_err;
- }
-
- if (sent_status) {
- cmd->i_state = ISTATE_SENT_STATUS;
- sent_status = 0;
- }
- spin_unlock_bh(&cmd->istate_lock);
-
- if (atomic_read(&conn->check_immediate_queue))
- goto get_immediate;
+ ret = handle_immediate_queue(conn);
+ if (ret < 0)
+ goto transport_err;
- goto get_response;
- } else
- conn->tx_response_queue = 0;
+ ret = handle_response_queue(conn);
+ if (ret == -EAGAIN)
+ goto restart;
+ else if (ret < 0)
+ goto transport_err;
}
transport_err:
@@ -3952,9 +3935,9 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
* has been reset -> returned sleeping pre-handler state.
*/
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_increment_maxcmdsn(cmd, sess);
@@ -3972,7 +3955,7 @@ static void iscsit_stop_timers_for_cmds(
struct iscsi_cmd *cmd;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
if (cmd->data_direction == DMA_TO_DEVICE)
iscsit_stop_dataout_timer(cmd);
}
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index 5db2dde..12abb4c 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -18,8 +18,7 @@ extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8);
-extern int iscsit_send_r2t(struct iscsi_cmd *, struct iscsi_conn *);
-extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, int);
+extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, bool recovery);
extern void iscsit_thread_get_cpumask(struct iscsi_conn *);
extern int iscsi_target_tx_thread(void *);
extern int iscsi_target_rx_thread(void *);
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 00c58cc..69dc8e3 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -1538,7 +1538,7 @@ static int lio_write_pending(struct se_cmd *se_cmd)
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
if (!cmd->immediate_data && !cmd->unsolicited_data)
- return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 1);
+ return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false);
return 0;
}
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 2aaee7e..1c70144 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -296,12 +296,11 @@ struct iscsi_datain_req {
u32 runlength;
u32 data_length;
u32 data_offset;
- u32 data_offset_end;
u32 data_sn;
u32 next_burst_len;
u32 read_data_done;
u32 seq_send_order;
- struct list_head dr_list;
+ struct list_head cmd_datain_node;
} ____cacheline_aligned;
struct iscsi_ooo_cmdsn {
@@ -381,8 +380,6 @@ struct iscsi_cmd {
u32 buf_ptr_size;
/* Used to store DataDigest */
u32 data_crc;
- /* Total size in bytes associated with command */
- u32 data_length;
/* Counter for MaxOutstandingR2T */
u32 outstanding_r2ts;
/* Next R2T Offset when DataSequenceInOrder=Yes */
@@ -464,16 +461,13 @@ struct iscsi_cmd {
/* Session the command is part of, used for connection recovery */
struct iscsi_session *sess;
/* list_head for connection list */
- struct list_head i_list;
+ struct list_head i_conn_node;
/* The TCM I/O descriptor that is accessed via container_of() */
struct se_cmd se_cmd;
/* Sense buffer that will be mapped into outgoing status */
#define ISCSI_SENSE_BUFFER_LEN (TRANSPORT_SENSE_BUFFER + 2)
unsigned char sense_buffer[ISCSI_SENSE_BUFFER_LEN];
- struct scatterlist *t_mem_sg;
- u32 t_mem_sg_nents;
-
u32 padding;
u8 pad_bytes[4];
@@ -500,8 +494,6 @@ struct iscsi_conn {
u8 network_transport;
enum iscsi_timer_flags_table nopin_timer_flags;
enum iscsi_timer_flags_table nopin_response_timer_flags;
- u8 tx_immediate_queue;
- u8 tx_response_queue;
/* Used to know what thread encountered a transport failure */
u8 which_thread;
/* connection id assigned by the Initiator */
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c
index 8c04951..848fee7 100644
--- a/drivers/target/iscsi/iscsi_target_datain_values.c
+++ b/drivers/target/iscsi/iscsi_target_datain_values.c
@@ -37,7 +37,7 @@ struct iscsi_datain_req *iscsit_allocate_datain_req(void)
" struct iscsi_datain_req\n");
return NULL;
}
- INIT_LIST_HEAD(&dr->dr_list);
+ INIT_LIST_HEAD(&dr->cmd_datain_node);
return dr;
}
@@ -45,14 +45,14 @@ struct iscsi_datain_req *iscsit_allocate_datain_req(void)
void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
{
spin_lock(&cmd->datain_lock);
- list_add_tail(&dr->dr_list, &cmd->datain_list);
+ list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
spin_unlock(&cmd->datain_lock);
}
void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
{
spin_lock(&cmd->datain_lock);
- list_del(&dr->dr_list);
+ list_del(&dr->cmd_datain_node);
spin_unlock(&cmd->datain_lock);
kmem_cache_free(lio_dr_cache, dr);
@@ -63,8 +63,8 @@ void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
struct iscsi_datain_req *dr, *dr_tmp;
spin_lock(&cmd->datain_lock);
- list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) {
- list_del(&dr->dr_list);
+ list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
+ list_del(&dr->cmd_datain_node);
kmem_cache_free(lio_dr_cache, dr);
}
spin_unlock(&cmd->datain_lock);
@@ -72,17 +72,14 @@ void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
{
- struct iscsi_datain_req *dr;
-
if (list_empty(&cmd->datain_list)) {
pr_err("cmd->datain_list is empty for ITT:"
" 0x%08x\n", cmd->init_task_tag);
return NULL;
}
- list_for_each_entry(dr, &cmd->datain_list, dr_list)
- break;
- return dr;
+ return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
+ cmd_datain_node);
}
/*
@@ -113,7 +110,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
read_data_done = (!dr->recovery) ?
cmd->read_data_done : dr->read_data_done;
- read_data_left = (cmd->data_length - read_data_done);
+ read_data_left = (cmd->se_cmd.data_length - read_data_done);
if (!read_data_left) {
pr_err("ITT: 0x%08x read_data_left is zero!\n",
cmd->init_task_tag);
@@ -212,7 +209,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
seq_send_order = (!dr->recovery) ?
cmd->seq_send_order : dr->seq_send_order;
- read_data_left = (cmd->data_length - read_data_done);
+ read_data_left = (cmd->se_cmd.data_length - read_data_done);
if (!read_data_left) {
pr_err("ITT: 0x%08x read_data_left is zero!\n",
cmd->init_task_tag);
@@ -231,8 +228,8 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
offset = (seq->offset + seq->next_burst_len);
if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->data_length) {
- datain->length = (cmd->data_length - offset);
+ cmd->se_cmd.data_length) {
+ datain->length = (cmd->se_cmd.data_length - offset);
datain->offset = offset;
datain->flags |= ISCSI_FLAG_CMD_FINAL;
@@ -264,7 +261,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
}
}
- if ((read_data_done + datain->length) == cmd->data_length)
+ if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
datain->flags |= ISCSI_FLAG_DATA_STATUS;
datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
@@ -333,7 +330,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
read_data_done = (!dr->recovery) ?
cmd->read_data_done : dr->read_data_done;
- read_data_left = (cmd->data_length - read_data_done);
+ read_data_left = (cmd->se_cmd.data_length - read_data_done);
if (!read_data_left) {
pr_err("ITT: 0x%08x read_data_left is zero!\n",
cmd->init_task_tag);
@@ -344,7 +341,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
if (!pdu)
return dr;
- if ((read_data_done + pdu->length) == cmd->data_length) {
+ if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
pdu->flags |= ISCSI_FLAG_DATA_ACK;
@@ -433,7 +430,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
seq_send_order = (!dr->recovery) ?
cmd->seq_send_order : dr->seq_send_order;
- read_data_left = (cmd->data_length - read_data_done);
+ read_data_left = (cmd->se_cmd.data_length - read_data_done);
if (!read_data_left) {
pr_err("ITT: 0x%08x read_data_left is zero!\n",
cmd->init_task_tag);
@@ -463,7 +460,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
} else
seq->next_burst_len += pdu->length;
- if ((read_data_done + pdu->length) == cmd->data_length)
+ if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
pdu->flags |= ISCSI_FLAG_DATA_STATUS;
pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index 1ab0560..1a02016 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -48,9 +48,9 @@ void iscsit_set_dataout_sequence_values(
if (cmd->unsolicited_data) {
cmd->seq_start_offset = cmd->write_data_done;
cmd->seq_end_offset = (cmd->write_data_done +
- (cmd->data_length >
+ (cmd->se_cmd.data_length >
conn->sess->sess_ops->FirstBurstLength) ?
- conn->sess->sess_ops->FirstBurstLength : cmd->data_length);
+ conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length);
return;
}
@@ -59,15 +59,15 @@ void iscsit_set_dataout_sequence_values(
if (!cmd->seq_start_offset && !cmd->seq_end_offset) {
cmd->seq_start_offset = cmd->write_data_done;
- cmd->seq_end_offset = (cmd->data_length >
+ cmd->seq_end_offset = (cmd->se_cmd.data_length >
conn->sess->sess_ops->MaxBurstLength) ?
(cmd->write_data_done +
- conn->sess->sess_ops->MaxBurstLength) : cmd->data_length;
+ conn->sess->sess_ops->MaxBurstLength) : cmd->se_cmd.data_length;
} else {
cmd->seq_start_offset = cmd->seq_end_offset;
cmd->seq_end_offset = ((cmd->seq_end_offset +
conn->sess->sess_ops->MaxBurstLength) >=
- cmd->data_length) ? cmd->data_length :
+ cmd->se_cmd.data_length) ? cmd->se_cmd.data_length :
(cmd->seq_end_offset +
conn->sess->sess_ops->MaxBurstLength);
}
@@ -182,13 +182,13 @@ static int iscsit_dataout_check_unsolicited_sequence(
if (!conn->sess->sess_ops->DataPDUInOrder)
goto out;
- if ((first_burst_len != cmd->data_length) &&
+ if ((first_burst_len != cmd->se_cmd.data_length) &&
(first_burst_len != conn->sess->sess_ops->FirstBurstLength)) {
pr_err("Unsolicited non-immediate data"
" received %u does not equal FirstBurstLength: %u, and"
" does not equal ExpXferLen %u.\n", first_burst_len,
conn->sess->sess_ops->FirstBurstLength,
- cmd->data_length);
+ cmd->se_cmd.data_length);
transport_send_check_condition_and_sense(&cmd->se_cmd,
TCM_INCORRECT_AMOUNT_OF_DATA, 0);
return DATAOUT_CANNOT_RECOVER;
@@ -201,10 +201,10 @@ static int iscsit_dataout_check_unsolicited_sequence(
conn->sess->sess_ops->FirstBurstLength);
return DATAOUT_CANNOT_RECOVER;
}
- if (first_burst_len == cmd->data_length) {
+ if (first_burst_len == cmd->se_cmd.data_length) {
pr_err("Command ITT: 0x%08x reached"
" ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"
- " error.\n", cmd->init_task_tag, cmd->data_length);
+ " error.\n", cmd->init_task_tag, cmd->se_cmd.data_length);
return DATAOUT_CANNOT_RECOVER;
}
}
@@ -294,7 +294,7 @@ static int iscsit_dataout_check_sequence(
if ((next_burst_len <
conn->sess->sess_ops->MaxBurstLength) &&
((cmd->write_data_done + payload_length) <
- cmd->data_length)) {
+ cmd->se_cmd.data_length)) {
pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"
" before end of DataOUT sequence, protocol"
" error.\n", cmd->init_task_tag);
@@ -319,7 +319,7 @@ static int iscsit_dataout_check_sequence(
return DATAOUT_CANNOT_RECOVER;
}
if ((cmd->write_data_done + payload_length) ==
- cmd->data_length) {
+ cmd->se_cmd.data_length) {
pr_err("Command ITT: 0x%08x reached"
" last DataOUT PDU in sequence but ISCSI_FLAG_"
"CMD_FINAL is not set, protocol error.\n",
@@ -640,9 +640,12 @@ static int iscsit_dataout_post_crc_passed(
cmd->write_data_done += payload_length;
- return (cmd->write_data_done == cmd->data_length) ?
- DATAOUT_SEND_TO_TRANSPORT : (send_r2t) ?
- DATAOUT_SEND_R2T : DATAOUT_NORMAL;
+ if (cmd->write_data_done == cmd->se_cmd.data_length)
+ return DATAOUT_SEND_TO_TRANSPORT;
+ else if (send_r2t)
+ return DATAOUT_SEND_R2T;
+ else
+ return DATAOUT_NORMAL;
}
static int iscsit_dataout_post_crc_failed(
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 006f605..ecdd46d 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -279,11 +279,9 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no(
* seq->first_datasn and seq->last_datasn have not been set.
*/
if (!seq->sent) {
-#if 0
pr_err("Ignoring non-sent sequence 0x%08x ->"
" 0x%08x\n\n", seq->first_datasn,
seq->last_datasn);
-#endif
continue;
}
@@ -294,11 +292,10 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no(
*/
if ((seq->first_datasn < begrun) &&
(seq->last_datasn < begrun)) {
-#if 0
pr_err("Pre BegRun sequence 0x%08x ->"
" 0x%08x\n", seq->first_datasn,
seq->last_datasn);
-#endif
+
read_data_done += cmd->seq_list[i].xfer_len;
seq->next_burst_len = seq->pdu_send_order = 0;
continue;
@@ -309,11 +306,10 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no(
*/
if ((seq->first_datasn <= begrun) &&
(seq->last_datasn >= begrun)) {
-#if 0
pr_err("Found sequence begrun: 0x%08x in"
" 0x%08x -> 0x%08x\n", begrun,
seq->first_datasn, seq->last_datasn);
-#endif
+
seq_send_order = seq->seq_send_order;
data_sn = seq->first_datasn;
seq->next_burst_len = seq->pdu_send_order = 0;
@@ -369,10 +365,9 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no(
*/
if ((seq->first_datasn > begrun) ||
(seq->last_datasn > begrun)) {
-#if 0
pr_err("Post BegRun sequence 0x%08x -> 0x%08x\n",
seq->first_datasn, seq->last_datasn);
-#endif
+
seq->next_burst_len = seq->pdu_send_order = 0;
continue;
}
@@ -526,7 +521,7 @@ int iscsit_handle_status_snack(
found_cmd = 0;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
if (cmd->stat_sn == begrun) {
found_cmd = 1;
break;
@@ -987,7 +982,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
return 0;
iscsit_set_dataout_sequence_values(cmd);
- iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 0);
+ iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false);
}
return 0;
}
@@ -1121,8 +1116,8 @@ static int iscsit_set_dataout_timeout_values(
if (cmd->unsolicited_data) {
*offset = 0;
*length = (conn->sess->sess_ops->FirstBurstLength >
- cmd->data_length) ?
- cmd->data_length :
+ cmd->se_cmd.data_length) ?
+ cmd->se_cmd.data_length :
conn->sess->sess_ops->FirstBurstLength;
return 0;
}
@@ -1193,8 +1188,8 @@ static void iscsit_handle_dataout_timeout(unsigned long data)
if (conn->sess->sess_ops->DataPDUInOrder) {
pdu_offset = cmd->write_data_done;
if ((pdu_offset + (conn->sess->sess_ops->MaxBurstLength -
- cmd->next_burst_len)) > cmd->data_length)
- pdu_length = (cmd->data_length -
+ cmd->next_burst_len)) > cmd->se_cmd.data_length)
+ pdu_length = (cmd->se_cmd.data_length -
cmd->write_data_done);
else
pdu_length = (conn->sess->sess_ops->MaxBurstLength -
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 1af1f21..65aac14 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -138,9 +138,9 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
spin_lock(&cr->conn_recovery_cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp,
- &cr->conn_recovery_cmd_list, i_list) {
+ &cr->conn_recovery_cmd_list, i_conn_node) {
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
iscsit_free_cmd(cmd);
@@ -160,9 +160,9 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
spin_lock(&cr->conn_recovery_cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp,
- &cr->conn_recovery_cmd_list, i_list) {
+ &cr->conn_recovery_cmd_list, i_conn_node) {
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
iscsit_free_cmd(cmd);
@@ -220,7 +220,7 @@ int iscsit_remove_cmd_from_connection_recovery(
}
cr = cmd->cr;
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
return --cr->cmd_count;
}
@@ -234,7 +234,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
spin_lock(&cr->conn_recovery_cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp,
- &cr->conn_recovery_cmd_list, i_list) {
+ &cr->conn_recovery_cmd_list, i_conn_node) {
if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) &&
(cmd->deferred_i_state != ISTATE_REMOVE)) ||
@@ -297,11 +297,11 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
mutex_unlock(&sess->cmdsn_mutex);
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
continue;
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd);
@@ -339,14 +339,14 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
/*
* Only perform connection recovery on ISCSI_OP_SCSI_CMD or
* ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call
- * list_del(&cmd->i_list); to release the command to the
+ * list_del(&cmd->i_conn_node); to release the command to the
* session pool and remove it from the connection's list.
*
* Also stop the DataOUT timer, which will be restarted after
* sending the TMR response.
*/
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) &&
(cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) {
@@ -355,7 +355,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
" CID: %hu\n", cmd->iscsi_opcode,
cmd->init_task_tag, cmd->cmd_sn, conn->cid);
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
@@ -375,7 +375,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
*/
if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
(cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
@@ -397,7 +397,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
cmd->sess = conn->sess;
- list_del(&cmd->i_list);
+ list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_all_datain_reqs(cmd);
@@ -407,7 +407,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
* Add the struct iscsi_cmd to the connection recovery cmd list
*/
spin_lock(&cr->conn_recovery_cmd_lock);
- list_add_tail(&cmd->i_list, &cr->conn_recovery_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &cr->conn_recovery_cmd_list);
spin_unlock(&cr->conn_recovery_cmd_lock);
spin_lock_bh(&conn->cmd_lock);
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index eb05c9d..ed5241e 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -803,14 +803,6 @@ static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_pt
value = simple_strtoul(value_ptr, &tmpptr, 0);
-/* #warning FIXME: Fix this */
-#if 0
- if (strspn(endptr, WHITE_SPACE) != strlen(endptr)) {
- pr_err("Illegal value \"%s\" for \"%s\".\n",
- value, param->name);
- return -1;
- }
-#endif
if (IS_TYPERANGE_0_TO_2(param)) {
if ((value < 0) || (value > 2)) {
pr_err("Illegal value for \"%s\", must be"
@@ -1045,13 +1037,6 @@ static char *iscsi_check_valuelist_for_support(
tmp2 = strchr(acceptor_values, ',');
if (tmp2)
*tmp2 = '\0';
- if (!acceptor_values || !proposer_values) {
- if (tmp1)
- *tmp1 = ',';
- if (tmp2)
- *tmp2 = ',';
- return NULL;
- }
if (!strcmp(acceptor_values, proposer_values)) {
if (tmp2)
*tmp2 = ',';
@@ -1061,8 +1046,6 @@ static char *iscsi_check_valuelist_for_support(
*tmp2++ = ',';
acceptor_values = tmp2;
- if (!acceptor_values)
- break;
} while (acceptor_values);
if (tmp1)
*tmp1++ = ',';
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index fc69408..85a306e 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -24,11 +24,13 @@
#include "iscsi_target_core.h"
#include "iscsi_target_util.h"
+#include "iscsi_target_tpg.h"
#include "iscsi_target_seq_pdu_list.h"
#define OFFLOAD_BUF_SIZE 32768
-void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
+#ifdef DEBUG
+static void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
{
int i;
struct iscsi_seq *seq;
@@ -46,7 +48,7 @@ void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
}
}
-void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
+static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
{
int i;
struct iscsi_pdu *pdu;
@@ -61,6 +63,10 @@ void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
pdu->length, pdu->pdu_send_order, pdu->seq_no);
}
}
+#else
+static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {}
+static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {}
+#endif
static void iscsit_ordered_seq_lists(
struct iscsi_cmd *cmd,
@@ -135,11 +141,11 @@ redo:
seq_count++;
continue;
}
- array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+ array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
if (!array) {
pr_err("Unable to allocate memory"
" for random array.\n");
- return -1;
+ return -ENOMEM;
}
iscsit_create_random_array(array, seq_count);
@@ -155,11 +161,11 @@ redo:
}
if (seq_count) {
- array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+ array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
if (!array) {
pr_err("Unable to allocate memory for"
" random array.\n");
- return -1;
+ return -ENOMEM;
}
iscsit_create_random_array(array, seq_count);
@@ -187,10 +193,10 @@ static int iscsit_randomize_seq_lists(
if (!seq_count)
return 0;
- array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+ array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL);
if (!array) {
pr_err("Unable to allocate memory for random array.\n");
- return -1;
+ return -ENOMEM;
}
iscsit_create_random_array(array, seq_count);
@@ -221,11 +227,10 @@ static void iscsit_determine_counts_for_list(
if ((bl->type == PDULIST_UNSOLICITED) ||
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
- unsolicited_data_length = (cmd->data_length >
- conn->sess->sess_ops->FirstBurstLength) ?
- conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
+ unsolicited_data_length = min(cmd->se_cmd.data_length,
+ conn->sess->sess_ops->FirstBurstLength);
- while (offset < cmd->data_length) {
+ while (offset < cmd->se_cmd.data_length) {
*pdu_count += 1;
if (check_immediate) {
@@ -239,10 +244,10 @@ static void iscsit_determine_counts_for_list(
}
if (unsolicited_data_length > 0) {
if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
- >= cmd->data_length) {
+ >= cmd->se_cmd.data_length) {
unsolicited_data_length -=
- (cmd->data_length - offset);
- offset += (cmd->data_length - offset);
+ (cmd->se_cmd.data_length - offset);
+ offset += (cmd->se_cmd.data_length - offset);
continue;
}
if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
@@ -263,8 +268,8 @@ static void iscsit_determine_counts_for_list(
continue;
}
if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->data_length) {
- offset += (cmd->data_length - offset);
+ cmd->se_cmd.data_length) {
+ offset += (cmd->se_cmd.data_length - offset);
continue;
}
if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
@@ -283,10 +288,10 @@ static void iscsit_determine_counts_for_list(
/*
- * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
- * and DataPDUInOrder=No.
+ * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No
+ * or DataPDUInOrder=No.
*/
-static int iscsit_build_pdu_and_seq_list(
+static int iscsit_do_build_pdu_and_seq_lists(
struct iscsi_cmd *cmd,
struct iscsi_build_list *bl)
{
@@ -306,11 +311,10 @@ static int iscsit_build_pdu_and_seq_list(
if ((bl->type == PDULIST_UNSOLICITED) ||
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
- unsolicited_data_length = (cmd->data_length >
- conn->sess->sess_ops->FirstBurstLength) ?
- conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
+ unsolicited_data_length = min(cmd->se_cmd.data_length,
+ conn->sess->sess_ops->FirstBurstLength);
- while (offset < cmd->data_length) {
+ while (offset < cmd->se_cmd.data_length) {
pdu_count++;
if (!datapduinorder) {
pdu[i].offset = offset;
@@ -346,21 +350,21 @@ static int iscsit_build_pdu_and_seq_list(
if (unsolicited_data_length > 0) {
if ((offset +
conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->data_length) {
+ cmd->se_cmd.data_length) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_UNSOLICITED;
pdu[i].length =
- (cmd->data_length - offset);
+ (cmd->se_cmd.data_length - offset);
}
if (!datasequenceinorder) {
seq[seq_no].type = SEQTYPE_UNSOLICITED;
seq[seq_no].pdu_count = pdu_count;
seq[seq_no].xfer_len = (burstlength +
- (cmd->data_length - offset));
+ (cmd->se_cmd.data_length - offset));
}
unsolicited_data_length -=
- (cmd->data_length - offset);
- offset += (cmd->data_length - offset);
+ (cmd->se_cmd.data_length - offset);
+ offset += (cmd->se_cmd.data_length - offset);
continue;
}
if ((offset +
@@ -402,18 +406,18 @@ static int iscsit_build_pdu_and_seq_list(
continue;
}
if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->data_length) {
+ cmd->se_cmd.data_length) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_NORMAL;
- pdu[i].length = (cmd->data_length - offset);
+ pdu[i].length = (cmd->se_cmd.data_length - offset);
}
if (!datasequenceinorder) {
seq[seq_no].type = SEQTYPE_NORMAL;
seq[seq_no].pdu_count = pdu_count;
seq[seq_no].xfer_len = (burstlength +
- (cmd->data_length - offset));
+ (cmd->se_cmd.data_length - offset));
}
- offset += (cmd->data_length - offset);
+ offset += (cmd->se_cmd.data_length - offset);
continue;
}
if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
@@ -464,9 +468,8 @@ static int iscsit_build_pdu_and_seq_list(
} else
iscsit_ordered_seq_lists(cmd, bl->type);
}
-#if 0
+
iscsit_dump_seq_list(cmd);
-#endif
}
if (!datapduinorder) {
if (bl->data_direction & ISCSI_PDU_WRITE) {
@@ -484,50 +487,86 @@ static int iscsit_build_pdu_and_seq_list(
} else
iscsit_ordered_pdu_lists(cmd, bl->type);
}
-#if 0
+
iscsit_dump_pdu_list(cmd);
-#endif
}
return 0;
}
-/*
- * Only called while DataSequenceInOrder=No or DataPDUInOrder=No.
- */
-int iscsit_do_build_list(
+int iscsit_build_pdu_and_seq_lists(
struct iscsi_cmd *cmd,
- struct iscsi_build_list *bl)
+ u32 immediate_data_length)
{
+ struct iscsi_build_list bl;
u32 pdu_count = 0, seq_count = 1;
struct iscsi_conn *conn = cmd->conn;
struct iscsi_pdu *pdu = NULL;
struct iscsi_seq *seq = NULL;
- iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count);
+ struct iscsi_session *sess = conn->sess;
+ struct iscsi_node_attrib *na;
+
+ /*
+ * Do nothing if no OOO shenanigans
+ */
+ if (sess->sess_ops->DataSequenceInOrder &&
+ sess->sess_ops->DataPDUInOrder)
+ return 0;
+
+ if (cmd->data_direction == DMA_NONE)
+ return 0;
+
+ na = iscsit_tpg_get_node_attrib(sess);
+ memset(&bl, 0, sizeof(struct iscsi_build_list));
+
+ if (cmd->data_direction == DMA_FROM_DEVICE) {
+ bl.data_direction = ISCSI_PDU_READ;
+ bl.type = PDULIST_NORMAL;
+ if (na->random_datain_pdu_offsets)
+ bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
+ if (na->random_datain_seq_offsets)
+ bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
+ } else {
+ bl.data_direction = ISCSI_PDU_WRITE;
+ bl.immediate_data_length = immediate_data_length;
+ if (na->random_r2t_offsets)
+ bl.randomize |= RANDOM_R2T_OFFSETS;
+
+ if (!cmd->immediate_data && !cmd->unsolicited_data)
+ bl.type = PDULIST_NORMAL;
+ else if (cmd->immediate_data && !cmd->unsolicited_data)
+ bl.type = PDULIST_IMMEDIATE;
+ else if (!cmd->immediate_data && cmd->unsolicited_data)
+ bl.type = PDULIST_UNSOLICITED;
+ else if (cmd->immediate_data && cmd->unsolicited_data)
+ bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
+ }
+
+ iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
if (!conn->sess->sess_ops->DataSequenceInOrder) {
- seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC);
+ seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
if (!seq) {
pr_err("Unable to allocate struct iscsi_seq list\n");
- return -1;
+ return -ENOMEM;
}
cmd->seq_list = seq;
cmd->seq_count = seq_count;
}
if (!conn->sess->sess_ops->DataPDUInOrder) {
- pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC);
+ pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
if (!pdu) {
pr_err("Unable to allocate struct iscsi_pdu list.\n");
kfree(seq);
- return -1;
+ return -ENOMEM;
}
cmd->pdu_list = pdu;
cmd->pdu_count = pdu_count;
}
- return iscsit_build_pdu_and_seq_list(cmd, bl);
+ return iscsit_do_build_pdu_and_seq_lists(cmd, &bl);
}
struct iscsi_pdu *iscsit_get_pdu_holder(
@@ -572,13 +611,12 @@ redo:
pdu = &cmd->pdu_list[cmd->pdu_start];
for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
-#if 0
pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
"_send_order: %d, pdu[i].offset: %d,"
" pdu[i].length: %d\n", pdu[i].seq_no,
pdu[i].pdu_send_order, pdu[i].offset,
pdu[i].length);
-#endif
+
if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
cmd->pdu_send_order++;
return &pdu[i];
@@ -601,11 +639,11 @@ redo:
pr_err("struct iscsi_seq is NULL!\n");
return NULL;
}
-#if 0
+
pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
" seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
seq->seq_no);
-#endif
+
pdu = &cmd->pdu_list[seq->pdu_start];
if (seq->pdu_send_order == seq->pdu_count) {
@@ -645,12 +683,11 @@ struct iscsi_seq *iscsit_get_seq_holder(
}
for (i = 0; i < cmd->seq_count; i++) {
-#if 0
pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
"xfer_len: %d, seq_list[i].seq_no %u\n",
cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
cmd->seq_list[i].seq_no);
-#endif
+
if ((cmd->seq_list[i].orig_offset +
cmd->seq_list[i].xfer_len) >=
(offset + length))
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
index 0d52a10..d5b1537 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
@@ -78,7 +78,7 @@ struct iscsi_seq {
u32 xfer_len;
} ____cacheline_aligned;
-extern int iscsit_do_build_list(struct iscsi_cmd *, struct iscsi_build_list *);
+extern int iscsit_build_pdu_and_seq_lists(struct iscsi_cmd *, u32);
extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32);
extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *);
extern struct iscsi_seq *iscsit_get_seq_holder(struct iscsi_cmd *, u32, u32);
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index e01da9d..f4e640b 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -78,10 +78,7 @@ int iscsit_tmr_task_warm_reset(
{
struct iscsi_session *sess = conn->sess;
struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
-#if 0
- struct iscsi_init_task_mgt_cmnd *hdr =
- (struct iscsi_init_task_mgt_cmnd *) buf;
-#endif
+
if (!na->tmr_warm_reset) {
pr_err("TMR Opcode TARGET_WARM_RESET authorization"
" failed for Initiator Node: %s\n",
@@ -216,7 +213,7 @@ static int iscsit_task_reassign_complete_nop_out(
iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess);
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
cmd->i_state = ISTATE_SEND_NOPIN;
@@ -272,9 +269,9 @@ static int iscsit_task_reassign_complete_write(
offset = cmd->next_burst_len = cmd->write_data_done;
if ((conn->sess->sess_ops->FirstBurstLength - offset) >=
- cmd->data_length) {
+ cmd->se_cmd.data_length) {
no_build_r2ts = 1;
- length = (cmd->data_length - offset);
+ length = (cmd->se_cmd.data_length - offset);
} else
length = (conn->sess->sess_ops->FirstBurstLength - offset);
@@ -292,7 +289,7 @@ static int iscsit_task_reassign_complete_write(
/*
* iscsit_build_r2ts_for_cmd() can handle the rest from here.
*/
- return iscsit_build_r2ts_for_cmd(cmd, conn, 2);
+ return iscsit_build_r2ts_for_cmd(cmd, conn, true);
}
static int iscsit_task_reassign_complete_read(
@@ -385,7 +382,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd(
iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess);
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 4eba86d..b42cdeb 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -163,7 +163,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
}
cmd->conn = conn;
- INIT_LIST_HEAD(&cmd->i_list);
+ INIT_LIST_HEAD(&cmd->i_conn_node);
INIT_LIST_HEAD(&cmd->datain_list);
INIT_LIST_HEAD(&cmd->cmd_r2t_list);
init_completion(&cmd->reject_comp);
@@ -176,174 +176,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
return cmd;
}
-/*
- * Called from iscsi_handle_scsi_cmd()
- */
-struct iscsi_cmd *iscsit_allocate_se_cmd(
- struct iscsi_conn *conn,
- u32 data_length,
- int data_direction,
- int iscsi_task_attr)
-{
- struct iscsi_cmd *cmd;
- struct se_cmd *se_cmd;
- int sam_task_attr;
-
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return NULL;
-
- cmd->data_direction = data_direction;
- cmd->data_length = data_length;
- /*
- * Figure out the SAM Task Attribute for the incoming SCSI CDB
- */
- if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) ||
- (iscsi_task_attr == ISCSI_ATTR_SIMPLE))
- sam_task_attr = MSG_SIMPLE_TAG;
- else if (iscsi_task_attr == ISCSI_ATTR_ORDERED)
- sam_task_attr = MSG_ORDERED_TAG;
- else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE)
- sam_task_attr = MSG_HEAD_TAG;
- else if (iscsi_task_attr == ISCSI_ATTR_ACA)
- sam_task_attr = MSG_ACA_TAG;
- else {
- pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using"
- " MSG_SIMPLE_TAG\n", iscsi_task_attr);
- sam_task_attr = MSG_SIMPLE_TAG;
- }
-
- se_cmd = &cmd->se_cmd;
- /*
- * Initialize struct se_cmd descriptor from target_core_mod infrastructure
- */
- transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops,
- conn->sess->se_sess, data_length, data_direction,
- sam_task_attr, &cmd->sense_buffer[0]);
- return cmd;
-}
-
-struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
- struct iscsi_conn *conn,
- u8 function)
-{
- struct iscsi_cmd *cmd;
- struct se_cmd *se_cmd;
- int rc;
- u8 tcm_function;
-
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return NULL;
-
- cmd->data_direction = DMA_NONE;
-
- cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
- if (!cmd->tmr_req) {
- pr_err("Unable to allocate memory for"
- " Task Management command!\n");
- goto out;
- }
- /*
- * TASK_REASSIGN for ERL=2 / connection stays inside of
- * LIO-Target $FABRIC_MOD
- */
- if (function == ISCSI_TM_FUNC_TASK_REASSIGN)
- return cmd;
-
- se_cmd = &cmd->se_cmd;
- /*
- * Initialize struct se_cmd descriptor from target_core_mod infrastructure
- */
- transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops,
- conn->sess->se_sess, 0, DMA_NONE,
- MSG_SIMPLE_TAG, &cmd->sense_buffer[0]);
-
- switch (function) {
- case ISCSI_TM_FUNC_ABORT_TASK:
- tcm_function = TMR_ABORT_TASK;
- break;
- case ISCSI_TM_FUNC_ABORT_TASK_SET:
- tcm_function = TMR_ABORT_TASK_SET;
- break;
- case ISCSI_TM_FUNC_CLEAR_ACA:
- tcm_function = TMR_CLEAR_ACA;
- break;
- case ISCSI_TM_FUNC_CLEAR_TASK_SET:
- tcm_function = TMR_CLEAR_TASK_SET;
- break;
- case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
- tcm_function = TMR_LUN_RESET;
- break;
- case ISCSI_TM_FUNC_TARGET_WARM_RESET:
- tcm_function = TMR_TARGET_WARM_RESET;
- break;
- case ISCSI_TM_FUNC_TARGET_COLD_RESET:
- tcm_function = TMR_TARGET_COLD_RESET;
- break;
- default:
- pr_err("Unknown iSCSI TMR Function:"
- " 0x%02x\n", function);
- goto out;
- }
-
- rc = core_tmr_alloc_req(se_cmd, cmd->tmr_req, tcm_function, GFP_KERNEL);
- if (rc < 0)
- goto out;
-
- cmd->tmr_req->se_tmr_req = se_cmd->se_tmr_req;
-
- return cmd;
-out:
- iscsit_release_cmd(cmd);
- return NULL;
-}
-
-int iscsit_decide_list_to_build(
- struct iscsi_cmd *cmd,
- u32 immediate_data_length)
-{
- struct iscsi_build_list bl;
- struct iscsi_conn *conn = cmd->conn;
- struct iscsi_session *sess = conn->sess;
- struct iscsi_node_attrib *na;
-
- if (sess->sess_ops->DataSequenceInOrder &&
- sess->sess_ops->DataPDUInOrder)
- return 0;
-
- if (cmd->data_direction == DMA_NONE)
- return 0;
-
- na = iscsit_tpg_get_node_attrib(sess);
- memset(&bl, 0, sizeof(struct iscsi_build_list));
-
- if (cmd->data_direction == DMA_FROM_DEVICE) {
- bl.data_direction = ISCSI_PDU_READ;
- bl.type = PDULIST_NORMAL;
- if (na->random_datain_pdu_offsets)
- bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
- if (na->random_datain_seq_offsets)
- bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
- } else {
- bl.data_direction = ISCSI_PDU_WRITE;
- bl.immediate_data_length = immediate_data_length;
- if (na->random_r2t_offsets)
- bl.randomize |= RANDOM_R2T_OFFSETS;
-
- if (!cmd->immediate_data && !cmd->unsolicited_data)
- bl.type = PDULIST_NORMAL;
- else if (cmd->immediate_data && !cmd->unsolicited_data)
- bl.type = PDULIST_IMMEDIATE;
- else if (!cmd->immediate_data && cmd->unsolicited_data)
- bl.type = PDULIST_UNSOLICITED;
- else if (cmd->immediate_data && cmd->unsolicited_data)
- bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
- }
-
- return iscsit_do_build_list(cmd, &bl);
-}
-
struct iscsi_seq *iscsit_get_seq_holder_for_datain(
struct iscsi_cmd *cmd,
u32 seq_send_order)
@@ -502,14 +334,14 @@ int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))
return 0;
- if (((cmd->first_burst_len + payload_length) != cmd->data_length) &&
+ if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) &&
((cmd->first_burst_len + payload_length) !=
conn->sess->sess_ops->FirstBurstLength)) {
pr_err("Unsolicited non-immediate data received %u"
" does not equal FirstBurstLength: %u, and does"
" not equal ExpXferLen %u.\n",
(cmd->first_burst_len + payload_length),
- conn->sess->sess_ops->FirstBurstLength, cmd->data_length);
+ conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length);
transport_send_check_condition_and_sense(se_cmd,
TCM_INCORRECT_AMOUNT_OF_DATA, 0);
return -1;
@@ -524,7 +356,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
struct iscsi_cmd *cmd;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
if (cmd->init_task_tag == init_task_tag) {
spin_unlock_bh(&conn->cmd_lock);
return cmd;
@@ -545,7 +377,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
struct iscsi_cmd *cmd;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
if (cmd->init_task_tag == init_task_tag) {
spin_unlock_bh(&conn->cmd_lock);
return cmd;
@@ -568,7 +400,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_ttt(
struct iscsi_cmd *cmd = NULL;
spin_lock_bh(&conn->cmd_lock);
- list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+ list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
if (cmd->targ_xfer_tag == targ_xfer_tag) {
spin_unlock_bh(&conn->cmd_lock);
return cmd;
@@ -596,7 +428,7 @@ int iscsit_find_cmd_for_recovery(
spin_lock(&sess->cr_i_lock);
list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) {
spin_lock(&cr->conn_recovery_cmd_lock);
- list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) {
+ list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) {
if (cmd->init_task_tag == init_task_tag) {
spin_unlock(&cr->conn_recovery_cmd_lock);
spin_unlock(&sess->cr_i_lock);
@@ -616,7 +448,7 @@ int iscsit_find_cmd_for_recovery(
spin_lock(&sess->cr_a_lock);
list_for_each_entry(cr, &sess->cr_active_list, cr_list) {
spin_lock(&cr->conn_recovery_cmd_lock);
- list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) {
+ list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) {
if (cmd->init_task_tag == init_task_tag) {
spin_unlock(&cr->conn_recovery_cmd_lock);
spin_unlock(&sess->cr_a_lock);
@@ -813,7 +645,6 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
void iscsit_release_cmd(struct iscsi_cmd *cmd)
{
struct iscsi_conn *conn = cmd->conn;
- int i;
iscsit_free_r2ts_from_list(cmd);
iscsit_free_all_datain_reqs(cmd);
@@ -824,11 +655,6 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
kfree(cmd->tmr_req);
kfree(cmd->iov_data);
- for (i = 0; i < cmd->t_mem_sg_nents; i++)
- __free_page(sg_page(&cmd->t_mem_sg[i]));
-
- kfree(cmd->t_mem_sg);
-
if (conn) {
iscsit_remove_cmd_from_immediate_queue(cmd, conn);
iscsit_remove_cmd_from_response_queue(cmd, conn);
@@ -1038,7 +864,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
spin_unlock_bh(&conn->sess->ttt_lock);
spin_lock_bh(&conn->cmd_lock);
- list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+ list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
if (want_response)
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 835bf7d..e1c729b 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -9,9 +9,6 @@ extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
-extern struct iscsi_cmd *iscsit_allocate_se_cmd(struct iscsi_conn *, u32, int, int);
-extern struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(struct iscsi_conn *, u8);
-extern int iscsit_decide_list_to_build(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index a9b4eee..38dfac2 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -213,7 +213,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
* associated read buffers, go ahead and do that here for type
* SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently
* guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
- * by target core in transport_generic_allocate_tasks() ->
+ * by target core in target_setup_cmd_from_cdb() ->
* transport_generic_cmd_sequencer().
*/
if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
@@ -227,7 +227,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
}
}
- ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
+ ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
if (ret == -ENOMEM) {
transport_send_check_condition_and_sense(se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 0000000..132da54
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,11 @@
+config SBP_TARGET
+ tristate "FireWire SBP-2 fabric module"
+ depends on FIREWIRE && EXPERIMENTAL
+ help
+ Say Y or M here to enable SCSI target functionality over FireWire.
+ This enables you to expose SCSI devices to other nodes on the FireWire
+ bus, for example hard disks. Similar to FireWire Target Disk mode on
+ many Apple computers.
+
+ To compile this driver as a module, say M here: The module will be
+ called sbp-target.
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 0000000..27747ad
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SBP_TARGET) += sbp_target.o
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
new file mode 100644
index 0000000..37c6098
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.c
@@ -0,0 +1,2621 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011 Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "sbp_target.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *sbp_fabric_configfs;
+
+/* FireWire address region for management and command block address handlers */
+static const struct fw_address_region sbp_register_region = {
+ .start = CSR_REGISTER_BASE + 0x10000,
+ .end = 0x1000000000000ULL,
+};
+
+static const u32 sbp_unit_directory_template[] = {
+ 0x1200609e, /* unit_specifier_id: NCITS/T10 */
+ 0x13010483, /* unit_sw_version: 1155D Rev 4 */
+ 0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+ 0x390104d8, /* command_set: SPC-2 */
+ 0x3b000000, /* command_set_revision: 0 */
+ 0x3c000001, /* firmware_revision: 1 */
+};
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *);
+static int sbp_run_transaction(struct fw_card *, int, int, int, int,
+ unsigned long long, void *, size_t);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+ int ret;
+ __be32 high, low;
+
+ ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+ &high, sizeof(high));
+ if (ret != RCODE_COMPLETE)
+ return ret;
+
+ ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+ &low, sizeof(low));
+ if (ret != RCODE_COMPLETE)
+ return ret;
+
+ *guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+ return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+ struct sbp_tpg *tpg, u64 guid)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess, *found = NULL;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+ if (sess->guid == guid)
+ found = sess;
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return found;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+ struct sbp_session *session, struct se_lun *lun)
+{
+ struct sbp_login_descriptor *login, *found = NULL;
+
+ spin_lock_bh(&session->lock);
+ list_for_each_entry(login, &session->login_list, link) {
+ if (login->lun == lun)
+ found = login;
+ }
+ spin_unlock_bh(&session->lock);
+
+ return found;
+}
+
+static int sbp_login_count_all_by_lun(
+ struct sbp_tpg *tpg,
+ struct se_lun *lun,
+ int exclusive)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login;
+ int count = 0;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry(login, &sess->login_list, link) {
+ if (login->lun != lun)
+ continue;
+
+ if (!exclusive || login->exclusive)
+ count++;
+ }
+ spin_unlock_bh(&sess->lock);
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+ struct sbp_tpg *tpg, int login_id)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login, *found = NULL;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry(login, &sess->login_list, link) {
+ if (login->login_id == login_id)
+ found = login;
+ }
+ spin_unlock_bh(&sess->lock);
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return found;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+ struct se_portal_group *se_tpg = &tpg->se_tpg;
+ struct se_lun *se_lun;
+
+ if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+ return ERR_PTR(-EINVAL);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+ se_lun = se_tpg->tpg_lun_list[lun];
+
+ if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+ se_lun = ERR_PTR(-ENODEV);
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+ struct sbp_tpg *tpg,
+ u64 guid)
+{
+ struct sbp_session *sess;
+ int ret;
+ char guid_str[17];
+ struct se_node_acl *se_nacl;
+
+ sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+ if (!sess) {
+ pr_err("failed to allocate session descriptor\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ sess->se_sess = transport_init_session();
+ if (IS_ERR(sess->se_sess)) {
+ pr_err("failed to init se_session\n");
+
+ ret = PTR_ERR(sess->se_sess);
+ kfree(sess);
+ return ERR_PTR(ret);
+ }
+
+ snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+ se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+ if (!se_nacl) {
+ pr_warn("Node ACL not found for %s\n", guid_str);
+
+ transport_free_session(sess->se_sess);
+ kfree(sess);
+
+ return ERR_PTR(-EPERM);
+ }
+
+ sess->se_sess->se_node_acl = se_nacl;
+
+ spin_lock_init(&sess->lock);
+ INIT_LIST_HEAD(&sess->login_list);
+ INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+
+ sess->guid = guid;
+
+ transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+ return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+ spin_lock_bh(&sess->lock);
+ if (!list_empty(&sess->login_list)) {
+ spin_unlock_bh(&sess->lock);
+ return;
+ }
+ spin_unlock_bh(&sess->lock);
+
+ if (cancel_work)
+ cancel_delayed_work_sync(&sess->maint_work);
+
+ transport_deregister_session_configfs(sess->se_sess);
+ transport_deregister_session(sess->se_sess);
+
+ if (sess->card)
+ fw_card_put(sess->card);
+
+ kfree(sess);
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *);
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+ bool cancel_work)
+{
+ struct sbp_session *sess = login->sess;
+
+ /* FIXME: abort/wait on tasks */
+
+ sbp_target_agent_unregister(login->tgt_agt);
+
+ if (sess) {
+ spin_lock_bh(&sess->lock);
+ list_del(&login->link);
+ spin_unlock_bh(&sess->lock);
+
+ sbp_session_release(sess, cancel_work);
+ }
+
+ kfree(login);
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+ struct sbp_login_descriptor *);
+
+static void sbp_management_request_login(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ struct se_lun *se_lun;
+ int ret;
+ u64 guid;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login;
+ struct sbp_login_response_block *response;
+ int login_response_len;
+
+ se_lun = sbp_get_lun_from_tpg(tpg,
+ LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+ if (IS_ERR(se_lun)) {
+ pr_notice("login to unknown LUN: %d\n",
+ LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+ return;
+ }
+
+ ret = read_peer_guid(&guid, req);
+ if (ret != RCODE_COMPLETE) {
+ pr_warn("failed to read peer GUID: %d\n", ret);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+ se_lun->unpacked_lun, guid);
+
+ sess = sbp_session_find_by_guid(tpg, guid);
+ if (sess) {
+ login = sbp_login_find_by_lun(sess, se_lun);
+ if (login) {
+ pr_notice("initiator already logged-in\n");
+
+ /*
+ * SBP-2 R4 says we should return access denied, but
+ * that can confuse initiators. Instead we need to
+ * treat this like a reconnect, but send the login
+ * response block like a fresh login.
+ *
+ * This is required particularly in the case of Apple
+ * devices booting off the FireWire target, where
+ * the firmware has an active login to the target. When
+ * the OS takes control of the session it issues its own
+ * LOGIN rather than a RECONNECT. To avoid the machine
+ * waiting until the reconnect_hold expires, we can skip
+ * the ACCESS_DENIED errors to speed things up.
+ */
+
+ goto already_logged_in;
+ }
+ }
+
+ /*
+ * check exclusive bit in login request
+ * reject with access_denied if any logins present
+ */
+ if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+ sbp_login_count_all_by_lun(tpg, se_lun, 0)) {
+ pr_warn("refusing exclusive login with other active logins\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ /*
+ * check exclusive bit in any existing login descriptor
+ * reject with access_denied if any exclusive logins present
+ */
+ if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) {
+ pr_warn("refusing login while another exclusive login present\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ /*
+ * check we haven't exceeded the number of allowed logins
+ * reject with resources_unavailable if we have
+ */
+ if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >=
+ tport->max_logins_per_lun) {
+ pr_warn("max number of logins reached\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ if (!sess) {
+ sess = sbp_session_create(tpg, guid);
+ if (IS_ERR(sess)) {
+ switch (PTR_ERR(sess)) {
+ case -EPERM:
+ ret = SBP_STATUS_ACCESS_DENIED;
+ break;
+ default:
+ ret = SBP_STATUS_RESOURCES_UNAVAIL;
+ break;
+ }
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(ret));
+ return;
+ }
+
+ sess->node_id = req->node_addr;
+ sess->card = fw_card_get(req->card);
+ sess->generation = req->generation;
+ sess->speed = req->speed;
+
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ }
+
+ /* only take the latest reconnect_hold into account */
+ sess->reconnect_hold = min(
+ 1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+ tport->max_reconnect_timeout) - 1;
+
+ login = kmalloc(sizeof(*login), GFP_KERNEL);
+ if (!login) {
+ pr_err("failed to allocate login descriptor\n");
+
+ sbp_session_release(sess, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ login->sess = sess;
+ login->lun = se_lun;
+ login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+ login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+ login->login_id = atomic_inc_return(&login_id);
+
+ login->tgt_agt = sbp_target_agent_register(login);
+ if (IS_ERR(login->tgt_agt)) {
+ ret = PTR_ERR(login->tgt_agt);
+ pr_err("failed to map command block handler: %d\n", ret);
+
+ sbp_session_release(sess, true);
+ kfree(login);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ spin_lock_bh(&sess->lock);
+ list_add_tail(&login->link, &sess->login_list);
+ spin_unlock_bh(&sess->lock);
+
+already_logged_in:
+ response = kzalloc(sizeof(*response), GFP_KERNEL);
+ if (!response) {
+ pr_err("failed to allocate login response block\n");
+
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ login_response_len = clamp_val(
+ LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length)),
+ 12, sizeof(*response));
+ response->misc = cpu_to_be32(
+ ((login_response_len & 0xffff) << 16) |
+ (login->login_id & 0xffff));
+ response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+ addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+ &response->command_block_agent);
+
+ ret = sbp_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+ sess->node_id, sess->generation, sess->speed,
+ sbp2_pointer_to_addr(&req->orb.ptr2), response,
+ login_response_len);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("failed to write login response block: %x\n", ret);
+
+ kfree(response);
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ kfree(response);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_query_logins(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ pr_notice("QUERY LOGINS not implemented\n");
+ /* FIXME: implement */
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+static void sbp_management_request_reconnect(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ int ret;
+ u64 guid;
+ struct sbp_login_descriptor *login;
+
+ ret = read_peer_guid(&guid, req);
+ if (ret != RCODE_COMPLETE) {
+ pr_warn("failed to read peer GUID: %d\n", ret);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+ login = sbp_login_find_by_id(tpg,
+ RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+ if (!login) {
+ pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ if (login->sess->guid != guid) {
+ pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ spin_lock_bh(&login->sess->lock);
+ if (login->sess->card)
+ fw_card_put(login->sess->card);
+
+ /* update the node details */
+ login->sess->generation = req->generation;
+ login->sess->node_id = req->node_addr;
+ login->sess->card = fw_card_get(req->card);
+ login->sess->speed = req->speed;
+ spin_unlock_bh(&login->sess->lock);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_logout(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ int login_id;
+ struct sbp_login_descriptor *login;
+
+ login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+ login = sbp_login_find_by_id(tpg, login_id);
+ if (!login) {
+ pr_warn("cannot find login: %d\n", login_id);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+ return;
+ }
+
+ pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+ login->lun->unpacked_lun, login->login_id);
+
+ if (req->node_addr != login->sess->node_id) {
+ pr_warn("logout from different node ID\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+ bool card_valid = false;
+
+ spin_lock_bh(&sess->lock);
+
+ if (sess->card) {
+ spin_lock_irq(&sess->card->lock);
+ card_valid = (sess->card->local_node != NULL);
+ spin_unlock_irq(&sess->card->lock);
+
+ if (!card_valid) {
+ fw_card_put(sess->card);
+ sess->card = NULL;
+ }
+ }
+
+ if (!card_valid || (sess->generation != sess->card->generation)) {
+ pr_info("Waiting for reconnect from node: %016llx\n",
+ sess->guid);
+
+ sess->node_id = -1;
+ sess->reconnect_expires = get_jiffies_64() +
+ ((sess->reconnect_hold + 1) * HZ);
+ }
+
+ spin_unlock_bh(&sess->lock);
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+ struct sbp_login_descriptor *login, *temp;
+ LIST_HEAD(login_list);
+
+ pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+ login->sess = NULL;
+ list_del(&login->link);
+ list_add_tail(&login->link, &login_list);
+ }
+ spin_unlock_bh(&sess->lock);
+
+ list_for_each_entry_safe(login, temp, &login_list, link) {
+ list_del(&login->link);
+ sbp_login_release(login, false);
+ }
+
+ sbp_session_release(sess, false);
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+ struct sbp_session *sess = container_of(work, struct sbp_session,
+ maint_work.work);
+
+ /* could be called while tearing down the session */
+ spin_lock_bh(&sess->lock);
+ if (list_empty(&sess->login_list)) {
+ spin_unlock_bh(&sess->lock);
+ return;
+ }
+ spin_unlock_bh(&sess->lock);
+
+ if (sess->node_id != -1) {
+ /* check for bus reset and make node_id invalid */
+ session_check_for_reset(sess);
+
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ } else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+ /* still waiting for reconnect */
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ } else {
+ /* reconnect timeout has expired */
+ session_reconnect_expired(sess);
+ }
+}
+
+static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ __be32 state;
+
+ switch (tcode) {
+ case TCODE_READ_QUADLET_REQUEST:
+ pr_debug("tgt_agent AGENT_STATE READ\n");
+
+ spin_lock_bh(&agent->lock);
+ state = cpu_to_be32(agent->state);
+ spin_unlock_bh(&agent->lock);
+ memcpy(data, &state, sizeof(state));
+
+ return RCODE_COMPLETE;
+
+ case TCODE_WRITE_QUADLET_REQUEST:
+ /* ignored */
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ pr_debug("tgt_agent AGENT_RESET\n");
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_RESET;
+ spin_unlock_bh(&agent->lock);
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ struct sbp2_pointer *ptr = data;
+
+ switch (tcode) {
+ case TCODE_WRITE_BLOCK_REQUEST:
+ spin_lock_bh(&agent->lock);
+ if (agent->state != AGENT_STATE_SUSPENDED &&
+ agent->state != AGENT_STATE_RESET) {
+ spin_unlock_bh(&agent->lock);
+ pr_notice("Ignoring ORB_POINTER write while active.\n");
+ return RCODE_CONFLICT_ERROR;
+ }
+ agent->state = AGENT_STATE_ACTIVE;
+ spin_unlock_bh(&agent->lock);
+
+ agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+ agent->doorbell = false;
+
+ pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
+ agent->orb_pointer);
+
+ queue_work(system_unbound_wq, &agent->work);
+
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ pr_debug("tgt_agent ORB_POINTER READ\n");
+ spin_lock_bh(&agent->lock);
+ addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+ spin_unlock_bh(&agent->lock);
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ spin_lock_bh(&agent->lock);
+ if (agent->state != AGENT_STATE_SUSPENDED) {
+ spin_unlock_bh(&agent->lock);
+ pr_debug("Ignoring DOORBELL while active.\n");
+ return RCODE_CONFLICT_ERROR;
+ }
+ agent->state = AGENT_STATE_ACTIVE;
+ spin_unlock_bh(&agent->lock);
+
+ agent->doorbell = true;
+
+ pr_debug("tgt_agent DOORBELL\n");
+
+ queue_work(system_unbound_wq, &agent->work);
+
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+ int tcode, void *data, struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+ /* ignored as we don't send unsolicited status */
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static void tgt_agent_rw(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source, int generation,
+ unsigned long long offset, void *data, size_t length,
+ void *callback_data)
+{
+ struct sbp_target_agent *agent = callback_data;
+ struct sbp_session *sess = agent->login->sess;
+ int sess_gen, sess_node, rcode;
+
+ spin_lock_bh(&sess->lock);
+ sess_gen = sess->generation;
+ sess_node = sess->node_id;
+ spin_unlock_bh(&sess->lock);
+
+ if (generation != sess_gen) {
+ pr_notice("ignoring request with wrong generation\n");
+ rcode = RCODE_TYPE_ERROR;
+ goto out;
+ }
+
+ if (source != sess_node) {
+ pr_notice("ignoring request from foreign node (%x != %x)\n",
+ source, sess_node);
+ rcode = RCODE_TYPE_ERROR;
+ goto out;
+ }
+
+ /* turn offset into the offset from the start of the block */
+ offset -= agent->handler.offset;
+
+ if (offset == 0x00 && length == 4) {
+ /* AGENT_STATE */
+ rcode = tgt_agent_rw_agent_state(card, tcode, data, agent);
+ } else if (offset == 0x04 && length == 4) {
+ /* AGENT_RESET */
+ rcode = tgt_agent_rw_agent_reset(card, tcode, data, agent);
+ } else if (offset == 0x08 && length == 8) {
+ /* ORB_POINTER */
+ rcode = tgt_agent_rw_orb_pointer(card, tcode, data, agent);
+ } else if (offset == 0x10 && length == 4) {
+ /* DOORBELL */
+ rcode = tgt_agent_rw_doorbell(card, tcode, data, agent);
+ } else if (offset == 0x14 && length == 4) {
+ /* UNSOLICITED_STATUS_ENABLE */
+ rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+ data, agent);
+ } else {
+ rcode = RCODE_ADDRESS_ERROR;
+ }
+
+out:
+ fw_send_response(card, request, rcode);
+}
+
+static void sbp_handle_command(struct sbp_target_request *);
+static int sbp_send_status(struct sbp_target_request *);
+static void sbp_free_request(struct sbp_target_request *);
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+ struct sbp_target_request *req =
+ container_of(work, struct sbp_target_request, work);
+
+ pr_debug("tgt_orb ptr:0x%llx next_ORB:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+ req->orb_pointer,
+ sbp2_pointer_to_addr(&req->orb.next_orb),
+ sbp2_pointer_to_addr(&req->orb.data_descriptor),
+ be32_to_cpu(req->orb.misc));
+
+ if (req->orb_pointer >> 32)
+ pr_debug("ORB with high bits set\n");
+
+ switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+ case 0:/* Format specified by this standard */
+ sbp_handle_command(req);
+ return;
+ case 1: /* Reserved for future standardization */
+ case 2: /* Vendor-dependent */
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_REQ_TYPE_NOTSUPP));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ case 3: /* Dummy ORB */
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_DUMMY_ORB_COMPLETE));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ default:
+ BUG();
+ }
+}
+
+/* used to double-check we haven't been issued an AGENT_RESET */
+static inline bool tgt_agent_check_active(struct sbp_target_agent *agent)
+{
+ bool active;
+
+ spin_lock_bh(&agent->lock);
+ active = (agent->state == AGENT_STATE_ACTIVE);
+ spin_unlock_bh(&agent->lock);
+
+ return active;
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+ struct sbp_target_agent *agent =
+ container_of(work, struct sbp_target_agent, work);
+ struct sbp_session *sess = agent->login->sess;
+ struct sbp_target_request *req;
+ int ret;
+ bool doorbell = agent->doorbell;
+ u64 next_orb = agent->orb_pointer;
+
+ while (next_orb && tgt_agent_check_active(agent)) {
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_DEAD;
+ spin_unlock_bh(&agent->lock);
+ return;
+ }
+
+ req->login = agent->login;
+ req->orb_pointer = next_orb;
+
+ req->status.status = cpu_to_be32(STATUS_BLOCK_ORB_OFFSET_HIGH(
+ req->orb_pointer >> 32));
+ req->status.orb_low = cpu_to_be32(
+ req->orb_pointer & 0xfffffffc);
+
+ /* read in the ORB */
+ ret = sbp_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+ sess->node_id, sess->generation, sess->speed,
+ req->orb_pointer, &req->orb, sizeof(req->orb));
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("tgt_orb fetch failed: %x\n", ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_FINISHED) |
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(1) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_UNSPECIFIED_ERROR));
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_DEAD;
+ spin_unlock_bh(&agent->lock);
+
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ /* check the next_ORB field */
+ if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+ next_orb = 0;
+ req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_FINISHED));
+ } else {
+ next_orb = sbp2_pointer_to_addr(&req->orb.next_orb);
+ req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_CONTINUING));
+ }
+
+ if (tgt_agent_check_active(agent) && !doorbell) {
+ INIT_WORK(&req->work, tgt_agent_process_work);
+ queue_work(system_unbound_wq, &req->work);
+ } else {
+ /* don't process this request, just check next_ORB */
+ sbp_free_request(req);
+ }
+
+ spin_lock_bh(&agent->lock);
+ doorbell = agent->doorbell = false;
+
+ /* check if we should carry on processing */
+ if (next_orb)
+ agent->orb_pointer = next_orb;
+ else
+ agent->state = AGENT_STATE_SUSPENDED;
+
+ spin_unlock_bh(&agent->lock);
+ };
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+ struct sbp_login_descriptor *login)
+{
+ struct sbp_target_agent *agent;
+ int ret;
+
+ agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ if (!agent)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&agent->lock);
+
+ agent->handler.length = 0x20;
+ agent->handler.address_callback = tgt_agent_rw;
+ agent->handler.callback_data = agent;
+
+ agent->login = login;
+ agent->state = AGENT_STATE_RESET;
+ INIT_WORK(&agent->work, tgt_agent_fetch_work);
+ agent->orb_pointer = 0;
+ agent->doorbell = false;
+
+ ret = fw_core_add_address_handler(&agent->handler,
+ &sbp_register_region);
+ if (ret < 0) {
+ kfree(agent);
+ return ERR_PTR(ret);
+ }
+
+ return agent;
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+ fw_core_remove_address_handler(&agent->handler);
+ cancel_work_sync(&agent->work);
+ kfree(agent);
+}
+
+/*
+ * Simple wrapper around fw_run_transaction that retries the transaction several
+ * times in case of failure, with an exponential backoff.
+ */
+static int sbp_run_transaction(struct fw_card *card, int tcode, int destination_id,
+ int generation, int speed, unsigned long long offset,
+ void *payload, size_t length)
+{
+ int attempt, ret, delay;
+
+ for (attempt = 1; attempt <= 5; attempt++) {
+ ret = fw_run_transaction(card, tcode, destination_id,
+ generation, speed, offset, payload, length);
+
+ switch (ret) {
+ case RCODE_COMPLETE:
+ case RCODE_TYPE_ERROR:
+ case RCODE_ADDRESS_ERROR:
+ case RCODE_GENERATION:
+ return ret;
+
+ default:
+ delay = 5 * attempt * attempt;
+ usleep_range(delay, delay * 2);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Wrapper around sbp_run_transaction that gets the card, destination,
+ * generation and speed out of the request's session.
+ */
+static int sbp_run_request_transaction(struct sbp_target_request *req,
+ int tcode, unsigned long long offset, void *payload,
+ size_t length)
+{
+ struct sbp_login_descriptor *login = req->login;
+ struct sbp_session *sess = login->sess;
+ struct fw_card *card;
+ int node_id, generation, speed, ret;
+
+ spin_lock_bh(&sess->lock);
+ card = fw_card_get(sess->card);
+ node_id = sess->node_id;
+ generation = sess->generation;
+ speed = sess->speed;
+ spin_unlock_bh(&sess->lock);
+
+ ret = sbp_run_transaction(card, tcode, node_id, generation, speed,
+ offset, payload, length);
+
+ fw_card_put(card);
+
+ return ret;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+ int ret, cmd_len, copy_len;
+
+ cmd_len = scsi_command_size(req->orb.command_block);
+
+ req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+ if (!req->cmd_buf)
+ return -ENOMEM;
+
+ memcpy(req->cmd_buf, req->orb.command_block,
+ min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+ if (cmd_len > sizeof(req->orb.command_block)) {
+ pr_debug("sbp_fetch_command: filling in long command\n");
+ copy_len = cmd_len - sizeof(req->orb.command_block);
+
+ ret = sbp_run_request_transaction(req,
+ TCODE_READ_BLOCK_REQUEST,
+ req->orb_pointer + sizeof(req->orb),
+ req->cmd_buf + sizeof(req->orb.command_block),
+ copy_len);
+ if (ret != RCODE_COMPLETE)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+ int pg_tbl_sz, ret;
+ struct sbp_page_table_entry *pg_tbl;
+
+ if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+ return 0;
+
+ pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+ sizeof(struct sbp_page_table_entry);
+
+ pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+ if (!pg_tbl)
+ return -ENOMEM;
+
+ ret = sbp_run_request_transaction(req, TCODE_READ_BLOCK_REQUEST,
+ sbp2_pointer_to_addr(&req->orb.data_descriptor),
+ pg_tbl, pg_tbl_sz);
+ if (ret != RCODE_COMPLETE) {
+ kfree(pg_tbl);
+ return -EIO;
+ }
+
+ req->pg_tbl = pg_tbl;
+ return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req,
+ u32 *data_len, enum dma_data_direction *data_dir)
+{
+ int data_size, direction, idx;
+
+ data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+ direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+ if (!data_size) {
+ *data_len = 0;
+ *data_dir = DMA_NONE;
+ return;
+ }
+
+ *data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ if (req->pg_tbl) {
+ *data_len = 0;
+ for (idx = 0; idx < data_size; idx++) {
+ *data_len += be16_to_cpu(
+ req->pg_tbl[idx].segment_length);
+ }
+ } else {
+ *data_len = data_size;
+ }
+}
+
+static void sbp_handle_command(struct sbp_target_request *req)
+{
+ struct sbp_login_descriptor *login = req->login;
+ struct sbp_session *sess = login->sess;
+ int ret, unpacked_lun;
+ u32 data_length;
+ enum dma_data_direction data_dir;
+
+ ret = sbp_fetch_command(req);
+ if (ret) {
+ pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ ret = sbp_fetch_page_table(req);
+ if (ret) {
+ pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+ ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ unpacked_lun = req->login->lun->unpacked_lun;
+ sbp_calc_data_length_direction(req, &data_length, &data_dir);
+
+ pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n",
+ req->orb_pointer, unpacked_lun, data_length, data_dir);
+
+ target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+ req->sense_buf, unpacked_lun, data_length,
+ MSG_SIMPLE_TAG, data_dir, 0);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+static int sbp_rw_data(struct sbp_target_request *req)
+{
+ struct sbp_session *sess = req->login->sess;
+ int tcode, sg_miter_flags, max_payload, pg_size, speed, node_id,
+ generation, num_pte, length, tfr_length,
+ rcode = RCODE_COMPLETE;
+ struct sbp_page_table_entry *pte;
+ unsigned long long offset;
+ struct fw_card *card;
+ struct sg_mapping_iter iter;
+
+ if (req->se_cmd.data_direction == DMA_FROM_DEVICE) {
+ tcode = TCODE_WRITE_BLOCK_REQUEST;
+ sg_miter_flags = SG_MITER_FROM_SG;
+ } else {
+ tcode = TCODE_READ_BLOCK_REQUEST;
+ sg_miter_flags = SG_MITER_TO_SG;
+ }
+
+ max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+ speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+
+ pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+ if (pg_size) {
+ pr_err("sbp_run_transaction: page size ignored\n");
+ pg_size = 0x100 << pg_size;
+ }
+
+ spin_lock_bh(&sess->lock);
+ card = fw_card_get(sess->card);
+ node_id = sess->node_id;
+ generation = sess->generation;
+ spin_unlock_bh(&sess->lock);
+
+ if (req->pg_tbl) {
+ pte = req->pg_tbl;
+ num_pte = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+ offset = 0;
+ length = 0;
+ } else {
+ pte = NULL;
+ num_pte = 0;
+
+ offset = sbp2_pointer_to_addr(&req->orb.data_descriptor);
+ length = req->se_cmd.data_length;
+ }
+
+ sg_miter_start(&iter, req->se_cmd.t_data_sg, req->se_cmd.t_data_nents,
+ sg_miter_flags);
+
+ while (length || num_pte) {
+ if (!length) {
+ offset = (u64)be16_to_cpu(pte->segment_base_hi) << 32 |
+ be32_to_cpu(pte->segment_base_lo);
+ length = be16_to_cpu(pte->segment_length);
+
+ pte++;
+ num_pte--;
+ }
+
+ sg_miter_next(&iter);
+
+ tfr_length = min3(length, max_payload, (int)iter.length);
+
+ /* FIXME: take page_size into account */
+
+ rcode = sbp_run_transaction(card, tcode, node_id,
+ generation, speed,
+ offset, iter.addr, tfr_length);
+
+ if (rcode != RCODE_COMPLETE)
+ break;
+
+ length -= tfr_length;
+ offset += tfr_length;
+ iter.consumed = tfr_length;
+ }
+
+ sg_miter_stop(&iter);
+ fw_card_put(card);
+
+ if (rcode == RCODE_COMPLETE) {
+ WARN_ON(length != 0);
+ return 0;
+ } else {
+ return -EIO;
+ }
+}
+
+static int sbp_send_status(struct sbp_target_request *req)
+{
+ int ret, length;
+ struct sbp_login_descriptor *login = req->login;
+
+ length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+ ret = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+ login->status_fifo_addr, &req->status, length);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("sbp_send_status: write failed: 0x%x\n", ret);
+ return -EIO;
+ }
+
+ pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n",
+ req->orb_pointer);
+
+ return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+ struct se_cmd *se_cmd = &req->se_cmd;
+ u8 *sense = req->sense_buf;
+ u8 *status = req->status.data;
+
+ WARN_ON(se_cmd->scsi_sense_length < 18);
+
+ switch (sense[0] & 0x7f) { /* sfmt */
+ case 0x70: /* current, fixed */
+ status[0] = 0 << 6;
+ break;
+ case 0x71: /* deferred, fixed */
+ status[0] = 1 << 6;
+ break;
+ case 0x72: /* current, descriptor */
+ case 0x73: /* deferred, descriptor */
+ default:
+ /*
+ * TODO: SBP-3 specifies what we should do with descriptor
+ * format sense data
+ */
+ pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+ sense[0]);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+ return;
+ }
+
+ status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+ status[1] =
+ (sense[0] & 0x80) | /* valid */
+ ((sense[2] & 0xe0) >> 1) | /* mark, eom, ili */
+ (sense[2] & 0x0f); /* sense_key */
+ status[2] = se_cmd->scsi_asc; /* sense_code */
+ status[3] = se_cmd->scsi_ascq; /* sense_qualifier */
+
+ /* information */
+ status[4] = sense[3];
+ status[5] = sense[4];
+ status[6] = sense[5];
+ status[7] = sense[6];
+
+ /* CDB-dependent */
+ status[8] = sense[8];
+ status[9] = sense[9];
+ status[10] = sense[10];
+ status[11] = sense[11];
+
+ /* fru */
+ status[12] = sense[14];
+
+ /* sense_key-dependent */
+ status[13] = sense[15];
+ status[14] = sense[16];
+ status[15] = sense[17];
+
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(5) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static int sbp_send_sense(struct sbp_target_request *req)
+{
+ struct se_cmd *se_cmd = &req->se_cmd;
+
+ if (se_cmd->scsi_sense_length) {
+ sbp_sense_mangle(req);
+ } else {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+ }
+
+ return sbp_send_status(req);
+}
+
+static void sbp_free_request(struct sbp_target_request *req)
+{
+ kfree(req->pg_tbl);
+ kfree(req->cmd_buf);
+ kfree(req);
+}
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+ struct sbp_management_agent *agent =
+ container_of(work, struct sbp_management_agent, work);
+ struct sbp_management_request *req = agent->request;
+ int ret;
+ int status_data_len = 0;
+
+ /* fetch the ORB from the initiator */
+ ret = sbp_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ agent->orb_offset, &req->orb, sizeof(req->orb));
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("mgt_orb fetch failed: %x\n", ret);
+ goto out;
+ }
+
+ pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x status_fifo:0x%llx\n",
+ sbp2_pointer_to_addr(&req->orb.ptr1),
+ sbp2_pointer_to_addr(&req->orb.ptr2),
+ be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+ sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+ if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+ ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+ pr_err("mgt_orb bad request\n");
+ goto out;
+ }
+
+ switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+ case MANAGEMENT_ORB_FUNCTION_LOGIN:
+ sbp_management_request_login(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+ sbp_management_request_query_logins(agent, req,
+ &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+ sbp_management_request_reconnect(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+ pr_notice("SET PASSWORD not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+ sbp_management_request_logout(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+ pr_notice("ABORT TASK not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+ pr_notice("ABORT TASK SET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+ pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+ pr_notice("TARGET RESET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ default:
+ pr_notice("unknown management function 0x%x\n",
+ MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+ }
+
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+ STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+ STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+ req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+ /* write the status block back to the initiator */
+ ret = sbp_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ sbp2_pointer_to_addr(&req->orb.status_fifo),
+ &req->status, 8 + status_data_len);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("mgt_orb status write failed: %x\n", ret);
+ goto out;
+ }
+
+out:
+ fw_card_put(req->card);
+ kfree(req);
+
+ spin_lock_bh(&agent->lock);
+ agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+ spin_unlock_bh(&agent->lock);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+ struct fw_request *request, int tcode, int destination, int source,
+ int generation, unsigned long long offset, void *data, size_t length,
+ void *callback_data)
+{
+ struct sbp_management_agent *agent = callback_data;
+ struct sbp2_pointer *ptr = data;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ if (!agent->tport->enable)
+ goto out;
+
+ if ((offset != agent->handler.offset) || (length != 8))
+ goto out;
+
+ if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+ struct sbp_management_request *req;
+ int prev_state;
+
+ spin_lock_bh(&agent->lock);
+ prev_state = agent->state;
+ agent->state = MANAGEMENT_AGENT_STATE_BUSY;
+ spin_unlock_bh(&agent->lock);
+
+ if (prev_state == MANAGEMENT_AGENT_STATE_BUSY) {
+ pr_notice("ignoring management request while busy\n");
+ rcode = RCODE_CONFLICT_ERROR;
+ goto out;
+ }
+
+ req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ if (!req) {
+ rcode = RCODE_CONFLICT_ERROR;
+ goto out;
+ }
+
+ req->card = fw_card_get(card);
+ req->generation = generation;
+ req->node_addr = source;
+ req->speed = fw_get_request_speed(request);
+
+ agent->orb_offset = sbp2_pointer_to_addr(ptr);
+ agent->request = req;
+
+ queue_work(system_unbound_wq, &agent->work);
+ rcode = RCODE_COMPLETE;
+ } else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+ addr_to_sbp2_pointer(agent->orb_offset, ptr);
+ rcode = RCODE_COMPLETE;
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+out:
+ fw_send_response(card, request, rcode);
+}
+
+static struct sbp_management_agent *sbp_management_agent_register(
+ struct sbp_tport *tport)
+{
+ int ret;
+ struct sbp_management_agent *agent;
+
+ agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ if (!agent)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&agent->lock);
+ agent->tport = tport;
+ agent->handler.length = 0x08;
+ agent->handler.address_callback = sbp_mgt_agent_rw;
+ agent->handler.callback_data = agent;
+ agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+ INIT_WORK(&agent->work, sbp_mgt_agent_process);
+ agent->orb_offset = 0;
+ agent->request = NULL;
+
+ ret = fw_core_add_address_handler(&agent->handler,
+ &sbp_register_region);
+ if (ret < 0) {
+ kfree(agent);
+ return ERR_PTR(ret);
+ }
+
+ return agent;
+}
+
+static void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+ fw_core_remove_address_handler(&agent->handler);
+ cancel_work_sync(&agent->work);
+ kfree(agent);
+}
+
+static int sbp_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int sbp_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *sbp_get_fabric_name(void)
+{
+ return "sbp";
+}
+
+static char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct sbp_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+ if (!nacl) {
+ pr_err("Unable to alocate struct sbp_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void sbp_release_fabric_acl(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct sbp_nacl *nacl =
+ container_of(se_nacl, struct sbp_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ sbp_free_request(req);
+}
+
+static int sbp_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void sbp_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static int sbp_write_pending(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+ int ret;
+
+ ret = sbp_rw_data(req);
+ if (ret) {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ return ret;
+ }
+
+ transport_generic_process_write(se_cmd);
+
+ return 0;
+}
+
+static int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ /* only used for printk until we do TMRs */
+ return (u32)req->orb_pointer;
+}
+
+static int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+ int ret;
+
+ ret = sbp_rw_data(req);
+ if (ret) {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ return ret;
+ }
+
+ return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int sbp_queue_status(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ return sbp_send_sense(req);
+}
+
+static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+ return 0;
+}
+
+static u16 sbp_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ transport_generic_free_cmd(&req->se_cmd, 0);
+ return 1;
+}
+
+/*
+ * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3)
+ */
+static u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+ * This is defined in section 7.5.1 Table 362 in spc4r17
+ */
+ return SCSI_PROTOCOL_SBP;
+}
+
+static u32 sbp_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ int ret;
+
+ /*
+ * Set PROTOCOL IDENTIFIER to 3h for SBP
+ */
+ buf[0] = SCSI_PROTOCOL_SBP;
+ /*
+ * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+ * over IEEE 1394
+ */
+ ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+ if (ret < 0)
+ pr_debug("sbp transport_id: invalid hex string\n");
+
+ /*
+ * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+
+static u32 sbp_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+ * over IEEE 1394
+ *
+ * The SBP Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+static char *sbp_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+ * for initiator ports using SCSI over SBP Serial SCSI Protocol
+ *
+ * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+ * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[8];
+}
+
+static int sbp_count_se_tpg_luns(struct se_portal_group *tpg)
+{
+ int i, count = 0;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ struct se_lun *se_lun = tpg->tpg_lun_list[i];
+
+ if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+ continue;
+
+ count++;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return count;
+}
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+ int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i;
+ u32 *data;
+
+ if (tport->unit_directory.data) {
+ fw_core_remove_descriptor(&tport->unit_directory);
+ kfree(tport->unit_directory.data);
+ tport->unit_directory.data = NULL;
+ }
+
+ if (!tport->enable || !tport->tpg)
+ return 0;
+
+ num_luns = sbp_count_se_tpg_luns(&tport->tpg->se_tpg);
+
+ /*
+ * Number of entries in the final unit directory:
+ * - all of those in the template
+ * - management_agent
+ * - unit_characteristics
+ * - reconnect_timeout
+ * - unit unique ID
+ * - one for each LUN
+ *
+ * MUST NOT include leaf or sub-directory entries
+ */
+ num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+ if (tport->directory_id != -1)
+ num_entries++;
+
+ /* allocate num_entries + 4 for the header and unique ID leaf */
+ data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* directory_length */
+ data[idx++] = num_entries << 16;
+
+ /* directory_id */
+ if (tport->directory_id != -1)
+ data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+ /* unit directory template */
+ memcpy(&data[idx], sbp_unit_directory_template,
+ sizeof(sbp_unit_directory_template));
+ idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+ /* management_agent */
+ mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+ data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+ /* unit_characteristics */
+ data[idx++] = 0x3a000000 |
+ (((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+ SBP_ORB_FETCH_SIZE;
+
+ /* reconnect_timeout */
+ data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+ /* unit unique ID (leaf is just after LUNs) */
+ data[idx++] = 0x8d000000 | (num_luns + 1);
+
+ spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i];
+ struct se_device *dev;
+ int type;
+
+ if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+ continue;
+
+ spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+ dev = se_lun->lun_se_dev;
+ type = dev->transport->get_device_type(dev);
+
+ /* logical_unit_number */
+ data[idx++] = 0x14000000 |
+ ((type << 16) & 0x1f0000) |
+ (se_lun->unpacked_lun & 0xffff);
+
+ spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+ }
+ spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+ /* unit unique ID leaf */
+ data[idx++] = 2 << 16;
+ data[idx++] = tport->guid >> 32;
+ data[idx++] = tport->guid;
+
+ tport->unit_directory.length = idx;
+ tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+ tport->unit_directory.data = data;
+
+ ret = fw_core_add_descriptor(&tport->unit_directory);
+ if (ret < 0) {
+ kfree(tport->unit_directory.data);
+ tport->unit_directory.data = NULL;
+ }
+
+ return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+ const char *cp;
+ char c, nibble;
+ int pos = 0, err;
+
+ *wwn = 0;
+ for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+ c = *cp;
+ if (c == '\n' && cp[1] == '\0')
+ continue;
+ if (c == '\0') {
+ err = 2;
+ if (pos != 16)
+ goto fail;
+ return cp - name;
+ }
+ err = 3;
+ if (isdigit(c))
+ nibble = c - '0';
+ else if (isxdigit(c) && (islower(c) || !strict))
+ nibble = tolower(c) - 'a' + 10;
+ else
+ goto fail;
+ *wwn = (*wwn << 4) | nibble;
+ pos++;
+ }
+ err = 4;
+fail:
+ printk(KERN_INFO "err %u len %zu pos %u\n",
+ err, cp - name, pos);
+ return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+ return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+ struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl, *se_nacl_new;
+ struct sbp_nacl *nacl;
+ u64 guid = 0;
+ u32 nexus_depth = 1;
+
+ if (sbp_parse_wwn(name, &guid, 1) < 0)
+ return ERR_PTR(-EINVAL);
+
+ se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+ if (!se_nacl_new)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+ * when converting a NodeACL from demo mode -> explict
+ */
+ se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+ name, nexus_depth);
+ if (IS_ERR(se_nacl)) {
+ sbp_release_fabric_acl(se_tpg, se_nacl_new);
+ return se_nacl;
+ }
+
+ nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+ nacl->guid = guid;
+ sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+ return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+ struct sbp_nacl *nacl =
+ container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+ core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+ kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+ struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+
+ return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+ struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ int ret;
+
+ if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0)
+ tport->enable = 0;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct sbp_tport *tport =
+ container_of(wwn, struct sbp_tport, tport_wwn);
+
+ struct sbp_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ if (tport->tpg) {
+ pr_err("Only one TPG per Unit is possible.\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ if (!tpg) {
+ pr_err("Unable to allocate struct sbp_tpg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+ tport->tpg = tpg;
+
+ /* default attribute values */
+ tport->enable = 0;
+ tport->directory_id = -1;
+ tport->mgt_orb_timeout = 15;
+ tport->max_reconnect_timeout = 5;
+ tport->max_logins_per_lun = 1;
+
+ tport->mgt_agt = sbp_management_agent_register(tport);
+ if (IS_ERR(tport->mgt_agt)) {
+ ret = PTR_ERR(tport->mgt_agt);
+ kfree(tpg);
+ return ERR_PTR(ret);
+ }
+
+ ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+ &tpg->se_tpg, (void *)tpg,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ sbp_management_agent_unregister(tport->mgt_agt);
+ kfree(tpg);
+ return ERR_PTR(ret);
+ }
+
+ return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ core_tpg_deregister(se_tpg);
+ sbp_management_agent_unregister(tport->mgt_agt);
+ tport->tpg = NULL;
+ kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct sbp_tport *tport;
+ u64 guid = 0;
+
+ if (sbp_parse_wwn(name, &guid, 1) < 0)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+ if (!tport) {
+ pr_err("Unable to allocate struct sbp_tport\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tport->guid = guid;
+ sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+ return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+ struct sbp_tport *tport =
+ container_of(wwn, struct sbp_tport, tport_wwn);
+
+ kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+ struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+ &sbp_wwn_version.attr,
+ NULL,
+};
+
+static ssize_t sbp_tpg_show_directory_id(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ if (tport->directory_id == -1)
+ return sprintf(page, "implicit\n");
+ else
+ return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+
+ if (tport->enable) {
+ pr_err("Cannot change the directory_id on an active target.\n");
+ return -EBUSY;
+ }
+
+ if (strstr(page, "implicit") == page) {
+ tport->directory_id = -1;
+ } else {
+ if (kstrtoul(page, 16, &val) < 0)
+ return -EINVAL;
+ if (val > 0xffffff)
+ return -EINVAL;
+
+ tport->directory_id = val;
+ }
+
+ return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ if (tport->enable == val)
+ return count;
+
+ if (val) {
+ if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) {
+ pr_err("Cannot enable a target with no LUNs!\n");
+ return -EINVAL;
+ }
+ } else {
+ /* XXX: force-shutdown sessions instead? */
+ spin_lock_bh(&se_tpg->session_lock);
+ if (!list_empty(&se_tpg->tpg_sess_list)) {
+ spin_unlock_bh(&se_tpg->session_lock);
+ return -EBUSY;
+ }
+ spin_unlock_bh(&se_tpg->session_lock);
+ }
+
+ tport->enable = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0) {
+ pr_err("Could not update Config ROM\n");
+ return ret;
+ }
+
+ return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+ &sbp_tpg_directory_id.attr,
+ &sbp_tpg_enable.attr,
+ NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 127))
+ return -EINVAL;
+
+ if (tport->mgt_orb_timeout == val)
+ return count;
+
+ tport->mgt_orb_timeout = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 32767))
+ return -EINVAL;
+
+ if (tport->max_reconnect_timeout == val)
+ return count;
+
+ tport->max_reconnect_timeout = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 127))
+ return -EINVAL;
+
+ /* XXX: also check against current count? */
+
+ tport->max_logins_per_lun = val;
+
+ return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+ &sbp_tpg_attrib_mgt_orb_timeout.attr,
+ &sbp_tpg_attrib_max_reconnect_timeout.attr,
+ &sbp_tpg_attrib_max_logins_per_lun.attr,
+ NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+ .get_fabric_name = sbp_get_fabric_name,
+ .get_fabric_proto_ident = sbp_get_fabric_proto_ident,
+ .tpg_get_wwn = sbp_get_fabric_wwn,
+ .tpg_get_tag = sbp_get_tag,
+ .tpg_get_default_depth = sbp_get_default_depth,
+ .tpg_get_pr_transport_id = sbp_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = sbp_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = sbp_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = sbp_check_true,
+ .tpg_check_demo_mode_cache = sbp_check_true,
+ .tpg_check_demo_mode_write_protect = sbp_check_false,
+ .tpg_check_prod_mode_write_protect = sbp_check_false,
+ .tpg_alloc_fabric_acl = sbp_alloc_fabric_acl,
+ .tpg_release_fabric_acl = sbp_release_fabric_acl,
+ .tpg_get_inst_index = sbp_tpg_get_inst_index,
+ .release_cmd = sbp_release_cmd,
+ .shutdown_session = sbp_shutdown_session,
+ .close_session = sbp_close_session,
+ .sess_get_index = sbp_sess_get_index,
+ .write_pending = sbp_write_pending,
+ .write_pending_status = sbp_write_pending_status,
+ .set_default_node_attributes = sbp_set_default_node_attrs,
+ .get_task_tag = sbp_get_task_tag,
+ .get_cmd_state = sbp_get_cmd_state,
+ .queue_data_in = sbp_queue_data_in,
+ .queue_status = sbp_queue_status,
+ .queue_tm_rsp = sbp_queue_tm_rsp,
+ .get_fabric_sense_len = sbp_get_fabric_sense_len,
+ .set_fabric_sense_len = sbp_set_fabric_sense_len,
+ .check_stop_free = sbp_check_stop_free,
+
+ .fabric_make_wwn = sbp_make_tport,
+ .fabric_drop_wwn = sbp_drop_tport,
+ .fabric_make_tpg = sbp_make_tpg,
+ .fabric_drop_tpg = sbp_drop_tpg,
+ .fabric_post_link = sbp_post_link_lun,
+ .fabric_pre_unlink = sbp_pre_unlink_lun,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = sbp_make_nodeacl,
+ .fabric_drop_nodeacl = sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+ if (!fabric) {
+ pr_err("target_fabric_configfs_init() failed\n");
+ return -ENOMEM;
+ }
+
+ fabric->tf_ops = sbp_ops;
+
+ /*
+ * Setup default attribute lists for various fabric->tf_cit_tmpl
+ */
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ pr_err("target_fabric_configfs_register() failed for SBP\n");
+ return ret;
+ }
+
+ sbp_fabric_configfs = fabric;
+
+ return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+ if (!sbp_fabric_configfs)
+ return;
+
+ target_fabric_configfs_deregister(sbp_fabric_configfs);
+ sbp_fabric_configfs = NULL;
+};
+
+static int __init sbp_init(void)
+{
+ int ret;
+
+ ret = sbp_register_configfs();
+ if (ret < 0)
+ return ret;
+
+ return 0;
+};
+
+static void sbp_exit(void)
+{
+ sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h
new file mode 100644
index 0000000..6d0d74a
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.h
@@ -0,0 +1,251 @@
+#ifndef _SBP_BASE_H
+#define _SBP_BASE_H
+
+#include <linux/firewire.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <target/target_core_base.h>
+
+#define SBP_VERSION "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE 8
+
+#define MANAGEMENT_AGENT_STATE_IDLE 0
+#define MANAGEMENT_AGENT_STATE_BUSY 1
+
+#define ORB_NOTIFY(v) (((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v) (((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v) (((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN 0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS 0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT 0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD 0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT 0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK 0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET 0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET 0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET 0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v) (((v) >> 28) & 0x01)
+#define LOGIN_ORB_RESERVED(v) (((v) >> 24) & 0x0f)
+#define LOGIN_ORB_RECONNECT(v) (((v) >> 20) & 0x0f)
+#define LOGIN_ORB_LUN(v) (((v) >> 0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v) (((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v) (((v) >> 0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v) (((v) >> 0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v) (((v) >> 0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v) (((v) >> 27) & 0x01)
+#define CMDBLK_ORB_SPEED(v) (((v) >> 24) & 0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v) (((v) >> 20) & 0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v) (((v) >> 19) & 0x01)
+#define CMDBLK_ORB_PG_SIZE(v) (((v) >> 16) & 0x07)
+#define CMDBLK_ORB_DATA_SIZE(v) (((v) >> 0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v) (((v) & 0x03) << 30)
+#define STATUS_BLOCK_RESP(v) (((v) & 0x03) << 28)
+#define STATUS_BLOCK_DEAD(v) (((v) ? 1 : 0) << 27)
+#define STATUS_BLOCK_LEN(v) (((v) & 0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v) (((v) & 0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v) (((v) & 0xffff) << 0)
+
+#define STATUS_SRC_ORB_CONTINUING 0
+#define STATUS_SRC_ORB_FINISHED 1
+#define STATUS_SRC_UNSOLICITED 2
+
+#define STATUS_RESP_REQUEST_COMPLETE 0
+#define STATUS_RESP_TRANSPORT_FAILURE 1
+#define STATUS_RESP_ILLEGAL_REQUEST 2
+#define STATUS_RESP_VENDOR_DEPENDENT 3
+
+#define SBP_STATUS_OK 0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP 1
+#define SBP_STATUS_SPEED_NOTSUPP 2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP 3
+#define SBP_STATUS_ACCESS_DENIED 4
+#define SBP_STATUS_LUN_NOTSUPP 5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL 6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL 8
+#define SBP_STATUS_FUNCTION_REJECTED 9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN 10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE 11
+#define SBP_STATUS_REQUEST_ABORTED 12
+#define SBP_STATUS_UNSPECIFIED_ERROR 0xff
+
+#define AGENT_STATE_RESET 0
+#define AGENT_STATE_ACTIVE 1
+#define AGENT_STATE_SUSPENDED 2
+#define AGENT_STATE_DEAD 3
+
+struct sbp2_pointer {
+ __be32 high;
+ __be32 low;
+};
+
+struct sbp_command_block_orb {
+ struct sbp2_pointer next_orb;
+ struct sbp2_pointer data_descriptor;
+ __be32 misc;
+ u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+ __be16 segment_length;
+ __be16 segment_base_hi;
+ __be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+ struct sbp2_pointer ptr1;
+ struct sbp2_pointer ptr2;
+ __be32 misc;
+ __be32 length;
+ struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+ __be32 status;
+ __be32 orb_low;
+ u8 data[24];
+};
+
+struct sbp_login_response_block {
+ __be32 misc;
+ struct sbp2_pointer command_block_agent;
+ __be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+ struct sbp_session *sess;
+ struct list_head link;
+
+ struct se_lun *lun;
+
+ u64 status_fifo_addr;
+ int exclusive;
+ u16 login_id;
+
+ struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+ spinlock_t lock;
+ struct se_session *se_sess;
+ struct list_head login_list;
+ struct delayed_work maint_work;
+
+ u64 guid; /* login_owner_EUI_64 */
+ int node_id; /* login_owner_ID */
+
+ struct fw_card *card;
+ int generation;
+ int speed;
+
+ int reconnect_hold;
+ u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+ /* Initiator EUI-64 */
+ u64 guid;
+ /* ASCII formatted GUID for SBP Initiator port */
+ char iport_name[SBP_NAMELEN];
+ /* Returned by sbp_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+struct sbp_tpg {
+ /* Target portal group tag for TCM */
+ u16 tport_tpgt;
+ /* Pointer back to sbp_tport */
+ struct sbp_tport *tport;
+ /* Returned by sbp_make_tpg() */
+ struct se_portal_group se_tpg;
+};
+
+struct sbp_tport {
+ /* Target Unit Identifier (EUI-64) */
+ u64 guid;
+ /* Target port name */
+ char tport_name[SBP_NAMELEN];
+ /* Returned by sbp_make_tport() */
+ struct se_wwn tport_wwn;
+
+ struct sbp_tpg *tpg;
+
+ /* FireWire unit directory */
+ struct fw_descriptor unit_directory;
+
+ /* SBP Management Agent */
+ struct sbp_management_agent *mgt_agt;
+
+ /* Parameters */
+ int enable;
+ s32 directory_id;
+ int mgt_orb_timeout;
+ int max_reconnect_timeout;
+ int max_logins_per_lun;
+};
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+ return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+ (be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+ ptr->high = cpu_to_be32(addr >> 32);
+ ptr->low = cpu_to_be32(addr);
+}
+
+struct sbp_target_agent {
+ spinlock_t lock;
+ struct fw_address_handler handler;
+ struct sbp_login_descriptor *login;
+ int state;
+ struct work_struct work;
+ u64 orb_pointer;
+ bool doorbell;
+};
+
+struct sbp_target_request {
+ struct sbp_login_descriptor *login;
+ u64 orb_pointer;
+ struct sbp_command_block_orb orb;
+ struct sbp_status_block status;
+ struct work_struct work;
+
+ struct se_cmd se_cmd;
+ struct sbp_page_table_entry *pg_tbl;
+ void *cmd_buf;
+
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_management_agent {
+ spinlock_t lock;
+ struct sbp_tport *tport;
+ struct fw_address_handler handler;
+ int state;
+ struct work_struct work;
+ u64 orb_offset;
+ struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+ struct sbp_management_orb orb;
+ struct sbp_status_block status;
+ struct fw_card *card;
+ int generation;
+ int node_addr;
+ int speed;
+};
+
+#endif
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index c7746a3..e624b83 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -59,26 +59,31 @@ struct t10_alua_lu_gp *default_lu_gp;
*
* See spc4r17 section 6.27
*/
-int target_emulate_report_target_port_groups(struct se_task *task)
+int target_emulate_report_target_port_groups(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
struct se_port *port;
struct t10_alua_tg_pt_gp *tg_pt_gp;
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
unsigned char *buf;
- u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
- Target port group descriptor */
+ u32 rd_len = 0, off;
+ int ext_hdr = (cmd->t_task_cdb[1] & 0x20);
/*
- * Need at least 4 bytes of response data or else we can't
- * even fit the return data length.
+ * Skip over RESERVED area to first Target port group descriptor
+ * depending on the PARAMETER DATA FORMAT type..
*/
- if (cmd->data_length < 4) {
- pr_warn("REPORT TARGET PORT GROUPS allocation length %u"
- " too small\n", cmd->data_length);
+ if (ext_hdr != 0)
+ off = 8;
+ else
+ off = 4;
+
+ if (cmd->data_length < off) {
+ pr_warn("REPORT TARGET PORT GROUPS allocation length %u too"
+ " small for %s header\n", cmd->data_length,
+ (ext_hdr) ? "extended" : "normal");
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
return -EINVAL;
}
-
buf = transport_kmap_data_sg(cmd);
spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
@@ -159,15 +164,34 @@ int target_emulate_report_target_port_groups(struct se_task *task)
/*
* Set the RETURN DATA LENGTH set in the header of the DataIN Payload
*/
- buf[0] = ((rd_len >> 24) & 0xff);
- buf[1] = ((rd_len >> 16) & 0xff);
- buf[2] = ((rd_len >> 8) & 0xff);
- buf[3] = (rd_len & 0xff);
+ put_unaligned_be32(rd_len, &buf[0]);
+ /*
+ * Fill in the Extended header parameter data format if requested
+ */
+ if (ext_hdr != 0) {
+ buf[4] = 0x10;
+ /*
+ * Set the implict transition time (in seconds) for the application
+ * client to use as a base for it's transition timeout value.
+ *
+ * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN
+ * this CDB was received upon to determine this value individually
+ * for ALUA target port group.
+ */
+ port = cmd->se_lun->lun_sep;
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (tg_pt_gp_mem) {
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (tg_pt_gp)
+ buf[5] = tg_pt_gp->tg_pt_gp_implict_trans_secs;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ }
+ }
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
@@ -176,9 +200,8 @@ int target_emulate_report_target_port_groups(struct se_task *task)
*
* See spc4r17 section 6.35
*/
-int target_emulate_set_target_port_groups(struct se_task *task)
+int target_emulate_set_target_port_groups(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct se_subsystem_dev *su_dev = dev->se_sub_dev;
struct se_port *port, *l_port = cmd->se_lun->lun_sep;
@@ -351,8 +374,7 @@ int target_emulate_set_target_port_groups(struct se_task *task)
out:
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
@@ -391,7 +413,7 @@ static inline int core_alua_state_standby(
case RECEIVE_DIAGNOSTIC:
case SEND_DIAGNOSTIC:
case MAINTENANCE_IN:
- switch (cdb[1]) {
+ switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
return 0;
default:
@@ -433,7 +455,7 @@ static inline int core_alua_state_unavailable(
case INQUIRY:
case REPORT_LUNS:
case MAINTENANCE_IN:
- switch (cdb[1]) {
+ switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
return 0;
default:
@@ -473,7 +495,7 @@ static inline int core_alua_state_transition(
case INQUIRY:
case REPORT_LUNS:
case MAINTENANCE_IN:
- switch (cdb[1]) {
+ switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
return 0;
default:
@@ -1359,6 +1381,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
*/
tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS;
tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS;
+ tg_pt_gp->tg_pt_gp_implict_trans_secs = ALUA_DEFAULT_IMPLICT_TRANS_SECS;
if (def_group) {
spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
@@ -1855,6 +1878,37 @@ ssize_t core_alua_store_trans_delay_msecs(
return count;
}
+ssize_t core_alua_show_implict_trans_secs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_implict_trans_secs);
+}
+
+ssize_t core_alua_store_implict_trans_secs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ pr_err("Unable to extract implict_trans_secs\n");
+ return -EINVAL;
+ }
+ if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) {
+ pr_err("Passed implict_trans_secs: %lu, exceeds"
+ " ALUA_MAX_IMPLICT_TRANS_SECS: %d\n", tmp,
+ ALUA_MAX_IMPLICT_TRANS_SECS);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_implict_trans_secs = (int)tmp;
+
+ return count;
+}
+
ssize_t core_alua_show_preferred_bit(
struct t10_alua_tg_pt_gp *tg_pt_gp,
char *page)
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index c5b4ecd..f920c17 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -52,6 +52,12 @@
#define ALUA_DEFAULT_TRANS_DELAY_MSECS 0
#define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */
/*
+ * Used for the recommended application client implict transition timeout
+ * in seconds, returned by the REPORT_TARGET_PORT_GROUPS w/ extended header.
+ */
+#define ALUA_DEFAULT_IMPLICT_TRANS_SECS 0
+#define ALUA_MAX_IMPLICT_TRANS_SECS 255
+/*
* Used by core_alua_update_tpg_primary_metadata() and
* core_alua_update_tpg_secondary_metadata()
*/
@@ -66,8 +72,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
-extern int target_emulate_report_target_port_groups(struct se_task *);
-extern int target_emulate_set_target_port_groups(struct se_task *);
+extern int target_emulate_report_target_port_groups(struct se_cmd *);
+extern int target_emulate_set_target_port_groups(struct se_cmd *);
extern int core_alua_check_nonop_delay(struct se_cmd *);
extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
struct se_device *, struct se_port *,
@@ -107,6 +113,10 @@ extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
char *);
extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
const char *, size_t);
+extern ssize_t core_alua_show_implict_trans_secs(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_implict_trans_secs(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *,
char *);
extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *,
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 30a6770..9888693 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -432,6 +432,7 @@ static int
target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
{
struct se_device *dev = cmd->se_dev;
+ u32 max_sectors;
int have_tp = 0;
/*
@@ -456,7 +457,9 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
/*
* Set MAXIMUM TRANSFER LENGTH
*/
- put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, &buf[8]);
+ max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors,
+ dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
+ put_unaligned_be32(max_sectors, &buf[8]);
/*
* Set OPTIMAL TRANSFER LENGTH
@@ -598,9 +601,8 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
-int target_emulate_inquiry(struct se_task *task)
+int target_emulate_inquiry(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
unsigned char *buf, *map_buf;
@@ -664,16 +666,13 @@ out:
}
transport_kunmap_data_sg(cmd);
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
-int target_emulate_readcapacity(struct se_task *task)
+int target_emulate_readcapacity(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
@@ -697,14 +696,12 @@ int target_emulate_readcapacity(struct se_task *task)
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
-int target_emulate_readcapacity_16(struct se_task *task)
+int target_emulate_readcapacity_16(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks = dev->transport->get_blocks(dev);
@@ -732,8 +729,7 @@ int target_emulate_readcapacity_16(struct se_task *task)
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
@@ -872,9 +868,8 @@ target_modesense_dpofua(unsigned char *buf, int type)
}
}
-int target_emulate_modesense(struct se_task *task)
+int target_emulate_modesense(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
char *cdb = cmd->t_task_cdb;
unsigned char *rbuf;
@@ -947,14 +942,12 @@ int target_emulate_modesense(struct se_task *task)
memcpy(rbuf, buf, offset);
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
-int target_emulate_request_sense(struct se_task *task)
+int target_emulate_request_sense(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
unsigned char *cdb = cmd->t_task_cdb;
unsigned char *buf;
u8 ua_asc = 0, ua_ascq = 0;
@@ -1008,8 +1001,7 @@ int target_emulate_request_sense(struct se_task *task)
end:
transport_kunmap_data_sg(cmd);
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
@@ -1017,9 +1009,8 @@ end:
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-int target_emulate_unmap(struct se_task *task)
+int target_emulate_unmap(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf, *ptr = NULL;
unsigned char *cdb = &cmd->t_task_cdb[0];
@@ -1066,10 +1057,8 @@ int target_emulate_unmap(struct se_task *task)
err:
transport_kunmap_data_sg(cmd);
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
@@ -1077,9 +1066,8 @@ err:
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-int target_emulate_write_same(struct se_task *task)
+int target_emulate_write_same(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
@@ -1118,79 +1106,25 @@ int target_emulate_write_same(struct se_task *task)
return ret;
}
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
-int target_emulate_synchronize_cache(struct se_task *task)
+int target_emulate_synchronize_cache(struct se_cmd *cmd)
{
- struct se_device *dev = task->task_se_cmd->se_dev;
- struct se_cmd *cmd = task->task_se_cmd;
-
- if (!dev->transport->do_sync_cache) {
+ if (!cmd->se_dev->transport->do_sync_cache) {
pr_err("SYNCHRONIZE_CACHE emulation not supported"
- " for: %s\n", dev->transport->name);
+ " for: %s\n", cmd->se_dev->transport->name);
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
return -ENOSYS;
}
- dev->transport->do_sync_cache(task);
+ cmd->se_dev->transport->do_sync_cache(cmd);
return 0;
}
-int target_emulate_noop(struct se_task *task)
+int target_emulate_noop(struct se_cmd *cmd)
{
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, GOOD);
return 0;
}
-
-/*
- * Write a CDB into @cdb that is based on the one the intiator sent us,
- * but updated to only cover the sectors that the current task handles.
- */
-void target_get_task_cdb(struct se_task *task, unsigned char *cdb)
-{
- struct se_cmd *cmd = task->task_se_cmd;
- unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb);
-
- memcpy(cdb, cmd->t_task_cdb, cdb_len);
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
- unsigned long long lba = task->task_lba;
- u32 sectors = task->task_sectors;
-
- switch (cdb_len) {
- case 6:
- /* 21-bit LBA and 8-bit sectors */
- cdb[1] = (lba >> 16) & 0x1f;
- cdb[2] = (lba >> 8) & 0xff;
- cdb[3] = lba & 0xff;
- cdb[4] = sectors & 0xff;
- break;
- case 10:
- /* 32-bit LBA and 16-bit sectors */
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be16(sectors, &cdb[7]);
- break;
- case 12:
- /* 32-bit LBA and 32-bit sectors */
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[6]);
- break;
- case 16:
- /* 64-bit LBA and 32-bit sectors */
- put_unaligned_be64(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[10]);
- break;
- case 32:
- /* 64-bit LBA and 32-bit sectors, extended CDB */
- put_unaligned_be64(lba, &cdb[12]);
- put_unaligned_be32(sectors, &cdb[28]);
- break;
- default:
- BUG();
- }
- }
-}
-EXPORT_SYMBOL(target_get_task_cdb);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index cbb6653..801efa8 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -683,9 +683,6 @@ SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB_RO(hw_max_sectors);
SE_DEV_ATTR_RO(hw_max_sectors);
-DEF_DEV_ATTRIB(max_sectors);
-SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR);
-
DEF_DEV_ATTRIB(fabric_max_sectors);
SE_DEV_ATTR(fabric_max_sectors, S_IRUGO | S_IWUSR);
@@ -727,7 +724,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_hw_block_size.attr,
&target_core_dev_attrib_block_size.attr,
&target_core_dev_attrib_hw_max_sectors.attr,
- &target_core_dev_attrib_max_sectors.attr,
&target_core_dev_attrib_fabric_max_sectors.attr,
&target_core_dev_attrib_optimal_sectors.attr,
&target_core_dev_attrib_hw_queue_depth.attr,
@@ -2451,6 +2447,26 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(
SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);
/*
+ * implict_trans_secs
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_implict_trans_secs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_implict_trans_secs(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_implict_trans_secs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_implict_trans_secs(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(implict_trans_secs, S_IRUGO | S_IWUSR);
+
+/*
* preferred
*/
@@ -2574,6 +2590,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
&target_core_alua_tg_pt_gp_alua_write_metadata.attr,
&target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,
&target_core_alua_tg_pt_gp_trans_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_implict_trans_secs.attr,
&target_core_alua_tg_pt_gp_preferred.attr,
&target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,
&target_core_alua_tg_pt_gp_members.attr,
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index aa62677..5ad9728 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -643,9 +643,8 @@ void core_dev_unexport(
lun->lun_se_dev = NULL;
}
-int target_report_luns(struct se_task *se_task)
+int target_report_luns(struct se_cmd *se_cmd)
{
- struct se_cmd *se_cmd = se_task->task_se_cmd;
struct se_dev_entry *deve;
struct se_session *se_sess = se_cmd->se_sess;
unsigned char *buf;
@@ -696,8 +695,7 @@ done:
buf[3] = (lun_count & 0xff);
transport_kunmap_data_sg(se_cmd);
- se_task->task_scsi_status = GOOD;
- transport_complete_task(se_task, 1);
+ target_complete_cmd(se_cmd, GOOD);
return 0;
}
@@ -878,15 +876,12 @@ void se_dev_set_default_attribs(
dev->se_sub_dev->se_dev_attrib.hw_block_size = limits->logical_block_size;
dev->se_sub_dev->se_dev_attrib.block_size = limits->logical_block_size;
/*
- * max_sectors is based on subsystem plugin dependent requirements.
+ * Align max_hw_sectors down to PAGE_SIZE I/O transfers
*/
- dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors;
- /*
- * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
- */
- limits->max_sectors = se_dev_align_max_sectors(limits->max_sectors,
+ limits->max_hw_sectors = se_dev_align_max_sectors(limits->max_hw_sectors,
limits->logical_block_size);
- dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors;
+ dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors;
+
/*
* Set fabric_max_sectors, which is reported in block limits
* VPD page (B0h).
@@ -1170,64 +1165,6 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
return 0;
}
-int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
-{
- int force = 0; /* Force setting for VDEVS */
-
- if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
- pr_err("dev[%p]: Unable to change SE Device"
- " max_sectors while dev_export_obj: %d count exists\n",
- dev, atomic_read(&dev->dev_export_obj.obj_access_count));
- return -EINVAL;
- }
- if (!max_sectors) {
- pr_err("dev[%p]: Illegal ZERO value for"
- " max_sectors\n", dev);
- return -EINVAL;
- }
- if (max_sectors < DA_STATUS_MAX_SECTORS_MIN) {
- pr_err("dev[%p]: Passed max_sectors: %u less than"
- " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, max_sectors,
- DA_STATUS_MAX_SECTORS_MIN);
- return -EINVAL;
- }
- if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
- if (max_sectors > dev->se_sub_dev->se_dev_attrib.hw_max_sectors) {
- pr_err("dev[%p]: Passed max_sectors: %u"
- " greater than TCM/SE_Device max_sectors:"
- " %u\n", dev, max_sectors,
- dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
- return -EINVAL;
- }
- } else {
- if (!force && (max_sectors >
- dev->se_sub_dev->se_dev_attrib.hw_max_sectors)) {
- pr_err("dev[%p]: Passed max_sectors: %u"
- " greater than TCM/SE_Device max_sectors"
- ": %u, use force=1 to override.\n", dev,
- max_sectors, dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
- return -EINVAL;
- }
- if (max_sectors > DA_STATUS_MAX_SECTORS_MAX) {
- pr_err("dev[%p]: Passed max_sectors: %u"
- " greater than DA_STATUS_MAX_SECTORS_MAX:"
- " %u\n", dev, max_sectors,
- DA_STATUS_MAX_SECTORS_MAX);
- return -EINVAL;
- }
- }
- /*
- * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
- */
- max_sectors = se_dev_align_max_sectors(max_sectors,
- dev->se_sub_dev->se_dev_attrib.block_size);
-
- dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors;
- pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
- dev, max_sectors);
- return 0;
-}
-
int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)
{
if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
@@ -1341,7 +1278,6 @@ struct se_lun *core_dev_add_lun(
u32 lun)
{
struct se_lun *lun_p;
- u32 lun_access = 0;
int rc;
if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) {
@@ -1354,12 +1290,8 @@ struct se_lun *core_dev_add_lun(
if (IS_ERR(lun_p))
return lun_p;
- if (dev->dev_flags & DF_READ_ONLY)
- lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
- else
- lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
-
- rc = core_tpg_post_addlun(tpg, lun_p, lun_access, dev);
+ rc = core_tpg_post_addlun(tpg, lun_p,
+ TRANSPORT_LUNFLAGS_READ_WRITE, dev);
if (rc < 0)
return ERR_PTR(rc);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 7ed58e2..686dba1 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -133,15 +133,10 @@ static struct se_device *fd_create_virtdevice(
ret = PTR_ERR(dev_p);
goto fail;
}
-#if 0
- if (di->no_create_file)
- flags = O_RDWR | O_LARGEFILE;
- else
- flags = O_RDWR | O_CREAT | O_LARGEFILE;
-#else
+
+ /* O_DIRECT too? */
flags = O_RDWR | O_CREAT | O_LARGEFILE;
-#endif
-/* flags |= O_DIRECT; */
+
/*
* If fd_buffered_io=1 has not been set explicitly (the default),
* use O_SYNC to force FILEIO writes to disk.
@@ -169,6 +164,7 @@ static struct se_device *fd_create_virtdevice(
inode = file->f_mapping->host;
if (S_ISBLK(inode->i_mode)) {
struct request_queue *q;
+ unsigned long long dev_size;
/*
* Setup the local scope queue_limits from struct request_queue->limits
* to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
@@ -183,13 +179,12 @@ static struct se_device *fd_create_virtdevice(
* one (1) logical sector from underlying struct block_device
*/
fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
- fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) -
+ dev_size = (i_size_read(file->f_mapping->host) -
fd_dev->fd_block_size);
pr_debug("FILEIO: Using size: %llu bytes from struct"
" block_device blocks: %llu logical_block_size: %d\n",
- fd_dev->fd_dev_size,
- div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size),
+ dev_size, div_u64(dev_size, fd_dev->fd_block_size),
fd_dev->fd_block_size);
} else {
if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
@@ -249,53 +244,33 @@ static void fd_free_device(void *p)
kfree(fd_dev);
}
-static inline struct fd_request *FILE_REQ(struct se_task *task)
+static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents)
{
- return container_of(task, struct fd_request, fd_task);
-}
-
-
-static struct se_task *
-fd_alloc_task(unsigned char *cdb)
-{
- struct fd_request *fd_req;
-
- fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL);
- if (!fd_req) {
- pr_err("Unable to allocate struct fd_request\n");
- return NULL;
- }
-
- return &fd_req->fd_task;
-}
-
-static int fd_do_readv(struct se_task *task)
-{
- struct fd_request *req = FILE_REQ(task);
- struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct se_device *se_dev = cmd->se_dev;
struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
- struct scatterlist *sg = task->task_sg;
+ struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
- loff_t pos = (task->task_lba *
+ loff_t pos = (cmd->t_task_lba *
se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret = 0, i;
- iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
+ iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
if (!iov) {
pr_err("Unable to allocate fd_do_readv iov[]\n");
return -ENOMEM;
}
- for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
+ for_each_sg(sgl, sg, sgl_nents, i) {
iov[i].iov_len = sg->length;
iov[i].iov_base = sg_virt(sg);
}
old_fs = get_fs();
set_fs(get_ds());
- ret = vfs_readv(fd, &iov[0], task->task_sg_nents, &pos);
+ ret = vfs_readv(fd, &iov[0], sgl_nents, &pos);
set_fs(old_fs);
kfree(iov);
@@ -305,10 +280,10 @@ static int fd_do_readv(struct se_task *task)
* block_device.
*/
if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) {
- if (ret < 0 || ret != task->task_size) {
+ if (ret < 0 || ret != cmd->data_length) {
pr_err("vfs_readv() returned %d,"
" expecting %d for S_ISBLK\n", ret,
- (int)task->task_size);
+ (int)cmd->data_length);
return (ret < 0 ? ret : -EINVAL);
}
} else {
@@ -322,38 +297,38 @@ static int fd_do_readv(struct se_task *task)
return 1;
}
-static int fd_do_writev(struct se_task *task)
+static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents)
{
- struct fd_request *req = FILE_REQ(task);
- struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct se_device *se_dev = cmd->se_dev;
struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
- struct scatterlist *sg = task->task_sg;
+ struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
- loff_t pos = (task->task_lba *
+ loff_t pos = (cmd->t_task_lba *
se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret, i = 0;
- iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
+ iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
if (!iov) {
pr_err("Unable to allocate fd_do_writev iov[]\n");
return -ENOMEM;
}
- for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
+ for_each_sg(sgl, sg, sgl_nents, i) {
iov[i].iov_len = sg->length;
iov[i].iov_base = sg_virt(sg);
}
old_fs = get_fs();
set_fs(get_ds());
- ret = vfs_writev(fd, &iov[0], task->task_sg_nents, &pos);
+ ret = vfs_writev(fd, &iov[0], sgl_nents, &pos);
set_fs(old_fs);
kfree(iov);
- if (ret < 0 || ret != task->task_size) {
+ if (ret < 0 || ret != cmd->data_length) {
pr_err("vfs_writev() returned %d\n", ret);
return (ret < 0 ? ret : -EINVAL);
}
@@ -361,9 +336,8 @@ static int fd_do_writev(struct se_task *task)
return 1;
}
-static void fd_emulate_sync_cache(struct se_task *task)
+static void fd_emulate_sync_cache(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct fd_dev *fd_dev = dev->dev_ptr;
int immed = (cmd->t_task_cdb[1] & 0x2);
@@ -375,7 +349,7 @@ static void fd_emulate_sync_cache(struct se_task *task)
* for this SYNCHRONIZE_CACHE op
*/
if (immed)
- transport_complete_sync_cache(cmd, 1);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
/*
* Determine if we will be flushing the entire device.
@@ -395,33 +369,37 @@ static void fd_emulate_sync_cache(struct se_task *task)
if (ret != 0)
pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
- if (!immed)
- transport_complete_sync_cache(cmd, ret == 0);
+ if (immed)
+ return;
+
+ if (ret) {
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
+ } else {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ }
}
-/*
- * WRITE Force Unit Access (FUA) emulation on a per struct se_task
- * LBA range basis..
- */
-static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
+static void fd_emulate_write_fua(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct fd_dev *fd_dev = dev->dev_ptr;
- loff_t start = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
- loff_t end = start + task->task_size;
+ loff_t start = cmd->t_task_lba *
+ dev->se_sub_dev->se_dev_attrib.block_size;
+ loff_t end = start + cmd->data_length;
int ret;
pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
- task->task_lba, task->task_size);
+ cmd->t_task_lba, cmd->data_length);
ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
if (ret != 0)
pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
}
-static int fd_do_task(struct se_task *task)
+static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents, enum dma_data_direction data_direction)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
int ret = 0;
@@ -429,10 +407,10 @@ static int fd_do_task(struct se_task *task)
* Call vectorized fileio functions to map struct scatterlist
* physical memory addresses to struct iovec virtual memory.
*/
- if (task->task_data_direction == DMA_FROM_DEVICE) {
- ret = fd_do_readv(task);
+ if (data_direction == DMA_FROM_DEVICE) {
+ ret = fd_do_readv(cmd, sgl, sgl_nents);
} else {
- ret = fd_do_writev(task);
+ ret = fd_do_writev(cmd, sgl, sgl_nents);
if (ret > 0 &&
dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 &&
@@ -443,7 +421,7 @@ static int fd_do_task(struct se_task *task)
* and return some sense data to let the initiator
* know the FUA WRITE cache sync failed..?
*/
- fd_emulate_write_fua(cmd, task);
+ fd_emulate_write_fua(cmd);
}
}
@@ -452,24 +430,11 @@ static int fd_do_task(struct se_task *task)
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
return ret;
}
- if (ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (ret)
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
-/* fd_free_task(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static void fd_free_task(struct se_task *task)
-{
- struct fd_request *req = FILE_REQ(task);
-
- kfree(req);
-}
-
enum {
Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err
};
@@ -605,10 +570,20 @@ static u32 fd_get_device_type(struct se_device *dev)
static sector_t fd_get_blocks(struct se_device *dev)
{
struct fd_dev *fd_dev = dev->dev_ptr;
- unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
- dev->se_sub_dev->se_dev_attrib.block_size);
+ struct file *f = fd_dev->fd_file;
+ struct inode *i = f->f_mapping->host;
+ unsigned long long dev_size;
+ /*
+ * When using a file that references an underlying struct block_device,
+ * ensure dev_size is always based on the current inode size in order
+ * to handle underlying block_device resize operations.
+ */
+ if (S_ISBLK(i->i_mode))
+ dev_size = (i_size_read(i) - fd_dev->fd_block_size);
+ else
+ dev_size = fd_dev->fd_dev_size;
- return blocks_long;
+ return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size);
}
static struct se_subsystem_api fileio_template = {
@@ -622,10 +597,8 @@ static struct se_subsystem_api fileio_template = {
.allocate_virtdevice = fd_allocate_virtdevice,
.create_virtdevice = fd_create_virtdevice,
.free_device = fd_free_device,
- .alloc_task = fd_alloc_task,
- .do_task = fd_do_task,
+ .execute_cmd = fd_execute_cmd,
.do_sync_cache = fd_emulate_sync_cache,
- .free_task = fd_free_task,
.check_configfs_dev_params = fd_check_configfs_dev_params,
.set_configfs_dev_params = fd_set_configfs_dev_params,
.show_configfs_dev_params = fd_show_configfs_dev_params,
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index 59e6e73..fbd59ef 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -12,10 +12,6 @@
#define RRF_EMULATE_CDB 0x01
#define RRF_GOT_LBA 0x02
-struct fd_request {
- struct se_task fd_task;
-};
-
#define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02
#define FDBD_USE_BUFFERED_IO 0x04
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 2ec299e..fd47950 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -189,26 +189,6 @@ static void iblock_free_device(void *p)
kfree(ib_dev);
}
-static inline struct iblock_req *IBLOCK_REQ(struct se_task *task)
-{
- return container_of(task, struct iblock_req, ib_task);
-}
-
-static struct se_task *
-iblock_alloc_task(unsigned char *cdb)
-{
- struct iblock_req *ib_req;
-
- ib_req = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
- if (!ib_req) {
- pr_err("Unable to allocate memory for struct iblock_req\n");
- return NULL;
- }
-
- atomic_set(&ib_req->pending, 1);
- return &ib_req->ib_task;
-}
-
static unsigned long long iblock_emulate_read_cap_with_block_size(
struct se_device *dev,
struct block_device *bd,
@@ -295,8 +275,16 @@ static void iblock_end_io_flush(struct bio *bio, int err)
if (err)
pr_err("IBLOCK: cache flush failed: %d\n", err);
- if (cmd)
- transport_complete_sync_cache(cmd, err == 0);
+ if (cmd) {
+ if (err) {
+ cmd->scsi_sense_reason =
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
+ } else {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ }
+ }
+
bio_put(bio);
}
@@ -304,9 +292,8 @@ static void iblock_end_io_flush(struct bio *bio, int err)
* Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must
* always flush the whole cache.
*/
-static void iblock_emulate_sync_cache(struct se_task *task)
+static void iblock_emulate_sync_cache(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
int immed = (cmd->t_task_cdb[1] & 0x2);
struct bio *bio;
@@ -316,7 +303,7 @@ static void iblock_emulate_sync_cache(struct se_task *task)
* for this SYNCHRONIZE_CACHE op.
*/
if (immed)
- transport_complete_sync_cache(cmd, 1);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
bio = bio_alloc(GFP_KERNEL, 0);
bio->bi_end_io = iblock_end_io_flush;
@@ -335,11 +322,6 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier);
}
-static void iblock_free_task(struct se_task *task)
-{
- kfree(IBLOCK_REQ(task));
-}
-
enum {
Opt_udev_path, Opt_force, Opt_err
};
@@ -448,19 +430,35 @@ static ssize_t iblock_show_configfs_dev_params(
return bl;
}
+static void iblock_complete_cmd(struct se_cmd *cmd)
+{
+ struct iblock_req *ibr = cmd->priv;
+ u8 status;
+
+ if (!atomic_dec_and_test(&ibr->pending))
+ return;
+
+ if (atomic_read(&ibr->ib_bio_err_cnt))
+ status = SAM_STAT_CHECK_CONDITION;
+ else
+ status = SAM_STAT_GOOD;
+
+ target_complete_cmd(cmd, status);
+ kfree(ibr);
+}
+
static void iblock_bio_destructor(struct bio *bio)
{
- struct se_task *task = bio->bi_private;
- struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
+ struct se_cmd *cmd = bio->bi_private;
+ struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
bio_free(bio, ib_dev->ibd_bio_set);
}
static struct bio *
-iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
+iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
{
- struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
- struct iblock_req *ib_req = IBLOCK_REQ(task);
+ struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
struct bio *bio;
/*
@@ -476,19 +474,11 @@ iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
return NULL;
}
- pr_debug("Allocated bio: %p task_sg_nents: %u using ibd_bio_set:"
- " %p\n", bio, task->task_sg_nents, ib_dev->ibd_bio_set);
- pr_debug("Allocated bio: %p task_size: %u\n", bio, task->task_size);
-
bio->bi_bdev = ib_dev->ibd_bd;
- bio->bi_private = task;
+ bio->bi_private = cmd;
bio->bi_destructor = iblock_bio_destructor;
bio->bi_end_io = &iblock_bio_done;
bio->bi_sector = lba;
- atomic_inc(&ib_req->pending);
-
- pr_debug("Set bio->bi_sector: %llu\n", (unsigned long long)bio->bi_sector);
- pr_debug("Set ib_req->pending: %d\n", atomic_read(&ib_req->pending));
return bio;
}
@@ -503,20 +493,21 @@ static void iblock_submit_bios(struct bio_list *list, int rw)
blk_finish_plug(&plug);
}
-static int iblock_do_task(struct se_task *task)
+static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents, enum dma_data_direction data_direction)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
- struct iblock_req *ibr = IBLOCK_REQ(task);
+ struct iblock_req *ibr;
struct bio *bio;
struct bio_list list;
struct scatterlist *sg;
- u32 i, sg_num = task->task_sg_nents;
+ u32 sg_num = sgl_nents;
sector_t block_lba;
unsigned bio_cnt;
int rw;
+ int i;
- if (task->task_data_direction == DMA_TO_DEVICE) {
+ if (data_direction == DMA_TO_DEVICE) {
/*
* Force data to disk if we pretend to not have a volatile
* write cache, or the initiator set the Force Unit Access bit.
@@ -532,17 +523,17 @@ static int iblock_do_task(struct se_task *task)
}
/*
- * Do starting conversion up from non 512-byte blocksize with
- * struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
+ * Convert the blocksize advertised to the initiator to the 512 byte
+ * units unconditionally used by the Linux block layer.
*/
if (dev->se_sub_dev->se_dev_attrib.block_size == 4096)
- block_lba = (task->task_lba << 3);
+ block_lba = (cmd->t_task_lba << 3);
else if (dev->se_sub_dev->se_dev_attrib.block_size == 2048)
- block_lba = (task->task_lba << 2);
+ block_lba = (cmd->t_task_lba << 2);
else if (dev->se_sub_dev->se_dev_attrib.block_size == 1024)
- block_lba = (task->task_lba << 1);
+ block_lba = (cmd->t_task_lba << 1);
else if (dev->se_sub_dev->se_dev_attrib.block_size == 512)
- block_lba = task->task_lba;
+ block_lba = cmd->t_task_lba;
else {
pr_err("Unsupported SCSI -> BLOCK LBA conversion:"
" %u\n", dev->se_sub_dev->se_dev_attrib.block_size);
@@ -550,17 +541,22 @@ static int iblock_do_task(struct se_task *task)
return -ENOSYS;
}
- bio = iblock_get_bio(task, block_lba, sg_num);
- if (!bio) {
- cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return -ENOMEM;
- }
+ ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+ if (!ibr)
+ goto fail;
+ cmd->priv = ibr;
+
+ bio = iblock_get_bio(cmd, block_lba, sgl_nents);
+ if (!bio)
+ goto fail_free_ibr;
bio_list_init(&list);
bio_list_add(&list, bio);
+
+ atomic_set(&ibr->pending, 2);
bio_cnt = 1;
- for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
+ for_each_sg(sgl, sg, sgl_nents, i) {
/*
* XXX: if the length the device accepts is shorter than the
* length of the S/G list entry this will cause and
@@ -573,9 +569,11 @@ static int iblock_do_task(struct se_task *task)
bio_cnt = 0;
}
- bio = iblock_get_bio(task, block_lba, sg_num);
+ bio = iblock_get_bio(cmd, block_lba, sg_num);
if (!bio)
- goto fail;
+ goto fail_put_bios;
+
+ atomic_inc(&ibr->pending);
bio_list_add(&list, bio);
bio_cnt++;
}
@@ -586,17 +584,16 @@ static int iblock_do_task(struct se_task *task)
}
iblock_submit_bios(&list, rw);
-
- if (atomic_dec_and_test(&ibr->pending)) {
- transport_complete_task(task,
- !atomic_read(&ibr->ib_bio_err_cnt));
- }
+ iblock_complete_cmd(cmd);
return 0;
-fail:
+fail_put_bios:
while ((bio = bio_list_pop(&list)))
bio_put(bio);
+fail_free_ibr:
+ kfree(ibr);
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+fail:
return -ENOMEM;
}
@@ -621,8 +618,8 @@ static sector_t iblock_get_blocks(struct se_device *dev)
static void iblock_bio_done(struct bio *bio, int err)
{
- struct se_task *task = bio->bi_private;
- struct iblock_req *ibr = IBLOCK_REQ(task);
+ struct se_cmd *cmd = bio->bi_private;
+ struct iblock_req *ibr = cmd->priv;
/*
* Set -EIO if !BIO_UPTODATE and the passed is still err=0
@@ -642,14 +639,7 @@ static void iblock_bio_done(struct bio *bio, int err)
bio_put(bio);
- if (!atomic_dec_and_test(&ibr->pending))
- return;
-
- pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
- task, bio, task->task_lba,
- (unsigned long long)bio->bi_sector, err);
-
- transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt));
+ iblock_complete_cmd(cmd);
}
static struct se_subsystem_api iblock_template = {
@@ -663,11 +653,9 @@ static struct se_subsystem_api iblock_template = {
.allocate_virtdevice = iblock_allocate_virtdevice,
.create_virtdevice = iblock_create_virtdevice,
.free_device = iblock_free_device,
- .alloc_task = iblock_alloc_task,
- .do_task = iblock_do_task,
+ .execute_cmd = iblock_execute_cmd,
.do_discard = iblock_do_discard,
.do_sync_cache = iblock_emulate_sync_cache,
- .free_task = iblock_free_task,
.check_configfs_dev_params = iblock_check_configfs_dev_params,
.set_configfs_dev_params = iblock_set_configfs_dev_params,
.show_configfs_dev_params = iblock_show_configfs_dev_params,
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index e929370..66cf7b9 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -7,7 +7,6 @@
#define IBLOCK_LBA_SHIFT 9
struct iblock_req {
- struct se_task ib_task;
atomic_t pending;
atomic_t ib_bio_err_cnt;
} ____cacheline_aligned;
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 21c0563..165e824 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -5,15 +5,15 @@
extern struct t10_alua_lu_gp *default_lu_gp;
/* target_core_cdb.c */
-int target_emulate_inquiry(struct se_task *task);
-int target_emulate_readcapacity(struct se_task *task);
-int target_emulate_readcapacity_16(struct se_task *task);
-int target_emulate_modesense(struct se_task *task);
-int target_emulate_request_sense(struct se_task *task);
-int target_emulate_unmap(struct se_task *task);
-int target_emulate_write_same(struct se_task *task);
-int target_emulate_synchronize_cache(struct se_task *task);
-int target_emulate_noop(struct se_task *task);
+int target_emulate_inquiry(struct se_cmd *cmd);
+int target_emulate_readcapacity(struct se_cmd *cmd);
+int target_emulate_readcapacity_16(struct se_cmd *cmd);
+int target_emulate_modesense(struct se_cmd *cmd);
+int target_emulate_request_sense(struct se_cmd *cmd);
+int target_emulate_unmap(struct se_cmd *cmd);
+int target_emulate_write_same(struct se_cmd *cmd);
+int target_emulate_synchronize_cache(struct se_cmd *cmd);
+int target_emulate_noop(struct se_cmd *cmd);
/* target_core_device.c */
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
@@ -28,7 +28,7 @@ int core_dev_export(struct se_device *, struct se_portal_group *,
struct se_lun *);
void core_dev_unexport(struct se_device *, struct se_portal_group *,
struct se_lun *);
-int target_report_luns(struct se_task *);
+int target_report_luns(struct se_cmd *);
void se_release_device_for_hba(struct se_device *);
void se_release_vpd_for_dev(struct se_device *);
int se_free_virtual_device(struct se_device *, struct se_hba *);
@@ -104,8 +104,7 @@ void release_se_kmem_caches(void);
u32 scsi_get_new_index(scsi_index_t);
void transport_subsystem_check_init(void);
void transport_cmd_finish_abort(struct se_cmd *, int);
-void __transport_remove_task_from_execute_queue(struct se_task *,
- struct se_device *);
+void __target_remove_from_execute_list(struct se_cmd *);
unsigned char *transport_dump_cmd_direction(struct se_cmd *);
void transport_dump_dev_state(struct se_device *, char *, int *);
void transport_dump_dev_info(struct se_device *, struct se_lun *,
@@ -114,7 +113,7 @@ void transport_dump_vpd_proto_id(struct t10_vpd *, unsigned char *, int);
int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int);
int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int);
int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
-bool target_stop_task(struct se_task *task, unsigned long *flags);
+bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);
int transport_clear_lun_from_sessions(struct se_lun *);
void transport_send_task_abort(struct se_cmd *);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 86f0c3b..8556499 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -193,9 +193,8 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd)
return 0;
}
-int target_scsi2_reservation_release(struct se_task *task)
+int target_scsi2_reservation_release(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
struct se_portal_group *tpg = sess->se_tpg;
@@ -220,6 +219,9 @@ int target_scsi2_reservation_release(struct se_task *task)
if (dev->dev_reserved_node_acl != sess->se_node_acl)
goto out_unlock;
+ if (dev->dev_res_bin_isid != sess->sess_bin_isid)
+ goto out_unlock;
+
dev->dev_reserved_node_acl = NULL;
dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) {
@@ -234,16 +236,13 @@ int target_scsi2_reservation_release(struct se_task *task)
out_unlock:
spin_unlock(&dev->dev_reservation_lock);
out:
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
-int target_scsi2_reservation_reserve(struct se_task *task)
+int target_scsi2_reservation_reserve(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
struct se_portal_group *tpg = sess->se_tpg;
@@ -304,10 +303,8 @@ int target_scsi2_reservation_reserve(struct se_task *task)
out_unlock:
spin_unlock(&dev->dev_reservation_lock);
out:
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
@@ -500,11 +497,10 @@ static int core_scsi3_pr_seq_non_holder(
* statement.
*/
if (!ret && !other_cdb) {
-#if 0
pr_debug("Allowing explict CDB: 0x%02x for %s"
" reservation holder\n", cdb[0],
core_scsi3_pr_dump_type(pr_reg_type));
-#endif
+
return ret;
}
/*
@@ -532,14 +528,14 @@ static int core_scsi3_pr_seq_non_holder(
* as we expect registered non-reservation holding
* nexuses to issue CDBs.
*/
-#if 0
+
if (!registered_nexus) {
pr_debug("Allowing implict CDB: 0x%02x"
" for %s reservation on unregistered"
" nexus\n", cdb[0],
core_scsi3_pr_dump_type(pr_reg_type));
}
-#endif
+
return 0;
}
} else if ((reg_only) || (all_reg)) {
@@ -548,11 +544,11 @@ static int core_scsi3_pr_seq_non_holder(
* For PR_*_REG_ONLY and PR_*_ALL_REG reservations,
* allow commands from registered nexuses.
*/
-#if 0
+
pr_debug("Allowing implict CDB: 0x%02x for %s"
" reservation\n", cdb[0],
core_scsi3_pr_dump_type(pr_reg_type));
-#endif
+
return 0;
}
}
@@ -1666,12 +1662,12 @@ static int core_scsi3_decode_spec_i_port(
ret = -EINVAL;
goto out;
}
-#if 0
+
pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u"
" tid_len: %d for %s + %s\n",
dest_tpg->se_tpg_tfo->get_fabric_name(), cmd->data_length,
tpdl, tid_len, i_str, iport_ptr);
-#endif
+
if (tid_len > tpdl) {
pr_err("SPC-3 PR SPEC_I_PT: Illegal tid_len:"
" %u for Transport ID: %s\n", tid_len, ptr);
@@ -1714,12 +1710,12 @@ static int core_scsi3_decode_spec_i_port(
ret = -EINVAL;
goto out;
}
-#if 0
+
pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s"
" dest_se_deve mapped_lun: %u\n",
dest_tpg->se_tpg_tfo->get_fabric_name(),
dest_node_acl->initiatorname, dest_se_deve->mapped_lun);
-#endif
+
/*
* Skip any TransportIDs that already have a registration for
* this target port.
@@ -3473,10 +3469,10 @@ static int core_scsi3_emulate_pro_register_and_move(
buf = transport_kmap_data_sg(cmd);
proto_ident = (buf[24] & 0x0f);
-#if 0
+
pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:"
" 0x%02x\n", proto_ident);
-#endif
+
if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) {
pr_err("SPC-3 PR REGISTER_AND_MOVE: Received"
" proto_ident: 0x%02x does not match ident: 0x%02x"
@@ -3575,11 +3571,11 @@ after_iport_check:
ret = -EINVAL;
goto out;
}
-#if 0
+
pr_debug("SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:"
" %s from TransportID\n", dest_tf_ops->get_fabric_name(),
dest_node_acl->initiatorname);
-#endif
+
/*
* Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET
* PORT IDENTIFIER.
@@ -3603,12 +3599,12 @@ after_iport_check:
ret = -EINVAL;
goto out;
}
-#if 0
+
pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN"
" ACL for dest_se_deve->mapped_lun: %u\n",
dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname,
dest_se_deve->mapped_lun);
-#endif
+
/*
* A persistent reservation needs to already existing in order to
* successfully complete the REGISTER_AND_MOVE service action..
@@ -3799,9 +3795,8 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
/*
* See spc4r17 section 6.14 Table 170
*/
-int target_scsi3_emulate_pr_out(struct se_task *task)
+int target_scsi3_emulate_pr_out(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
unsigned char *cdb = &cmd->t_task_cdb[0];
unsigned char *buf;
u64 res_key, sa_res_key;
@@ -3941,10 +3936,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task)
}
out:
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
@@ -4299,9 +4292,8 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
return 0;
}
-int target_scsi3_emulate_pr_in(struct se_task *task)
+int target_scsi3_emulate_pr_in(struct se_cmd *cmd)
{
- struct se_cmd *cmd = task->task_se_cmd;
int ret;
/*
@@ -4342,10 +4334,8 @@ int target_scsi3_emulate_pr_in(struct se_task *task)
break;
}
- if (!ret) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
return ret;
}
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index 7a233fe..af6c460 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -47,8 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache;
extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
char *, u32);
-extern int target_scsi2_reservation_release(struct se_task *task);
-extern int target_scsi2_reservation_reserve(struct se_task *task);
+extern int target_scsi2_reservation_release(struct se_cmd *);
+extern int target_scsi2_reservation_reserve(struct se_cmd *);
extern int core_scsi3_alloc_aptpl_registration(
struct t10_reservation *, u64,
unsigned char *, unsigned char *, u32,
@@ -61,8 +61,8 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,
extern void core_scsi3_free_all_registrations(struct se_device *);
extern unsigned char *core_scsi3_pr_dump_type(int);
-extern int target_scsi3_emulate_pr_in(struct se_task *task);
-extern int target_scsi3_emulate_pr_out(struct se_task *task);
+extern int target_scsi3_emulate_pr_in(struct se_cmd *);
+extern int target_scsi3_emulate_pr_out(struct se_cmd *);
extern int core_setup_reservations(struct se_device *, int);
#endif /* TARGET_CORE_PR_H */
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 94c905f..4ce2cf6 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -663,22 +663,12 @@ static void pscsi_free_device(void *p)
kfree(pdv);
}
-static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
+static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
{
- return container_of(task, struct pscsi_plugin_task, pscsi_task);
-}
-
-
-/* pscsi_transport_complete():
- *
- *
- */
-static int pscsi_transport_complete(struct se_task *task)
-{
- struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
+ struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
struct scsi_device *sd = pdv->pdv_sd;
int result;
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_plugin_task *pt = cmd->priv;
unsigned char *cdb = &pt->pscsi_cdb[0];
result = pt->pscsi_result;
@@ -688,12 +678,11 @@ static int pscsi_transport_complete(struct se_task *task)
*/
if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
(status_byte(result) << 1) == SAM_STAT_GOOD) {
- if (!task->task_se_cmd->se_deve)
+ if (!cmd->se_deve)
goto after_mode_sense;
- if (task->task_se_cmd->se_deve->lun_flags &
- TRANSPORT_LUNFLAGS_READ_ONLY) {
- unsigned char *buf = transport_kmap_data_sg(task->task_se_cmd);
+ if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) {
+ unsigned char *buf = transport_kmap_data_sg(cmd);
if (cdb[0] == MODE_SENSE_10) {
if (!(buf[3] & 0x80))
@@ -703,7 +692,7 @@ static int pscsi_transport_complete(struct se_task *task)
buf[2] |= 0x80;
}
- transport_kunmap_data_sg(task->task_se_cmd);
+ transport_kunmap_data_sg(cmd);
}
}
after_mode_sense:
@@ -722,7 +711,6 @@ after_mode_sense:
if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) &&
(status_byte(result) << 1) == SAM_STAT_GOOD) {
unsigned char *buf;
- struct scatterlist *sg = task->task_sg;
u16 bdl;
u32 blocksize;
@@ -757,35 +745,6 @@ after_mode_select:
return 0;
}
-static struct se_task *
-pscsi_alloc_task(unsigned char *cdb)
-{
- struct pscsi_plugin_task *pt;
-
- /*
- * Dynamically alloc cdb space, since it may be larger than
- * TCM_MAX_COMMAND_SIZE
- */
- pt = kzalloc(sizeof(*pt) + scsi_command_size(cdb), GFP_KERNEL);
- if (!pt) {
- pr_err("Unable to allocate struct pscsi_plugin_task\n");
- return NULL;
- }
-
- return &pt->pscsi_task;
-}
-
-static void pscsi_free_task(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
-
- /*
- * We do not release the bio(s) here associated with this task, as
- * this is handled by bio_put() and pscsi_bi_endio().
- */
- kfree(pt);
-}
-
enum {
Opt_scsi_host_id, Opt_scsi_channel_id, Opt_scsi_target_id,
Opt_scsi_lun_id, Opt_err
@@ -958,26 +917,25 @@ static inline struct bio *pscsi_get_bio(int sg_num)
return bio;
}
-static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
+static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents, enum dma_data_direction data_direction,
struct bio **hbio)
{
- struct se_cmd *cmd = task->task_se_cmd;
- struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
- u32 task_sg_num = task->task_sg_nents;
+ struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
struct bio *bio = NULL, *tbio = NULL;
struct page *page;
struct scatterlist *sg;
- u32 data_len = task->task_size, i, len, bytes, off;
- int nr_pages = (task->task_size + task_sg[0].offset +
+ u32 data_len = cmd->data_length, i, len, bytes, off;
+ int nr_pages = (cmd->data_length + sgl[0].offset +
PAGE_SIZE - 1) >> PAGE_SHIFT;
int nr_vecs = 0, rc;
- int rw = (task->task_data_direction == DMA_TO_DEVICE);
+ int rw = (data_direction == DMA_TO_DEVICE);
*hbio = NULL;
pr_debug("PSCSI: nr_pages: %d\n", nr_pages);
- for_each_sg(task_sg, sg, task_sg_num, i) {
+ for_each_sg(sgl, sg, sgl_nents, i) {
page = sg_page(sg);
off = sg->offset;
len = sg->length;
@@ -1009,7 +967,7 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
* Set *hbio pointer to handle the case:
* nr_pages > BIO_MAX_PAGES, where additional
* bios need to be added to complete a given
- * struct se_task
+ * command.
*/
if (!*hbio)
*hbio = tbio = bio;
@@ -1049,7 +1007,7 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
}
}
- return task->task_sg_nents;
+ return sgl_nents;
fail:
while (*hbio) {
bio = *hbio;
@@ -1061,52 +1019,61 @@ fail:
return -ENOMEM;
}
-static int pscsi_do_task(struct se_task *task)
+static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents, enum dma_data_direction data_direction)
{
- struct se_cmd *cmd = task->task_se_cmd;
- struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
+ struct pscsi_plugin_task *pt;
struct request *req;
struct bio *hbio;
int ret;
- target_get_task_cdb(task, pt->pscsi_cdb);
+ /*
+ * Dynamically alloc cdb space, since it may be larger than
+ * TCM_MAX_COMMAND_SIZE
+ */
+ pt = kzalloc(sizeof(*pt) + scsi_command_size(cmd->t_task_cdb), GFP_KERNEL);
+ if (!pt) {
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return -ENOMEM;
+ }
+ cmd->priv = pt;
+
+ memcpy(pt->pscsi_cdb, cmd->t_task_cdb,
+ scsi_command_size(cmd->t_task_cdb));
- if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+ if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
req = blk_get_request(pdv->pdv_sd->request_queue,
- (task->task_data_direction == DMA_TO_DEVICE),
+ (data_direction == DMA_TO_DEVICE),
GFP_KERNEL);
if (!req || IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed: %ld\n",
req ? IS_ERR(req) : -ENOMEM);
cmd->scsi_sense_reason =
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return -ENODEV;
+ goto fail;
}
} else {
- BUG_ON(!task->task_size);
+ BUG_ON(!cmd->data_length);
- /*
- * Setup the main struct request for the task->task_sg[] payload
- */
- ret = pscsi_map_sg(task, task->task_sg, &hbio);
+ ret = pscsi_map_sg(cmd, sgl, sgl_nents, data_direction, &hbio);
if (ret < 0) {
cmd->scsi_sense_reason =
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return ret;
+ goto fail;
}
req = blk_make_request(pdv->pdv_sd->request_queue, hbio,
GFP_KERNEL);
if (IS_ERR(req)) {
pr_err("pSCSI: blk_make_request() failed\n");
- goto fail;
+ goto fail_free_bio;
}
}
req->cmd_type = REQ_TYPE_BLOCK_PC;
req->end_io = pscsi_req_done;
- req->end_io_data = task;
+ req->end_io_data = cmd;
req->cmd_len = scsi_command_size(pt->pscsi_cdb);
req->cmd = &pt->pscsi_cdb[0];
req->sense = &pt->pscsi_sense[0];
@@ -1118,12 +1085,12 @@ static int pscsi_do_task(struct se_task *task)
req->retries = PS_RETRY;
blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
- (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
+ (cmd->sam_task_attr == MSG_HEAD_TAG),
pscsi_req_done);
return 0;
-fail:
+fail_free_bio:
while (hbio) {
struct bio *bio = hbio;
hbio = hbio->bi_next;
@@ -1131,16 +1098,14 @@ fail:
bio_endio(bio, 0); /* XXX: should be error */
}
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+fail:
+ kfree(pt);
return -ENOMEM;
}
-/* pscsi_get_sense_buffer():
- *
- *
- */
-static unsigned char *pscsi_get_sense_buffer(struct se_task *task)
+static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd)
{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_plugin_task *pt = cmd->priv;
return pt->pscsi_sense;
}
@@ -1180,48 +1145,36 @@ static sector_t pscsi_get_blocks(struct se_device *dev)
return 0;
}
-/* pscsi_handle_SAM_STATUS_failures():
- *
- *
- */
-static inline void pscsi_process_SAM_status(
- struct se_task *task,
- struct pscsi_plugin_task *pt)
+static void pscsi_req_done(struct request *req, int uptodate)
{
- task->task_scsi_status = status_byte(pt->pscsi_result);
- if (task->task_scsi_status) {
- task->task_scsi_status <<= 1;
- pr_debug("PSCSI Status Byte exception at task: %p CDB:"
- " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ struct se_cmd *cmd = req->end_io_data;
+ struct pscsi_plugin_task *pt = cmd->priv;
+
+ pt->pscsi_result = req->errors;
+ pt->pscsi_resid = req->resid_len;
+
+ cmd->scsi_status = status_byte(pt->pscsi_result) << 1;
+ if (cmd->scsi_status) {
+ pr_debug("PSCSI Status Byte exception at cmd: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0],
pt->pscsi_result);
}
switch (host_byte(pt->pscsi_result)) {
case DID_OK:
- transport_complete_task(task, (!task->task_scsi_status));
+ target_complete_cmd(cmd, cmd->scsi_status);
break;
default:
- pr_debug("PSCSI Host Byte exception at task: %p CDB:"
- " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ pr_debug("PSCSI Host Byte exception at cmd: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0],
pt->pscsi_result);
- task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
- task->task_se_cmd->scsi_sense_reason =
- TCM_UNSUPPORTED_SCSI_OPCODE;
- transport_complete_task(task, 0);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
break;
}
-}
-static void pscsi_req_done(struct request *req, int uptodate)
-{
- struct se_task *task = req->end_io_data;
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
-
- pt->pscsi_result = req->errors;
- pt->pscsi_resid = req->resid_len;
-
- pscsi_process_SAM_status(task, pt);
__blk_put_request(req->q, req);
+ kfree(pt);
}
static struct se_subsystem_api pscsi_template = {
@@ -1235,9 +1188,7 @@ static struct se_subsystem_api pscsi_template = {
.create_virtdevice = pscsi_create_virtdevice,
.free_device = pscsi_free_device,
.transport_complete = pscsi_transport_complete,
- .alloc_task = pscsi_alloc_task,
- .do_task = pscsi_do_task,
- .free_task = pscsi_free_task,
+ .execute_cmd = pscsi_execute_cmd,
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
index 43f1c41..bc1e5e11 100644
--- a/drivers/target/target_core_pscsi.h
+++ b/drivers/target/target_core_pscsi.h
@@ -22,7 +22,6 @@
#include <linux/kobject.h>
struct pscsi_plugin_task {
- struct se_task pscsi_task;
unsigned char pscsi_sense[SCSI_SENSE_BUFFERSIZE];
int pscsi_direction;
int pscsi_result;
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 8b68f7b..d0ceb87 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -64,9 +64,6 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id)
pr_debug("CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on"
" Generic Target Core Stack %s\n", hba->hba_id,
RD_HBA_VERSION, TARGET_CORE_MOD_VERSION);
- pr_debug("CORE_HBA[%d] - Attached Ramdisk HBA: %u to Generic"
- " MaxSectors: %u\n", hba->hba_id,
- rd_host->rd_host_id, RD_MAX_SECTORS);
return 0;
}
@@ -199,10 +196,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
return 0;
}
-static void *rd_allocate_virtdevice(
- struct se_hba *hba,
- const char *name,
- int rd_direct)
+static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name)
{
struct rd_dev *rd_dev;
struct rd_host *rd_host = hba->hba_ptr;
@@ -214,25 +208,12 @@ static void *rd_allocate_virtdevice(
}
rd_dev->rd_host = rd_host;
- rd_dev->rd_direct = rd_direct;
return rd_dev;
}
-static void *rd_MEMCPY_allocate_virtdevice(struct se_hba *hba, const char *name)
-{
- return rd_allocate_virtdevice(hba, name, 0);
-}
-
-/* rd_create_virtdevice():
- *
- *
- */
-static struct se_device *rd_create_virtdevice(
- struct se_hba *hba,
- struct se_subsystem_dev *se_dev,
- void *p,
- int rd_direct)
+static struct se_device *rd_create_virtdevice(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev, void *p)
{
struct se_device *dev;
struct se_dev_limits dev_limits;
@@ -247,13 +228,12 @@ static struct se_device *rd_create_virtdevice(
if (ret < 0)
goto fail;
- snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP");
- snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION :
- RD_MCP_VERSION);
+ snprintf(prod, 16, "RAMDISK-MCP");
+ snprintf(rev, 4, "%s", RD_MCP_VERSION);
dev_limits.limits.logical_block_size = RD_BLOCKSIZE;
- dev_limits.limits.max_hw_sectors = RD_MAX_SECTORS;
- dev_limits.limits.max_sectors = RD_MAX_SECTORS;
+ dev_limits.limits.max_hw_sectors = UINT_MAX;
+ dev_limits.limits.max_sectors = UINT_MAX;
dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;
dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH;
@@ -264,12 +244,10 @@ static struct se_device *rd_create_virtdevice(
goto fail;
rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++;
- rd_dev->rd_queue_depth = dev->queue_depth;
- pr_debug("CORE_RD[%u] - Added TCM %s Ramdisk Device ID: %u of"
+ pr_debug("CORE_RD[%u] - Added TCM MEMCPY Ramdisk Device ID: %u of"
" %u pages in %u tables, %lu total bytes\n",
- rd_host->rd_host_id, (!rd_dev->rd_direct) ? "MEMCPY" :
- "DIRECT", rd_dev->rd_dev_id, rd_dev->rd_page_count,
+ rd_host->rd_host_id, rd_dev->rd_dev_id, rd_dev->rd_page_count,
rd_dev->sg_table_count,
(unsigned long)(rd_dev->rd_page_count * PAGE_SIZE));
@@ -280,18 +258,6 @@ fail:
return ERR_PTR(ret);
}
-static struct se_device *rd_MEMCPY_create_virtdevice(
- struct se_hba *hba,
- struct se_subsystem_dev *se_dev,
- void *p)
-{
- return rd_create_virtdevice(hba, se_dev, p, 0);
-}
-
-/* rd_free_device(): (Part of se_subsystem_api_t template)
- *
- *
- */
static void rd_free_device(void *p)
{
struct rd_dev *rd_dev = p;
@@ -300,29 +266,6 @@ static void rd_free_device(void *p)
kfree(rd_dev);
}
-static inline struct rd_request *RD_REQ(struct se_task *task)
-{
- return container_of(task, struct rd_request, rd_task);
-}
-
-static struct se_task *
-rd_alloc_task(unsigned char *cdb)
-{
- struct rd_request *rd_req;
-
- rd_req = kzalloc(sizeof(struct rd_request), GFP_KERNEL);
- if (!rd_req) {
- pr_err("Unable to allocate struct rd_request\n");
- return NULL;
- }
-
- return &rd_req->rd_task;
-}
-
-/* rd_get_sg_table():
- *
- *
- */
static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
{
u32 i;
@@ -341,31 +284,41 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
return NULL;
}
-static int rd_MEMCPY(struct rd_request *req, u32 read_rd)
+static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
+ u32 sgl_nents, enum dma_data_direction data_direction)
{
- struct se_task *task = &req->rd_task;
- struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
+ struct se_device *se_dev = cmd->se_dev;
+ struct rd_dev *dev = se_dev->dev_ptr;
struct rd_dev_sg_table *table;
struct scatterlist *rd_sg;
struct sg_mapping_iter m;
- u32 rd_offset = req->rd_offset;
+ u32 rd_offset;
+ u32 rd_size;
+ u32 rd_page;
u32 src_len;
+ u64 tmp;
+
+ tmp = cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size;
+ rd_offset = do_div(tmp, PAGE_SIZE);
+ rd_page = tmp;
+ rd_size = cmd->data_length;
- table = rd_get_sg_table(dev, req->rd_page);
+ table = rd_get_sg_table(dev, rd_page);
if (!table)
return -EINVAL;
- rd_sg = &table->sg_table[req->rd_page - table->page_start_offset];
+ rd_sg = &table->sg_table[rd_page - table->page_start_offset];
pr_debug("RD[%u]: %s LBA: %llu, Size: %u Page: %u, Offset: %u\n",
- dev->rd_dev_id, read_rd ? "Read" : "Write",
- task->task_lba, req->rd_size, req->rd_page,
- rd_offset);
+ dev->rd_dev_id,
+ data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
+ cmd->t_task_lba, rd_size, rd_page, rd_offset);
src_len = PAGE_SIZE - rd_offset;
- sg_miter_start(&m, task->task_sg, task->task_sg_nents,
- read_rd ? SG_MITER_TO_SG : SG_MITER_FROM_SG);
- while (req->rd_size) {
+ sg_miter_start(&m, sgl, sgl_nents,
+ data_direction == DMA_FROM_DEVICE ?
+ SG_MITER_TO_SG : SG_MITER_FROM_SG);
+ while (rd_size) {
u32 len;
void *rd_addr;
@@ -375,13 +328,13 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd)
rd_addr = sg_virt(rd_sg) + rd_offset;
- if (read_rd)
+ if (data_direction == DMA_FROM_DEVICE)
memcpy(m.addr, rd_addr, len);
else
memcpy(rd_addr, m.addr, len);
- req->rd_size -= len;
- if (!req->rd_size)
+ rd_size -= len;
+ if (!rd_size)
continue;
src_len -= len;
@@ -391,15 +344,15 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd)
}
/* rd page completed, next one please */
- req->rd_page++;
+ rd_page++;
rd_offset = 0;
src_len = PAGE_SIZE;
- if (req->rd_page <= table->page_end_offset) {
+ if (rd_page <= table->page_end_offset) {
rd_sg++;
continue;
}
- table = rd_get_sg_table(dev, req->rd_page);
+ table = rd_get_sg_table(dev, rd_page);
if (!table) {
sg_miter_stop(&m);
return -EINVAL;
@@ -409,43 +362,11 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd)
rd_sg = table->sg_table;
}
sg_miter_stop(&m);
- return 0;
-}
-/* rd_MEMCPY_do_task(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static int rd_MEMCPY_do_task(struct se_task *task)
-{
- struct se_device *dev = task->task_se_cmd->se_dev;
- struct rd_request *req = RD_REQ(task);
- u64 tmp;
- int ret;
-
- tmp = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
- req->rd_offset = do_div(tmp, PAGE_SIZE);
- req->rd_page = tmp;
- req->rd_size = task->task_size;
-
- ret = rd_MEMCPY(req, task->task_data_direction == DMA_FROM_DEVICE);
- if (ret != 0)
- return ret;
-
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
-/* rd_free_task(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static void rd_free_task(struct se_task *task)
-{
- kfree(RD_REQ(task));
-}
-
enum {
Opt_rd_pages, Opt_err
};
@@ -512,9 +433,8 @@ static ssize_t rd_show_configfs_dev_params(
char *b)
{
struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
- ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: %s\n",
- rd_dev->rd_dev_id, (rd_dev->rd_direct) ?
- "rd_direct" : "rd_mcp");
+ ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: rd_mcp\n",
+ rd_dev->rd_dev_id);
bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu"
" SG_table_count: %u\n", rd_dev->rd_page_count,
PAGE_SIZE, rd_dev->sg_table_count);
@@ -545,12 +465,10 @@ static struct se_subsystem_api rd_mcp_template = {
.transport_type = TRANSPORT_PLUGIN_VHBA_VDEV,
.attach_hba = rd_attach_hba,
.detach_hba = rd_detach_hba,
- .allocate_virtdevice = rd_MEMCPY_allocate_virtdevice,
- .create_virtdevice = rd_MEMCPY_create_virtdevice,
+ .allocate_virtdevice = rd_allocate_virtdevice,
+ .create_virtdevice = rd_create_virtdevice,
.free_device = rd_free_device,
- .alloc_task = rd_alloc_task,
- .do_task = rd_MEMCPY_do_task,
- .free_task = rd_free_task,
+ .execute_cmd = rd_execute_cmd,
.check_configfs_dev_params = rd_check_configfs_dev_params,
.set_configfs_dev_params = rd_set_configfs_dev_params,
.show_configfs_dev_params = rd_show_configfs_dev_params,
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
index 784e56a..2145812 100644
--- a/drivers/target/target_core_rd.h
+++ b/drivers/target/target_core_rd.h
@@ -2,7 +2,6 @@
#define TARGET_CORE_RD_H
#define RD_HBA_VERSION "v4.0"
-#define RD_DR_VERSION "4.0"
#define RD_MCP_VERSION "4.0"
/* Largest piece of memory kmalloc can allocate */
@@ -10,28 +9,11 @@
#define RD_DEVICE_QUEUE_DEPTH 32
#define RD_MAX_DEVICE_QUEUE_DEPTH 128
#define RD_BLOCKSIZE 512
-#define RD_MAX_SECTORS 1024
/* Used in target_core_init_configfs() for virtual LUN 0 access */
int __init rd_module_init(void);
void rd_module_exit(void);
-#define RRF_EMULATE_CDB 0x01
-#define RRF_GOT_LBA 0x02
-
-struct rd_request {
- struct se_task rd_task;
-
- /* Offset from start of page */
- u32 rd_offset;
- /* Starting page in Ramdisk for request */
- u32 rd_page;
- /* Total number of pages needed for request */
- u32 rd_page_count;
- /* Scatterlist count */
- u32 rd_size;
-} ____cacheline_aligned;
-
struct rd_dev_sg_table {
u32 page_start_offset;
u32 page_end_offset;
@@ -42,7 +24,6 @@ struct rd_dev_sg_table {
#define RDF_HAS_PAGE_COUNT 0x01
struct rd_dev {
- int rd_direct;
u32 rd_flags;
/* Unique Ramdisk Device ID in Ramdisk HBA */
u32 rd_dev_id;
@@ -50,7 +31,6 @@ struct rd_dev {
u32 rd_page_count;
/* Number of SG tables in sg_table_array */
u32 sg_table_count;
- u32 rd_queue_depth;
/* Array of rd_dev_sg_table_t containing scatterlists */
struct rd_dev_sg_table *sg_table_array;
/* Ramdisk HBA device is connected to */
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index f015839..84caf1b 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -244,7 +244,7 @@ static void core_tmr_drain_tmr_list(
}
}
-static void core_tmr_drain_task_list(
+static void core_tmr_drain_state_list(
struct se_device *dev,
struct se_cmd *prout_cmd,
struct se_node_acl *tmr_nacl,
@@ -252,12 +252,13 @@ static void core_tmr_drain_task_list(
struct list_head *preempt_and_abort_list)
{
LIST_HEAD(drain_task_list);
- struct se_cmd *cmd;
- struct se_task *task, *task_tmp;
+ struct se_cmd *cmd, *next;
unsigned long flags;
int fe_count;
+
/*
- * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
+ * Complete outstanding commands with TASK_ABORTED SAM status.
+ *
* This is following sam4r17, section 5.6 Aborting commands, Table 38
* for TMR LUN_RESET:
*
@@ -278,56 +279,43 @@ static void core_tmr_drain_task_list(
* in the Control Mode Page.
*/
spin_lock_irqsave(&dev->execute_task_lock, flags);
- list_for_each_entry_safe(task, task_tmp, &dev->state_task_list,
- t_state_list) {
- if (!task->task_se_cmd) {
- pr_err("task->task_se_cmd is NULL!\n");
- continue;
- }
- cmd = task->task_se_cmd;
-
+ list_for_each_entry_safe(cmd, next, &dev->state_list, state_list) {
/*
* For PREEMPT_AND_ABORT usage, only process commands
* with a matching reservation key.
*/
if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
continue;
+
/*
* Not aborting PROUT PREEMPT_AND_ABORT CDB..
*/
if (prout_cmd == cmd)
continue;
- list_move_tail(&task->t_state_list, &drain_task_list);
- task->t_state_active = false;
- /*
- * Remove from task execute list before processing drain_task_list
- */
- if (!list_empty(&task->t_execute_list))
- __transport_remove_task_from_execute_queue(task, dev);
+ list_move_tail(&cmd->state_list, &drain_task_list);
+ cmd->state_active = false;
+
+ if (!list_empty(&cmd->execute_list))
+ __target_remove_from_execute_list(cmd);
}
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
while (!list_empty(&drain_task_list)) {
- task = list_entry(drain_task_list.next, struct se_task, t_state_list);
- list_del(&task->t_state_list);
- cmd = task->task_se_cmd;
+ cmd = list_entry(drain_task_list.next, struct se_cmd, state_list);
+ list_del(&cmd->state_list);
- pr_debug("LUN_RESET: %s cmd: %p task: %p"
+ pr_debug("LUN_RESET: %s cmd: %p"
" ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d"
"cdb: 0x%02x\n",
- (preempt_and_abort_list) ? "Preempt" : "", cmd, task,
+ (preempt_and_abort_list) ? "Preempt" : "", cmd,
cmd->se_tfo->get_task_tag(cmd), 0,
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
cmd->t_task_cdb[0]);
pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
- " t_task_cdbs: %d t_task_cdbs_left: %d"
- " t_task_cdbs_sent: %d -- CMD_T_ACTIVE: %d"
+ " -- CMD_T_ACTIVE: %d"
" CMD_T_STOP: %d CMD_T_SENT: %d\n",
cmd->se_tfo->get_task_tag(cmd), cmd->pr_res_key,
- cmd->t_task_list_num,
- atomic_read(&cmd->t_task_cdbs_left),
- atomic_read(&cmd->t_task_cdbs_sent),
(cmd->transport_state & CMD_T_ACTIVE) != 0,
(cmd->transport_state & CMD_T_STOP) != 0,
(cmd->transport_state & CMD_T_SENT) != 0);
@@ -343,20 +331,13 @@ static void core_tmr_drain_task_list(
cancel_work_sync(&cmd->work);
spin_lock_irqsave(&cmd->t_state_lock, flags);
- target_stop_task(task, &flags);
+ target_stop_cmd(cmd, &flags);
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- pr_debug("LUN_RESET: Skipping task: %p, dev: %p for"
- " t_task_cdbs_ex_left: %d\n", task, dev,
- atomic_read(&cmd->t_task_cdbs_ex_left));
- continue;
- }
fe_count = atomic_read(&cmd->t_fe_count);
if (!(cmd->transport_state & CMD_T_ACTIVE)) {
pr_debug("LUN_RESET: got CMD_T_ACTIVE for"
- " task: %p, t_fe_count: %d dev: %p\n", task,
+ " cdb: %p, t_fe_count: %d dev: %p\n", cmd,
fe_count, dev);
cmd->transport_state |= CMD_T_ABORTED;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -364,8 +345,8 @@ static void core_tmr_drain_task_list(
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
continue;
}
- pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for task: %p,"
- " t_fe_count: %d dev: %p\n", task, fe_count, dev);
+ pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for cdb: %p,"
+ " t_fe_count: %d dev: %p\n", cmd, fe_count, dev);
cmd->transport_state |= CMD_T_ABORTED;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -384,13 +365,11 @@ static void core_tmr_drain_cmd_list(
struct se_queue_obj *qobj = &dev->dev_queue_obj;
struct se_cmd *cmd, *tcmd;
unsigned long flags;
+
/*
- * Release all commands remaining in the struct se_device cmd queue.
+ * Release all commands remaining in the per-device command queue.
*
- * This follows the same logic as above for the struct se_device
- * struct se_task state list, where commands are returned with
- * TASK_ABORTED status, if there is an outstanding $FABRIC_MOD
- * reference, otherwise the struct se_cmd is released.
+ * This follows the same logic as above for the state list.
*/
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
list_for_each_entry_safe(cmd, tcmd, &qobj->qobj_list, se_queue_node) {
@@ -466,7 +445,7 @@ int core_tmr_lun_reset(
dev->transport->name, tas);
core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
- core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas,
+ core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas,
preempt_and_abort_list);
core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas,
preempt_and_abort_list);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index e320ec2..8bd58e2 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -153,10 +153,7 @@ void core_tpg_add_node_to_devs(
* demo_mode_write_protect is ON, or READ_ONLY;
*/
if (!tpg->se_tpg_tfo->tpg_check_demo_mode_write_protect(tpg)) {
- if (dev->dev_flags & DF_READ_ONLY)
- lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
- else
- lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
} else {
/*
* Allow only optical drives to issue R/W in default RO
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 443704f..b05fdc0 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -72,7 +72,6 @@ static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *);
static void transport_complete_task_attr(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
struct se_device *dev);
-static void transport_free_dev_tasks(struct se_cmd *cmd);
static int transport_generic_get_mem(struct se_cmd *cmd);
static void transport_put_cmd(struct se_cmd *cmd);
static void transport_remove_cmd_from_queue(struct se_cmd *cmd);
@@ -331,9 +330,9 @@ void target_get_session(struct se_session *se_sess)
}
EXPORT_SYMBOL(target_get_session);
-int target_put_session(struct se_session *se_sess)
+void target_put_session(struct se_session *se_sess)
{
- return kref_put(&se_sess->sess_kref, target_release_session);
+ kref_put(&se_sess->sess_kref, target_release_session);
}
EXPORT_SYMBOL(target_put_session);
@@ -444,31 +443,23 @@ EXPORT_SYMBOL(transport_deregister_session);
/*
* Called with cmd->t_state_lock held.
*/
-static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
+static void target_remove_from_state_list(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
- struct se_task *task;
unsigned long flags;
if (!dev)
return;
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (task->task_flags & TF_ACTIVE)
- continue;
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- if (task->t_state_active) {
- pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n",
- cmd->se_tfo->get_task_tag(cmd), dev, task);
+ if (cmd->transport_state & CMD_T_BUSY)
+ return;
- list_del(&task->t_state_list);
- atomic_dec(&cmd->t_task_cdbs_ex_left);
- task->t_state_active = false;
- }
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ if (cmd->state_active) {
+ list_del(&cmd->state_list);
+ cmd->state_active = false;
}
-
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
/* transport_cmd_check_stop():
@@ -497,7 +488,7 @@ static int transport_cmd_check_stop(
cmd->transport_state &= ~CMD_T_ACTIVE;
if (transport_off == 2)
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
complete(&cmd->transport_lun_stop_comp);
@@ -513,7 +504,7 @@ static int transport_cmd_check_stop(
cmd->se_tfo->get_task_tag(cmd));
if (transport_off == 2)
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
/*
* Clear struct se_cmd->se_lun before the transport_off == 2 handoff
@@ -529,7 +520,7 @@ static int transport_cmd_check_stop(
if (transport_off) {
cmd->transport_state &= ~CMD_T_ACTIVE;
if (transport_off == 2) {
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
/*
* Clear struct se_cmd->se_lun before the transport_off == 2
* handoff to fabric module.
@@ -577,7 +568,7 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -669,29 +660,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd)
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
}
-/*
- * Completion function used by TCM subsystem plugins (such as FILEIO)
- * for queueing up response from struct se_subsystem_api->do_task()
- */
-void transport_complete_sync_cache(struct se_cmd *cmd, int good)
-{
- struct se_task *task = list_entry(cmd->t_task_list.next,
- struct se_task, t_list);
-
- if (good) {
- cmd->scsi_status = SAM_STAT_GOOD;
- task->task_scsi_status = GOOD;
- } else {
- task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
- task->task_se_cmd->scsi_sense_reason =
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
- }
-
- transport_complete_task(task, good);
-}
-EXPORT_SYMBOL(transport_complete_sync_cache);
-
static void target_complete_failure_work(struct work_struct *work)
{
struct se_cmd *cmd = container_of(work, struct se_cmd, work);
@@ -699,40 +667,32 @@ static void target_complete_failure_work(struct work_struct *work)
transport_generic_request_failure(cmd);
}
-/* transport_complete_task():
- *
- * Called from interrupt and non interrupt context depending
- * on the transport plugin.
- */
-void transport_complete_task(struct se_task *task, int success)
+void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
{
- struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
+ int success = scsi_status == GOOD;
unsigned long flags;
+ cmd->scsi_status = scsi_status;
+
+
spin_lock_irqsave(&cmd->t_state_lock, flags);
- task->task_flags &= ~TF_ACTIVE;
+ cmd->transport_state &= ~CMD_T_BUSY;
- /*
- * See if any sense data exists, if so set the TASK_SENSE flag.
- * Also check for any other post completion work that needs to be
- * done by the plugins.
- */
if (dev && dev->transport->transport_complete) {
- if (dev->transport->transport_complete(task) != 0) {
+ if (dev->transport->transport_complete(cmd,
+ cmd->t_data_sg) != 0) {
cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
- task->task_flags |= TF_HAS_SENSE;
success = 1;
}
}
/*
- * See if we are waiting for outstanding struct se_task
- * to complete for an exception condition
+ * See if we are waiting to complete for an exception condition.
*/
- if (task->task_flags & TF_REQUEST_STOP) {
+ if (cmd->transport_state & CMD_T_REQUEST_STOP) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- complete(&task->task_stop_comp);
+ complete(&cmd->task_stop_comp);
return;
}
@@ -740,15 +700,6 @@ void transport_complete_task(struct se_task *task, int success)
cmd->transport_state |= CMD_T_FAILED;
/*
- * Decrement the outstanding t_task_cdbs_left count. The last
- * struct se_task from struct se_cmd will complete itself into the
- * device queue depending upon int success.
- */
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- /*
* Check for case where an explict ABORT_TASK has been received
* and transport_wait_for_tasks() will be waiting for completion..
*/
@@ -770,157 +721,77 @@ void transport_complete_task(struct se_task *task, int success)
queue_work(target_completion_wq, &cmd->work);
}
-EXPORT_SYMBOL(transport_complete_task);
-
-/*
- * Called by transport_add_tasks_from_cmd() once a struct se_cmd's
- * struct se_task list are ready to be added to the active execution list
- * struct se_device
+EXPORT_SYMBOL(target_complete_cmd);
- * Called with se_dev_t->execute_task_lock called.
- */
-static inline int transport_add_task_check_sam_attr(
- struct se_task *task,
- struct se_task *task_prev,
- struct se_device *dev)
+static void target_add_to_state_list(struct se_cmd *cmd)
{
- /*
- * No SAM Task attribute emulation enabled, add to tail of
- * execution queue
- */
- if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) {
- list_add_tail(&task->t_execute_list, &dev->execute_task_list);
- return 0;
- }
- /*
- * HEAD_OF_QUEUE attribute for received CDB, which means
- * the first task that is associated with a struct se_cmd goes to
- * head of the struct se_device->execute_task_list, and task_prev
- * after that for each subsequent task
- */
- if (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG) {
- list_add(&task->t_execute_list,
- (task_prev != NULL) ?
- &task_prev->t_execute_list :
- &dev->execute_task_list);
-
- pr_debug("Set HEAD_OF_QUEUE for task CDB: 0x%02x"
- " in execution queue\n",
- task->task_se_cmd->t_task_cdb[0]);
- return 1;
+ struct se_device *dev = cmd->se_dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ if (!cmd->state_active) {
+ list_add_tail(&cmd->state_list, &dev->state_list);
+ cmd->state_active = true;
}
- /*
- * For ORDERED, SIMPLE or UNTAGGED attribute tasks once they have been
- * transitioned from Dermant -> Active state, and are added to the end
- * of the struct se_device->execute_task_list
- */
- list_add_tail(&task->t_execute_list, &dev->execute_task_list);
- return 0;
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
-/* __transport_add_task_to_execute_queue():
- *
- * Called with se_dev_t->execute_task_lock called.
- */
-static void __transport_add_task_to_execute_queue(
- struct se_task *task,
- struct se_task *task_prev,
- struct se_device *dev)
+static void __target_add_to_execute_list(struct se_cmd *cmd)
{
- int head_of_queue;
-
- head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev);
- atomic_inc(&dev->execute_tasks);
+ struct se_device *dev = cmd->se_dev;
+ bool head_of_queue = false;
- if (task->t_state_active)
+ if (!list_empty(&cmd->execute_list))
return;
- /*
- * Determine if this task needs to go to HEAD_OF_QUEUE for the
- * state list as well. Running with SAM Task Attribute emulation
- * will always return head_of_queue == 0 here
- */
- if (head_of_queue)
- list_add(&task->t_state_list, (task_prev) ?
- &task_prev->t_state_list :
- &dev->state_task_list);
- else
- list_add_tail(&task->t_state_list, &dev->state_task_list);
- task->t_state_active = true;
+ if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED &&
+ cmd->sam_task_attr == MSG_HEAD_TAG)
+ head_of_queue = true;
- pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n",
- task->task_se_cmd->se_tfo->get_task_tag(task->task_se_cmd),
- task, dev);
-}
+ if (head_of_queue)
+ list_add(&cmd->execute_list, &dev->execute_list);
+ else
+ list_add_tail(&cmd->execute_list, &dev->execute_list);
-static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- struct se_task *task;
- unsigned long flags;
+ atomic_inc(&dev->execute_tasks);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- spin_lock(&dev->execute_task_lock);
- if (!task->t_state_active) {
- list_add_tail(&task->t_state_list,
- &dev->state_task_list);
- task->t_state_active = true;
-
- pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n",
- task->task_se_cmd->se_tfo->get_task_tag(
- task->task_se_cmd), task, dev);
- }
- spin_unlock(&dev->execute_task_lock);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-}
+ if (cmd->state_active)
+ return;
-static void __transport_add_tasks_from_cmd(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- struct se_task *task, *task_prev = NULL;
+ if (head_of_queue)
+ list_add(&cmd->state_list, &dev->state_list);
+ else
+ list_add_tail(&cmd->state_list, &dev->state_list);
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (!list_empty(&task->t_execute_list))
- continue;
- /*
- * __transport_add_task_to_execute_queue() handles the
- * SAM Task Attribute emulation if enabled
- */
- __transport_add_task_to_execute_queue(task, task_prev, dev);
- task_prev = task;
- }
+ cmd->state_active = true;
}
-static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
+static void target_add_to_execute_list(struct se_cmd *cmd)
{
unsigned long flags;
struct se_device *dev = cmd->se_dev;
spin_lock_irqsave(&dev->execute_task_lock, flags);
- __transport_add_tasks_from_cmd(cmd);
+ __target_add_to_execute_list(cmd);
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
-void __transport_remove_task_from_execute_queue(struct se_task *task,
- struct se_device *dev)
+void __target_remove_from_execute_list(struct se_cmd *cmd)
{
- list_del_init(&task->t_execute_list);
- atomic_dec(&dev->execute_tasks);
+ list_del_init(&cmd->execute_list);
+ atomic_dec(&cmd->se_dev->execute_tasks);
}
-static void transport_remove_task_from_execute_queue(
- struct se_task *task,
- struct se_device *dev)
+static void target_remove_from_execute_list(struct se_cmd *cmd)
{
+ struct se_device *dev = cmd->se_dev;
unsigned long flags;
- if (WARN_ON(list_empty(&task->t_execute_list)))
+ if (WARN_ON(list_empty(&cmd->execute_list)))
return;
spin_lock_irqsave(&dev->execute_task_lock, flags);
- __transport_remove_task_from_execute_queue(task, dev);
+ __target_remove_from_execute_list(cmd);
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
@@ -999,8 +870,9 @@ void transport_dump_dev_state(
*bl += sprintf(b + *bl, " Execute/Max Queue Depth: %d/%d",
atomic_read(&dev->execute_tasks), dev->queue_depth);
- *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n",
- dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.max_sectors);
+ *bl += sprintf(b + *bl, " SectorSize: %u HwMaxSectors: %u\n",
+ dev->se_sub_dev->se_dev_attrib.block_size,
+ dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
*bl += sprintf(b + *bl, " ");
}
@@ -1344,9 +1216,9 @@ struct se_device *transport_add_device_to_core_hba(
INIT_LIST_HEAD(&dev->dev_list);
INIT_LIST_HEAD(&dev->dev_sep_list);
INIT_LIST_HEAD(&dev->dev_tmr_list);
- INIT_LIST_HEAD(&dev->execute_task_list);
+ INIT_LIST_HEAD(&dev->execute_list);
INIT_LIST_HEAD(&dev->delayed_cmd_list);
- INIT_LIST_HEAD(&dev->state_task_list);
+ INIT_LIST_HEAD(&dev->state_list);
INIT_LIST_HEAD(&dev->qf_cmd_list);
spin_lock_init(&dev->execute_task_lock);
spin_lock_init(&dev->delayed_cmd_lock);
@@ -1457,6 +1329,7 @@ static inline void transport_generic_prepare_cdb(
case VERIFY_16: /* SBC - VRProtect */
case WRITE_VERIFY: /* SBC - VRProtect */
case WRITE_VERIFY_12: /* SBC - VRProtect */
+ case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
break;
default:
cdb[1] &= 0x1f; /* clear logical unit number */
@@ -1464,29 +1337,6 @@ static inline void transport_generic_prepare_cdb(
}
}
-static struct se_task *
-transport_generic_get_task(struct se_cmd *cmd,
- enum dma_data_direction data_direction)
-{
- struct se_task *task;
- struct se_device *dev = cmd->se_dev;
-
- task = dev->transport->alloc_task(cmd->t_task_cdb);
- if (!task) {
- pr_err("Unable to allocate struct se_task\n");
- return NULL;
- }
-
- INIT_LIST_HEAD(&task->t_list);
- INIT_LIST_HEAD(&task->t_execute_list);
- INIT_LIST_HEAD(&task->t_state_list);
- init_completion(&task->task_stop_comp);
- task->task_se_cmd = cmd;
- task->task_data_direction = data_direction;
-
- return task;
-}
-
static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
/*
@@ -1507,11 +1357,13 @@ void transport_init_se_cmd(
INIT_LIST_HEAD(&cmd->se_qf_node);
INIT_LIST_HEAD(&cmd->se_queue_node);
INIT_LIST_HEAD(&cmd->se_cmd_list);
- INIT_LIST_HEAD(&cmd->t_task_list);
+ INIT_LIST_HEAD(&cmd->execute_list);
+ INIT_LIST_HEAD(&cmd->state_list);
init_completion(&cmd->transport_lun_fe_stop_comp);
init_completion(&cmd->transport_lun_stop_comp);
init_completion(&cmd->t_transport_stop_comp);
init_completion(&cmd->cmd_wait_comp);
+ init_completion(&cmd->task_stop_comp);
spin_lock_init(&cmd->t_state_lock);
cmd->transport_state = CMD_T_DEV_ACTIVE;
@@ -1521,6 +1373,8 @@ void transport_init_se_cmd(
cmd->data_direction = data_direction;
cmd->sam_task_attr = task_attr;
cmd->sense_buffer = sense_buffer;
+
+ cmd->state_active = false;
}
EXPORT_SYMBOL(transport_init_se_cmd);
@@ -1550,11 +1404,11 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd)
return 0;
}
-/* transport_generic_allocate_tasks():
+/* target_setup_cmd_from_cdb():
*
* Called from fabric RX Thread.
*/
-int transport_generic_allocate_tasks(
+int target_setup_cmd_from_cdb(
struct se_cmd *cmd,
unsigned char *cdb)
{
@@ -1620,7 +1474,7 @@ int transport_generic_allocate_tasks(
spin_unlock(&cmd->se_lun->lun_sep_lock);
return 0;
}
-EXPORT_SYMBOL(transport_generic_allocate_tasks);
+EXPORT_SYMBOL(target_setup_cmd_from_cdb);
/*
* Used by fabric module frontends to queue tasks directly.
@@ -1701,6 +1555,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
*/
transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
data_length, data_dir, task_attr, sense);
+ if (flags & TARGET_SCF_UNKNOWN_SIZE)
+ se_cmd->unknown_data_length = 1;
/*
* Obtain struct se_cmd->cmd_kref reference and add new cmd to
* se_sess->sess_cmd_list. A second kref_get here is necessary
@@ -1726,11 +1582,18 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
* Sanitize CDBs via transport_generic_cmd_sequencer() and
* allocate the necessary tasks to complete the received CDB+data
*/
- rc = transport_generic_allocate_tasks(se_cmd, cdb);
+ rc = target_setup_cmd_from_cdb(se_cmd, cdb);
if (rc != 0) {
transport_generic_request_failure(se_cmd);
return;
}
+
+ /*
+ * Check if we need to delay processing because of ALUA
+ * Active/NonOptimized primary access state..
+ */
+ core_alua_check_nonop_delay(se_cmd);
+
/*
* Dispatch se_cmd descriptor to se_lun->lun_se_dev backend
* for immediate execution of READs, otherwise wait for
@@ -1872,72 +1735,30 @@ int transport_generic_handle_tmr(
EXPORT_SYMBOL(transport_generic_handle_tmr);
/*
- * If the task is active, request it to be stopped and sleep until it
+ * If the cmd is active, request it to be stopped and sleep until it
* has completed.
*/
-bool target_stop_task(struct se_task *task, unsigned long *flags)
+bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
{
- struct se_cmd *cmd = task->task_se_cmd;
bool was_active = false;
- if (task->task_flags & TF_ACTIVE) {
- task->task_flags |= TF_REQUEST_STOP;
+ if (cmd->transport_state & CMD_T_BUSY) {
+ cmd->transport_state |= CMD_T_REQUEST_STOP;
spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
- pr_debug("Task %p waiting to complete\n", task);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("Task %p stopped successfully\n", task);
+ pr_debug("cmd %p waiting to complete\n", cmd);
+ wait_for_completion(&cmd->task_stop_comp);
+ pr_debug("cmd %p stopped successfully\n", cmd);
spin_lock_irqsave(&cmd->t_state_lock, *flags);
- atomic_dec(&cmd->t_task_cdbs_left);
- task->task_flags &= ~(TF_ACTIVE | TF_REQUEST_STOP);
+ cmd->transport_state &= ~CMD_T_REQUEST_STOP;
+ cmd->transport_state &= ~CMD_T_BUSY;
was_active = true;
}
return was_active;
}
-static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
-{
- struct se_task *task, *task_tmp;
- unsigned long flags;
- int ret = 0;
-
- pr_debug("ITT[0x%08x] - Stopping tasks\n",
- cmd->se_tfo->get_task_tag(cmd));
-
- /*
- * No tasks remain in the execution queue
- */
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_for_each_entry_safe(task, task_tmp,
- &cmd->t_task_list, t_list) {
- pr_debug("Processing task %p\n", task);
- /*
- * If the struct se_task has not been sent and is not active,
- * remove the struct se_task from the execution queue.
- */
- if (!(task->task_flags & (TF_ACTIVE | TF_SENT))) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- transport_remove_task_from_execute_queue(task,
- cmd->se_dev);
-
- pr_debug("Task %p removed from execute queue\n", task);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- continue;
- }
-
- if (!target_stop_task(task, &flags)) {
- pr_debug("Task %p - did nothing\n", task);
- ret++;
- }
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- return ret;
-}
-
/*
* Handle SAM-esque emulation for generic transport request failures.
*/
@@ -1951,13 +1772,7 @@ void transport_generic_request_failure(struct se_cmd *cmd)
pr_debug("-----[ i_state: %d t_state: %d scsi_sense_reason: %d\n",
cmd->se_tfo->get_cmd_state(cmd),
cmd->t_state, cmd->scsi_sense_reason);
- pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d"
- " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
- " CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n",
- cmd->t_task_list_num,
- atomic_read(&cmd->t_task_cdbs_left),
- atomic_read(&cmd->t_task_cdbs_sent),
- atomic_read(&cmd->t_task_cdbs_ex_left),
+ pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n",
(cmd->transport_state & CMD_T_ACTIVE) != 0,
(cmd->transport_state & CMD_T_STOP) != 0,
(cmd->transport_state & CMD_T_SENT) != 0);
@@ -2156,7 +1971,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd)
* Called from fabric module context in transport_generic_new_cmd() and
* transport_generic_process_write()
*/
-static int transport_execute_tasks(struct se_cmd *cmd)
+static void transport_execute_tasks(struct se_cmd *cmd)
{
int add_tasks;
struct se_device *se_dev = cmd->se_dev;
@@ -2170,71 +1985,52 @@ static int transport_execute_tasks(struct se_cmd *cmd)
* attribute for the tasks of the received struct se_cmd CDB
*/
add_tasks = transport_execute_task_attr(cmd);
- if (!add_tasks)
- goto execute_tasks;
- /*
- * __transport_execute_tasks() -> __transport_add_tasks_from_cmd()
- * adds associated se_tasks while holding dev->execute_task_lock
- * before I/O dispath to avoid a double spinlock access.
- */
- __transport_execute_tasks(se_dev, cmd);
- return 0;
+ if (add_tasks) {
+ __transport_execute_tasks(se_dev, cmd);
+ return;
+ }
}
-
-execute_tasks:
__transport_execute_tasks(se_dev, NULL);
- return 0;
}
-/*
- * Called to check struct se_device tcq depth window, and once open pull struct se_task
- * from struct se_device->execute_task_list and
- *
- * Called from transport_processing_thread()
- */
static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd)
{
int error;
struct se_cmd *cmd = NULL;
- struct se_task *task = NULL;
unsigned long flags;
check_depth:
spin_lock_irq(&dev->execute_task_lock);
if (new_cmd != NULL)
- __transport_add_tasks_from_cmd(new_cmd);
+ __target_add_to_execute_list(new_cmd);
- if (list_empty(&dev->execute_task_list)) {
+ if (list_empty(&dev->execute_list)) {
spin_unlock_irq(&dev->execute_task_lock);
return 0;
}
- task = list_first_entry(&dev->execute_task_list,
- struct se_task, t_execute_list);
- __transport_remove_task_from_execute_queue(task, dev);
+ cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list);
+ __target_remove_from_execute_list(cmd);
spin_unlock_irq(&dev->execute_task_lock);
- cmd = task->task_se_cmd;
spin_lock_irqsave(&cmd->t_state_lock, flags);
- task->task_flags |= (TF_ACTIVE | TF_SENT);
- atomic_inc(&cmd->t_task_cdbs_sent);
-
- if (atomic_read(&cmd->t_task_cdbs_sent) ==
- cmd->t_task_list_num)
- cmd->transport_state |= CMD_T_SENT;
+ cmd->transport_state |= CMD_T_BUSY;
+ cmd->transport_state |= CMD_T_SENT;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (cmd->execute_task)
- error = cmd->execute_task(task);
- else
- error = dev->transport->do_task(task);
+ if (cmd->execute_cmd)
+ error = cmd->execute_cmd(cmd);
+ else {
+ error = dev->transport->execute_cmd(cmd, cmd->t_data_sg,
+ cmd->t_data_nents, cmd->data_direction);
+ }
+
if (error != 0) {
spin_lock_irqsave(&cmd->t_state_lock, flags);
- task->task_flags &= ~TF_ACTIVE;
+ cmd->transport_state &= ~CMD_T_BUSY;
cmd->transport_state &= ~CMD_T_SENT;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_stop_tasks_for_cmd(cmd);
transport_generic_request_failure(cmd);
}
@@ -2392,12 +2188,12 @@ static inline u32 transport_get_size(
} else /* bytes */
return sectors;
}
-#if 0
+
pr_debug("Returning block_size: %u, sectors: %u == %u for"
- " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, sectors,
- dev->se_sub_dev->se_dev_attrib.block_size * sectors,
- dev->transport->name);
-#endif
+ " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size,
+ sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors,
+ dev->transport->name);
+
return dev->se_sub_dev->se_dev_attrib.block_size * sectors;
}
@@ -2462,7 +2258,6 @@ static int transport_get_sense_data(struct se_cmd *cmd)
{
unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
struct se_device *dev = cmd->se_dev;
- struct se_task *task = NULL, *task_tmp;
unsigned long flags;
u32 offset = 0;
@@ -2477,44 +2272,37 @@ static int transport_get_sense_data(struct se_cmd *cmd)
return 0;
}
- list_for_each_entry_safe(task, task_tmp,
- &cmd->t_task_list, t_list) {
- if (!(task->task_flags & TF_HAS_SENSE))
- continue;
-
- if (!dev->transport->get_sense_buffer) {
- pr_err("dev->transport->get_sense_buffer"
- " is NULL\n");
- continue;
- }
-
- sense_buffer = dev->transport->get_sense_buffer(task);
- if (!sense_buffer) {
- pr_err("ITT[0x%08x]_TASK[%p]: Unable to locate"
- " sense buffer for task with sense\n",
- cmd->se_tfo->get_task_tag(cmd), task);
- continue;
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
+ goto out;
- offset = cmd->se_tfo->set_fabric_sense_len(cmd,
- TRANSPORT_SENSE_BUFFER);
+ if (!dev->transport->get_sense_buffer) {
+ pr_err("dev->transport->get_sense_buffer is NULL\n");
+ goto out;
+ }
- memcpy(&buffer[offset], sense_buffer,
- TRANSPORT_SENSE_BUFFER);
- cmd->scsi_status = task->task_scsi_status;
- /* Automatically padded */
- cmd->scsi_sense_length =
- (TRANSPORT_SENSE_BUFFER + offset);
-
- pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x"
- " and sense\n",
- dev->se_hba->hba_id, dev->transport->name,
- cmd->scsi_status);
- return 0;
+ sense_buffer = dev->transport->get_sense_buffer(cmd);
+ if (!sense_buffer) {
+ pr_err("ITT 0x%08x cmd %p: Unable to locate"
+ " sense buffer for task with sense\n",
+ cmd->se_tfo->get_task_tag(cmd), cmd);
+ goto out;
}
+
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
+
+ memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
+
+ /* Automatically padded */
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+
+ pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
+ dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
+ return 0;
+
+out:
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return -1;
}
@@ -2581,7 +2369,7 @@ static int target_check_write_same_discard(unsigned char *flags, struct se_devic
* Generic Command Sequencer that should work for most DAS transport
* drivers.
*
- * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD
+ * Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD
* RX Thread.
*
* FIXME: Need to support other SCSI OPCODES where as well.
@@ -2615,11 +2403,10 @@ static int transport_generic_cmd_sequencer(
* by the ALUA primary or secondary access state..
*/
if (ret > 0) {
-#if 0
pr_debug("[%s]: ALUA TG Port not available,"
" SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n",
cmd->se_tfo->get_fabric_name(), alua_ascq);
-#endif
+
transport_set_sense_codes(cmd, 0x04, alua_ascq);
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
@@ -2695,6 +2482,7 @@ static int transport_generic_cmd_sequencer(
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
case WRITE_10:
+ case WRITE_VERIFY:
sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
@@ -2796,7 +2584,7 @@ static int transport_generic_cmd_sequencer(
if (target_check_write_same_discard(&cdb[10], dev) < 0)
goto out_unsupported_cdb;
if (!passthrough)
- cmd->execute_task = target_emulate_write_same;
+ cmd->execute_cmd = target_emulate_write_same;
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
@@ -2810,9 +2598,9 @@ static int transport_generic_cmd_sequencer(
/*
* Check for emulated MI_REPORT_TARGET_PGS.
*/
- if (cdb[1] == MI_REPORT_TARGET_PGS &&
+ if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
- cmd->execute_task =
+ cmd->execute_cmd =
target_emulate_report_target_port_groups;
}
size = (cdb[6] << 24) | (cdb[7] << 16) |
@@ -2835,13 +2623,13 @@ static int transport_generic_cmd_sequencer(
size = cdb[4];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_modesense;
+ cmd->execute_cmd = target_emulate_modesense;
break;
case MODE_SENSE_10:
size = (cdb[7] << 8) + cdb[8];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_modesense;
+ cmd->execute_cmd = target_emulate_modesense;
break;
case GPCMD_READ_BUFFER_CAPACITY:
case GPCMD_SEND_OPC:
@@ -2863,13 +2651,13 @@ static int transport_generic_cmd_sequencer(
break;
case PERSISTENT_RESERVE_IN:
if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
- cmd->execute_task = target_scsi3_emulate_pr_in;
+ cmd->execute_cmd = target_scsi3_emulate_pr_in;
size = (cdb[7] << 8) + cdb[8];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case PERSISTENT_RESERVE_OUT:
if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
- cmd->execute_task = target_scsi3_emulate_pr_out;
+ cmd->execute_cmd = target_scsi3_emulate_pr_out;
size = (cdb[7] << 8) + cdb[8];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
@@ -2890,7 +2678,7 @@ static int transport_generic_cmd_sequencer(
*/
if (cdb[1] == MO_SET_TARGET_PGS &&
su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
- cmd->execute_task =
+ cmd->execute_cmd =
target_emulate_set_target_port_groups;
}
@@ -2912,7 +2700,7 @@ static int transport_generic_cmd_sequencer(
cmd->sam_task_attr = MSG_HEAD_TAG;
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_inquiry;
+ cmd->execute_cmd = target_emulate_inquiry;
break;
case READ_BUFFER:
size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
@@ -2922,7 +2710,7 @@ static int transport_generic_cmd_sequencer(
size = READ_CAP_LEN;
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_readcapacity;
+ cmd->execute_cmd = target_emulate_readcapacity;
break;
case READ_MEDIA_SERIAL_NUMBER:
case SECURITY_PROTOCOL_IN:
@@ -2934,7 +2722,7 @@ static int transport_generic_cmd_sequencer(
switch (cmd->t_task_cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
if (!passthrough)
- cmd->execute_task =
+ cmd->execute_cmd =
target_emulate_readcapacity_16;
break;
default:
@@ -2977,7 +2765,7 @@ static int transport_generic_cmd_sequencer(
size = cdb[4];
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_request_sense;
+ cmd->execute_cmd = target_emulate_request_sense;
break;
case READ_ELEMENT_STATUS:
size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
@@ -3006,7 +2794,7 @@ static int transport_generic_cmd_sequencer(
* emulation disabled.
*/
if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
- cmd->execute_task = target_scsi2_reservation_reserve;
+ cmd->execute_cmd = target_scsi2_reservation_reserve;
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case RELEASE:
@@ -3021,7 +2809,7 @@ static int transport_generic_cmd_sequencer(
size = cmd->data_length;
if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
- cmd->execute_task = target_scsi2_reservation_release;
+ cmd->execute_cmd = target_scsi2_reservation_release;
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case SYNCHRONIZE_CACHE:
@@ -3053,13 +2841,13 @@ static int transport_generic_cmd_sequencer(
if (transport_cmd_get_valid_sectors(cmd) < 0)
goto out_invalid_cdb_field;
}
- cmd->execute_task = target_emulate_synchronize_cache;
+ cmd->execute_cmd = target_emulate_synchronize_cache;
break;
case UNMAP:
size = get_unaligned_be16(&cdb[7]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_unmap;
+ cmd->execute_cmd = target_emulate_unmap;
break;
case WRITE_SAME_16:
sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
@@ -3079,7 +2867,7 @@ static int transport_generic_cmd_sequencer(
if (target_check_write_same_discard(&cdb[1], dev) < 0)
goto out_unsupported_cdb;
if (!passthrough)
- cmd->execute_task = target_emulate_write_same;
+ cmd->execute_cmd = target_emulate_write_same;
break;
case WRITE_SAME:
sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
@@ -3102,7 +2890,7 @@ static int transport_generic_cmd_sequencer(
if (target_check_write_same_discard(&cdb[1], dev) < 0)
goto out_unsupported_cdb;
if (!passthrough)
- cmd->execute_task = target_emulate_write_same;
+ cmd->execute_cmd = target_emulate_write_same;
break;
case ALLOW_MEDIUM_REMOVAL:
case ERASE:
@@ -3115,7 +2903,7 @@ static int transport_generic_cmd_sequencer(
case WRITE_FILEMARKS:
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
if (!passthrough)
- cmd->execute_task = target_emulate_noop;
+ cmd->execute_cmd = target_emulate_noop;
break;
case GPCMD_CLOSE_TRACK:
case INITIALIZE_ELEMENT_STATUS:
@@ -3125,7 +2913,7 @@ static int transport_generic_cmd_sequencer(
cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
break;
case REPORT_LUNS:
- cmd->execute_task = target_report_luns;
+ cmd->execute_cmd = target_report_luns;
size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
/*
* Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
@@ -3135,6 +2923,42 @@ static int transport_generic_cmd_sequencer(
cmd->sam_task_attr = MSG_HEAD_TAG;
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
+ case GET_EVENT_STATUS_NOTIFICATION:
+ size = (cdb[7] << 8) | cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case ATA_16:
+ /* Only support ATA passthrough to pSCSI backends.. */
+ if (!passthrough)
+ goto out_unsupported_cdb;
+
+ /* T_LENGTH */
+ switch (cdb[2] & 0x3) {
+ case 0x0:
+ sectors = 0;
+ break;
+ case 0x1:
+ sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4];
+ break;
+ case 0x2:
+ sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6];
+ break;
+ case 0x3:
+ pr_err("T_LENGTH=0x3 not supported for ATA_16\n");
+ goto out_invalid_cdb_field;
+ }
+
+ /* BYTE_BLOCK */
+ if (cdb[2] & 0x4) {
+ /* BLOCK T_TYPE: 512 or sector */
+ size = sectors * ((cdb[2] & 0x10) ?
+ dev->se_sub_dev->se_dev_attrib.block_size : 512);
+ } else {
+ /* BYTE */
+ size = sectors;
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
default:
pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
" 0x%02x, sending CHECK_CONDITION.\n",
@@ -3142,6 +2966,9 @@ static int transport_generic_cmd_sequencer(
goto out_unsupported_cdb;
}
+ if (cmd->unknown_data_length)
+ cmd->data_length = size;
+
if (size != cmd->data_length) {
pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
" %u does not match SCSI CDB Length: %u for SAM Opcode:"
@@ -3177,15 +3004,25 @@ static int transport_generic_cmd_sequencer(
cmd->data_length = size;
}
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB &&
- sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) {
- printk_ratelimited(KERN_ERR "SCSI OP %02xh with too big sectors %u\n",
- cdb[0], sectors);
- goto out_invalid_cdb_field;
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
+ printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+ " big sectors %u exceeds fabric_max_sectors:"
+ " %u\n", cdb[0], sectors,
+ su_dev->se_dev_attrib.fabric_max_sectors);
+ goto out_invalid_cdb_field;
+ }
+ if (sectors > su_dev->se_dev_attrib.hw_max_sectors) {
+ printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+ " big sectors %u exceeds backend hw_max_sectors:"
+ " %u\n", cdb[0], sectors,
+ su_dev->se_dev_attrib.hw_max_sectors);
+ goto out_invalid_cdb_field;
+ }
}
/* reject any command that we don't have a handler for */
- if (!(passthrough || cmd->execute_task ||
+ if (!(passthrough || cmd->execute_cmd ||
(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
goto out_unsupported_cdb;
@@ -3250,7 +3087,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
cmd_p->t_task_cdb[0],
cmd_p->sam_task_attr, cmd_p->se_ordered_id);
- transport_add_tasks_from_cmd(cmd_p);
+ target_add_to_execute_list(cmd_p);
new_active_tasks++;
spin_lock(&dev->delayed_cmd_lock);
@@ -3346,10 +3183,6 @@ static void target_complete_ok_work(struct work_struct *work)
if (transport_get_sense_data(cmd) < 0)
reason = TCM_NON_EXISTENT_LUN;
- /*
- * Only set when an struct se_task->task_scsi_status returned
- * a non GOOD status.
- */
if (cmd->scsi_status) {
ret = transport_send_check_condition_and_sense(
cmd, reason, 1);
@@ -3424,33 +3257,6 @@ queue_full:
transport_handle_queue_full(cmd, cmd->se_dev);
}
-static void transport_free_dev_tasks(struct se_cmd *cmd)
-{
- struct se_task *task, *task_tmp;
- unsigned long flags;
- LIST_HEAD(dispose_list);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_for_each_entry_safe(task, task_tmp,
- &cmd->t_task_list, t_list) {
- if (!(task->task_flags & TF_ACTIVE))
- list_move_tail(&task->t_list, &dispose_list);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- while (!list_empty(&dispose_list)) {
- task = list_first_entry(&dispose_list, struct se_task, t_list);
-
- if (task->task_sg != cmd->t_data_sg &&
- task->task_sg != cmd->t_bidi_data_sg)
- kfree(task->task_sg);
-
- list_del(&task->t_list);
-
- cmd->se_dev->transport->free_task(task);
- }
-}
-
static inline void transport_free_sgl(struct scatterlist *sgl, int nents)
{
struct scatterlist *sg;
@@ -3511,7 +3317,6 @@ static void transport_release_cmd(struct se_cmd *cmd)
static void transport_put_cmd(struct se_cmd *cmd)
{
unsigned long flags;
- int free_tasks = 0;
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (atomic_read(&cmd->t_fe_count)) {
@@ -3519,21 +3324,12 @@ static void transport_put_cmd(struct se_cmd *cmd)
goto out_busy;
}
- if (atomic_read(&cmd->t_se_count)) {
- if (!atomic_dec_and_test(&cmd->t_se_count))
- goto out_busy;
- }
-
if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
- transport_all_task_dev_remove_state(cmd);
- free_tasks = 1;
+ target_remove_from_state_list(cmd);
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (free_tasks != 0)
- transport_free_dev_tasks(cmd);
-
transport_free_pages(cmd);
transport_release_cmd(cmd);
return;
@@ -3683,245 +3479,14 @@ out:
return -ENOMEM;
}
-/* Reduce sectors if they are too long for the device */
-static inline sector_t transport_limit_task_sectors(
- struct se_device *dev,
- unsigned long long lba,
- sector_t sectors)
-{
- sectors = min_t(sector_t, sectors, dev->se_sub_dev->se_dev_attrib.max_sectors);
-
- if (dev->transport->get_device_type(dev) == TYPE_DISK)
- if ((lba + sectors) > transport_dev_end_lba(dev))
- sectors = ((transport_dev_end_lba(dev) - lba) + 1);
-
- return sectors;
-}
-
-
-/*
- * This function can be used by HW target mode drivers to create a linked
- * scatterlist from all contiguously allocated struct se_task->task_sg[].
- * This is intended to be called during the completion path by TCM Core
- * when struct target_core_fabric_ops->check_task_sg_chaining is enabled.
- */
-void transport_do_task_sg_chain(struct se_cmd *cmd)
-{
- struct scatterlist *sg_first = NULL;
- struct scatterlist *sg_prev = NULL;
- int sg_prev_nents = 0;
- struct scatterlist *sg;
- struct se_task *task;
- u32 chained_nents = 0;
- int i;
-
- BUG_ON(!cmd->se_tfo->task_sg_chaining);
-
- /*
- * Walk the struct se_task list and setup scatterlist chains
- * for each contiguously allocated struct se_task->task_sg[].
- */
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (!task->task_sg)
- continue;
-
- if (!sg_first) {
- sg_first = task->task_sg;
- chained_nents = task->task_sg_nents;
- } else {
- sg_chain(sg_prev, sg_prev_nents, task->task_sg);
- chained_nents += task->task_sg_nents;
- }
- /*
- * For the padded tasks, use the extra SGL vector allocated
- * in transport_allocate_data_tasks() for the sg_prev_nents
- * offset into sg_chain() above.
- *
- * We do not need the padding for the last task (or a single
- * task), but in that case we will never use the sg_prev_nents
- * value below which would be incorrect.
- */
- sg_prev_nents = (task->task_sg_nents + 1);
- sg_prev = task->task_sg;
- }
- /*
- * Setup the starting pointer and total t_tasks_sg_linked_no including
- * padding SGs for linking and to mark the end.
- */
- cmd->t_tasks_sg_chained = sg_first;
- cmd->t_tasks_sg_chained_no = chained_nents;
-
- pr_debug("Setup cmd: %p cmd->t_tasks_sg_chained: %p and"
- " t_tasks_sg_chained_no: %u\n", cmd, cmd->t_tasks_sg_chained,
- cmd->t_tasks_sg_chained_no);
-
- for_each_sg(cmd->t_tasks_sg_chained, sg,
- cmd->t_tasks_sg_chained_no, i) {
-
- pr_debug("SG[%d]: %p page: %p length: %d offset: %d\n",
- i, sg, sg_page(sg), sg->length, sg->offset);
- if (sg_is_chain(sg))
- pr_debug("SG: %p sg_is_chain=1\n", sg);
- if (sg_is_last(sg))
- pr_debug("SG: %p sg_is_last=1\n", sg);
- }
-}
-EXPORT_SYMBOL(transport_do_task_sg_chain);
-
-/*
- * Break up cmd into chunks transport can handle
- */
-static int
-transport_allocate_data_tasks(struct se_cmd *cmd,
- enum dma_data_direction data_direction,
- struct scatterlist *cmd_sg, unsigned int sgl_nents)
-{
- struct se_device *dev = cmd->se_dev;
- int task_count, i;
- unsigned long long lba;
- sector_t sectors, dev_max_sectors;
- u32 sector_size;
-
- if (transport_cmd_get_valid_sectors(cmd) < 0)
- return -EINVAL;
-
- dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
- sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
-
- WARN_ON(cmd->data_length % sector_size);
-
- lba = cmd->t_task_lba;
- sectors = DIV_ROUND_UP(cmd->data_length, sector_size);
- task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors);
-
- /*
- * If we need just a single task reuse the SG list in the command
- * and avoid a lot of work.
- */
- if (task_count == 1) {
- struct se_task *task;
- unsigned long flags;
-
- task = transport_generic_get_task(cmd, data_direction);
- if (!task)
- return -ENOMEM;
-
- task->task_sg = cmd_sg;
- task->task_sg_nents = sgl_nents;
-
- task->task_lba = lba;
- task->task_sectors = sectors;
- task->task_size = task->task_sectors * sector_size;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_add_tail(&task->t_list, &cmd->t_task_list);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- return task_count;
- }
-
- for (i = 0; i < task_count; i++) {
- struct se_task *task;
- unsigned int task_size, task_sg_nents_padded;
- struct scatterlist *sg;
- unsigned long flags;
- int count;
-
- task = transport_generic_get_task(cmd, data_direction);
- if (!task)
- return -ENOMEM;
-
- task->task_lba = lba;
- task->task_sectors = min(sectors, dev_max_sectors);
- task->task_size = task->task_sectors * sector_size;
-
- /*
- * This now assumes that passed sg_ents are in PAGE_SIZE chunks
- * in order to calculate the number per task SGL entries
- */
- task->task_sg_nents = DIV_ROUND_UP(task->task_size, PAGE_SIZE);
- /*
- * Check if the fabric module driver is requesting that all
- * struct se_task->task_sg[] be chained together.. If so,
- * then allocate an extra padding SG entry for linking and
- * marking the end of the chained SGL for every task except
- * the last one for (task_count > 1) operation, or skipping
- * the extra padding for the (task_count == 1) case.
- */
- if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) {
- task_sg_nents_padded = (task->task_sg_nents + 1);
- } else
- task_sg_nents_padded = task->task_sg_nents;
-
- task->task_sg = kmalloc(sizeof(struct scatterlist) *
- task_sg_nents_padded, GFP_KERNEL);
- if (!task->task_sg) {
- cmd->se_dev->transport->free_task(task);
- return -ENOMEM;
- }
-
- sg_init_table(task->task_sg, task_sg_nents_padded);
-
- task_size = task->task_size;
-
- /* Build new sgl, only up to task_size */
- for_each_sg(task->task_sg, sg, task->task_sg_nents, count) {
- if (cmd_sg->length > task_size)
- break;
-
- *sg = *cmd_sg;
- task_size -= cmd_sg->length;
- cmd_sg = sg_next(cmd_sg);
- }
-
- lba += task->task_sectors;
- sectors -= task->task_sectors;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_add_tail(&task->t_list, &cmd->t_task_list);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- }
-
- return task_count;
-}
-
-static int
-transport_allocate_control_task(struct se_cmd *cmd)
-{
- struct se_task *task;
- unsigned long flags;
-
- /* Workaround for handling zero-length control CDBs */
- if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
- !cmd->data_length)
- return 0;
-
- task = transport_generic_get_task(cmd, cmd->data_direction);
- if (!task)
- return -ENOMEM;
-
- task->task_sg = cmd->t_data_sg;
- task->task_size = cmd->data_length;
- task->task_sg_nents = cmd->t_data_nents;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_add_tail(&task->t_list, &cmd->t_task_list);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- /* Success! Return number of tasks allocated */
- return 1;
-}
-
/*
- * Allocate any required ressources to execute the command, and either place
- * it on the execution queue if possible. For writes we might not have the
- * payload yet, thus notify the fabric via a call to ->write_pending instead.
+ * Allocate any required resources to execute the command. For writes we
+ * might not have the payload yet, so notify the fabric via a call to
+ * ->write_pending instead. Otherwise place it on the execution queue.
*/
int transport_generic_new_cmd(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
- int task_cdbs, task_cdbs_bidi = 0;
- int set_counts = 1;
int ret = 0;
/*
@@ -3936,35 +3501,9 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
goto out_fail;
}
- /*
- * For BIDI command set up the read tasks first.
- */
- if (cmd->t_bidi_data_sg &&
- dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
- BUG_ON(!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB));
-
- task_cdbs_bidi = transport_allocate_data_tasks(cmd,
- DMA_FROM_DEVICE, cmd->t_bidi_data_sg,
- cmd->t_bidi_data_nents);
- if (task_cdbs_bidi <= 0)
- goto out_fail;
-
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
- set_counts = 0;
- }
-
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
- task_cdbs = transport_allocate_data_tasks(cmd,
- cmd->data_direction, cmd->t_data_sg,
- cmd->t_data_nents);
- } else {
- task_cdbs = transport_allocate_control_task(cmd);
- }
-
- if (task_cdbs < 0)
- goto out_fail;
- else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) {
+ /* Workaround for handling zero-length control CDBs */
+ if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
+ !cmd->data_length) {
spin_lock_irq(&cmd->t_state_lock);
cmd->t_state = TRANSPORT_COMPLETE;
cmd->transport_state |= CMD_T_ACTIVE;
@@ -3982,29 +3521,31 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
return 0;
}
- if (set_counts) {
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib;
+
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ return -EINVAL;
+
+ BUG_ON(cmd->data_length % attr->block_size);
+ BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) >
+ attr->hw_max_sectors);
}
- cmd->t_task_list_num = (task_cdbs + task_cdbs_bidi);
- atomic_set(&cmd->t_task_cdbs_left, cmd->t_task_list_num);
- atomic_set(&cmd->t_task_cdbs_ex_left, cmd->t_task_list_num);
+ atomic_inc(&cmd->t_fe_count);
/*
- * For WRITEs, let the fabric know its buffer is ready..
- * This WRITE struct se_cmd (and all of its associated struct se_task's)
- * will be added to the struct se_device execution queue after its WRITE
- * data has arrived. (ie: It gets handled by the transport processing
- * thread a second time)
+ * For WRITEs, let the fabric know its buffer is ready.
+ *
+ * The command will be added to the execution queue after its write
+ * data has arrived.
*/
if (cmd->data_direction == DMA_TO_DEVICE) {
- transport_add_tasks_to_state_queue(cmd);
+ target_add_to_state_list(cmd);
return transport_generic_write_pending(cmd);
}
/*
- * Everything else but a WRITE, add the struct se_cmd's struct se_task's
- * to the execution queue.
+ * Everything else but a WRITE, add the command to the execution queue.
*/
transport_execute_tasks(cmd);
return 0;
@@ -4091,8 +3632,6 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
- transport_free_dev_tasks(cmd);
-
transport_put_cmd(cmd);
}
}
@@ -4233,7 +3772,8 @@ EXPORT_SYMBOL(target_wait_for_sess_cmds);
static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
{
unsigned long flags;
- int ret;
+ int ret = 0;
+
/*
* If the frontend has already requested this struct se_cmd to
* be stopped, we can safely ignore this struct se_cmd.
@@ -4253,10 +3793,21 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq);
- ret = transport_stop_tasks_for_cmd(cmd);
+ // XXX: audit task_flags checks.
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if ((cmd->transport_state & CMD_T_BUSY) &&
+ (cmd->transport_state & CMD_T_SENT)) {
+ if (!target_stop_cmd(cmd, &flags))
+ ret++;
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cmd->t_state_lock,
+ flags);
+ target_remove_from_execute_list(cmd);
+ }
- pr_debug("ConfigFS: cmd: %p t_tasks: %d stop tasks ret:"
- " %d\n", cmd, cmd->t_task_list_num, ret);
+ pr_debug("ConfigFS: cmd: %p stop tasks ret:"
+ " %d\n", cmd, ret);
if (!ret) {
pr_debug("ConfigFS: ITT[0x%08x] - stopping cmd....\n",
cmd->se_tfo->get_task_tag(cmd));
@@ -4328,10 +3879,9 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun)
goto check_cond;
}
cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags);
- transport_free_dev_tasks(cmd);
/*
* The Storage engine stopped this struct se_cmd before it was
* send to the fabric frontend for delivery back to the
@@ -4444,7 +3994,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
wait_for_completion(&cmd->transport_lun_fe_stop_comp);
spin_lock_irqsave(&cmd->t_state_lock, flags);
- transport_all_task_dev_remove_state(cmd);
+ target_remove_from_state_list(cmd);
/*
* At this point, the frontend who was the originator of this
* struct se_cmd, now owns the structure and can be released through
@@ -4710,12 +4260,12 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
if (!send_status ||
(cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
return 1;
-#if 0
+
pr_debug("Sending delayed SAM_STAT_TASK_ABORTED"
" status for CDB: 0x%02x ITT: 0x%08x\n",
cmd->t_task_cdb[0],
cmd->se_tfo->get_task_tag(cmd));
-#endif
+
cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
cmd->se_tfo->queue_status(cmd);
ret = 1;
@@ -4748,11 +4298,11 @@ void transport_send_task_abort(struct se_cmd *cmd)
}
}
cmd->scsi_status = SAM_STAT_TASK_ABORTED;
-#if 0
+
pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x,"
" ITT: 0x%08x\n", cmd->t_task_cdb[0],
cmd->se_tfo->get_task_tag(cmd));
-#endif
+
cmd->se_tfo->queue_status(cmd);
}
@@ -4865,7 +4415,7 @@ get_cmd:
}
out:
- WARN_ON(!list_empty(&dev->state_task_list));
+ WARN_ON(!list_empty(&dev->state_list));
WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list));
dev->process_thread = NULL;
return 0;
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index a375f25..f03fb97 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -215,20 +215,10 @@ int ft_write_pending(struct se_cmd *se_cmd)
*/
if ((ep->xid <= lport->lro_xid) &&
(fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
- if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
- /*
- * cmd may have been broken up into multiple
- * tasks. Link their sgs together so we can
- * operate on them all at once.
- */
- transport_do_task_sg_chain(se_cmd);
- cmd->sg = se_cmd->t_tasks_sg_chained;
- cmd->sg_cnt =
- se_cmd->t_tasks_sg_chained_no;
- }
- if (cmd->sg && lport->tt.ddp_target(lport, ep->xid,
- cmd->sg,
- cmd->sg_cnt))
+ if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) &&
+ lport->tt.ddp_target(lport, ep->xid,
+ se_cmd->t_data_sg,
+ se_cmd->t_data_nents))
cmd->was_ddp_setup = 1;
}
}
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 2948dc9..9501844 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -576,9 +576,6 @@ int ft_register_configfs(void)
}
fabric->tf_ops = ft_fabric_ops;
- /* Allowing support for task_sg_chaining */
- fabric->tf_ops.task_sg_chaining = 1;
-
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index dc7c0db..071a505 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -228,7 +228,7 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
"payload, Frame will be dropped if"
"'Sequence Initiative' bit in f_ctl is"
"not set\n", __func__, ep->xid, f_ctl,
- cmd->sg, cmd->sg_cnt);
+ se_cmd->t_data_sg, se_cmd->t_data_nents);
/*
* Invalidate HW DDP context if it was setup for respective
* command. Invalidation of HW DDP context is requited in both
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 6cc4358..35819e3 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tty_lock();
+ tty_lock(tty);
tmp.line = tty->index;
tmp.port = state->port;
tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor;
- tty_unlock();
+ tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- tty_lock();
+ tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
- tty_unlock();
+ tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
if (new_serial.baud_base < 9600) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1116,7 +1116,7 @@ check_and_exit:
}
} else
retval = startup(tty, state);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 946f799..61fc74f 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
-static struct tty_struct * volatile bfin_jc_tty;
-static unsigned long bfin_jc_count;
-static DEFINE_MUTEX(bfin_jc_tty_mutex);
+static struct tty_port port;
static volatile struct circ_buf bfin_jc_write_buf;
static int
@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
+ struct tty_struct *tty = tty_port_tty_get(&port);
/* no one left to give data to, so sleep */
- if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
+ if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
+ continue;
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
+ tty_kref_put(tty);
if (inbound_len)
schedule();
else
@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
- struct tty_struct *tty;
- mutex_lock(&bfin_jc_tty_mutex);
- tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
tty_flip_buffer_push(tty);
}
}
- mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
bfin_write_emudat(outbound_len);
pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else {
- struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
- mutex_lock(&bfin_jc_tty_mutex);
- tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
- mutex_unlock(&bfin_jc_tty_mutex);
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
+ tty_kref_put(tty);
}
__set_current_state(TASK_RUNNING);
@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&bfin_jc_tty_mutex);
- pr_debug("open %lu\n", bfin_jc_count);
- ++bfin_jc_count;
- bfin_jc_tty = tty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port.lock, flags);
+ port.count++;
+ spin_unlock_irqrestore(&port.lock, flags);
+ tty_port_tty_set(&port, tty);
wake_up_process(bfin_jc_kthread);
- mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&bfin_jc_tty_mutex);
- pr_debug("close %lu\n", bfin_jc_count);
- if (--bfin_jc_count == 0)
- bfin_jc_tty = NULL;
+ unsigned long flags;
+ bool last;
+
+ spin_lock_irqsave(&port.lock, flags);
+ last = --port.count == 0;
+ spin_unlock_irqrestore(&port.lock, flags);
+ if (last)
+ tty_port_tty_set(&port, NULL);
wake_up_process(bfin_jc_kthread);
- mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
{
int ret;
+ tty_port_init(&port);
+
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabd..6984e1a 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->port.close_wait,
+ wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 8880adf..2d691eb 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
list_for_each_entry(hp, &hvc_structs, next) {
spin_lock_irqsave(&hp->lock, flags);
if (hp->index == index) {
- kref_get(&hp->kref);
+ tty_port_get(&hp->port);
spin_unlock_irqrestore(&hp->lock, flags);
spin_unlock(&hvc_structs_lock);
return hp;
@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
console_initcall(hvc_console_init);
/* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kref *kref)
+static void hvc_port_destruct(struct tty_port *port)
{
- struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+ struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
unsigned long flags;
spin_lock(&hvc_structs_lock);
@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
/* make sure no no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
return -1;
}
@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
- if (hp->count++ > 0) {
- tty_kref_get(tty);
- spin_unlock_irqrestore(&hp->lock, flags);
+ if (hp->port.count++ > 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
hvc_kick();
return 0;
} /* else count == 0 */
+ spin_unlock_irqrestore(&hp->port.lock, flags);
tty->driver_data = hp;
-
- hp->tty = tty_kref_get(tty);
-
- spin_unlock_irqrestore(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data);
@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference.
*/
if (rc) {
- spin_lock_irqsave(&hp->lock, flags);
- hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
- tty_kref_put(tty);
+ tty_port_tty_set(&hp->port, NULL);
tty->driver_data = NULL;
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
}
/* Force wakeup of the polling thread */
@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp = tty->driver_data;
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
- if (--hp->count == 0) {
+ if (--hp->port.count == 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
/* We are done with the tty pointer now. */
- hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
*/
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
} else {
- if (hp->count < 0)
+ if (hp->port.count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
- hp->vtermno, hp->count);
- spin_unlock_irqrestore(&hp->lock, flags);
+ hp->vtermno, hp->port.count);
+ spin_unlock_irqrestore(&hp->port.lock, flags);
}
- tty_kref_put(tty);
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
}
static void hvc_hangup(struct tty_struct *tty)
@@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
/* cancel pending tty resize work */
cancel_work_sync(&hp->tty_resize);
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
/*
* The N_TTY line discipline has problems such that in a close vs
* open->hangup case this can be called after the final close so prevent
* that from happening for now.
*/
- if (hp->count <= 0) {
- spin_unlock_irqrestore(&hp->lock, flags);
+ if (hp->port.count <= 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
return;
}
- temp_open_count = hp->count;
- hp->count = 0;
- hp->n_outbuf = 0;
- hp->tty = NULL;
+ temp_open_count = hp->port.count;
+ hp->port.count = 0;
+ spin_unlock_irqrestore(&hp->port.lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
- spin_unlock_irqrestore(&hp->lock, flags);
+ hp->n_outbuf = 0;
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
while(temp_open_count) {
--temp_open_count;
- tty_kref_put(tty);
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
}
}
@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (!hp)
return -EPIPE;
- if (hp->count <= 0)
+ /* FIXME what's this (unprotected) check for? */
+ if (hp->port.count <= 0)
return -EIO;
spin_lock_irqsave(&hp->lock, flags);
@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
hp = container_of(work, struct hvc_struct, tty_resize);
- spin_lock_irqsave(&hp->lock, hvc_flags);
- if (!hp->tty) {
- spin_unlock_irqrestore(&hp->lock, hvc_flags);
+ tty = tty_port_tty_get(&hp->port);
+ if (!tty)
return;
- }
- ws = hp->ws;
- tty = tty_kref_get(hp->tty);
+
+ spin_lock_irqsave(&hp->lock, hvc_flags);
+ ws = hp->ws;
spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty_do_resize(tty, &ws);
@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
}
/* No tty attached, just skip */
- tty = tty_kref_get(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
if (tty == NULL)
goto bail;
@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
tty_flip_buffer_push(tty);
}
- if (tty)
- tty_kref_put(tty);
+ tty_kref_put(tty);
return poll_mask;
}
@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
#endif
};
+static const struct tty_port_operations hvc_port_ops = {
+ .destruct = hvc_port_destruct,
+};
+
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
const struct hv_ops *ops,
int outbuf_size)
@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
- kref_init(&hp->kref);
+ tty_port_init(&hp->port);
+ hp->port.ops = &hvc_port_ops;
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
spin_lock_init(&hp->lock);
@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
unsigned long flags;
struct tty_struct *tty;
- spin_lock_irqsave(&hp->lock, flags);
- tty = tty_kref_get(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
+ spin_lock_irqsave(&hp->lock, flags);
if (hp->index < MAX_NR_HVC_CONSOLES)
vtermnos[hp->index] = -1;
@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
* kref cause it to be removed, which will probably be the tty_vhangup
* below.
*/
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
/*
* This function call will auto chain call hvc_hangup.
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index c335a14..674d23c 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -46,10 +46,9 @@
#define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct {
+ struct tty_port port;
spinlock_t lock;
int index;
- struct tty_struct *tty;
- int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
@@ -61,7 +60,6 @@ struct hvc_struct {
struct winsize ws;
struct work_struct tty_resize;
struct list_head next;
- struct kref kref; /* ref count & hvc_struct lifetime */
};
/* implemented by a low level driver */
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 83d5c88..d3d91da 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
if (devid == 0)
return -ENODEV;
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
- goto error_nomem;
+ return -ENOMEM;
dev_set_drvdata(&dev->dev, info);
info->xbdev = dev;
info->vtermno = xenbus_devid_to_vtermno(devid);
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 3436436..d56788c 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
/* One vty-server per hvcs_struct */
struct hvcs_struct {
+ struct tty_port port;
spinlock_t lock;
/*
@@ -269,9 +270,6 @@ struct hvcs_struct {
*/
unsigned int index;
- struct tty_struct *tty;
- int open_count;
-
/*
* Used to tell the driver kernel_thread what operations need to take
* place upon this hvcs_struct instance.
@@ -290,12 +288,11 @@ struct hvcs_struct {
int chars_in_buffer;
/*
- * Any variable below the kref is valid before a tty is connected and
+ * Any variable below is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
* whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
- struct kref kref; /* ref count & hvcs_struct lifetime */
int connected; /* is the vty-server currently connected to a vty? */
uint32_t p_unit_address; /* partner unit address */
uint32_t p_partition_ID; /* partner partition ID */
@@ -304,9 +301,6 @@ struct hvcs_struct {
struct vio_dev *vdev;
};
-/* Required to back map a kref to its containing object */
-#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static DEFINE_MUTEX(hvcs_init_mutex);
@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
spin_lock_irqsave(&hvcsd->lock, flags);
- if (hvcsd->open_count > 0) {
+ if (hvcsd->port.count > 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_INFO "HVCS: vterm state unchanged. "
"The hvcs device node is still in use.\n");
@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
static void hvcs_try_write(struct hvcs_struct *hvcsd)
{
uint32_t unit_address = hvcsd->vdev->unit_address;
- struct tty_struct *tty = hvcsd->tty;
+ struct tty_struct *tty = hvcsd->port.tty;
int sent;
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_lock_irqsave(&hvcsd->lock, flags);
unit_address = hvcsd->vdev->unit_address;
- tty = hvcsd->tty;
+ tty = hvcsd->port.tty;
hvcs_try_write(hvcsd);
@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
hvcs_index_list[index] = -1;
}
-/* callback when the kref ref count reaches zero */
-static void destroy_hvcs_struct(struct kref *kref)
+static void hvcs_destruct_port(struct tty_port *p)
{
- struct hvcs_struct *hvcsd = from_kref(kref);
+ struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
unsigned long flags;
@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
kfree(hvcsd);
}
+static const struct tty_port_operations hvcs_port_ops = {
+ .destruct = hvcs_destruct_port,
+};
+
static int hvcs_get_index(void)
{
int i;
@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
if (!hvcsd)
return -ENODEV;
-
+ tty_port_init(&hvcsd->port);
+ hvcsd->port.ops = &hvcs_port_ops;
spin_lock_init(&hvcsd->lock);
- /* Automatically incs the refcount the first time */
- kref_init(&hvcsd->kref);
hvcsd->vdev = dev;
dev_set_drvdata(&dev->dev, hvcsd);
@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
- tty = hvcsd->tty;
+ tty = hvcsd->port.tty;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
/*
* The hangup is a scheduled function which will auto chain call
@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
list_for_each_entry(hvcsd, &hvcs_structs, next) {
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->index == index) {
- kref_get(&hvcsd->kref);
+ tty_port_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release;
- hvcsd->open_count = 1;
- hvcsd->tty = tty;
+ hvcsd->port.count = 1;
+ hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* and will grab the spinlock and free the connection if it fails.
*/
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc;
}
@@ -1171,8 +1167,8 @@ fast_open:
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
- kref_get(&hvcsd->kref);
- hvcsd->open_count++;
+ tty_port_get(&hvcsd->port);
+ hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1186,7 +1182,7 @@ open_success:
error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
- if (--hvcsd->open_count == 0) {
+ if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
* execute any operations on the TTY even though it is obligated
* to deliver any pending I/O to the hypervisor.
*/
- hvcsd->tty = NULL;
+ hvcsd->port.tty = NULL;
irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
return;
- } else if (hvcsd->open_count < 0) {
+ } else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
" is missmanaged.\n",
- hvcsd->vdev->unit_address, hvcsd->open_count);
+ hvcsd->vdev->unit_address, hvcsd->port.count);
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
}
static void hvcs_hangup(struct tty_struct * tty)
@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */
- temp_open_count = hvcsd->open_count;
+ temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
- hvcsd->tty->driver_data = NULL;
- hvcsd->tty = NULL;
+ tty->driver_data = NULL;
+ hvcsd->port.tty = NULL;
- hvcsd->open_count = 0;
+ hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
* scenario. */
@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
* NOTE: If this hangup was signaled from user space then the
* final put will never happen.
*/
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
}
}
@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
* the middle of a write operation? This is a crummy place to do this
* but we want to keep it all in the spinlock.
*/
- if (hvcsd->open_count <= 0) {
+ if (hvcsd->port.count <= 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return -ENODEV;
}
@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
- if (!hvcsd || hvcsd->open_count <= 0)
+ if (!hvcsd || hvcsd->port.count <= 0)
return 0;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index a7488b7..6f5bc49 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -69,14 +69,13 @@
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
struct hvsi_struct {
+ struct tty_port port;
struct delayed_work writer;
struct work_struct handshaker;
wait_queue_head_t emptyq; /* woken when outbuf is emptied */
wait_queue_head_t stateq; /* woken when HVSI state changes */
spinlock_t lock;
int index;
- struct tty_struct *tty;
- int count;
uint8_t throttle_buf[128];
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
/* inbuf is for packet reassembly. leave a little room for leftovers. */
@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
}
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
- struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
+ struct tty_struct *tty, struct hvsi_struct **to_handshake)
{
struct hvsi_control *header = (struct hvsi_control *)packet;
@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
/* CD went away; no more connection */
pr_debug("hvsi%i: CD dropped\n", hp->index);
hp->mctrl &= TIOCM_CD;
- /* If userland hasn't done an open(2) yet, hp->tty is NULL. */
- if (hp->tty && !(hp->tty->flags & CLOCAL))
- *to_hangup = hp->tty;
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
}
break;
case VSV_CLOSE_PROTOCOL:
@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
}
}
-static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
+ const char *buf, int len)
{
int i;
@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
continue;
}
#endif /* CONFIG_MAGIC_SYSRQ */
- tty_insert_flip_char(hp->tty, c, 0);
+ tty_insert_flip_char(tty, c, 0);
}
}
@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
* revisited.
*/
#define TTY_THRESHOLD_THROTTLE 128
-static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
const uint8_t *packet)
{
const struct hvsi_header *header = (const struct hvsi_header *)packet;
@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
if (datalen == 0)
- return NULL;
+ return false;
if (overflow > 0) {
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE;
}
- hvsi_insert_chars(hp, data, datalen);
+ hvsi_insert_chars(hp, tty, data, datalen);
if (overflow > 0) {
/*
@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
hp->n_throttle = overflow;
}
- return hp->tty;
+ return true;
}
/*
@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* machine during console handshaking (in which case tty = NULL and we ignore
* incoming data).
*/
-static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
- struct tty_struct **hangup, struct hvsi_struct **handshake)
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
+ struct hvsi_struct **handshake)
{
uint8_t *packet = hp->inbuf;
int chunklen;
+ bool flip = false;
- *flip = NULL;
- *hangup = NULL;
*handshake = NULL;
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
case VS_DATA_PACKET_HEADER:
if (!is_open(hp))
break;
- if (hp->tty == NULL)
+ if (tty == NULL)
break; /* no tty buffer to put data in */
- *flip = hvsi_recv_data(hp, packet);
+ flip = hvsi_recv_data(hp, tty, packet);
break;
case VS_CONTROL_PACKET_HEADER:
- hvsi_recv_control(hp, packet, hangup, handshake);
+ hvsi_recv_control(hp, packet, tty, handshake);
break;
case VS_QUERY_RESPONSE_PACKET_HEADER:
hvsi_recv_response(hp, packet);
@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet);
- if (*hangup || *handshake) {
- pr_debug("%s: hangup or handshake\n", __func__);
- /*
- * we need to send the hangup now before receiving any more data.
- * If we get "data, hangup, data", we can't deliver the second
- * data before the hangup.
- */
+ if (*handshake) {
+ pr_debug("%s: handshake\n", __func__);
break;
}
}
compact_inbuf(hp, packet);
+ if (flip)
+ tty_flip_buffer_push(tty);
+
return 1;
}
-static void hvsi_send_overflow(struct hvsi_struct *hp)
+static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
{
pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle);
- hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+ hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
hp->n_throttle = 0;
}
@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
static irqreturn_t hvsi_interrupt(int irq, void *arg)
{
struct hvsi_struct *hp = (struct hvsi_struct *)arg;
- struct tty_struct *flip;
- struct tty_struct *hangup;
struct hvsi_struct *handshake;
+ struct tty_struct *tty;
unsigned long flags;
int again = 1;
pr_debug("%s\n", __func__);
+ tty = tty_port_tty_get(&hp->port);
+
while (again) {
spin_lock_irqsave(&hp->lock, flags);
- again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
+ again = hvsi_load_chunk(hp, tty, &handshake);
spin_unlock_irqrestore(&hp->lock, flags);
- /*
- * we have to call tty_flip_buffer_push() and tty_hangup() outside our
- * spinlock. But we also have to keep going until we've read all the
- * available data.
- */
-
- if (flip) {
- /* there was data put in the tty flip buffer */
- tty_flip_buffer_push(flip);
- flip = NULL;
- }
-
- if (hangup) {
- tty_hangup(hangup);
- }
-
if (handshake) {
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
schedule_work(&handshake->handshaker);
@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
}
spin_lock_irqsave(&hp->lock, flags);
- if (hp->tty && hp->n_throttle
- && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
- /* we weren't hung up and we weren't throttled, so we can deliver the
- * rest now */
- flip = hp->tty;
- hvsi_send_overflow(hp);
+ if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
+ /* we weren't hung up and we weren't throttled, so we can
+ * deliver the rest now */
+ hvsi_send_overflow(hp, tty);
+ tty_flip_buffer_push(tty);
}
spin_unlock_irqrestore(&hp->lock, flags);
- if (flip) {
- tty_flip_buffer_push(flip);
- }
+ tty_kref_put(tty);
return IRQ_HANDLED;
}
@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
if (hp->state == HVSI_FSP_DIED)
return -EIO;
+ tty_port_tty_set(&hp->port, tty);
spin_lock_irqsave(&hp->lock, flags);
- hp->tty = tty;
- hp->count++;
+ hp->port.count++;
atomic_set(&hp->seqno, 0);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
spin_unlock_irqrestore(&hp->lock, flags);
@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags);
- if (--hp->count == 0) {
- hp->tty = NULL;
+ if (--hp->port.count == 0) {
+ tty_port_tty_set(&hp->port, NULL);
hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
/* only close down connection if it is not the console */
@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags);
}
- } else if (hp->count < 0)
+ } else if (hp->port.count < 0)
printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
- hp - hvsi_ports, hp->count);
+ hp - hvsi_ports, hp->port.count);
spin_unlock_irqrestore(&hp->lock, flags);
}
@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
pr_debug("%s\n", __func__);
- spin_lock_irqsave(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
- hp->count = 0;
+ spin_lock_irqsave(&hp->lock, flags);
+ hp->port.count = 0;
hp->n_outbuf = 0;
- hp->tty = NULL;
-
spin_unlock_irqrestore(&hp->lock, flags);
}
@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
{
struct hvsi_struct *hp =
container_of(work, struct hvsi_struct, writer.work);
+ struct tty_struct *tty;
unsigned long flags;
#ifdef DEBUG
static long start_j = 0;
@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
start_j = 0;
#endif /* DEBUG */
wake_up_all(&hp->emptyq);
- tty_wakeup(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
}
out:
@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
* will see there is no room in outbuf and return.
*/
- while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
- int chunksize = min(count, hvsi_write_room(hp->tty));
+ while ((count > 0) && (hvsi_write_room(tty) > 0)) {
+ int chunksize = min(count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- int shouldflip = 0;
pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) {
- hvsi_send_overflow(hp);
- shouldflip = 1;
+ hvsi_send_overflow(hp, tty);
+ tty_flip_buffer_push(tty);
}
spin_unlock_irqrestore(&hp->lock, flags);
- if (shouldflip)
- tty_flip_buffer_push(hp->tty);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
}
@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
init_waitqueue_head(&hp->emptyq);
init_waitqueue_head(&hp->stateq);
spin_lock_init(&hp->lock);
+ tty_port_init(&hp->port);
hp->index = hvsi_count;
hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED;
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 6f4dd83..59c135d 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
pr_devel("HVSI@%x: open !\n", pv->termno);
/* Keep track of the tty data structure */
- pv->tty = tty_kref_get(hp->tty);
+ pv->tty = tty_port_tty_get(&hp->port);
hvsilib_establish(pv);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 4daf962..f8b5fa0 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -44,14 +44,13 @@
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
+ struct tty_port port;
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
- struct tty_struct *linux_tty;
- int open_count;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
return channel_names[tty_type];
}
-static void report_registering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": registering %s device ttyIPWp%d\n", iftype, tty->index);
-}
-
-static void report_deregistering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": deregistering %s device ttyIPWp%d\n", iftype,
- tty->index);
-}
-
static struct ipw_tty *get_tty(int index)
{
/*
@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV;
}
- if (tty->open_count == 0)
+ if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
- tty->open_count++;
+ tty->port.count++;
- tty->linux_tty = linux_tty;
+ tty->port.tty = linux_tty;
linux_tty->driver_data = tty;
linux_tty->low_latency = 1;
@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
static void do_ipw_close(struct ipw_tty *tty)
{
- tty->open_count--;
+ tty->port.count--;
- if (tty->open_count == 0) {
- struct tty_struct *linux_tty = tty->linux_tty;
+ if (tty->port.count == 0) {
+ struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) {
- tty->linux_tty = NULL;
+ tty->port.tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
- if (tty->open_count == 0) {
+ if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
- linux_tty = tty->linux_tty;
+ linux_tty = tty->port.tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
- if (!tty->open_count) {
+ if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
- if (!tty->open_count) {
+ if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
if (!tty)
return 0;
- if (!tty->open_count)
+ if (!tty->port.count)
return 0;
return tty->tx_bytes_queued;
@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
return get_control_lines(tty);
@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
return set_control_lines(tty, set, clear);
@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
@@ -492,6 +474,7 @@ static int add_tty(int j,
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
+ tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
@@ -500,8 +483,12 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
- if (get_tty(j) == ttys[j])
- report_registering(ttys[j]);
+ /* check if we provide raw device (if loopback is enabled) */
+ if (get_tty(j))
+ printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+ ": registering %s device ttyIPWp%d\n",
+ tty_type_name(tty_type), j);
+
return 0;
}
@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
- if (get_tty(j) == ttyj)
- report_deregistering(ttyj);
+ if (get_tty(j))
+ printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+ ": deregistering %s device ttyIPWp%d\n",
+ tty_type_name(ttyj->tty_type), j);
ttyj->closing = 1;
- if (ttyj->linux_tty != NULL) {
+ if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
- tty_hangup(ttyj->linux_tty);
- /* Wait till the tty_hangup has completed */
- flush_work_sync(&ttyj->linux_tty->hangup_work);
+ tty_vhangup(ttyj->port.tty);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
+ /* FIXME2: hangup does not mean all processes
+ * are gone */
mutex_lock(&ttyj->ipw_tty_mutex);
}
- while (ttyj->open_count)
+ while (ttyj->port.count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
- && tty->linux_tty) {
- tty_hangup(tty->linux_tty);
+ && tty->port.tty) {
+ tty_hangup(tty->port.tty);
}
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index c6f372d..90cc680 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount,
};
-struct tty_port_operations mxser_port_ops = {
+static struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts,
.activate = mxser_activate,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c314..656ad93 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
- tty_lock();
+ /* FIXME: should use a private lock */
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock;
}
/* block until there is a message: */
- wait_event_interruptible_tty(pInfo->read_wait,
+ wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient)));
}
@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
}
ret = -EPERM;
unlock:
- tty_unlock();
+ tty_unlock(tty);
return ret;
}
@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
- tty_lock();
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..ee1c268 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
unsigned long flags;
+ bool is_eof;
retval = 0;
spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
+ is_eof = n == 1 &&
+ tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && n == 1) {
- if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
- n--;
- }
+ if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+ n = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n;
*nr -= n;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index eeae7fa..59af394 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -26,11 +26,13 @@
#include <linux/bitops.h>
#include <linux/devpts_fs.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
+static DEFINE_MUTEX(devpts_mutex);
#endif
static void pty_close(struct tty_struct *tty, struct file *filp)
@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
tty->packet = 0;
+ /* Review - krefs on tty_link ?? */
if (!tty->link)
return;
tty->link->packet = 0;
@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
- if (tty->driver == ptm_driver)
+ if (tty->driver == ptm_driver) {
+ mutex_lock(&devpts_mutex);
devpts_pty_kill(tty->link);
+ mutex_unlock(&devpts_mutex);
+ }
#endif
- tty_unlock();
+ tty_unlock(tty);
tty_vhangup(tty->link);
- tty_lock();
+ tty_lock(tty);
}
}
@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
* @idx: tty index
*
* Look up a pty master device. Called under the tty_mutex for now.
- * This provides our locking.
+ * This provides our locking for the tty pointer.
*/
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct inode *pts_inode, int idx)
{
- struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+ struct tty_struct *tty;
+
+ mutex_lock(&devpts_mutex);
+ tty = devpts_get_tty(pts_inode, idx);
+ mutex_unlock(&devpts_mutex);
/* Master must be open before slave */
if (!tty)
return ERR_PTR(-EIO);
@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval;
/* find a device that is not in use. */
- tty_lock();
+ mutex_lock(&devpts_mutex);
index = devpts_new_index(inode);
- tty_unlock();
if (index < 0) {
retval = index;
goto err_file;
}
+ mutex_unlock(&devpts_mutex);
+
mutex_lock(&tty_mutex);
- tty_lock();
+ mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
- mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto out;
}
+ /* The tty returned here is locked so we can safely
+ drop the mutex */
+ mutex_unlock(&devpts_mutex);
+ mutex_unlock(&tty_mutex);
+
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
- tty_unlock();
+ tty_unlock(tty);
return 0;
err_release:
- tty_unlock();
+ tty_unlock(tty);
tty_release(inode, filp);
return retval;
out:
+ mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index);
- tty_unlock();
err_file:
+ mutex_unlock(&devpts_mutex);
tty_free_file(filp);
return retval;
}
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 5ce78252..3ed20e4 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -17,6 +17,7 @@
#include <asm/dbg.h>
#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/serial.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -56,8 +57,6 @@
#endif /* CONFIG_M68VZ328 */
#endif /* CONFIG_M68EZ328 */
-#include "68328serial.h"
-
/* Turn off usage of real serial interrupt code, to "support" Copilot */
#ifdef CONFIG_XCOPILOT_BUGS
#undef USE_INTS
@@ -65,33 +64,82 @@
#define USE_INTS
#endif
-static struct m68k_serial m68k_soft[NR_PORTS];
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ * -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real 328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ * -- Vladimir Gurevich
+ */
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct m68k_serial {
+ struct tty_port tport;
+ char is_cons; /* Is this our console. */
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int type; /* UART type */
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int line;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+};
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+#define SERIAL_MAGIC 0x5301
-struct tty_driver *serial_driver;
+/*
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
+static struct m68k_serial m68k_soft[NR_PORTS];
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
+static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
-#define RS_ISR_PASS_LIMIT 256
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+
+struct tty_driver *serial_driver;
-static void change_speed(struct m68k_serial *info);
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
/*
* Setup for console. Argument comes from the boot command line.
@@ -143,17 +191,6 @@ static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 0 };
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
- if (set) {
- /* set the RTS/CTS line */
- } else {
- /* clear it */
- }
- return;
-}
-
/* Utility routines */
static inline int get_baud(struct m68k_serial *ss)
{
@@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty)
static int rs_put_char(char ch)
{
- int flags, loops = 0;
+ unsigned long flags;
+ int loops = 0;
local_irq_save(flags);
@@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty)
local_irq_restore(flags);
}
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
-{
- /* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
+static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
+ unsigned short rx)
{
- /* If this is console input and this is a
- * 'break asserted' status change interrupt
- * see if we can drop into the debugger
- */
- if((status & URX_BREAK) && info->break_abort)
- batten_down_hatches();
- return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
- struct tty_struct *tty = info->tty;
m68328_uart *uart = &uart_addr[info->line];
unsigned char ch, flag;
@@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
if(info->is_cons) {
if(URX_BREAK & rx) { /* whee, break received */
- status_handle(info, rx);
return;
#ifdef CONFIG_MAGIC_SYSRQ
} else if (ch == 0x10) { /* ^P */
@@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
flag = TTY_NORMAL;
- if(rx & URX_PARITY_ERROR) {
+ if (rx & URX_PARITY_ERROR)
flag = TTY_PARITY;
- status_handle(info, rx);
- } else if(rx & URX_OVRUN) {
+ else if (rx & URX_OVRUN)
flag = TTY_OVERRUN;
- status_handle(info, rx);
- } else if(rx & URX_FRAME_ERROR) {
+ else if (rx & URX_FRAME_ERROR)
flag = TTY_FRAME;
- status_handle(info, rx);
- }
+
tty_insert_flip_char(tty, ch, flag);
#ifndef CONFIG_XCOPILOT_BUGS
} while((rx = uart->urx.w) & URX_DATA_READY);
@@ -301,7 +316,7 @@ clear_and_exit:
return;
}
-static void transmit_chars(struct m68k_serial *info)
+static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
@@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info)
goto clear_and_return;
}
- if((info->xmit_cnt <= 0) || info->tty->stopped) {
+ if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
/* That's peculiar... TX ints off */
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
goto clear_and_return;
@@ -340,6 +355,7 @@ clear_and_return:
irqreturn_t rs_interrupt(int irq, void *dev_id)
{
struct m68k_serial *info = dev_id;
+ struct tty_struct *tty = tty_port_tty_get(&info->tport);
m68328_uart *uart;
unsigned short rx;
unsigned short tx;
@@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
#ifdef USE_INTS
tx = uart->utx.w;
- if (rx & URX_DATA_READY) receive_chars(info, rx);
- if (tx & UTX_TX_AVAIL) transmit_chars(info);
+ if (rx & URX_DATA_READY)
+ receive_chars(info, tty, rx);
+ if (tx & UTX_TX_AVAIL)
+ transmit_chars(info, tty);
#else
- receive_chars(info, rx);
+ receive_chars(info, tty, rx);
#endif
+ tty_kref_put(tty);
+
return IRQ_HANDLED;
}
-static int startup(struct m68k_serial * info)
+static int startup(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
- if (info->flags & S_INITIALIZED)
+ if (info->tport.flags & ASYNC_INITIALIZED)
return 0;
if (!info->xmit_buf) {
@@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info)
*/
uart->ustcnt = USTCNT_UEN;
- info->xmit_fifo_size = 1;
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
(void)uart->urx.w;
@@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info)
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
#endif
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (tty)
+ clear_bit(TTY_IO_ERROR, &tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
* and set the speed of the serial port
*/
- change_speed(info);
+ change_speed(info, tty);
- info->flags |= S_INITIALIZED;
+ info->tport.flags |= ASYNC_INITIALIZED;
local_irq_restore(flags);
return 0;
}
@@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info)
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct m68k_serial * info)
+static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
uart->ustcnt = 0; /* All off! */
- if (!(info->flags & S_INITIALIZED))
+ if (!(info->tport.flags & ASYNC_INITIALIZED))
return;
local_irq_save(flags);
@@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info)
info->xmit_buf = 0;
}
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
- info->flags &= ~S_INITIALIZED;
+ info->tport.flags &= ~ASYNC_INITIALIZED;
local_irq_restore(flags);
}
@@ -488,7 +507,7 @@ struct {
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void change_speed(struct m68k_serial *info)
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned short port;
@@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info)
unsigned cflag;
int i;
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
+ cflag = tty->termios->c_cflag;
if (!(port = info->port))
return;
@@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info)
i = (i & ~CBAUDEX) + B38400;
}
- info->baud = baud_table[i];
uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
@@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info,
tmp.line = info->line;
tmp.port = info->port;
tmp.irq = info->irq;
- tmp.flags = info->flags;
+ tmp.flags = info->tport.flags;
tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
+ tmp.close_delay = info->tport.close_delay;
+ tmp.closing_wait = info->tport.closing_wait;
tmp.custom_divisor = info->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info,
return 0;
}
-static int set_serial_info(struct m68k_serial * info,
+static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
struct serial_struct * new_info)
{
+ struct tty_port *port = &info->tport;
struct serial_struct new_serial;
struct m68k_serial old_info;
int retval = 0;
@@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info,
if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.baud_base != info->baud_base) ||
(new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~S_USR_MASK) !=
- (info->flags & ~S_USR_MASK)))
+ (new_serial.close_delay != port->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
- info->flags = ((info->flags & ~S_USR_MASK) |
- (new_serial.flags & S_USR_MASK));
+ port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
info->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
- if (info->count > 1)
+ if (port->count > 1)
return -EBUSY;
/*
@@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info,
*/
info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~S_FLAGS) |
- (new_serial.flags & S_FLAGS));
+ port->flags = ((port->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
+ port->close_delay = new_serial.close_delay;
+ port->closing_wait = new_serial.closing_wait;
check_and_exit:
- retval = startup(info);
+ retval = startup(info, tty);
return retval;
}
@@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty,
return get_serial_info(info,
(struct serial_struct *) arg);
case TIOCSSERIAL:
- return set_serial_info(info,
+ return set_serial_info(info, tty,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- change_speed(info);
+ change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static void rs_close(struct tty_struct *tty, struct file * filp)
{
struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+ struct tty_port *port = &info->tport;
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
@@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
return;
}
- if ((tty->count == 1) && (info->count != 1)) {
+ if ((tty->count == 1) && (port->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* serial port won't be shutdown.
*/
printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
+ "port->count is %d\n", port->count);
+ port->count = 1;
}
- if (--info->count < 0) {
+ if (--port->count < 0) {
printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, info->count);
- info->count = 0;
+ info->line, port->count);
+ port->count = 0;
}
- if (info->count) {
+ if (port->count) {
local_irq_restore(flags);
return;
}
- info->flags |= S_CLOSING;
+ port->flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (info->closing_wait != S_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
@@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
uart->ustcnt &= ~USTCNT_RXEN;
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
- shutdown(info);
+ shutdown(info, tty);
rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
- info->event = 0;
- info->tty = NULL;
+ tty_port_tty_set(&info->tport, NULL);
#warning "This is not and has never been valid so fix it"
#if 0
if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
(tty->ldisc.open)(tty);
}
#endif
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
+ if (port->blocked_open) {
+ if (port->close_delay)
+ msleep_interruptible(jiffies_to_msecs(port->close_delay));
+ wake_up_interruptible(&port->open_wait);
}
- info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
- wake_up_interruptible(&info->close_wait);
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&port->close_wait);
local_irq_restore(flags);
}
@@ -1080,107 +1096,14 @@ void rs_hangup(struct tty_struct *tty)
return;
rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~S_NORMAL_ACTIVE;
- info->tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ shutdown(info, tty);
+ info->tport.count = 0;
+ info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+ tty_port_tty_set(&info->tport, NULL);
+ wake_up_interruptible(&info->tport.open_wait);
}
/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct m68k_serial *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & S_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (info->flags & S_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= S_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-
- info->count--;
- info->blocked_open++;
- while (1) {
- local_irq_disable();
- m68k_rtsdtr(info, 1);
- local_irq_enable();
- current->state = TASK_INTERRUPTIBLE;
- if (tty_hung_up_p(filp) ||
- !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & S_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & S_CLOSING) && do_clocal)
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- tty_unlock();
- schedule();
- tty_lock();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-
- if (retval)
- return retval;
- info->flags |= S_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its S structure into
* the IRQ chain. It also performs the serial-specific
@@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp)
if (serial_paranoia_check(info, tty->name, "rs_open"))
return -ENODEV;
- info->count++;
+ info->tport.count++;
tty->driver_data = info;
- info->tty = tty;
+ tty_port_tty_set(&info->tport, tty);
/*
* Start up serial port
*/
- retval = startup(info);
+ retval = startup(info, tty);
if (retval)
return retval;
- return block_til_ready(tty, filp, info);
+ return tty_port_block_til_ready(&info->tport, tty, filp);
}
/* Finally, routines used to initialize the serial driver. */
@@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = {
.set_ldisc = rs_set_ldisc,
};
+static const struct tty_port_operations rs_port_ops = {
+};
+
/* rs_init inits the driver */
static int __init
rs68328_init(void)
{
- int flags, i;
+ unsigned long flags;
+ int i;
struct m68k_serial *info;
serial_driver = alloc_tty_driver(NR_PORTS);
@@ -1273,19 +1200,13 @@ rs68328_init(void)
for(i=0;i<NR_PORTS;i++) {
info = &m68k_soft[i];
+ tty_port_init(&info->tport);
+ info->tport.ops = &rs_port_ops;
info->magic = SERIAL_MAGIC;
info->port = (int) &uart_addr[i];
- info->tty = NULL;
info->irq = uart_irqs[i];
info->custom_divisor = 16;
- info->close_delay = 50;
- info->closing_wait = 3000;
info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
info->line = i;
info->is_cons = 1; /* Means shortcuts work */
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h
deleted file mode 100644
index 3d2faab..0000000
--- a/drivers/tty/serial/68328serial.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
- * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
- *
- * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6; /* FIXME: We don't have AT&T Hub6 boards! */
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF 0
-#define S_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- on the callout port */
-#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK 0x0030
-#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS 0x0FFF /* Possible legal S flags */
-#define S_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING 0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- * -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real 328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- * -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
- char soft_carrier; /* Use soft carrier on this channel */
- char break_abort; /* Is serial console in, so process brk/abrt */
- char is_cons; /* Is this our console. */
-
- /* We need to know the current clock divisor
- * to read the bps rate the chip has currently
- * loaded.
- */
- unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
- int baud;
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* defined in tty.h */
- int type; /* UART type */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-/*
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 5c27f7e..47d061b 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {
},
};
-#if defined(CONFIG_MIPS_ALCHEMY)
+/* Uart divisor latch read */
+static int default_serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static void default_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_out(up, UART_DLL, value & 0xff);
+ serial_out(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_MIPS_ALCHEMY
/* Au1x00 UART hardware has a weird register layout */
static const u8 au_io_in_map[] = {
@@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {
[UART_MCR] = 6,
};
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+ offset = au_io_in_map[offset] << p->regshift;
+ return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = au_io_out_map[offset] << p->regshift;
+ __raw_writel(value, p->membase + offset);
+}
+
+/* Au1x00 haven't got a standard divisor latch */
+static int au_serial_dl_read(struct uart_8250_port *up)
{
- if (p->iotype != UPIO_AU)
- return offset;
- return au_io_in_map[offset];
+ return __raw_readl(up->port.membase + 0x28);
}
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void au_serial_dl_write(struct uart_8250_port *up, int value)
{
- if (p->iotype != UPIO_AU)
- return offset;
- return au_io_out_map[offset];
+ __raw_writel(value, up->port.membase + 0x28);
}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RM9K
static const u8
regmap_in[8] = {
@@ -344,87 +367,79 @@ static const u8
[UART_SCR] = 0x2c
};
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
{
- if (p->iotype != UPIO_RM9000)
- return offset;
- return regmap_in[offset];
+ offset = regmap_in[offset] << p->regshift;
+ return readl(p->membase + offset);
}
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void rm9k_serial_out(struct uart_port *p, int offset, int value)
{
- if (p->iotype != UPIO_RM9000)
- return offset;
- return regmap_out[offset];
+ offset = regmap_out[offset] << p->regshift;
+ writel(value, p->membase + offset);
}
-#else
+static int rm9k_serial_dl_read(struct uart_8250_port *up)
+{
+ return ((__raw_readl(up->port.membase + 0x10) << 8) |
+ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
+}
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
+static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ __raw_writel(value, up->port.membase + 0x08);
+ __raw_writel(value >> 8, up->port.membase + 0x10);
+}
#endif
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
return inb(p->iobase + 1);
}
static void hub6_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return readb(p->membase + offset);
}
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
writeb(value, p->membase + offset);
}
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
writel(value, p->membase + offset);
}
static unsigned int mem32_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return readl(p->membase + offset);
}
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
- offset = map_8250_in_reg(p, offset) << p->regshift;
- return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
- offset = map_8250_out_reg(p, offset) << p->regshift;
- __raw_writel(value, p->membase + offset);
-}
-
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return inb(p->iobase + offset);
}
static void io_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
@@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
+
+ up->dl_read = default_serial_dl_read;
+ up->dl_write = default_serial_dl_write;
+
switch (p->iotype) {
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
@@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out;
break;
- case UPIO_RM9000:
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
break;
+#ifdef CONFIG_SERIAL_8250_RM9K
+ case UPIO_RM9000:
+ p->serial_in = rm9k_serial_in;
+ p->serial_out = rm9k_serial_out;
+ up->dl_read = rm9k_serial_dl_read;
+ up->dl_write = rm9k_serial_dl_write;
+ break;
+#endif
+
+#ifdef CONFIG_MIPS_ALCHEMY
case UPIO_AU:
p->serial_in = au_serial_in;
p->serial_out = au_serial_out;
+ up->dl_read = au_serial_dl_read;
+ up->dl_write = au_serial_dl_write;
break;
+#endif
default:
p->serial_in = io_serial_in;
@@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
}
}
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
- return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
- serial_out(up, UART_DLL, value & 0xff);
- serial_out(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
- if (up->port.iotype == UPIO_AU)
- return __raw_readl(up->port.membase + 0x28);
- else
- return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
- if (up->port.iotype == UPIO_AU)
- __raw_writel(value, up->port.membase + 0x28);
- else
- _serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
- return (up->port.iotype == UPIO_RM9000) ?
- (((__raw_readl(up->port.membase + 0x10) << 8) |
- (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
- _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
- if (up->port.iotype == UPIO_RM9000) {
- __raw_writel(value, up->port.membase + 0x08);
- __raw_writel(value >> 8, up->port.membase + 0x10);
- } else {
- _serial_dl_write(up, value);
- }
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
/*
* For the 16C950
*/
@@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
+{
+ unsigned char fcr;
+
+ serial8250_clear_fifos(p);
+ fcr = uart_config[p->port.type].fcr;
+ serial_out(p, UART_FCR, fcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
@@ -1332,27 +1320,6 @@ static void serial8250_enable_ms(struct uart_port *port)
}
/*
- * Clear the Tegra rx fifo after a break
- *
- * FIXME: This needs to become a port specific callback once we have a
- * framework for this
- */
-static void clear_rx_fifo(struct uart_8250_port *up)
-{
- unsigned int status, tmout = 10000;
- do {
- status = serial_in(up, UART_LSR);
- if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
- status = serial_in(up, UART_RX);
- else
- break;
- if (--tmout == 0)
- break;
- udelay(1);
- } while (1);
-}
-
-/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
@@ -1386,20 +1353,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
up->lsr_saved_flags = 0;
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- /*
- * For statistics only
- */
if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++;
/*
- * If tegra port then clear the rx fifo to
- * accept another break/character.
- */
- if (port->type == PORT_TEGRA)
- clear_rx_fifo(up);
-
- /*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
@@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
quot++;
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
- if (baud < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
- else
- fcr = uart_config[port->type].fcr;
+ fcr = uart_config[port->type].fcr;
+ if (baud < 2400) {
+ fcr &= ~UART_FCR_TRIGGER_MASK;
+ fcr |= UART_FCR_TRIGGER_1;
+ }
}
/*
@@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
+ port.handle_break = p->handle_break;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
@@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
}
/**
- * serial8250_register_port - register a serial port
+ * serial8250_register_8250_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
@@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
*
* On success the port is ready to use and the line number is returned.
*/
-int serial8250_register_port(struct uart_port *port)
+int serial8250_register_8250_port(struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
- if (port->uartclk == 0)
+ if (up->port.uartclk == 0)
return -EINVAL;
mutex_lock(&serial_mutex);
- uart = serial8250_find_match_or_unused(port);
+ uart = serial8250_find_match_or_unused(&up->port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
- uart->port.iobase = port->iobase;
- uart->port.membase = port->membase;
- uart->port.irq = port->irq;
- uart->port.irqflags = port->irqflags;
- uart->port.uartclk = port->uartclk;
- uart->port.fifosize = port->fifosize;
- uart->port.regshift = port->regshift;
- uart->port.iotype = port->iotype;
- uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
- uart->port.mapbase = port->mapbase;
- uart->port.private_data = port->private_data;
- if (port->dev)
- uart->port.dev = port->dev;
-
- if (port->flags & UPF_FIXED_TYPE)
- serial8250_init_fixed_type_port(uart, port->type);
+ uart->port.iobase = up->port.iobase;
+ uart->port.membase = up->port.membase;
+ uart->port.irq = up->port.irq;
+ uart->port.irqflags = up->port.irqflags;
+ uart->port.uartclk = up->port.uartclk;
+ uart->port.fifosize = up->port.fifosize;
+ uart->port.regshift = up->port.regshift;
+ uart->port.iotype = up->port.iotype;
+ uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.private_data = up->port.private_data;
+ if (up->port.dev)
+ uart->port.dev = up->port.dev;
+
+ if (up->port.flags & UPF_FIXED_TYPE)
+ serial8250_init_fixed_type_port(uart, up->port.type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
- if (port->serial_in)
- uart->port.serial_in = port->serial_in;
- if (port->serial_out)
- uart->port.serial_out = port->serial_out;
- if (port->handle_irq)
- uart->port.handle_irq = port->handle_irq;
+ if (up->port.serial_in)
+ uart->port.serial_in = up->port.serial_in;
+ if (up->port.serial_out)
+ uart->port.serial_out = up->port.serial_out;
+ if (up->port.handle_irq)
+ uart->port.handle_irq = up->port.handle_irq;
/* Possibly override set_termios call */
- if (port->set_termios)
- uart->port.set_termios = port->set_termios;
- if (port->pm)
- uart->port.pm = port->pm;
+ if (up->port.set_termios)
+ uart->port.set_termios = up->port.set_termios;
+ if (up->port.pm)
+ uart->port.pm = up->port.pm;
+ if (up->port.handle_break)
+ uart->port.handle_break = up->port.handle_break;
+ if (up->dl_read)
+ uart->dl_read = up->dl_read;
+ if (up->dl_write)
+ uart->dl_write = up->dl_write;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
@@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port)
return ret;
}
+EXPORT_SYMBOL(serial8250_register_8250_port);
+
+/**
+ * serial8250_register_port - register a serial port
+ * @port: serial port template
+ *
+ * Configure the serial port specified by the request. If the
+ * port exists and is in use, it is hung up and unregistered
+ * first.
+ *
+ * The port is then probed and if necessary the IRQ is autodetected
+ * If this fails an error is returned.
+ *
+ * On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_port(struct uart_port *port)
+{
+ struct uart_8250_port up;
+
+ memset(&up, 0, sizeof(up));
+ memcpy(&up.port, port, sizeof(*port));
+ return serial8250_register_8250_port(&up);
+}
EXPORT_SYMBOL(serial8250_register_port);
/**
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 2868a1d..f9719d1 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -37,6 +37,10 @@ struct uart_8250_port {
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
+
+ /* 8250 specific callbacks */
+ int (*dl_read)(struct uart_8250_port *);
+ void (*dl_write)(struct uart_8250_port *, int);
};
struct old_serial_port {
@@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
up->port.serial_out(&up->port, offset, value);
}
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+
+static inline int serial_dl_read(struct uart_8250_port *up)
+{
+ return up->dl_read(up);
+}
+
+static inline void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ up->dl_write(up, value);
+}
+
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
new file mode 100644
index 0000000..3a0363e
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -0,0 +1,186 @@
+/*
+ * Renesas Emma Mobile 8250 driver
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "8250.h"
+
+#define UART_DLL_EM 9
+#define UART_DLM_EM 10
+
+struct serial8250_em_priv {
+ struct clk *sclk;
+ int line;
+};
+
+static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
+{
+ switch (offset) {
+ case UART_TX: /* TX @ 0x00 */
+ writeb(value, p->membase);
+ break;
+ case UART_FCR: /* FCR @ 0x0c (+1) */
+ case UART_LCR: /* LCR @ 0x10 (+1) */
+ case UART_MCR: /* MCR @ 0x14 (+1) */
+ case UART_SCR: /* SCR @ 0x20 (+1) */
+ writel(value, p->membase + ((offset + 1) << 2));
+ break;
+ case UART_IER: /* IER @ 0x04 */
+ value &= 0x0f; /* only 4 valid bits - not Xscale */
+ /* fall-through */
+ case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+ case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+ writel(value, p->membase + (offset << 2));
+ }
+}
+
+static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
+{
+ switch (offset) {
+ case UART_RX: /* RX @ 0x00 */
+ return readb(p->membase);
+ case UART_MCR: /* MCR @ 0x14 (+1) */
+ case UART_LSR: /* LSR @ 0x18 (+1) */
+ case UART_MSR: /* MSR @ 0x1c (+1) */
+ case UART_SCR: /* SCR @ 0x20 (+1) */
+ return readl(p->membase + ((offset + 1) << 2));
+ case UART_IER: /* IER @ 0x04 */
+ case UART_IIR: /* IIR @ 0x08 */
+ case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+ case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+ return readl(p->membase + (offset << 2));
+ }
+ return 0;
+}
+
+static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
+}
+
+static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_out(up, UART_DLL_EM, value & 0xff);
+ serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
+}
+
+static int __devinit serial8250_em_probe(struct platform_device *pdev)
+{
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct serial8250_em_priv *priv;
+ struct uart_8250_port up;
+ int ret = -EINVAL;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "missing registers or irq\n");
+ goto err0;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "unable to allocate private data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ priv->sclk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(priv->sclk)) {
+ dev_err(&pdev->dev, "unable to get clock\n");
+ ret = PTR_ERR(priv->sclk);
+ goto err1;
+ }
+
+ memset(&up, 0, sizeof(up));
+ up.port.mapbase = regs->start;
+ up.port.irq = irq->start;
+ up.port.type = PORT_UNKNOWN;
+ up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+ up.port.dev = &pdev->dev;
+ up.port.private_data = priv;
+
+ clk_enable(priv->sclk);
+ up.port.uartclk = clk_get_rate(priv->sclk);
+
+ up.port.iotype = UPIO_MEM32;
+ up.port.serial_in = serial8250_em_serial_in;
+ up.port.serial_out = serial8250_em_serial_out;
+ up.dl_read = serial8250_em_serial_dl_read;
+ up.dl_write = serial8250_em_serial_dl_write;
+
+ ret = serial8250_register_8250_port(&up);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port\n");
+ goto err2;
+ }
+
+ priv->line = ret;
+ platform_set_drvdata(pdev, priv);
+ return 0;
+
+ err2:
+ clk_disable(priv->sclk);
+ clk_put(priv->sclk);
+ err1:
+ kfree(priv);
+ err0:
+ return ret;
+}
+
+static int __devexit serial8250_em_remove(struct platform_device *pdev)
+{
+ struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ clk_disable(priv->sclk);
+ clk_put(priv->sclk);
+ kfree(priv);
+ return 0;
+}
+
+static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+ { .compatible = "renesas,em-uart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
+
+static struct platform_driver serial8250_em_platform_driver = {
+ .driver = {
+ .name = "serial8250-em",
+ .of_match_table = serial8250_em_dt_ids,
+ .owner = THIS_MODULE,
+ },
+ .probe = serial8250_em_probe,
+ .remove = __devexit_p(serial8250_em_remove),
+};
+
+module_platform_driver(serial8250_em_platform_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 858dca8..28e7c7c 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/tty.h>
+#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
#include <linux/bitops.h>
@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx);
}
+static void kt_handle_break(struct uart_port *p)
+{
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
+ /*
+ * On receipt of a BI, serial device in Intel ME (Intel
+ * management engine) needs to have its fifos cleared for sane
+ * SOL (Serial Over Lan) output.
+ */
+ serial8250_clear_and_reinit_fifos(up);
+}
+
+static unsigned int kt_serial_in(struct uart_port *p, int offset)
+{
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
+ unsigned int val;
+
+ /*
+ * When the Intel ME (management engine) gets reset its serial
+ * port registers could return 0 momentarily. Functions like
+ * serial8250_console_write, read and save the IER, perform
+ * some operation and then restore it. In order to avoid
+ * setting IER register inadvertently to 0, if the value read
+ * is 0, double check with ier value in uart_8250_port and use
+ * that instead. up->ier should be the same value as what is
+ * currently configured.
+ */
+ val = inb(p->iobase + offset);
+ if (offset == UART_IER) {
+ if (val == 0)
+ val = up->ier;
+ }
+ return val;
+}
+
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
port->flags |= UPF_BUG_THRE;
+ port->serial_in = kt_serial_in;
+ port->handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
@@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8812,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8813,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8814,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8027,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8028,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8029,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800C,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800D,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
@@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
+
+ /*
+ * Ensure that every init quirk is properly torn down
+ */
+ if (priv->quirk->exit)
+ priv->quirk->exit(priv->dev);
}
EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 175c204..a27dd05 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -269,3 +269,11 @@ config SERIAL_8250_DW
help
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
+
+config SERIAL_8250_EM
+ tristate "Support for Emma Mobile intergrated serial port"
+ depends on SERIAL_8250 && ARM && HAVE_CLK
+ help
+ Selecting this option will add support for the integrated serial
+ port hardware found on the Emma Mobile line of processors.
+ If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 464320f..d7533c7 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
+obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3d569cd..4ad721f 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -52,6 +52,7 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/types.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -67,30 +68,6 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
-
-#define UART_WA_SAVE_NR 14
-
-static void pl011_lockup_wa(unsigned long data);
-static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
- ST_UART011_DMAWM,
- ST_UART011_TIMEOUT,
- ST_UART011_LCRH_RX,
- UART011_IBRD,
- UART011_FBRD,
- ST_UART011_LCRH_TX,
- UART011_IFLS,
- ST_UART011_XFCR,
- ST_UART011_XON1,
- ST_UART011_XON2,
- ST_UART011_XOFF1,
- ST_UART011_XOFF2,
- UART011_CR,
- UART011_IMSC
-};
-
-static u32 uart_wa_regdata[UART_WA_SAVE_NR];
-static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
-
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
@@ -100,6 +77,7 @@ struct vendor_data {
bool oversampling;
bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
+ bool cts_event_workaround;
};
static struct vendor_data vendor_arm = {
@@ -109,6 +87,7 @@ static struct vendor_data vendor_arm = {
.lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
+ .cts_event_workaround = false,
};
static struct vendor_data vendor_st = {
@@ -119,6 +98,7 @@ static struct vendor_data vendor_st = {
.oversampling = true,
.interrupt_may_hang = true,
.dma_threshold = true,
+ .cts_event_workaround = true,
};
static struct uart_amba_port *amba_ports[UART_NR];
@@ -1054,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL
#endif
-
-/*
- * pl011_lockup_wa
- * This workaround aims to break the deadlock situation
- * when after long transfer over uart in hardware flow
- * control, uart interrupt registers cannot be cleared.
- * Hence uart transfer gets blocked.
- *
- * It is seen that during such deadlock condition ICR
- * don't get cleared even on multiple write. This leads
- * pass_counter to decrease and finally reach zero. This
- * can be taken as trigger point to run this UART_BT_WA.
- *
- */
-static void pl011_lockup_wa(unsigned long data)
-{
- struct uart_amba_port *uap = amba_ports[0];
- void __iomem *base = uap->port.membase;
- struct circ_buf *xmit = &uap->port.state->xmit;
- struct tty_struct *tty = uap->port.state->port.tty;
- int buf_empty_retries = 200;
- int loop;
-
- /* Stop HCI layer from submitting data for tx */
- tty->hw_stopped = 1;
- while (!uart_circ_empty(xmit)) {
- if (buf_empty_retries-- == 0)
- break;
- udelay(100);
- }
-
- /* Backup registers */
- for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
- uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
-
- /* Disable UART so that FIFO data is flushed out */
- writew(0x00, uap->port.membase + UART011_CR);
-
- /* Soft reset UART module */
- if (uap->port.dev->platform_data) {
- struct amba_pl011_data *plat;
-
- plat = uap->port.dev->platform_data;
- if (plat->reset)
- plat->reset();
- }
-
- /* Restore registers */
- for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
- writew(uart_wa_regdata[loop] ,
- uap->port.membase + uart_wa_reg[loop]);
-
- /* Initialise the old status of the modem signals */
- uap->old_status = readw(uap->port.membase + UART01x_FR) &
- UART01x_FR_MODEM_ANY;
-
- if (readl(base + UART011_MIS) & 0x2)
- printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
-
- /* Start Tx/Rx */
- tty->hw_stopped = 0;
-}
-
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1245,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
+ unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS);
if (status) {
do {
+ if (uap->vendor->cts_event_workaround) {
+ /* workaround to make sure that all bits are unlocked.. */
+ writew(0x00, uap->port.membase + UART011_ICR);
+
+ /*
+ * WA: introduce 26ns(1 uart clk) delay before W1C;
+ * single apb access will incur 2 pclk(133.12Mhz) delay,
+ * so add 2 dummy reads
+ */
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ }
+
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
uap->port.membase + UART011_ICR);
@@ -1267,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS)
pl011_tx_chars(uap);
- if (pass_counter-- == 0) {
- if (uap->interrupt_may_hang)
- tasklet_schedule(&pl011_lockup_tlet);
+ if (pass_counter-- == 0)
break;
- }
status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
@@ -1916,6 +1844,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
struct vendor_data *vendor = id->data;
+ struct pinctrl *pinctrl;
void __iomem *base;
int i, ret;
@@ -1940,6 +1869,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto free;
}
+ pinctrl = devm_pinctrl_get_select_default(&dev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto unmap;
+ }
+
uap->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 5832fde..bd97db2 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -1,7 +1,7 @@
/*
* Blackfin On-Chip Serial Driver
*
- * Copyright 2006-2010 Analog Devices Inc.
+ * Copyright 2006-2011 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -35,10 +35,6 @@
#include <asm/portmux.h>
#include <asm/cacheflush.h>
#include <asm/dma.h>
-
-#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
#include <asm/bfin_serial.h>
#ifdef CONFIG_SERIAL_BFIN_MODULE
@@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port)
uart->tx_count = 0;
uart->tx_done = 1;
#else
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#endif
@@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
struct circ_buf *xmit = &uart->port.state->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#endif
@@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
*/
UART_CLEAR_IER(uart, ETBEI);
uart->port.icount.tx += uart->tx_count;
- if (!uart_circ_empty(xmit)) {
+ if (!(xmit->tail == 0 && xmit->head == 0)) {
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
- unsigned short irqstat;
+ unsigned int irqstat;
int x_pos, pos;
spin_lock(&uart->rx_lock);
@@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
static unsigned int bfin_serial_tx_empty(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short lsr;
+ unsigned int lsr;
lsr = UART_GET_LSR(uart);
if (lsr & TEMT)
@@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)
static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- u16 lcr = UART_GET_LCR(uart);
+ u32 lcr = UART_GET_LCR(uart);
if (break_state)
lcr |= SB;
else
@@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port)
}
/* CTS RTS PINs are negative assertive. */
- UART_PUT_MCR(uart, ACTS);
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);
UART_SET_IER(uart, EDSSI);
}
#endif
@@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
unsigned long flags;
unsigned int baud, quot;
- unsigned short val, ier, lcr = 0;
+ unsigned int ier, lcr = 0;
switch (termios->c_cflag & CSIZE) {
case CS8:
@@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
/* Disable UART */
ier = UART_GET_IER(uart);
+ UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
UART_DISABLE_INTS(uart);
- /* Set DLAB in LCR to Access DLL and DLH */
+ /* Set DLAB in LCR to Access CLK */
UART_SET_DLAB(uart);
- UART_PUT_DLL(uart, quot & 0xFF);
- UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+ UART_PUT_CLK(uart, quot);
SSYNC();
/* Clear DLAB in LCR to Access THR RBR IER */
UART_CLEAR_DLAB(uart);
- UART_PUT_LCR(uart, lcr);
+ UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);
/* Enable UART */
UART_ENABLE_INTS(uart, ier);
-
- val = UART_GET_GCTL(uart);
- val |= UCEN;
- UART_PUT_GCTL(uart, val);
+ UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);
/* Port speed changed, update the per-port timeout. */
uart_update_timeout(port, termios->c_cflag, baud);
@@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short val;
+ unsigned int val;
switch (ld) {
case N_IRDA:
val = UART_GET_GCTL(uart);
- val |= (IREN | RPOLC);
+ val |= (UMOD_IRDA | RPOLC);
UART_PUT_GCTL(uart, val);
break;
default:
val = UART_GET_GCTL(uart);
- val &= ~(IREN | RPOLC);
+ val &= ~(UMOD_MASK | RPOLC);
UART_PUT_GCTL(uart, val);
}
}
@@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
static void bfin_serial_reset_irda(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short val;
+ unsigned int val;
val = UART_GET_GCTL(uart);
- val &= ~(IREN | RPOLC);
+ val &= ~(UMOD_MASK | RPOLC);
UART_PUT_GCTL(uart, val);
SSYNC();
- val |= (IREN | RPOLC);
+ val |= (UMOD_IRDA | RPOLC);
UART_PUT_GCTL(uart, val);
SSYNC();
}
@@ -1070,12 +1063,12 @@ static void __init
bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
int *parity, int *bits)
{
- unsigned short status;
+ unsigned int status;
status = UART_GET_IER(uart) & (ERBFI | ETBEI);
if (status == (ERBFI | ETBEI)) {
/* ok, the port was enabled */
- u16 lcr, dlh, dll;
+ u32 lcr, clk;
lcr = UART_GET_LCR(uart);
@@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
else
*parity = 'o';
}
- switch (lcr & 0x03) {
- case 0:
- *bits = 5;
- break;
- case 1:
- *bits = 6;
- break;
- case 2:
- *bits = 7;
- break;
- case 3:
- *bits = 8;
- break;
- }
- /* Set DLAB in LCR to Access DLL and DLH */
+ *bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5;
+
+ /* Set DLAB in LCR to Access CLK */
UART_SET_DLAB(uart);
- dll = UART_GET_DLL(uart);
- dlh = UART_GET_DLH(uart);
+ clk = UART_GET_CLK(uart);
/* Clear DLAB in LCR to Access THR RBR IER */
UART_CLEAR_DLAB(uart);
- *baud = get_sclk() / (16*(dll | dlh << 8));
+ *baud = get_sclk() / (16*clk);
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 836fe273..d0f719f 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -40,7 +40,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/hardware/clps7111.h>
#define UART_NR 2
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 5b07c0c..7264d4d 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Input */
#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
/* first some sanity checks */
- if (!tty || !info->xmit.buf || !tmp_buf)
+ if (!tty || !info->xmit.buf)
return 0;
#ifdef SERIAL_DEBUG_DATA
@@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
@@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
{
struct e100_serial *info;
int retval;
- unsigned long page;
int allocated_resources = 0;
info = rs_table + tty->index;
@@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- return -ENOMEM;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
/*
* If the port is in the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4487,6 +4462,7 @@ static int __init rs_init(void)
info->enabled = 0;
}
}
+ tty_port_init(&info->port);
info->uses_dma_in = 0;
info->uses_dma_out = 0;
info->line = i;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e7fecee..ec20673 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -47,6 +47,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -1464,6 +1465,7 @@ static int serial_imx_probe(struct platform_device *pdev)
void __iomem *base;
int ret = 0;
struct resource *res;
+ struct pinctrl *pinctrl;
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
if (!sport)
@@ -1503,6 +1505,12 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto unmap;
+ }
+
sport->clk = clk_get(&pdev->dev, "uart");
if (IS_ERR(sport->clk)) {
ret = PTR_ERR(sport->clk);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 55fd362..ec56d83 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,6 +32,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
@@ -369,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
writel(ctrl, u->membase + AUART_LINECTRL);
writel(ctrl2, u->membase + AUART_CTRL2);
+
+ uart_update_timeout(u, termios->c_cflag, baud);
}
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
@@ -678,6 +681,7 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
u32 version;
int ret = 0;
struct resource *r;
+ struct pinctrl *pinctrl;
s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
if (!s) {
@@ -685,6 +689,12 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
goto out;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_free;
+ }
+
s->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk)) {
ret = PTR_ERR(s->clk);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index e8c9cee..5410c06 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -12,10 +12,13 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_serial.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
@@ -24,6 +27,26 @@ struct of_serial_info {
int line;
};
+#ifdef CONFIG_ARCH_TEGRA
+void tegra_serial_handle_break(struct uart_port *p)
+{
+ unsigned int status, tmout = 10000;
+
+ do {
+ status = p->serial_in(p, UART_LSR);
+ if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+ status = p->serial_in(p, UART_RX);
+ else
+ break;
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+/* FIXME remove this export when tegra finishes conversion to open firmware */
+EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
+#endif
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
+ if (type == PORT_TEGRA)
+ port->handle_break = tegra_serial_handle_break;
+
return 0;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d00b38e..d3cda0c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -44,6 +44,13 @@
#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
+#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
+
+#define OMAP_UART_REV_42 0x0402
+#define OMAP_UART_REV_46 0x0406
+#define OMAP_UART_REV_52 0x0502
+#define OMAP_UART_REV_63 0x0603
+
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */
@@ -53,6 +60,17 @@
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
+/* MVR register bitmasks */
+#define OMAP_UART_MVR_SCHEME_SHIFT 30
+
+#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0
+#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4
+#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f
+
+#define OMAP_UART_MVR_MAJ_MASK 0x700
+#define OMAP_UART_MVR_MAJ_SHIFT 8
+#define OMAP_UART_MVR_MIN_MASK 0x3f
+
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
return;
}
+static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+{
+ u32 mvr, scheme;
+ u16 revision, major, minor;
+
+ mvr = serial_in(up, UART_OMAP_MVER);
+
+ /* Check revision register scheme */
+ scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
+
+ switch (scheme) {
+ case 0: /* Legacy Scheme: OMAP2/3 */
+ /* MINOR_REV[0:4], MAJOR_REV[4:7] */
+ major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
+ OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
+ minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
+ break;
+ case 1:
+ /* New Scheme: OMAP4+ */
+ /* MINOR_REV[0:5], MAJOR_REV[8:10] */
+ major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
+ OMAP_UART_MVR_MAJ_SHIFT;
+ minor = (mvr & OMAP_UART_MVR_MIN_MASK);
+ break;
+ default:
+ dev_warn(&up->pdev->dev,
+ "Unknown %s revision, defaulting to highest\n",
+ up->name);
+ /* highest possible revision */
+ major = 0xff;
+ minor = 0xff;
+ }
+
+ /* normalize revision for the driver */
+ revision = UART_BUILD_REVISION(major, minor);
+
+ switch (revision) {
+ case OMAP_UART_REV_46:
+ up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+ UART_ERRATA_i291_DMA_FORCEIDLE);
+ break;
+ case OMAP_UART_REV_52:
+ up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+ UART_ERRATA_i291_DMA_FORCEIDLE);
+ break;
+ case OMAP_UART_REV_63:
+ up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+ break;
+ default:
+ break;
+ }
+}
+
static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
"%d\n", DEFAULT_CLK_SPEED);
}
up->uart_dma.uart_base = mem->start;
- up->errata = omap_up_info->errata;
if (omap_up_info->dma_enabled) {
up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
+ omap_serial_fill_features_erratas(up);
+
ui[up->port.line] = up;
serial_omap_add_console_port(up);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c2816f4..4fdec6a6 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -39,6 +39,7 @@ enum {
PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
PCH_UART_HANDLED_MS_INT_SHIFT,
+ PCH_UART_HANDLED_LS_INT_SHIFT,
};
enum {
@@ -63,6 +64,8 @@ enum {
PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
+
#define PCH_UART_RBR 0x00
#define PCH_UART_THR 0x00
@@ -229,7 +232,6 @@ struct eg20t_port {
int start_tx;
int start_rx;
int tx_empty;
- int int_dis_flag;
int trigger;
int trigger_level;
struct pch_uart_buffer rxbuf;
@@ -237,7 +239,6 @@ struct eg20t_port {
unsigned int fcr;
unsigned int mcr;
unsigned int use_dma;
- unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx;
struct pch_dma_slave param_tx;
@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
return i;
}
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)
{
- unsigned int iir;
- int ret;
-
- iir = ioread8(priv->membase + UART_IIR);
- ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
- return ret;
+ return ioread8(priv->membase + UART_IIR) &\
+ (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
}
static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
dma_release_channel(priv->chan_rx);
priv->chan_rx = NULL;
}
- if (sg_dma_address(&priv->sg_rx))
- dma_free_coherent(port->dev, port->fifosize,
- sg_virt(&priv->sg_rx),
- sg_dma_address(&priv->sg_rx));
+
+ if (priv->rx_buf_dma) {
+ dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
+ priv->rx_buf_dma);
+ priv->rx_buf_virt = NULL;
+ priv->rx_buf_dma = 0;
+ }
return;
}
@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
unsigned int handled;
u8 lsr;
int ret = 0;
- unsigned int iid;
+ unsigned char iid;
unsigned long flags;
+ int next = 1;
+ u8 msr;
spin_lock_irqsave(&priv->port.lock, flags);
handled = 0;
- while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+ while (next) {
+ iid = pch_uart_hal_get_iid(priv);
+ if (iid & PCH_UART_IIR_IP) /* No Interrupt */
+ break;
switch (iid) {
case PCH_UART_IID_RLS: /* Receiver Line Status */
lsr = pch_uart_hal_get_line_status(priv);
@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
UART_LSR_PE | UART_LSR_OE)) {
pch_uart_err_ir(priv, lsr);
ret = PCH_UART_HANDLED_RX_ERR_INT;
+ } else {
+ ret = PCH_UART_HANDLED_LS_INT;
}
break;
case PCH_UART_IID_RDR: /* Received Data Ready */
@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = handle_tx(priv);
break;
case PCH_UART_IID_MS: /* Modem Status */
- ret = PCH_UART_HANDLED_MS_INT;
+ msr = pch_uart_hal_get_modem(priv);
+ next = 0; /* MS ir prioirty is the lowest. So, MS ir
+ means final interrupt */
+ if ((msr & UART_MSR_ANY_DELTA) == 0)
+ break;
+ ret |= PCH_UART_HANDLED_MS_INT;
break;
default: /* Never junp to this label */
- dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
+ dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
iid, jiffies);
ret = -1;
+ next = 0;
break;
}
handled |= (unsigned int)ret;
}
- if (handled == 0 && iid <= 1) {
- if (priv->int_dis_flag)
- priv->int_dis_flag = 0;
- }
spin_unlock_irqrestore(&priv->port.lock, flags);
return IRQ_RETVAL(handled);
@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port);
priv->start_rx = 0;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
- priv->int_dis_flag = 1;
}
/* Enable the modem status interrupts. */
@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
__func__);
return -EOPNOTSUPP;
#endif
- priv->use_dma_flag = 1;
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
if (!priv->use_dma)
pch_request_dma(port);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c4c05b..246b823 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
tty_unregister_driver(p);
put_tty_driver(p);
kfree(drv->state);
+ drv->state = NULL;
drv->tty_driver = NULL;
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3158e17..4604153 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1052,9 +1052,17 @@ static int sci_request_irq(struct sci_port *port)
if (SCIx_IRQ_IS_MUXED(port)) {
i = SCIx_MUX_IRQ;
irq = up->irq;
- } else
+ } else {
irq = port->cfg->irqs[i];
+ /*
+ * Certain port types won't support all of the
+ * available interrupt sources.
+ */
+ if (unlikely(!irq))
+ continue;
+ }
+
desc = sci_irq_desc + i;
port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
dev_name(up->dev), desc->desc);
@@ -1094,6 +1102,15 @@ static void sci_free_irq(struct sci_port *port)
* IRQ first.
*/
for (i = 0; i < SCIx_NR_IRQS; i++) {
+ unsigned int irq = port->cfg->irqs[i];
+
+ /*
+ * Certain port types won't support all of the available
+ * interrupt sources.
+ */
+ if (unlikely(!irq))
+ continue;
+
free_irq(port->cfg->irqs[i], port);
kfree(port->irqstr[i]);
@@ -1564,10 +1581,32 @@ static void sci_enable_ms(struct uart_port *port)
static void sci_break_ctl(struct uart_port *port, int break_state)
{
- /*
- * Not supported by hardware. Most parts couple break and rx
- * interrupts together, with break detection always enabled.
- */
+ struct sci_port *s = to_sci_port(port);
+ struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+ unsigned short scscr, scsptr;
+
+ /* check wheter the port has SCSPTR */
+ if (!reg->size) {
+ /*
+ * Not supported by hardware. Most parts couple break and rx
+ * interrupts together, with break detection always enabled.
+ */
+ return;
+ }
+
+ scsptr = serial_port_in(port, SCSPTR);
+ scscr = serial_port_in(port, SCSCR);
+
+ if (break_state == -1) {
+ scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
+ scscr &= ~SCSCR_TE;
+ } else {
+ scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
+ scscr |= SCSCR_TE;
+ }
+
+ serial_port_out(port, SCSPTR, scsptr);
+ serial_port_out(port, SCSCR, scscr);
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 593d40a..5ed0daa 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa1debf..45b43f1 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a3dddc1..4a1e4f0 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
printk("%s(%d):%s block_til_ready() count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..91e326f 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
-
/**
- * tty_buffer_request_room - grow tty buffer if needed
+ * __tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- *
- * Locking: Takes tty->buf.lock
+ * Locking: Caller must hold tty->buf.lock
*/
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
int left;
- unsigned long flags;
-
- spin_lock_irqsave(&tty->buf.lock, flags);
-
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
size = left;
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
+
+
+/**
+ * tty_buffer_request_room - grow tty buffer if needed
+ * @tty: tty structure
+ * @size: size desired
+ *
+ * Make at least size bytes of linear space available for the tty
+ * buffer. If we fail return the size we managed to find.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+ unsigned long flags;
+ int length;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ length = __tty_buffer_request_room(tty, size);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ return length;
+}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
copied += space;
chars += space;
flags += space;
@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index d939bd7..9e930c0 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
put_device(tty->dev);
kfree(tty->write_buf);
tty_buffer_free_all(tty);
+ tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
}
spin_unlock(&redirect_lock);
- tty_lock();
+ tty_lock(tty);
/* some functions below drop BTM, so we need this bit */
set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
- tty_unlock();
+ tty_unlock(tty);
if (f)
fput(f);
@@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit)
*/
void no_tty(void)
{
+ /* FIXME: Review locking here. The tty_lock never covered any race
+ between a new association and proc_clear_tty but possible we need
+ to protect against this anyway */
struct task_struct *tsk = current;
- tty_lock();
disassociate_ctty(0);
- tty_unlock();
proc_clear_tty(tsk);
}
@@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
{
if (tty) {
mutex_lock(&tty->atomic_write_lock);
- tty_lock();
+ tty_lock(tty);
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
- tty_unlock();
+ tty_unlock(tty);
tty->ops->write(tty, msg, strlen(msg));
} else
- tty_unlock();
+ tty_unlock(tty);
tty_write_unlock(tty);
}
return;
@@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
}
initialize_tty_struct(tty, driver, idx);
+ tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
if (retval < 0)
goto err_deinit_tty;
@@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
retval = tty_ldisc_setup(tty, tty->link);
if (retval)
goto err_release_tty;
+ /* Return the tty locked so that it cannot vanish under the caller */
return tty;
err_deinit_tty:
+ tty_unlock(tty);
deinitialize_tty_struct(tty);
free_tty_struct(tty);
err_module_put:
@@ -1425,6 +1430,7 @@ err_module_put:
/* call the tty release_tty routine to clean out this slot */
err_release_tty:
+ tty_unlock(tty);
printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
release_tty(tty, idx);
@@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty_paranoia_check(tty, inode, __func__))
return 0;
- tty_lock();
+ tty_lock(tty);
check_tty_count(tty, __func__);
__tty_fasync(-1, filp, 0);
@@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+ /* Review: parallel close */
o_tty = tty->link;
if (tty_release_checks(tty, o_tty, idx)) {
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
@@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty->ops->close)
tty->ops->close(tty, filp);
- tty_unlock();
+ tty_unlock(tty);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
@@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
opens on /dev/tty */
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock_pair(tty, o_tty);
tty_closing = tty->count <= 1;
o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
@@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
__func__, tty_name(tty, buf));
- tty_unlock();
+ tty_unlock_pair(tty, o_tty);
mutex_unlock(&tty_mutex);
schedule();
}
@@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
/* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing)) {
- tty_unlock();
+ tty_unlock_pair(tty, o_tty);
return 0;
}
@@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
tty_ldisc_release(tty, o_tty);
/*
* The release_tty function takes care of the details of clearing
- * the slots and preserving the termios structure.
+ * the slots and preserving the termios structure. The tty_unlock_pair
+ * should be safe as we keep a kref while the tty is locked (so the
+ * unlock never unlocks a freed tty).
*/
release_tty(tty, idx);
+ tty_unlock_pair(tty, o_tty);
/* Make this pty number available for reallocation */
if (devpts)
devpts_kill_index(inode, idx);
- tty_unlock();
return 0;
}
@@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp)
*
* We cannot return driver and index like for the other nodes because
* devpts will not work then. It expects inodes to be from devpts FS.
+ *
+ * We need to move to returning a refcounted object from all the lookup
+ * paths including this one.
*/
static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
{
@@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
/* noctty = 1; */
tty_kref_put(tty);
/* FIXME: we put a reference and return a TTY! */
+ /* This is only safe because the caller holds tty_mutex */
return tty;
}
@@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
* Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
* tty->count should protect the rest.
* ->siglock protects ->signal/->sighand
+ *
+ * Note: the tty_unlock/lock cases without a ref are only safe due to
+ * tty_mutex
*/
static int tty_open(struct inode *inode, struct file *filp)
@@ -1911,8 +1927,7 @@ retry_open:
retval = 0;
mutex_lock(&tty_mutex);
- tty_lock();
-
+ /* This is protected by the tty_mutex */
tty = tty_open_current_tty(device, filp);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
@@ -1933,17 +1948,19 @@ retry_open:
}
if (tty) {
+ tty_lock(tty);
retval = tty_reopen(tty);
- if (retval)
+ if (retval < 0) {
+ tty_unlock(tty);
tty = ERR_PTR(retval);
- } else
+ }
+ } else /* Returns with the tty_lock held for now */
tty = tty_init_dev(driver, index);
mutex_unlock(&tty_mutex);
if (driver)
tty_driver_kref_put(driver);
if (IS_ERR(tty)) {
- tty_unlock();
retval = PTR_ERR(tty);
goto err_file;
}
@@ -1972,7 +1989,7 @@ retry_open:
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
retval, tty->name);
#endif
- tty_unlock(); /* need to call tty_release without BTM */
+ tty_unlock(tty); /* need to call tty_release without BTM */
tty_release(inode, filp);
if (retval != -ERESTARTSYS)
return retval;
@@ -1984,17 +2001,15 @@ retry_open:
/*
* Need to reset f_op in case a hangup happened.
*/
- tty_lock();
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
- tty_unlock();
goto retry_open;
}
- tty_unlock();
+ tty_unlock(tty);
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock(tty);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
@@ -2002,11 +2017,10 @@ retry_open:
tty->session == NULL)
__proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
- tty_unlock();
+ tty_unlock(tty);
mutex_unlock(&tty_mutex);
return 0;
err_unlock:
- tty_unlock();
mutex_unlock(&tty_mutex);
/* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver))
@@ -2089,10 +2103,13 @@ out:
static int tty_fasync(int fd, struct file *filp, int on)
{
+ struct tty_struct *tty = file_tty(filp);
int retval;
- tty_lock();
+
+ tty_lock(tty);
retval = __tty_fasync(fd, filp, on);
- tty_unlock();
+ tty_unlock(tty);
+
return retval;
}
@@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->pgrp = NULL;
tty->overrun_time = jiffies;
tty_buffer_init(tty);
+ mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 24b95db..173a900 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -28,7 +28,6 @@
static DEFINE_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
@@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld)
return;
}
local_irq_restore(flags);
- wake_up(&tty_ldisc_idle);
+ wake_up(&ld->wq_idle);
}
/**
@@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
ld->ops = ldops;
atomic_set(&ld->users, 1);
+ init_waitqueue_head(&ld->wq_idle);
+
return ld;
}
@@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
{
long ret;
- ret = wait_event_timeout(tty_ldisc_idle,
+ ret = wait_event_timeout(tty->ldisc->wq_idle,
atomic_read(&tty->ldisc->users) == 1, timeout);
return ret > 0 ? 0 : -EBUSY;
}
@@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
- tty_lock();
+ tty_lock(tty);
/*
* We need to look at the tty locking here for pty/tty pairs
* when both sides try to change in parallel.
@@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
*/
if (tty->ldisc->ops->num == ldisc) {
- tty_unlock();
+ tty_unlock(tty);
tty_ldisc_put(new_ldisc);
return 0;
}
- tty_unlock();
+ tty_unlock(tty);
/*
* Problem: What do we do if this blocks ?
* We could deadlock here
@@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_wait_until_sent(tty, 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
@@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
wait_event(tty_ldisc_wait,
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
}
@@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
o_ldisc = tty->ldisc;
- tty_unlock();
+ tty_unlock(tty);
/*
* Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit
@@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* handle wait idle failure locked */
@@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
mutex_unlock(&tty->ldisc_mutex);
tty_ldisc_put(new_ldisc);
- tty_unlock();
+ tty_unlock(tty);
return -EIO;
}
@@ -707,7 +708,7 @@ enable:
if (o_work)
schedule_work(&o_tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
@@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* need to wait for another function taking the BTM
*/
clear_bit(TTY_LDISC, &tty->flags);
- tty_unlock();
+ tty_unlock(tty);
cancel_work_sync(&tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
retry:
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* At this point we have a closed ldisc and we want to
@@ -830,7 +831,7 @@ retry:
if (atomic_read(&tty->ldisc->users) != 1) {
char cur_n[TASK_COMM_LEN], tty_n[64];
long timeout = 3 * HZ;
- tty_unlock();
+ tty_unlock(tty);
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
* race with the set_ldisc code path.
*/
- tty_unlock();
+ tty_unlock(tty);
tty_ldisc_halt(tty);
tty_ldisc_flush_works(tty);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 9ff986c..69adc80 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,29 +4,59 @@
#include <linux/semaphore.h>
#include <linux/sched.h>
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
/*
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(void)
+
+void __lockfunc tty_lock(struct tty_struct *tty)
{
- mutex_lock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "L Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ tty_kref_get(tty);
+ mutex_lock(&tty->legacy_mutex);
}
EXPORT_SYMBOL(tty_lock);
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
{
- mutex_unlock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "U Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ mutex_unlock(&tty->legacy_mutex);
+ tty_kref_put(tty);
}
EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ if (tty < tty2) {
+ tty_lock(tty);
+ tty_lock(tty2);
+ } else {
+ if (tty2 && tty2 != tty)
+ tty_lock(tty2);
+ tty_lock(tty);
+ }
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ tty_unlock(tty);
+ if (tty2 && tty2 != tty)
+ tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index bf6e238..d9cca95 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
- wait_event_interruptible_tty(port->close_wait,
+ wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
@@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = -ERESTARTSYS;
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
finish_wait(&port->open_wait, &wait);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 8308fc7..2aaa0c2 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/tty.h>
#include <asm/uaccess.h>
+#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/vt_kern.h>
@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++) {
unsigned char uc;
__get_user(uc, arg+i);
@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
}
update_user_maps();
+ console_unlock();
return 0;
}
@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++)
- {
- ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
- __put_user((ch & ~0xff) ? 0 : ch, arg+i);
- }
+ {
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+ __put_user((ch & ~0xff) ? 0 : ch, arg+i);
+ }
+ console_unlock();
return 0;
}
@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++) {
unsigned short us;
__get_user(us, arg+i);
@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
}
update_user_maps();
+ console_unlock();
return 0;
}
@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++)
__put_user(p[i], arg+i);
+ console_unlock();
return 0;
}
@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
}
}
+/* Caller must hold the console lock */
void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
return 0;
}
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+/* ui is a leftover from using a hashtable, but might be used again
+ Caller must hold the lock */
+static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
-
+
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p && p->readonly) return -EIO;
+ if (p && p->readonly)
+ return -EIO;
+
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
- if (p) p->refcount++;
+ if (p)
+ p->refcount++;
return -ENOMEM;
}
q->refcount=1;
@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return 0;
}
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+ int ret;
+ console_lock();
+ ret = con_do_clear_unimap(vc, ui);
+ console_unlock();
+ return ret;
+}
+
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{
int err = 0, err1, i;
struct uni_pagedir *p, *q;
+ console_lock();
+
/* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p->readonly) return -EIO;
+ if (p->readonly) {
+ console_unlock();
+ return -EIO;
+ }
- if (!ct) return 0;
+ if (!ct) {
+ console_unlock();
+ return 0;
+ }
if (p->refcount > 1) {
int j, k;
u16 **p1, *p2, l;
- err1 = con_clear_unimap(vc, NULL);
- if (err1) return err1;
+ err1 = con_do_clear_unimap(vc, NULL);
+ if (err1) {
+ console_unlock();
+ return err1;
+ }
/*
* Since refcount was > 1, con_clear_unimap() allocated a
@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
*vc->vc_uni_pagedir_loc = (unsigned long)p;
con_release_unimap(q);
kfree(q);
- return err1;
+ console_unlock();
+ return err1;
}
}
} else {
@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/*
* Merge with fontmaps of any other virtual consoles.
*/
- if (con_unify_unimap(vc, p))
+ if (con_unify_unimap(vc, p)) {
+ console_unlock();
return err;
+ }
for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update inverse translations */
set_inverse_trans_unicode(vc, p);
-
+
+ console_unlock();
return err;
}
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
- The representation used was the most compact I could come up
- with. This routine is executed at sys_setup time, and when the
- PIO_FONTRESET ioctl is called. */
-
+/**
+ * con_set_default_unimap - set default unicode map
+ * @vc: the console we are updating
+ *
+ * Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+ * The representation used was the most compact I could come up
+ * with. This routine is executed at video setup, and when the
+ * PIO_FONTRESET ioctl is called.
+ *
+ * The caller must hold the console lock
+ */
int con_set_default_unimap(struct vc_data *vc)
{
int i, j, err = 0, err1;
@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
+
dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
if (p && !--p->refcount) {
@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
/* The default font is always 256 characters */
- err = con_clear_unimap(vc, NULL);
- if (err) return err;
+ err = con_do_clear_unimap(vc, NULL);
+ if (err)
+ return err;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
q = dfont_unitable;
@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
}
EXPORT_SYMBOL(con_set_default_unimap);
+/**
+ * con_copy_unimap - copy unimap between two vts
+ * @dst_vc: target
+ * @src_vt: source
+ *
+ * The caller must hold the console lock when invoking this method
+ */
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
{
struct uni_pagedir *q;
@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
*dst_vc->vc_uni_pagedir_loc = (long)q;
return 0;
}
+EXPORT_SYMBOL(con_copy_unimap);
+/**
+ * con_get_unimap - get the unicode map
+ * @vc: the console to read from
+ *
+ * Read the console unicode data for this console. Called from the ioctl
+ * handlers.
+ */
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
{
int i, j, k, ect;
u16 **p1, *p2;
struct uni_pagedir *p;
+ console_lock();
+
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
}
}
__put_user(ect, uct);
+ console_unlock();
return ((ect <= ct) ? 0 : -ENOMEM);
}
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
- struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-
- if (p)
- p->readonly = rdonly;
-}
-
/*
* Always use USER_MAP. These functions are used by the keyboard,
* which shouldn't be affected by G0/G1 switching, etc.
* If the user map still contains default values, i.e. the
* direct-to-font mapping, then assume user is using Latin1.
+ *
+ * FIXME: at some point we need to decide if we want to lock the table
+ * update element itself via the keyboard_event_lock for consistency with the
+ * keyboard driver as well as the consoles
*/
/* may be called during an interrupt */
u32 conv_8bit_to_uni(unsigned char c)
@@ -777,4 +837,3 @@ console_map_init(void)
con_set_default_unimap(vc_cons[i].d);
}
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 3b0c4e3..48cc6f2 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -53,17 +53,13 @@ extern void ctrl_alt_del(void);
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the
- * keypad to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
+#include <asm/kbdleds.h>
#else
-#define KBD_DEFLEDS 0
+static inline int kbd_defleds(void)
+{
+ return 0;
+}
#endif
#define KBD_DEFLOCK 0
@@ -1524,8 +1520,8 @@ int __init kbd_init(void)
int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- kbd_table[i].ledflagstate = KBD_DEFLEDS;
- kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+ kbd_table[i].ledflagstate = kbd_defleds();
+ kbd_table[i].default_ledflagstate = kbd_defleds();
kbd_table[i].ledmode = LED_SHOW_FLAGS;
kbd_table[i].lockstate = KBD_DEFLOCK;
kbd_table[i].slockstate = 0;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 2156188..84cbf29 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc)
vc->vc_sw->con_set_palette(vc, color_table);
}
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
- int i, j, k;
-
- WARN_CONSOLE_UNLOCKED();
-
- for (i = 0; i < 16; i++)
- if (set) {
- get_user(default_red[i], arg++);
- get_user(default_grn[i], arg++);
- get_user(default_blu[i], arg++);
- } else {
- put_user(default_red[i], arg++);
- put_user(default_grn[i], arg++);
- put_user(default_blu[i], arg++);
- }
- if (set) {
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- if (vc_cons_allocated(i)) {
- for (j = k = 0; j < 16; j++) {
- vc_cons[i].d->vc_palette[k++] = default_red[j];
- vc_cons[i].d->vc_palette[k++] = default_grn[j];
- vc_cons[i].d->vc_palette[k++] = default_blu[j];
- }
- set_palette(vc_cons[i].d);
- }
- }
- return 0;
-}
-
/*
* Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
@@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set)
int con_set_cmap(unsigned char __user *arg)
{
- int rc;
+ int i, j, k;
+ unsigned char colormap[3*16];
+
+ if (copy_from_user(colormap, arg, sizeof(colormap)))
+ return -EFAULT;
console_lock();
- rc = set_get_cmap (arg,1);
+ for (i = k = 0; i < 16; i++) {
+ default_red[i] = colormap[k++];
+ default_grn[i] = colormap[k++];
+ default_blu[i] = colormap[k++];
+ }
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ for (j = k = 0; j < 16; j++) {
+ vc_cons[i].d->vc_palette[k++] = default_red[j];
+ vc_cons[i].d->vc_palette[k++] = default_grn[j];
+ vc_cons[i].d->vc_palette[k++] = default_blu[j];
+ }
+ set_palette(vc_cons[i].d);
+ }
console_unlock();
- return rc;
+ return 0;
}
int con_get_cmap(unsigned char __user *arg)
{
- int rc;
+ int i, k;
+ unsigned char colormap[3*16];
console_lock();
- rc = set_get_cmap (arg,0);
+ for (i = k = 0; i < 16; i++) {
+ colormap[k++] = default_red[i];
+ colormap[k++] = default_grn[i];
+ colormap[k++] = default_blu[i];
+ }
console_unlock();
- return rc;
+ if (copy_to_user(arg, colormap, sizeof(colormap)))
+ return -EFAULT;
+
+ return 0;
}
void reset_palette(struct vc_data *vc)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..6461854 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
ret = con_font_op(vc_cons[fg_console].d, &op);
if (ret)
break;
+ console_lock();
con_set_default_unimap(vc_cons[fg_console].d);
+ console_unlock();
break;
}
#endif
@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_SCRNMAP:
if (!perm)
ret = -EPERM;
- else {
- tty_lock();
+ else
ret = con_set_trans_old(up);
- tty_unlock();
- }
break;
case GIO_SCRNMAP:
- tty_lock();
ret = con_get_trans_old(up);
- tty_unlock();
break;
case PIO_UNISCRNMAP:
if (!perm)
ret = -EPERM;
- else {
- tty_lock();
+ else
ret = con_set_trans_new(up);
- tty_unlock();
- }
break;
case GIO_UNISCRNMAP:
- tty_lock();
ret = con_get_trans_new(up);
- tty_unlock();
break;
case PIO_UNIMAPCLR:
@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret)
ret = -EFAULT;
- else {
- tty_lock();
+ else
con_clear_unimap(vc, &ui);
- tty_unlock();
- }
break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
- tty_lock();
ret = do_unimap_ioctl(cmd, up, perm, vc);
- tty_unlock();
break;
case VT_LOCKSWITCH:
@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
case PIO_UNIMAP:
case GIO_UNIMAP:
- tty_lock();
ret = compat_unimap_ioctl(cmd, up, perm, vc);
- tty_unlock();
break;
/*
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index b98371d..42202cd 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -146,6 +146,14 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
priv->flags = 0; /* interrupt is enabled to begin with */
priv->pdev = pdev;
+ if (!uioinfo->irq) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ\n");
+ goto bad0;
+ }
+ uioinfo->irq = ret;
+ }
uiomem = &uioinfo->mem[0];
for (i = 0; i < pdev->num_resources; ++i) {
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 76316a3..a7773a3 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -133,6 +133,8 @@ source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
+source "drivers/usb/chipidea/Kconfig"
+
source "drivers/usb/renesas_usbhs/Kconfig"
source "drivers/usb/class/Kconfig"
@@ -177,6 +179,8 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
+source "drivers/usb/phy/Kconfig"
+
source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 53a7bc0..c691eea 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -46,12 +46,14 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
+obj-$(CONFIG_USB) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
obj-$(CONFIG_USB_MUSB_HDRC) += musb/
+obj-$(CONFIG_USB_CHIPIDEA) += chipidea/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_GADGET) += gadget/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 98b89fe..b7eb86a 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -674,7 +674,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
}
ret = offd;
- dbg("cm %#x", cm);
+ usb_dbg(instance->usbatm, "cm %#x\n", cm);
fail:
mutex_unlock(&instance->cm_serialize);
err:
@@ -733,7 +733,7 @@ static int cxacru_card_status(struct cxacru_data *instance)
{
int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
if (ret < 0) { /* firmware not loaded */
- dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+ usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret);
return ret;
}
return 0;
@@ -758,7 +758,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
int ret;
int start_polling = 1;
- dbg("cxacru_atm_start");
+ dev_dbg(&intf->dev, "%s\n", __func__);
/* Read MAC address */
ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
@@ -962,13 +962,13 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
buf, offb, NULL, CMD_TIMEOUT);
if (ret < 0) {
- dbg("sending fw %#x failed", fw);
+ dev_dbg(&usb_dev->dev, "sending fw %#x failed\n", fw);
goto cleanup;
}
offb = 0;
}
} while (offd < size);
- dbg("sent fw %#x", fw);
+ dev_dbg(&usb_dev->dev, "sent fw %#x\n", fw);
ret = 0;
@@ -988,7 +988,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
usb_dev->descriptor.idProduct };
__le32 val;
- dbg("cxacru_upload_firmware");
+ usb_dbg(usbatm, "%s\n", __func__);
/* FirmwarePllFClkValue */
val = cpu_to_le32(instance->modem_type->pll_f_clk);
@@ -1074,7 +1074,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
char buf[16];
sprintf(buf, "cxacru-%s.bin", phase);
- dbg("cxacru_find_firmware: looking for %s", buf);
+ usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf);
if (request_firmware(fw_p, buf, dev)) {
usb_dbg(usbatm, "no stage %s firmware found\n", phase);
@@ -1115,9 +1115,9 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
ret = cxacru_card_status(instance);
if (ret)
- dbg("modem initialisation failed");
+ usb_dbg(usbatm_instance, "modem initialisation failed\n");
else
- dbg("done setting up the modem");
+ usb_dbg(usbatm_instance, "done setting up the modem\n");
return ret;
}
@@ -1133,7 +1133,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
/* instance init */
instance = kzalloc(sizeof(*instance), GFP_KERNEL);
if (!instance) {
- dbg("cxacru_bind: no memory for instance data");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n");
return -ENOMEM;
}
@@ -1149,31 +1149,31 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->rcv_buf) {
- dbg("cxacru_bind: no memory for rcv_buf");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_buf\n");
ret = -ENOMEM;
goto fail;
}
instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->snd_buf) {
- dbg("cxacru_bind: no memory for snd_buf");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_buf\n");
ret = -ENOMEM;
goto fail;
}
instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->rcv_urb) {
- dbg("cxacru_bind: no memory for rcv_urb");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n");
ret = -ENOMEM;
goto fail;
}
instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->snd_urb) {
- dbg("cxacru_bind: no memory for snd_urb");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n");
ret = -ENOMEM;
goto fail;
}
if (!cmd_ep) {
- dbg("cxacru_bind: no command endpoint");
+ usb_dbg(usbatm_instance, "cxacru_bind: no command endpoint\n");
ret = -ENODEV;
goto fail;
}
@@ -1227,10 +1227,10 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
struct cxacru_data *instance = usbatm_instance->driver_data;
int is_polling = 1;
- dbg("cxacru_unbind entered");
+ usb_dbg(usbatm_instance, "cxacru_unbind entered\n");
if (!instance) {
- dbg("cxacru_unbind: NULL instance!");
+ usb_dbg(usbatm_instance, "cxacru_unbind: NULL instance!\n");
return;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 98dd9e4..975e9c6 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -170,7 +170,7 @@ static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int sta
"%sabling SW buffering: usb_control_msg returned %d\n",
state ? "En" : "Dis", ret);
else
- dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
+ usb_dbg(usbatm, "speedtch_set_swbuff: %sbled SW buffering\n", state ? "En" : "Dis");
}
static void speedtch_test_sequence(struct speedtch_instance_data *instance)
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 01ea5d7..d7e422d 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1357,10 +1357,8 @@ static int uea_stat_e1(struct uea_softc *sc)
/* release the dsp firmware as it is not needed until
* the next failure
*/
- if (sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to
@@ -1496,10 +1494,8 @@ static int uea_stat_e4(struct uea_softc *sc)
/* release the dsp firmware as it is not needed until
* the next failure
*/
- if (sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to
@@ -2240,8 +2236,7 @@ static void uea_stop(struct uea_softc *sc)
/* flush the work item, when no one can schedule it */
flush_work_sync(&sc->task);
- if (sc->dsp_firm)
- release_firmware(sc->dsp_firm);
+ release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
}
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index d3448ca..ee62b35 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -86,7 +86,7 @@
#ifdef VERBOSE_DEBUG
static int usbatm_print_packet(const unsigned char *data, int len);
#define PACKETDEBUG(arg...) usbatm_print_packet(arg)
-#define vdbg(arg...) dbg(arg)
+#define vdbg(arg...) dev_dbg(arg)
#else
#define PACKETDEBUG(arg...)
#define vdbg(arg...)
@@ -714,7 +714,7 @@ static void usbatm_destroy_instance(struct kref *kref)
{
struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
tasklet_kill(&instance->rx_channel.tasklet);
tasklet_kill(&instance->tx_channel.tasklet);
@@ -724,14 +724,14 @@ static void usbatm_destroy_instance(struct kref *kref)
static void usbatm_get_instance(struct usbatm_data *instance)
{
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
kref_get(&instance->refcount);
}
static void usbatm_put_instance(struct usbatm_data *instance)
{
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
kref_put(&instance->refcount, usbatm_destroy_instance);
}
@@ -745,11 +745,10 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev)
{
struct usbatm_data *instance = atm_dev->dev_data;
- dbg("%s", __func__);
-
if (!instance)
return;
+ usb_dbg(instance, "%s\n", __func__);
atm_dev->dev_data = NULL; /* catch bugs */
usbatm_put_instance(instance); /* taken in usbatm_atm_init */
}
@@ -759,10 +758,8 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag
struct usbatm_data *instance = atm_dev->dev_data;
int left = *pos;
- if (!instance) {
- dbg("%s: NULL instance!", __func__);
+ if (!instance)
return -ENODEV;
- }
if (!left--)
return sprintf(page, "%s\n", instance->description);
@@ -804,10 +801,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
int vci = vcc->vci;
short vpi = vcc->vpi;
- if (!instance) {
- dbg("%s: NULL data!", __func__);
+ if (!instance)
return -ENODEV;
- }
atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
@@ -884,10 +879,8 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
struct usbatm_data *instance = vcc->dev->dev_data;
struct usbatm_vcc_data *vcc_data = vcc->dev_data;
- if (!instance || !vcc_data) {
- dbg("%s: NULL data!", __func__);
+ if (!instance || !vcc_data)
return;
- }
atm_dbg(instance, "%s entered\n", __func__);
@@ -929,10 +922,8 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
{
struct usbatm_data *instance = atm_dev->dev_data;
- if (!instance || instance->disconnected) {
- dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance");
+ if (!instance || instance->disconnected)
return -ENODEV;
- }
switch (cmd) {
case ATM_QUERYLOOP:
@@ -1336,8 +1327,6 @@ EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
static int __init usbatm_usb_init(void)
{
- dbg("%s: driver version %s", __func__, DRIVER_VERSION);
-
if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
return -EIO;
@@ -1357,7 +1346,6 @@ module_init(usbatm_usb_init);
static void __exit usbatm_usb_exit(void)
{
- dbg("%s", __func__);
}
module_exit(usbatm_usb_exit);
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 48ee0c5..14ec9f0 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -187,8 +187,6 @@ static int __init xusbatm_init(void)
{
int i;
- dbg("xusbatm_init");
-
if (!num_vendor ||
num_vendor != num_product ||
num_vendor != num_rx_endpoint ||
@@ -221,8 +219,6 @@ module_init(xusbatm_init);
static void __exit xusbatm_exit(void)
{
- dbg("xusbatm_exit entered");
-
usb_deregister(&xusbatm_usb_driver);
}
module_exit(xusbatm_exit);
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
new file mode 100644
index 0000000..fd36dc8
--- /dev/null
+++ b/drivers/usb/chipidea/Kconfig
@@ -0,0 +1,32 @@
+config USB_CHIPIDEA
+ tristate "ChipIdea Highspeed Dual Role Controller"
+ depends on USB
+ help
+ Say Y here if your system has a dual role high speed USB
+ controller based on ChipIdea silicon IP. Currently, only the
+ peripheral mode is supported.
+
+ When compiled dynamically, the module will be called ci-hdrc.ko.
+
+if USB_CHIPIDEA
+
+config USB_CHIPIDEA_UDC
+ bool "ChipIdea device controller"
+ depends on USB_GADGET
+ select USB_GADGET_DUALSPEED
+ help
+ Say Y here to enable device controller functionality of the
+ ChipIdea driver.
+
+config USB_CHIPIDEA_HOST
+ bool "ChipIdea host controller"
+ help
+ Say Y here to enable host controller functionality of the
+ ChipIdea driver.
+
+config USB_CHIPIDEA_DEBUG
+ bool "ChipIdea driver debug"
+ help
+ Say Y here to enable debugging output of the ChipIdea driver.
+
+endif
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
new file mode 100644
index 0000000..cc34937
--- /dev/null
+++ b/drivers/usb/chipidea/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
+
+ci_hdrc-y := core.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
+
+ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
+endif
+
+ifneq ($(CONFIG_ARCH_MSM),)
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
+endif
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
new file mode 100644
index 0000000..050de85
--- /dev/null
+++ b/drivers/usb/chipidea/bits.h
@@ -0,0 +1,90 @@
+/*
+ * bits.h - register bits of the ChipIdea USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_BITS_H
+#define __DRIVERS_USB_CHIPIDEA_BITS_H
+
+#include <linux/usb/ehci_def.h>
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN (0x1F << 0)
+#define DCCPARAMS_DC BIT(7)
+#define DCCPARAMS_HC BIT(8)
+
+/* TESTMODE */
+#define TESTMODE_FORCE BIT(0)
+
+/* USBCMD */
+#define USBCMD_RS BIT(0)
+#define USBCMD_RST BIT(1)
+#define USBCMD_SUTW BIT(13)
+#define USBCMD_ATDTW BIT(14)
+
+/* USBSTS & USBINTR */
+#define USBi_UI BIT(0)
+#define USBi_UEI BIT(1)
+#define USBi_PCI BIT(2)
+#define USBi_URI BIT(6)
+#define USBi_SLI BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA BIT(24)
+#define DEVICEADDR_USBADR (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_FPR BIT(6)
+#define PORTSC_SUSP BIT(7)
+#define PORTSC_HSP BIT(9)
+#define PORTSC_PTC (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD (0x03UL << 25)
+#define DEVLC_PSPD_HS (0x02UL << 25)
+
+/* OTGSC */
+#define OTGSC_IDPU BIT(5)
+#define OTGSC_ID BIT(8)
+#define OTGSC_AVV BIT(9)
+#define OTGSC_ASV BIT(10)
+#define OTGSC_BSV BIT(11)
+#define OTGSC_BSE BIT(12)
+#define OTGSC_IDIS BIT(16)
+#define OTGSC_AVVIS BIT(17)
+#define OTGSC_ASVIS BIT(18)
+#define OTGSC_BSVIS BIT(19)
+#define OTGSC_BSEIS BIT(20)
+#define OTGSC_IDIE BIT(24)
+#define OTGSC_AVVIE BIT(25)
+#define OTGSC_ASVIE BIT(26)
+#define OTGSC_BSVIE BIT(27)
+#define OTGSC_BSEIE BIT(28)
+
+/* USBMODE */
+#define USBMODE_CM (0x03UL << 0)
+#define USBMODE_CM_DC (0x02UL << 0)
+#define USBMODE_SLOM BIT(3)
+#define USBMODE_CI_SDIS BIT(4)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS BIT(0)
+#define ENDPTCTRL_RXT (0x03UL << 2)
+#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
+#define ENDPTCTRL_RXE BIT(7)
+#define ENDPTCTRL_TXS BIT(16)
+#define ENDPTCTRL_TXT (0x03UL << 18)
+#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
+#define ENDPTCTRL_TXE BIT(23)
+
+#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
new file mode 100644
index 0000000..50911f8
--- /dev/null
+++ b/drivers/usb/chipidea/ci.h
@@ -0,0 +1,313 @@
+/*
+ * ci.h - common structures, functions, and macros of the ChipIdea driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_CI_H
+#define __DRIVERS_USB_CHIPIDEA_CI_H
+
+#include <linux/list.h>
+#include <linux/irqreturn.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
+#define ENDPT_MAX 32
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/**
+ * struct ci13xxx_ep - endpoint representation
+ * @ep: endpoint structure for gadget drivers
+ * @dir: endpoint direction (TX/RX)
+ * @num: endpoint number
+ * @type: endpoint type
+ * @name: string description of the endpoint
+ * @qh: queue head for this endpoint
+ * @wedge: is the endpoint wedged
+ * @udc: pointer to the controller
+ * @lock: pointer to controller's spinlock
+ * @td_pool: pointer to controller's TD pool
+ */
+struct ci13xxx_ep {
+ struct usb_ep ep;
+ u8 dir;
+ u8 num;
+ u8 type;
+ char name[16];
+ struct {
+ struct list_head queue;
+ struct ci13xxx_qh *ptr;
+ dma_addr_t dma;
+ } qh;
+ int wedge;
+
+ /* global resources */
+ struct ci13xxx *udc;
+ spinlock_t *lock;
+ struct dma_pool *td_pool;
+};
+
+enum ci_role {
+ CI_ROLE_HOST = 0,
+ CI_ROLE_GADGET,
+ CI_ROLE_END,
+};
+
+/**
+ * struct ci_role_driver - host/gadget role driver
+ * start: start this role
+ * stop: stop this role
+ * irq: irq handler for this role
+ * name: role name string (host/gadget)
+ */
+struct ci_role_driver {
+ int (*start)(struct ci13xxx *);
+ void (*stop)(struct ci13xxx *);
+ irqreturn_t (*irq)(struct ci13xxx *);
+ const char *name;
+};
+
+/**
+ * struct hw_bank - hardware register mapping representation
+ * @lpm: set if the device is LPM capable
+ * @phys: physical address of the controller's registers
+ * @abs: absolute address of the beginning of register window
+ * @cap: capability registers
+ * @op: operational registers
+ * @size: size of the register window
+ * @regmap: register lookup table
+ */
+struct hw_bank {
+ unsigned lpm;
+ resource_size_t phys;
+ void __iomem *abs;
+ void __iomem *cap;
+ void __iomem *op;
+ size_t size;
+ void __iomem **regmap;
+};
+
+/**
+ * struct ci13xxx - chipidea device representation
+ * @dev: pointer to parent device
+ * @lock: access synchronization
+ * @hw_bank: hardware register mapping
+ * @irq: IRQ number
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @is_otg: if the device is otg-capable
+ * @work: work for role changing
+ * @wq: workqueue thread
+ * @qh_pool: allocation pool for queue heads
+ * @td_pool: allocation pool for transfer descriptors
+ * @gadget: device side representation for peripheral controller
+ * @driver: gadget driver
+ * @hw_ep_max: total number of endpoints supported by hardware
+ * @ci13xxx_ep: array of endpoints
+ * @ep0_dir: ep0 direction
+ * @ep0out: pointer to ep0 OUT endpoint
+ * @ep0in: pointer to ep0 IN endpoint
+ * @status: ep0 status request
+ * @setaddr: if we should set the address on status completion
+ * @address: usb address received from the host
+ * @remote_wakeup: host-enabled remote wakeup
+ * @suspended: suspended by host
+ * @test_mode: the selected test mode
+ * @udc_driver: platform specific information supplied by parent device
+ * @vbus_active: is VBUS active
+ * @transceiver: pointer to USB PHY, if any
+ * @hcd: pointer to usb_hcd for ehci host driver
+ */
+struct ci13xxx {
+ struct device *dev;
+ spinlock_t lock;
+ struct hw_bank hw_bank;
+ int irq;
+ struct ci_role_driver *roles[CI_ROLE_END];
+ enum ci_role role;
+ bool is_otg;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+
+ struct dma_pool *qh_pool;
+ struct dma_pool *td_pool;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ unsigned hw_ep_max;
+ struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX];
+ u32 ep0_dir;
+ struct ci13xxx_ep *ep0out, *ep0in;
+
+ struct usb_request *status;
+ bool setaddr;
+ u8 address;
+ u8 remote_wakeup;
+ u8 suspended;
+ u8 test_mode;
+
+ struct ci13xxx_udc_driver *udc_driver;
+ int vbus_active;
+ struct usb_phy *transceiver;
+ struct usb_hcd *hcd;
+};
+
+static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
+{
+ BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
+ return ci->roles[ci->role];
+}
+
+static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
+{
+ int ret;
+
+ if (role >= CI_ROLE_END)
+ return -EINVAL;
+
+ if (!ci->roles[role])
+ return -ENXIO;
+
+ ret = ci->roles[role]->start(ci);
+ if (!ret)
+ ci->role = role;
+ return ret;
+}
+
+static inline void ci_role_stop(struct ci13xxx *ci)
+{
+ enum ci_role role = ci->role;
+
+ if (role == CI_ROLE_END)
+ return;
+
+ ci->role = CI_ROLE_END;
+
+ ci->roles[role]->stop(ci);
+}
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS (32)
+
+/* register indices */
+enum ci13xxx_regs {
+ CAP_CAPLENGTH,
+ CAP_HCCPARAMS,
+ CAP_DCCPARAMS,
+ CAP_TESTMODE,
+ CAP_LAST = CAP_TESTMODE,
+ OP_USBCMD,
+ OP_USBSTS,
+ OP_USBINTR,
+ OP_DEVICEADDR,
+ OP_ENDPTLISTADDR,
+ OP_PORTSC,
+ OP_DEVLC,
+ OP_OTGSC,
+ OP_USBMODE,
+ OP_ENDPTSETUPSTAT,
+ OP_ENDPTPRIME,
+ OP_ENDPTFLUSH,
+ OP_ENDPTSTAT,
+ OP_ENDPTCOMPLETE,
+ OP_ENDPTCTRL,
+ /* endptctrl1..15 follow */
+ OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
+};
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static inline int ffs_nr(u32 x)
+{
+ int n = ffs(x);
+
+ return n ? n-1 : 32;
+}
+
+/**
+ * hw_read: reads from a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
+{
+ return ioread32(udc->hw_bank.regmap[reg]) & mask;
+}
+
+/**
+ * hw_write: writes to a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ * @data: new value
+ */
+static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask, u32 data)
+{
+ if (~mask)
+ data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
+ | (data & mask);
+
+ iowrite32(data, udc->hw_bank.regmap[reg]);
+}
+
+/**
+ * hw_test_and_clear: tests & clears a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask)
+{
+ u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
+
+ iowrite32(val, udc->hw_bank.regmap[reg]);
+ return val;
+}
+
+/**
+ * hw_test_and_write: tests & writes a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ * @data: new value
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask, u32 data)
+{
+ u32 val = hw_read(udc, reg, ~0);
+
+ hw_write(udc, reg, mask, data);
+ return (val & mask) >> ffs_nr(mask);
+}
+
+int hw_device_reset(struct ci13xxx *ci, u32 mode);
+
+int hw_port_test_set(struct ci13xxx *ci, u8 mode);
+
+u8 hw_port_test_get(struct ci13xxx *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/chipidea/ci13xxx_msm.c
index d07e44c..958069e 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/chipidea/ci13xxx_msm.c
@@ -10,15 +10,12 @@
#include <linux/pm_runtime.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
-#include "ci13xxx_udc.c"
+#include "ci.h"
-#define MSM_USB_BASE (udc->regs)
-
-static irqreturn_t msm_udc_irq(int irq, void *data)
-{
- return udc_irq();
-}
+#define MSM_USB_BASE (udc->hw_bank.abs)
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
@@ -60,53 +57,40 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
- struct resource *res;
- void __iomem *regs;
- int irq;
+ struct platform_device *plat_ci;
int ret;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get platform resource mem\n");
- return -ENXIO;
- }
-
- regs = ioremap(res->start, resource_size(res));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
+ plat_ci = platform_device_alloc("ci_hdrc", -1);
+ if (!plat_ci) {
+ dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
return -ENOMEM;
}
- ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
- if (ret < 0) {
- dev_err(&pdev->dev, "udc_probe failed\n");
- goto iounmap;
+ ret = platform_device_add_resources(plat_ci, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "can't add resources to platform device\n");
+ goto put_platform;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "IRQ not found\n");
- ret = -ENXIO;
- goto udc_remove;
- }
+ ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
+ sizeof(ci13xxx_msm_udc_driver));
+ if (ret)
+ goto put_platform;
- ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto udc_remove;
- }
+ ret = platform_device_add(plat_ci);
+ if (ret)
+ goto put_platform;
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
-udc_remove:
- udc_remove();
-iounmap:
- iounmap(regs);
+put_platform:
+ platform_device_put(plat_ci);
return ret;
}
diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c
index 883ab5e..e3dab27 100644
--- a/drivers/usb/gadget/ci13xxx_pci.c
+++ b/drivers/usb/chipidea/ci13xxx_pci.c
@@ -10,10 +10,12 @@
* published by the Free Software Foundation.
*/
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/pci.h>
-
-#include "ci13xxx_udc.c"
+#include <linux/interrupt.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
/* driver name */
#define UDC_DRIVER_NAME "ci13xxx_pci"
@@ -21,25 +23,20 @@
/******************************************************************************
* PCI block
*****************************************************************************/
-/**
- * ci13xxx_pci_irq: interrut handler
- * @irq: irq number
- * @pdev: USB Device Controller interrupt source
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * This is an ISR don't trace, use attribute interface instead
- */
-static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
-{
- if (irq == 0) {
- dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
- return IRQ_HANDLED;
- }
- return udc_irq();
-}
+struct ci13xxx_udc_driver pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .capoffset = DEF_CAPOFFSET,
+};
-static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
+struct ci13xxx_udc_driver langwell_pci_driver = {
.name = UDC_DRIVER_NAME,
+ .capoffset = 0,
+};
+
+struct ci13xxx_udc_driver penwell_pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .capoffset = 0,
+ .power_budget = 200,
};
/**
@@ -54,11 +51,15 @@ static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- void __iomem *regs = NULL;
- int retval = 0;
-
- if (id == NULL)
- return -EINVAL;
+ struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
+ struct platform_device *plat_ci;
+ struct resource res[3];
+ int retval = 0, nres = 2;
+
+ if (!driver) {
+ dev_err(&pdev->dev, "device doesn't provide driver data\n");
+ return -ENODEV;
+ }
retval = pci_enable_device(pdev);
if (retval)
@@ -70,41 +71,50 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
goto disable_device;
}
- retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
- if (retval)
- goto disable_device;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
- /* BAR 0 holds all the registers */
- regs = pci_iomap(pdev, 0, 0);
- if (!regs) {
- dev_err(&pdev->dev, "Error mapping memory!");
- retval = -EFAULT;
- goto release_regions;
+ plat_ci = platform_device_alloc("ci_hdrc", -1);
+ if (!plat_ci) {
+ dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
+ retval = -ENOMEM;
+ goto disable_device;
}
- pci_set_drvdata(pdev, (__force void *)regs);
- pci_set_master(pdev);
- pci_try_set_mwi(pdev);
+ memset(res, 0, sizeof(res));
+ res[0].start = pci_resource_start(pdev, 0);
+ res[0].end = pci_resource_end(pdev, 0);
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = pdev->irq;
+ res[1].flags = IORESOURCE_IRQ;
+
+ retval = platform_device_add_resources(plat_ci, res, nres);
+ if (retval) {
+ dev_err(&pdev->dev, "can't add resources to platform device\n");
+ goto put_platform;
+ }
- retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
+ retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
if (retval)
- goto iounmap;
+ goto put_platform;
+
+ dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
+ plat_ci->dev.dma_mask = pdev->dev.dma_mask;
+ plat_ci->dev.dma_parms = pdev->dev.dma_parms;
+ plat_ci->dev.parent = &pdev->dev;
- /* our device does not have MSI capability */
+ pci_set_drvdata(pdev, plat_ci);
- retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
- UDC_DRIVER_NAME, pdev);
+ retval = platform_device_add(plat_ci);
if (retval)
- goto gadget_remove;
+ goto put_platform;
return 0;
- gadget_remove:
- udc_remove();
- iounmap:
- pci_iounmap(pdev, regs);
- release_regions:
- pci_release_regions(pdev);
+ put_platform:
+ pci_set_drvdata(pdev, NULL);
+ platform_device_put(plat_ci);
disable_device:
pci_disable_device(pdev);
done:
@@ -121,10 +131,10 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
*/
static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
{
- free_irq(pdev->irq, pdev);
- udc_remove();
- pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
- pci_release_regions(pdev);
+ struct platform_device *plat_ci = pci_get_drvdata(pdev);
+
+ platform_device_unregister(plat_ci);
+ pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
@@ -135,8 +145,22 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
* Check "pci.h" for details
*/
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
- { PCI_DEVICE(0x153F, 0x1004) },
- { PCI_DEVICE(0x153F, 0x1006) },
+ {
+ PCI_DEVICE(0x153F, 0x1004),
+ .driver_data = (kernel_ulong_t)&pci_driver,
+ },
+ {
+ PCI_DEVICE(0x153F, 0x1006),
+ .driver_data = (kernel_ulong_t)&pci_driver,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
+ .driver_data = (kernel_ulong_t)&langwell_pci_driver,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
+ .driver_data = (kernel_ulong_t)&penwell_pci_driver,
+ },
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
@@ -148,27 +172,7 @@ static struct pci_driver ci13xxx_pci_driver = {
.remove = __devexit_p(ci13xxx_pci_remove),
};
-/**
- * ci13xxx_pci_init: module init
- *
- * Driver load
- */
-static int __init ci13xxx_pci_init(void)
-{
- return pci_register_driver(&ci13xxx_pci_driver);
-}
-module_init(ci13xxx_pci_init);
-
-/**
- * ci13xxx_pci_exit: module exit
- *
- * Driver unload
- */
-static void __exit ci13xxx_pci_exit(void)
-{
- pci_unregister_driver(&ci13xxx_pci_driver);
-}
-module_exit(ci13xxx_pci_exit);
+module_pci_driver(ci13xxx_pci_driver);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
new file mode 100644
index 0000000..15e03b3
--- /dev/null
+++ b/drivers/usb/chipidea/core.c
@@ -0,0 +1,474 @@
+/*
+ * core.c - ChipIdea USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Description: ChipIdea USB IP core family device controller
+ *
+ * This driver is composed of several blocks:
+ * - HW: hardware interface
+ * - DBG: debug facilities (optional)
+ * - UTIL: utilities
+ * - ISR: interrupts handling
+ * - ENDPT: endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS: bus glue code, bus abstraction layer
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN: non-empty bulk-in pipes cannot be halted
+ * if defined mass storage compliance succeeds but with warnings
+ * => case 4: Hi > Dn
+ * => case 5: Hi > Di
+ * => case 8: Hi <> Do
+ * if undefined usbtest 13 fails
+ * - TRACE: enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ * - Suspend & Remote Wakeup
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "host.h"
+#include "debug.h"
+
+/* Controller register map */
+static uintptr_t ci_regs_nolpm[] = {
+ [CAP_CAPLENGTH] = 0x000UL,
+ [CAP_HCCPARAMS] = 0x008UL,
+ [CAP_DCCPARAMS] = 0x024UL,
+ [CAP_TESTMODE] = 0x038UL,
+ [OP_USBCMD] = 0x000UL,
+ [OP_USBSTS] = 0x004UL,
+ [OP_USBINTR] = 0x008UL,
+ [OP_DEVICEADDR] = 0x014UL,
+ [OP_ENDPTLISTADDR] = 0x018UL,
+ [OP_PORTSC] = 0x044UL,
+ [OP_DEVLC] = 0x084UL,
+ [OP_OTGSC] = 0x064UL,
+ [OP_USBMODE] = 0x068UL,
+ [OP_ENDPTSETUPSTAT] = 0x06CUL,
+ [OP_ENDPTPRIME] = 0x070UL,
+ [OP_ENDPTFLUSH] = 0x074UL,
+ [OP_ENDPTSTAT] = 0x078UL,
+ [OP_ENDPTCOMPLETE] = 0x07CUL,
+ [OP_ENDPTCTRL] = 0x080UL,
+};
+
+static uintptr_t ci_regs_lpm[] = {
+ [CAP_CAPLENGTH] = 0x000UL,
+ [CAP_HCCPARAMS] = 0x008UL,
+ [CAP_DCCPARAMS] = 0x024UL,
+ [CAP_TESTMODE] = 0x0FCUL,
+ [OP_USBCMD] = 0x000UL,
+ [OP_USBSTS] = 0x004UL,
+ [OP_USBINTR] = 0x008UL,
+ [OP_DEVICEADDR] = 0x014UL,
+ [OP_ENDPTLISTADDR] = 0x018UL,
+ [OP_PORTSC] = 0x044UL,
+ [OP_DEVLC] = 0x084UL,
+ [OP_OTGSC] = 0x0C4UL,
+ [OP_USBMODE] = 0x0C8UL,
+ [OP_ENDPTSETUPSTAT] = 0x0D8UL,
+ [OP_ENDPTPRIME] = 0x0DCUL,
+ [OP_ENDPTFLUSH] = 0x0E0UL,
+ [OP_ENDPTSTAT] = 0x0E4UL,
+ [OP_ENDPTCOMPLETE] = 0x0E8UL,
+ [OP_ENDPTCTRL] = 0x0ECUL,
+};
+
+static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
+{
+ int i;
+
+ kfree(ci->hw_bank.regmap);
+
+ ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *),
+ GFP_KERNEL);
+ if (!ci->hw_bank.regmap)
+ return -ENOMEM;
+
+ for (i = 0; i < OP_ENDPTCTRL; i++)
+ ci->hw_bank.regmap[i] =
+ (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) +
+ (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]);
+
+ for (; i <= OP_LAST; i++)
+ ci->hw_bank.regmap[i] = ci->hw_bank.op +
+ 4 * (i - OP_ENDPTCTRL) +
+ (is_lpm
+ ? ci_regs_lpm[OP_ENDPTCTRL]
+ : ci_regs_nolpm[OP_ENDPTCTRL]);
+
+ return 0;
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+int hw_port_test_set(struct ci13xxx *ci, u8 mode)
+{
+ const u8 TEST_MODE_MAX = 7;
+
+ if (mode > TEST_MODE_MAX)
+ return -EINVAL;
+
+ hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+ return 0;
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+u8 hw_port_test_get(struct ci13xxx *ci)
+{
+ return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
+{
+ u32 reg;
+
+ /* bank is a module variable */
+ ci->hw_bank.abs = base;
+
+ ci->hw_bank.cap = ci->hw_bank.abs;
+ ci->hw_bank.cap += ci->udc_driver->capoffset;
+ ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+
+ hw_alloc_regmap(ci, false);
+ reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
+ ffs_nr(HCCPARAMS_LEN);
+ ci->hw_bank.lpm = reg;
+ hw_alloc_regmap(ci, !!reg);
+ ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
+ ci->hw_bank.size += OP_LAST;
+ ci->hw_bank.size /= sizeof(u32);
+
+ reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
+ ffs_nr(DCCPARAMS_DEN);
+ ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
+
+ if (ci->hw_ep_max > ENDPT_MAX)
+ return -ENODEV;
+
+ dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
+ ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
+
+ /* setup lock mode ? */
+
+ /* ENDPTSETUPSTAT is '0' by default */
+
+ /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+ return 0;
+}
+
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @ci: the controller
+ *
+ * This function returns an error code
+ */
+int hw_device_reset(struct ci13xxx *ci, u32 mode)
+{
+ /* should flush & stop before reset */
+ hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+
+ hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
+ while (hw_read(ci, OP_USBCMD, USBCMD_RST))
+ udelay(10); /* not RTOS friendly */
+
+
+ if (ci->udc_driver->notify_event)
+ ci->udc_driver->notify_event(ci,
+ CI13XXX_CONTROLLER_RESET_EVENT);
+
+ if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ /* USBMODE should be configured step by step */
+ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+ hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
+ /* HW >= 2.3 */
+ hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
+
+ if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
+ pr_err("cannot enter in %s mode", ci_role(ci)->name);
+ pr_err("lpm = %i", ci->hw_bank.lpm);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+static enum ci_role ci_otg_role(struct ci13xxx *ci)
+{
+ u32 sts = hw_read(ci, OP_OTGSC, ~0);
+ enum ci_role role = sts & OTGSC_ID
+ ? CI_ROLE_GADGET
+ : CI_ROLE_HOST;
+
+ return role;
+}
+
+/**
+ * ci_role_work - perform role changing based on ID pin
+ * @work: work struct
+ */
+static void ci_role_work(struct work_struct *work)
+{
+ struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
+ enum ci_role role = ci_otg_role(ci);
+
+ hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+
+ if (role != ci->role) {
+ dev_dbg(ci->dev, "switching from %s to %s\n",
+ ci_role(ci)->name, ci->roles[role]->name);
+
+ ci_role_stop(ci);
+ ci_role_start(ci, role);
+ }
+}
+
+static ssize_t show_role(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *ci = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", ci_role(ci)->name);
+}
+
+static ssize_t store_role(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *ci = dev_get_drvdata(dev);
+ enum ci_role role;
+ int ret;
+
+ for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+ if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
+ break;
+
+ if (role == CI_ROLE_END || role == ci->role)
+ return -EINVAL;
+
+ ci_role_stop(ci);
+ ret = ci_role_start(ci, role);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
+
+static irqreturn_t ci_irq(int irq, void *data)
+{
+ struct ci13xxx *ci = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ if (ci->is_otg) {
+ u32 sts = hw_read(ci, OP_OTGSC, ~0);
+
+ if (sts & OTGSC_IDIS) {
+ queue_work(ci->wq, &ci->work);
+ ret = IRQ_HANDLED;
+ }
+ }
+
+ return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
+}
+
+static int __devinit ci_hdrc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ci13xxx *ci;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ if (!dev->platform_data) {
+ dev_err(dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing resource\n");
+ return -ENODEV;
+ }
+
+ base = devm_request_and_ioremap(dev, res);
+ if (!res) {
+ dev_err(dev, "can't request and ioremap resource\n");
+ return -ENOMEM;
+ }
+
+ ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
+ if (!ci) {
+ dev_err(dev, "can't allocate device\n");
+ return -ENOMEM;
+ }
+
+ ci->dev = dev;
+ ci->udc_driver = dev->platform_data;
+
+ ret = hw_device_init(ci, base);
+ if (ret < 0) {
+ dev_err(dev, "can't initialize hardware\n");
+ return -ENODEV;
+ }
+
+ ci->hw_bank.phys = res->start;
+
+ ci->irq = platform_get_irq(pdev, 0);
+ if (ci->irq < 0) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+
+ INIT_WORK(&ci->work, ci_role_work);
+ ci->wq = create_singlethread_workqueue("ci_otg");
+ if (!ci->wq) {
+ dev_err(dev, "can't create workqueue\n");
+ return -ENODEV;
+ }
+
+ /* initialize role(s) before the interrupt is requested */
+ ret = ci_hdrc_host_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support host\n");
+
+ ret = ci_hdrc_gadget_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support gadget\n");
+
+ if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
+ dev_err(dev, "no supported roles\n");
+ ret = -ENODEV;
+ goto rm_wq;
+ }
+
+ if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+ ci->is_otg = true;
+ ci->role = ci_otg_role(ci);
+ } else {
+ ci->role = ci->roles[CI_ROLE_HOST]
+ ? CI_ROLE_HOST
+ : CI_ROLE_GADGET;
+ }
+
+ ret = ci_role_start(ci, ci->role);
+ if (ret) {
+ dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
+ ret = -ENODEV;
+ goto rm_wq;
+ }
+
+ platform_set_drvdata(pdev, ci);
+ ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
+ ci);
+ if (ret)
+ goto stop;
+
+ ret = device_create_file(dev, &dev_attr_role);
+ if (ret)
+ goto rm_attr;
+
+ if (ci->is_otg)
+ hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
+
+ return ret;
+
+rm_attr:
+ device_remove_file(dev, &dev_attr_role);
+stop:
+ ci_role_stop(ci);
+rm_wq:
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+
+ return ret;
+}
+
+static int __devexit ci_hdrc_remove(struct platform_device *pdev)
+{
+ struct ci13xxx *ci = platform_get_drvdata(pdev);
+
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+ device_remove_file(ci->dev, &dev_attr_role);
+ free_irq(ci->irq, ci);
+ ci_role_stop(ci);
+
+ return 0;
+}
+
+static struct platform_driver ci_hdrc_driver = {
+ .probe = ci_hdrc_probe,
+ .remove = __devexit_p(ci_hdrc_remove),
+ .driver = {
+ .name = "ci_hdrc",
+ },
+};
+
+module_platform_driver(ci_hdrc_driver);
+
+MODULE_ALIAS("platform:ci_hdrc");
+MODULE_ALIAS("platform:ci13xxx");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("ChipIdea HDRC Driver");
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
new file mode 100644
index 0000000..c4b3e15
--- /dev/null
+++ b/drivers/usb/chipidea/debug.c
@@ -0,0 +1,804 @@
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* Interrupt statistics */
+#define ISR_MASK 0x1F
+static struct isr_statistics {
+ u32 test;
+ u32 ui;
+ u32 uei;
+ u32 pci;
+ u32 uri;
+ u32 sli;
+ u32 none;
+ struct {
+ u32 cnt;
+ u32 buf[ISR_MASK+1];
+ u32 idx;
+ } hndl;
+} isr_statistics;
+
+void dbg_interrupt(u32 intmask)
+{
+ if (!intmask) {
+ isr_statistics.none++;
+ return;
+ }
+
+ isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
+ isr_statistics.hndl.idx &= ISR_MASK;
+ isr_statistics.hndl.cnt++;
+
+ if (USBi_URI & intmask)
+ isr_statistics.uri++;
+ if (USBi_PCI & intmask)
+ isr_statistics.pci++;
+ if (USBi_UEI & intmask)
+ isr_statistics.uei++;
+ if (USBi_UI & intmask)
+ isr_statistics.ui++;
+ if (USBi_SLI & intmask)
+ isr_statistics.sli++;
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf: destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
+{
+ unsigned i;
+
+ if (size > udc->hw_bank.size)
+ size = udc->hw_bank.size;
+
+ for (i = 0; i < size; i++)
+ buf[i] = hw_read(udc, i * sizeof(u32), ~0);
+
+ return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
+{
+ /* align */
+ addr /= sizeof(u32);
+
+ if (addr >= udc->hw_bank.size)
+ return -EINVAL;
+
+ /* align */
+ addr *= sizeof(u32);
+
+ hw_write(udc, addr, ~0, data);
+ return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(struct ci13xxx *udc, int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_write(udc, OP_USBINTR, BIT(n), 0);
+ hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
+ return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(struct ci13xxx *udc, int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+ hw_write(udc, OP_USBINTR, BIT(n), BIT(n));
+ hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
+ hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0);
+ return 0;
+}
+
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget *gadget = &udc->gadget;
+ int n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
+ gadget->speed);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
+ gadget->max_speed);
+ /* TODO: Scheduled for removal in 3.8. */
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
+ gadget_is_dualspeed(gadget));
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
+ gadget->is_otg);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
+ gadget->is_a_peripheral);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
+ gadget->b_hnp_enable);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
+ gadget->a_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+ gadget->a_alt_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
+ (gadget->name ? gadget->name : ""));
+
+ return n;
+}
+static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget_driver *driver = udc->driver;
+ int n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ if (driver == NULL)
+ return scnprintf(buf, PAGE_SIZE,
+ "There is no gadget attached!\n");
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
+ (driver->function ? driver->function : ""));
+ n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+ driver->max_speed);
+
+ return n;
+}
+static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG 64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX 128UL
+
+/* Event buffer descriptor */
+static struct {
+ char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
+ unsigned idx; /* index */
+ unsigned tty; /* print to console? */
+ rwlock_t lck; /* lock */
+} dbg_data = {
+ .idx = 0,
+ .tty = 0,
+ .lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned *idx)
+{
+ *idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned *idx)
+{
+ *idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_print: prints the common part of the event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ * @extra: extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+ struct timeval tval;
+ unsigned int stamp;
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_data.lck, flags);
+
+ do_gettimeofday(&tval);
+ stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
+ stamp = stamp * 1000000 + tval.tv_usec;
+
+ scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+ "%04X\t? %02X %-7.7s %4i ?\t%s\n",
+ stamp, addr, name, status, extra);
+
+ dbg_inc(&dbg_data.idx);
+
+ write_unlock_irqrestore(&dbg_data.lck, flags);
+
+ if (dbg_data.tty != 0)
+ pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
+ stamp, addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr: endpoint address
+ * @td: transfer descriptor
+ * @status: status
+ */
+void dbg_done(u8 addr, const u32 token, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ scnprintf(msg, sizeof(msg), "%d %02X",
+ (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+ (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
+ dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ */
+void dbg_event(u8 addr, const char *name, int status)
+{
+ if (name != NULL)
+ dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr: endpoint address
+ * @req: USB request
+ * @status: status
+ */
+void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%d %d", !req->no_interrupt, req->length);
+ dbg_print(addr, "QUEUE", status, msg);
+ }
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req: setup request
+ */
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%02X %02X %04X %04X %d", req->bRequestType,
+ req->bRequest, le16_to_cpu(req->wValue),
+ le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+ dbg_print(addr, "SETUP", 0, msg);
+ }
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev->parent, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ read_lock_irqsave(&dbg_data.lck, flags);
+
+ i = dbg_data.idx;
+ for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+ n += strlen(dbg_data.buf[i]);
+ if (n >= PAGE_SIZE) {
+ n -= strlen(dbg_data.buf[i]);
+ break;
+ }
+ }
+ for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+ j += scnprintf(buf + j, PAGE_SIZE - j,
+ "%s", dbg_data.buf[i]);
+
+ read_unlock_irqrestore(&dbg_data.lck, flags);
+
+ return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned tty;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+ dev_err(dev, "<1|0>: enable|disable console log\n");
+ goto done;
+ }
+
+ dbg_data.tty = tty;
+ dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 intr;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*n += scnprintf(buf + n, PAGE_SIZE - n,
+ "status = %08x\n", hw_read_intr_status(udc));
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "enable = %08x\n", hw_read_intr_enable(udc));*/
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+ isr_statistics.test);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
+ isr_statistics.ui);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
+ isr_statistics.uei);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
+ isr_statistics.pci);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
+ isr_statistics.uri);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
+ isr_statistics.sli);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+ isr_statistics.none);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+ isr_statistics.hndl.cnt);
+
+ for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+ i &= ISR_MASK;
+ intr = isr_statistics.hndl.buf[i];
+
+ if (USBi_UI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
+ intr &= ~USBi_UI;
+ if (USBi_UEI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+ intr &= ~USBi_UEI;
+ if (USBi_PCI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+ intr &= ~USBi_PCI;
+ if (USBi_URI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+ intr &= ~USBi_URI;
+ if (USBi_SLI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+ intr &= ~USBi_SLI;
+ if (intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+ if (isr_statistics.hndl.buf[i])
+ n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ * (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned en, bit;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "EINVAL\n");
+ goto done;
+ }
+
+ if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+ dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (en) {
+ if (hw_intr_force(udc, bit))
+ dev_err(dev, "invalid bit number\n");
+ else
+ isr_statistics.test++;
+ } else {
+ if (hw_intr_clear(udc, bit))
+ dev_err(dev, "invalid bit number\n");
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "EINVAL\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ mode = hw_port_test_get(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &mode) != 1) {
+ dev_err(udc->dev, "<mode>: set port test mode");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (hw_port_test_set(udc, mode))
+ dev_err(udc->dev, "invalid mode\n");
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
+ show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ for (i = 0; i < udc->hw_ep_max/2; i++) {
+ struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+ struct ci13xxx_ep *mEpTx =
+ &udc->ci13xxx_ep[i + udc->hw_ep_max/2];
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: RX=%08X TX=%08X\n",
+ i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+ for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X %08X\n", j,
+ *((u32 *)mEpRx->qh.ptr + j),
+ *((u32 *)mEpTx->qh.ptr + j));
+ }
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+#define DUMP_ENTRIES 512
+static ssize_t show_registers(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 *dump;
+ unsigned i, k, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+ if (!dump) {
+ dev_err(udc->dev, "%s: out of memory\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ k = hw_register_read(udc, dump, DUMP_ENTRIES);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ for (i = 0; i < k; i++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "reg[0x%04X] = 0x%08X\n",
+ i * (unsigned)sizeof(u32), dump[i]);
+ }
+ kfree(dump);
+
+ return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long addr, data, flags;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+ dev_err(udc->dev,
+ "<addr> <data>: write data to register address\n");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (hw_register_write(udc, addr, data))
+ dev_err(udc->dev, "invalid address range\n");
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
+ show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ struct list_head *ptr = NULL;
+ struct ci13xxx_req *req = NULL;
+ unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ for (i = 0; i < udc->hw_ep_max; i++)
+ list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+ {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: TD=%08X %s\n",
+ i % udc->hw_ep_max/2, (u32)req->dma,
+ ((i < udc->hw_ep_max/2) ? "RX" : "TX"));
+
+ for (j = 0; j < qSize; j++)
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X\n", j,
+ *((u32 *)req->ptr + j));
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_create_files(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev == NULL)
+ return -EINVAL;
+ retval = device_create_file(dev, &dev_attr_device);
+ if (retval)
+ goto done;
+ retval = device_create_file(dev, &dev_attr_driver);
+ if (retval)
+ goto rm_device;
+ retval = device_create_file(dev, &dev_attr_events);
+ if (retval)
+ goto rm_driver;
+ retval = device_create_file(dev, &dev_attr_inters);
+ if (retval)
+ goto rm_events;
+ retval = device_create_file(dev, &dev_attr_port_test);
+ if (retval)
+ goto rm_inters;
+ retval = device_create_file(dev, &dev_attr_qheads);
+ if (retval)
+ goto rm_port_test;
+ retval = device_create_file(dev, &dev_attr_registers);
+ if (retval)
+ goto rm_qheads;
+ retval = device_create_file(dev, &dev_attr_requests);
+ if (retval)
+ goto rm_registers;
+ return 0;
+
+ rm_registers:
+ device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+ device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+ device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+ device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+ device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+ device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+ device_remove_file(dev, &dev_attr_device);
+ done:
+ return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_remove_files(struct device *dev)
+{
+ if (dev == NULL)
+ return -EINVAL;
+ device_remove_file(dev, &dev_attr_requests);
+ device_remove_file(dev, &dev_attr_registers);
+ device_remove_file(dev, &dev_attr_qheads);
+ device_remove_file(dev, &dev_attr_port_test);
+ device_remove_file(dev, &dev_attr_inters);
+ device_remove_file(dev, &dev_attr_events);
+ device_remove_file(dev, &dev_attr_driver);
+ device_remove_file(dev, &dev_attr_device);
+ return 0;
+}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
new file mode 100644
index 0000000..80d9686
--- /dev/null
+++ b/drivers/usb/chipidea/debug.h
@@ -0,0 +1,56 @@
+/*
+ * debug.h - ChipIdea USB driver debug interfaces
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_DEBUG_H
+#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
+
+#ifdef CONFIG_USB_CHIPIDEA_DEBUG
+void dbg_interrupt(u32 intmask);
+void dbg_done(u8 addr, const u32 token, int status);
+void dbg_event(u8 addr, const char *name, int status);
+void dbg_queue(u8 addr, const struct usb_request *req, int status);
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
+int dbg_create_files(struct device *dev);
+int dbg_remove_files(struct device *dev);
+#else
+static inline void dbg_interrupt(u32 intmask)
+{
+}
+
+static inline void dbg_done(u8 addr, const u32 token, int status)
+{
+}
+
+static inline void dbg_event(u8 addr, const char *name, int status)
+{
+}
+
+static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+}
+
+static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+}
+
+static inline int dbg_create_files(struct device *dev)
+{
+ return 0;
+}
+
+static inline int dbg_remove_files(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
new file mode 100644
index 0000000..9eacd21
--- /dev/null
+++ b/drivers/usb/chipidea/host.c
@@ -0,0 +1,160 @@
+/*
+ * host.c - ChipIdea USB host controller driver
+ *
+ * Copyright (c) 2012 Intel Corporation
+ *
+ * Author: Alexander Shishkin
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/chipidea.h>
+
+#define CHIPIDEA_EHCI
+#include "../host/ehci-hcd.c"
+
+#include "ci.h"
+#include "bits.h"
+#include "host.h"
+
+static int ci_ehci_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ hcd->has_tt = 1;
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ehci_port_power(ehci, 0);
+
+ return ret;
+}
+
+static const struct hc_driver ci_ehci_hc_driver = {
+ .description = "ehci_hcd",
+ .product_desc = "ChipIdea HDRC EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ci_ehci_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,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * 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,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static irqreturn_t host_irq(struct ci13xxx *ci)
+{
+ return usb_hcd_irq(ci->irq, ci->hcd);
+}
+
+static int host_start(struct ci13xxx *ci)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ dev_set_drvdata(ci->dev, ci);
+ hcd->rsrc_start = ci->hw_bank.phys;
+ hcd->rsrc_len = ci->hw_bank.size;
+ hcd->regs = ci->hw_bank.abs;
+ hcd->has_tt = 1;
+
+ hcd->power_budget = ci->udc_driver->power_budget;
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = ci->hw_bank.cap;
+ ehci->has_hostpc = ci->hw_bank.lpm;
+
+ ret = usb_add_hcd(hcd, 0, 0);
+ if (ret)
+ usb_put_hcd(hcd);
+ else
+ ci->hcd = hcd;
+
+ return ret;
+}
+
+static void host_stop(struct ci13xxx *ci)
+{
+ struct usb_hcd *hcd = ci->hcd;
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
+
+int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+ struct ci_role_driver *rdrv;
+
+ if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
+ return -ENXIO;
+
+ rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = host_start;
+ rdrv->stop = host_stop;
+ rdrv->irq = host_irq;
+ rdrv->name = "host";
+ ci->roles[CI_ROLE_HOST] = rdrv;
+
+ return 0;
+}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
new file mode 100644
index 0000000..761fb1f
--- /dev/null
+++ b/drivers/usb/chipidea/host.h
@@ -0,0 +1,17 @@
+#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H
+#define __DRIVERS_USB_CHIPIDEA_HOST_H
+
+#ifdef CONFIG_USB_CHIPIDEA_HOST
+
+int ci_hdrc_host_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+ return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
new file mode 100644
index 0000000..51f9694
--- /dev/null
+++ b/drivers/usb/chipidea/udc.c
@@ -0,0 +1,1809 @@
+/*
+ * udc.c - ChipIdea UDC driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+ return num + (dir ? 16 : 0);
+}
+
+static inline int ep_to_bit(struct ci13xxx *udc, int n)
+{
+ int fill = 16 - udc->hw_ep_max / 2;
+
+ if (n >= udc->hw_ep_max / 2)
+ n += fill;
+
+ return n;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ * without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(struct ci13xxx *udc, u32 dma)
+{
+ if (dma) {
+ hw_write(udc, OP_ENDPTLISTADDR, ~0, dma);
+ /* interrupt, error, port change, reset, sleep/suspend */
+ hw_write(udc, OP_USBINTR, ~0,
+ USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+ hw_write(udc, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+ } else {
+ hw_write(udc, OP_USBCMD, USBCMD_RS, 0);
+ hw_write(udc, OP_USBINTR, ~0, 0);
+ }
+ return 0;
+}
+
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(struct ci13xxx *udc, int num, int dir)
+{
+ int n = hw_ep_bit(num, dir);
+
+ do {
+ /* flush any pending transfer */
+ hw_write(udc, OP_ENDPTFLUSH, BIT(n), BIT(n));
+ while (hw_read(udc, OP_ENDPTFLUSH, BIT(n)))
+ cpu_relax();
+ } while (hw_read(udc, OP_ENDPTSTAT, BIT(n)));
+
+ return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(struct ci13xxx *udc, int num, int dir)
+{
+ hw_ep_flush(udc, num, dir);
+ hw_write(udc, OP_ENDPTCTRL + num,
+ dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+ return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(struct ci13xxx *udc, int num, int dir, int type)
+{
+ u32 mask, data;
+
+ if (dir) {
+ mask = ENDPTCTRL_TXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_TXS; /* unstall */
+ mask |= ENDPTCTRL_TXR; /* reset data toggle */
+ data |= ENDPTCTRL_TXR;
+ mask |= ENDPTCTRL_TXE; /* enable */
+ data |= ENDPTCTRL_TXE;
+ } else {
+ mask = ENDPTCTRL_RXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_RXS; /* unstall */
+ mask |= ENDPTCTRL_RXR; /* reset data toggle */
+ data |= ENDPTCTRL_RXR;
+ mask |= ENDPTCTRL_RXE; /* enable */
+ data |= ENDPTCTRL_RXE;
+ }
+ hw_write(udc, OP_ENDPTCTRL + num, mask, data);
+ return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(struct ci13xxx *udc, int num, int dir)
+{
+ u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+ return hw_read(udc, OP_ENDPTCTRL + num, mask) ? 1 : 0;
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ * interruption)
+ * @n: endpoint number
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(struct ci13xxx *udc, int n)
+{
+ n = ep_to_bit(udc, n);
+ return hw_test_and_clear(udc, OP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(struct ci13xxx *udc, int num, int dir, int is_ctrl)
+{
+ int n = hw_ep_bit(num, dir);
+
+ if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ hw_write(udc, OP_ENDPTPRIME, BIT(n), BIT(n));
+
+ while (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+ cpu_relax();
+ if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ /* status shoult be tested according with manual but it doesn't work */
+ return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ * without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(struct ci13xxx *udc, int num, int dir, int value)
+{
+ if (value != 0 && value != 1)
+ return -EINVAL;
+
+ do {
+ enum ci13xxx_regs reg = OP_ENDPTCTRL + num;
+ u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+ u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+ /* data toggle - reserved for EP0 but it's in ESS */
+ hw_write(udc, reg, mask_xs|mask_xr,
+ value ? mask_xs : mask_xr);
+ } while (value != hw_ep_get_halt(udc, num, dir));
+
+ return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(struct ci13xxx *udc)
+{
+ return udc->hw_bank.lpm ? hw_read(udc, OP_DEVLC, DEVLC_PSPD) :
+ hw_read(udc, OP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(struct ci13xxx *udc)
+{
+ return hw_read(udc, OP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(struct ci13xxx *udc)
+{
+ return hw_read(udc, OP_USBSTS, ~0);
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ * interruption)
+ * @n: endpoint number
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(struct ci13xxx *udc, int n)
+{
+ n = ep_to_bit(udc, n);
+ return hw_test_and_clear(udc, OP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ * without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(struct ci13xxx *udc)
+{
+ u32 reg = hw_read_intr_status(udc) & hw_read_intr_enable(udc);
+
+ hw_write(udc, OP_USBSTS, ~0, reg);
+ return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(struct ci13xxx *udc)
+{
+ return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(struct ci13xxx *udc)
+{
+ return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function explicitly sets the address, without the "USBADRA" (advance)
+ * feature, which is not supported by older versions of the controller.
+ */
+static void hw_usb_set_address(struct ci13xxx *udc, u8 value)
+{
+ hw_write(udc, OP_DEVICEADDR, DEVICEADDR_USBADR,
+ value << ffs_nr(DEVICEADDR_USBADR));
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ * interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(struct ci13xxx *udc)
+{
+ hw_usb_set_address(udc, 0);
+
+ /* ESS flushes only at end?!? */
+ hw_write(udc, OP_ENDPTFLUSH, ~0, ~0);
+
+ /* clear setup token semaphores */
+ hw_write(udc, OP_ENDPTSETUPSTAT, 0, 0);
+
+ /* clear complete status */
+ hw_write(udc, OP_ENDPTCOMPLETE, 0, 0);
+
+ /* wait until all bits cleared */
+ while (hw_read(udc, OP_ENDPTPRIME, ~0))
+ udelay(10); /* not RTOS friendly */
+
+ /* reset all endpoints ? */
+
+ /* reset internal status and wait for further instructions
+ no need to verify the port reset status (ESS does it) */
+
+ return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep: endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+ return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ struct ci13xxx *udc = mEp->udc;
+ unsigned i;
+ int ret = 0;
+ unsigned length = mReq->req.length;
+
+ /* don't queue twice */
+ if (mReq->req.status == -EALREADY)
+ return -EALREADY;
+
+ mReq->req.status = -EALREADY;
+
+ if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
+ mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+ &mReq->zdma);
+ if (mReq->zptr == NULL)
+ return -ENOMEM;
+
+ memset(mReq->zptr, 0, sizeof(*mReq->zptr));
+ mReq->zptr->next = TD_TERMINATE;
+ mReq->zptr->token = TD_STATUS_ACTIVE;
+ if (!mReq->req.no_interrupt)
+ mReq->zptr->token |= TD_IOC;
+ }
+ ret = usb_gadget_map_request(&udc->gadget, &mReq->req, mEp->dir);
+ if (ret)
+ return ret;
+
+ /*
+ * TD configuration
+ * TODO - handle requests which spawns into several TDs
+ */
+ memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+ mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
+ mReq->ptr->token &= TD_TOTAL_BYTES;
+ mReq->ptr->token |= TD_STATUS_ACTIVE;
+ if (mReq->zptr) {
+ mReq->ptr->next = mReq->zdma;
+ } else {
+ mReq->ptr->next = TD_TERMINATE;
+ if (!mReq->req.no_interrupt)
+ mReq->ptr->token |= TD_IOC;
+ }
+ mReq->ptr->page[0] = mReq->req.dma;
+ for (i = 1; i < 5; i++)
+ mReq->ptr->page[i] =
+ (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ if (!list_empty(&mEp->qh.queue)) {
+ struct ci13xxx_req *mReqPrev;
+ int n = hw_ep_bit(mEp->num, mEp->dir);
+ int tmp_stat;
+
+ mReqPrev = list_entry(mEp->qh.queue.prev,
+ struct ci13xxx_req, queue);
+ if (mReqPrev->zptr)
+ mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+ else
+ mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ wmb();
+ if (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+ goto done;
+ do {
+ hw_write(udc, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
+ tmp_stat = hw_read(udc, OP_ENDPTSTAT, BIT(n));
+ } while (!hw_read(udc, OP_USBCMD, USBCMD_ATDTW));
+ hw_write(udc, OP_USBCMD, USBCMD_ATDTW, 0);
+ if (tmp_stat)
+ goto done;
+ }
+
+ /* QH configuration */
+ mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
+ mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
+ mEp->qh.ptr->cap |= QH_ZLT;
+
+ wmb(); /* synchronize before ep prime */
+
+ ret = hw_ep_prime(udc, mEp->num, mEp->dir,
+ mEp->type == USB_ENDPOINT_XFER_CONTROL);
+done:
+ return ret;
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ if (mReq->req.status != -EALREADY)
+ return -EINVAL;
+
+ if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ return -EBUSY;
+
+ if (mReq->zptr) {
+ if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+ return -EBUSY;
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ }
+
+ mReq->req.status = 0;
+
+ usb_gadget_unmap_request(&mEp->udc->gadget, &mReq->req, mEp->dir);
+
+ mReq->req.status = mReq->ptr->token & TD_STATUS;
+ if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+
+ mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
+ mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = mReq->req.length - mReq->req.actual;
+ mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
+
+ return mReq->req.actual;
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ if (mEp == NULL)
+ return -EINVAL;
+
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ while (!list_empty(&mEp->qh.queue)) {
+
+ /* pop oldest request */
+ struct ci13xxx_req *mReq = \
+ list_entry(mEp->qh.queue.next,
+ struct ci13xxx_req, queue);
+ list_del_init(&mReq->queue);
+ mReq->req.status = -ESHUTDOWN;
+
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+ }
+ return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+{
+ struct usb_ep *ep;
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->remote_wakeup = 0;
+ udc->suspended = 0;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* flush all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_fifo_flush(ep);
+ }
+ usb_ep_fifo_flush(&udc->ep0out->ep);
+ usb_ep_fifo_flush(&udc->ep0in->ep);
+
+ if (udc->driver)
+ udc->driver->disconnect(gadget);
+
+ /* make sure to disable all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_disable(ep);
+ }
+
+ if (udc->status != NULL) {
+ usb_ep_free_request(&udc->ep0in->ep, udc->status);
+ udc->status = NULL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ int retval;
+
+ dbg_event(0xFF, "BUS RST", 0);
+
+ spin_unlock(&udc->lock);
+ retval = _gadget_stop_activity(&udc->gadget);
+ if (retval)
+ goto done;
+
+ retval = hw_usb_reset(udc);
+ if (retval)
+ goto done;
+
+ udc->status = usb_ep_alloc_request(&udc->ep0in->ep, GFP_ATOMIC);
+ if (udc->status == NULL)
+ retval = -ENOMEM;
+
+done:
+ spin_lock(&udc->lock);
+
+ if (retval)
+ dev_err(udc->dev, "error: %i\n", retval);
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep: endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (ep == NULL || req == NULL)
+ return;
+
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @udc: udc struct
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx *udc,
+ struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct ci13xxx_ep *mEp = udc->ep0in;
+ struct usb_request *req = NULL;
+ gfp_t gfp_flags = GFP_ATOMIC;
+ int dir, num, retval;
+
+ if (mEp == NULL || setup == NULL)
+ return -EINVAL;
+
+ spin_unlock(mEp->lock);
+ req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
+ spin_lock(mEp->lock);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->complete = isr_get_status_complete;
+ req->length = 2;
+ req->buf = kzalloc(req->length, gfp_flags);
+ if (req->buf == NULL) {
+ retval = -ENOMEM;
+ goto err_free_req;
+ }
+
+ if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* Assume that device is bus powered for now. */
+ *(u16 *)req->buf = udc->remote_wakeup << 1;
+ retval = 0;
+ } else if ((setup->bRequestType & USB_RECIP_MASK) \
+ == USB_RECIP_ENDPOINT) {
+ dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+ TX : RX;
+ num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+ *(u16 *)req->buf = hw_ep_get_halt(udc, num, dir);
+ }
+ /* else do nothing; reserved for future use */
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
+ spin_lock(mEp->lock);
+ if (retval)
+ goto err_free_buf;
+
+ return 0;
+
+ err_free_buf:
+ kfree(req->buf);
+ err_free_req:
+ spin_unlock(mEp->lock);
+ usb_ep_free_request(&mEp->ep, req);
+ spin_lock(mEp->lock);
+ return retval;
+}
+
+/**
+ * isr_setup_status_complete: setup_status request complete function
+ * @ep: endpoint
+ * @req: request handled
+ *
+ * Caller must release lock. Put the port in test mode if test mode
+ * feature is selected.
+ */
+static void
+isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx *udc = req->context;
+ unsigned long flags;
+
+ if (udc->setaddr) {
+ hw_usb_set_address(udc, udc->address);
+ udc->setaddr = false;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->test_mode)
+ hw_port_test_set(udc, udc->test_mode);
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @udc: udc struct
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx *udc)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ int retval;
+ struct ci13xxx_ep *mEp;
+
+ mEp = (udc->ep0_dir == TX) ? udc->ep0out : udc->ep0in;
+ udc->status->context = udc;
+ udc->status->complete = isr_setup_status_complete;
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
+ spin_lock(mEp->lock);
+
+ return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct ci13xxx_req *mReq, *mReqTemp;
+ struct ci13xxx_ep *mEpTemp = mEp;
+ int uninitialized_var(retval);
+
+ if (list_empty(&mEp->qh.queue))
+ return -EINVAL;
+
+ list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+ queue) {
+ retval = _hardware_dequeue(mEp, mReq);
+ if (retval < 0)
+ break;
+ list_del_init(&mReq->queue);
+ dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+ mReq->req.length)
+ mEpTemp = mEp->udc->ep0in;
+ mReq->req.complete(&mEpTemp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+ }
+
+ if (retval == -EBUSY)
+ retval = 0;
+ if (retval < 0)
+ dbg_event(_usb_addr(mEp), "DONE", retval);
+
+ return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ unsigned i;
+ u8 tmode = 0;
+
+ for (i = 0; i < udc->hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ int type, num, dir, err = -EINVAL;
+ struct usb_ctrlrequest req;
+
+ if (mEp->ep.desc == NULL)
+ continue; /* not configured */
+
+ if (hw_test_and_clear_complete(udc, i)) {
+ err = isr_tr_complete_low(mEp);
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (err > 0) /* needs status phase */
+ err = isr_setup_status_phase(udc);
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp),
+ "ERROR", err);
+ spin_unlock(&udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ dev_err(udc->dev,
+ "error: ep_set_halt\n");
+ spin_lock(&udc->lock);
+ }
+ }
+ }
+
+ if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+ !hw_test_and_clear_setup_status(udc, i))
+ continue;
+
+ if (i != 0) {
+ dev_warn(udc->dev, "ctrl traffic at endpoint %d\n", i);
+ continue;
+ }
+
+ /*
+ * Flush data and handshake transactions of previous
+ * setup packet.
+ */
+ _ep_nuke(udc->ep0out);
+ _ep_nuke(udc->ep0in);
+
+ /* read_setup_packet */
+ do {
+ hw_test_and_set_setup_guard(udc);
+ memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+ } while (!hw_test_and_clear_setup_guard(udc));
+
+ type = req.bRequestType;
+
+ udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+ dbg_setup(_usb_addr(mEp), &req);
+
+ switch (req.bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += udc->hw_ep_max/2;
+ if (!udc->ci13xxx_ep[num].wedge) {
+ spin_unlock(&udc->lock);
+ err = usb_ep_clear_halt(
+ &udc->ci13xxx_ep[num].ep);
+ spin_lock(&udc->lock);
+ if (err)
+ break;
+ }
+ err = isr_setup_status_phase(udc);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+ le16_to_cpu(req.wValue) ==
+ USB_DEVICE_REMOTE_WAKEUP) {
+ if (req.wLength != 0)
+ break;
+ udc->remote_wakeup = 0;
+ err = isr_setup_status_phase(udc);
+ } else {
+ goto delegate;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
+ type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+ type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 2 ||
+ le16_to_cpu(req.wValue) != 0)
+ break;
+ err = isr_get_status_response(udc, &req);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 0 ||
+ le16_to_cpu(req.wIndex) != 0)
+ break;
+ udc->address = (u8)le16_to_cpu(req.wValue);
+ udc->setaddr = true;
+ err = isr_setup_status_phase(udc);
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += udc->hw_ep_max/2;
+
+ spin_unlock(&udc->lock);
+ err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+ spin_lock(&udc->lock);
+ if (!err)
+ isr_setup_status_phase(udc);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+ if (req.wLength != 0)
+ break;
+ switch (le16_to_cpu(req.wValue)) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ udc->remote_wakeup = 1;
+ err = isr_setup_status_phase(udc);
+ break;
+ case USB_DEVICE_TEST_MODE:
+ tmode = le16_to_cpu(req.wIndex) >> 8;
+ switch (tmode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ udc->test_mode = tmode;
+ err = isr_setup_status_phase(
+ udc);
+ break;
+ default:
+ break;
+ }
+ default:
+ goto delegate;
+ }
+ } else {
+ goto delegate;
+ }
+ break;
+ default:
+delegate:
+ if (req.wLength == 0) /* no data phase */
+ udc->ep0_dir = TX;
+
+ spin_unlock(&udc->lock);
+ err = udc->driver->setup(&udc->gadget, &req);
+ spin_lock(&udc->lock);
+ break;
+ }
+
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp), "ERROR", err);
+
+ spin_unlock(&udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ dev_err(udc->dev, "error: ep_set_halt\n");
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should enable ctrl endpts */
+
+ mEp->ep.desc = desc;
+
+ if (!list_empty(&mEp->qh.queue))
+ dev_warn(mEp->udc->dev, "enabling a non-empty endpoint!\n");
+
+ mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
+ mEp->num = usb_endpoint_num(desc);
+ mEp->type = usb_endpoint_type(desc);
+
+ mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+
+ dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+ mEp->qh.ptr->cap = 0;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->qh.ptr->cap |= QH_IOS;
+ else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+ mEp->qh.ptr->cap &= ~QH_MULT;
+ else
+ mEp->qh.ptr->cap &= ~QH_ZLT;
+
+ mEp->qh.ptr->cap |=
+ (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+ mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
+
+ /*
+ * Enable endpoints in the HW other than ep0 as ep0
+ * is always enabled
+ */
+ if (mEp->num)
+ retval |= hw_ep_enable(mEp->udc, mEp->num, mEp->dir, mEp->type);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL)
+ return -EINVAL;
+ else if (mEp->ep.desc == NULL)
+ return -EBUSY;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should disable ctrl endpts */
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+ retval |= _ep_nuke(mEp);
+ retval |= hw_ep_disable(mEp->udc, mEp->num, mEp->dir);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ mEp->ep.desc = NULL;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = NULL;
+
+ if (ep == NULL)
+ return NULL;
+
+ mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+ if (mReq != NULL) {
+ INIT_LIST_HEAD(&mReq->queue);
+
+ mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+ &mReq->dma);
+ if (mReq->ptr == NULL) {
+ kfree(mReq);
+ mReq = NULL;
+ }
+ }
+
+ dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+ return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL) {
+ return;
+ } else if (!list_empty(&mReq->queue)) {
+ dev_err(mEp->udc->dev, "freeing queued request\n");
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mReq->ptr)
+ dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+ kfree(mReq);
+
+ dbg_event(_usb_addr(mEp), "FREE", 0);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *udc = mEp->udc;
+ int retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (udc->ep0_dir == RX) ?
+ udc->ep0out : udc->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->udc->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ retval = -EBUSY;
+ dev_err(mEp->udc->dev, "request already in queue\n");
+ goto done;
+ }
+
+ if (req->length > 4 * CI13XXX_PAGE_SIZE) {
+ req->length = 4 * CI13XXX_PAGE_SIZE;
+ retval = -EMSGSIZE;
+ dev_warn(mEp->udc->dev, "request length truncated\n");
+ }
+
+ dbg_queue(_usb_addr(mEp), req, retval);
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY) {
+ dbg_event(_usb_addr(mEp), "QUEUE", retval);
+ retval = 0;
+ }
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ done:
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
+ mEp->ep.desc == NULL || list_empty(&mReq->queue) ||
+ list_empty(&mEp->qh.queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ /* pop request */
+ list_del_init(&mReq->queue);
+
+ usb_gadget_unmap_request(&mEp->udc->gadget, req, mEp->dir);
+
+ req->status = -ECONNRESET;
+
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return 0;
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+ /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+ if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+ !list_empty(&mEp->qh.queue)) {
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return -EAGAIN;
+ }
+#endif
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "HALT", value);
+ retval |= hw_ep_set_halt(mEp->udc, mEp->num, mEp->dir, value);
+
+ if (!value)
+ mEp->wedge = 0;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ if (ep == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "WEDGE", 0);
+ mEp->wedge = 1;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+ return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ if (ep == NULL) {
+ dev_err(mEp->udc->dev, "%02X: -EINVAL\n", _usb_addr(mEp));
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+ .enable = ep_enable,
+ .disable = ep_disable,
+ .alloc_request = ep_alloc_request,
+ .free_request = ep_free_request,
+ .queue = ep_queue,
+ .dequeue = ep_dequeue,
+ .set_halt = ep_set_halt,
+ .set_wedge = ep_set_wedge,
+ .fifo_flush = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int gadget_ready = 0;
+
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->vbus_active = is_active;
+ if (udc->driver)
+ gadget_ready = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (gadget_ready) {
+ if (is_active) {
+ pm_runtime_get_sync(&_gadget->dev);
+ hw_device_reset(udc, USBMODE_CM_DC);
+ hw_device_state(udc, udc->ep0out->qh.dma);
+ } else {
+ hw_device_state(udc, 0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
+ _gadget_stop_activity(&udc->gadget);
+ pm_runtime_put_sync(&_gadget->dev);
+ }
+ }
+
+ return 0;
+}
+
+static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (!udc->remote_wakeup) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ if (!hw_read(udc, OP_PORTSC, PORTSC_SUSP)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hw_write(udc, OP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+out:
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return ret;
+}
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+
+ if (udc->transceiver)
+ return usb_phy_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops = {
+ .vbus_session = ci13xxx_vbus_session,
+ .wakeup = ci13xxx_wakeup,
+ .vbus_draw = ci13xxx_vbus_draw,
+ .udc_start = ci13xxx_start,
+ .udc_stop = ci13xxx_stop,
+};
+
+static int init_eps(struct ci13xxx *udc)
+{
+ int retval = 0, i, j;
+
+ for (i = 0; i < udc->hw_ep_max/2; i++)
+ for (j = RX; j <= TX; j++) {
+ int k = i + j * udc->hw_ep_max/2;
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+ scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+ (j == TX) ? "in" : "out");
+
+ mEp->udc = udc;
+ mEp->lock = &udc->lock;
+ mEp->td_pool = udc->td_pool;
+
+ mEp->ep.name = mEp->name;
+ mEp->ep.ops = &usb_ep_ops;
+ mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+
+ INIT_LIST_HEAD(&mEp->qh.queue);
+ mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+ &mEp->qh.dma);
+ if (mEp->qh.ptr == NULL)
+ retval = -ENOMEM;
+ else
+ memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+ /*
+ * set up shorthands for ep0 out and in endpoints,
+ * don't add to gadget's ep_list
+ */
+ if (i == 0) {
+ if (j == RX)
+ udc->ep0out = mEp;
+ else
+ udc->ep0in = mEp;
+
+ continue;
+ }
+
+ list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+ }
+
+ return retval;
+}
+
+/**
+ * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
+ * @driver: the driver being registered
+ *
+ * Interrupts are enabled here.
+ */
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int retval = -ENOMEM;
+
+ if (driver->disconnect == NULL)
+ return -EINVAL;
+
+
+ udc->ep0out->ep.desc = &ctrl_endpt_out_desc;
+ retval = usb_ep_enable(&udc->ep0out->ep);
+ if (retval)
+ return retval;
+
+ udc->ep0in->ep.desc = &ctrl_endpt_in_desc;
+ retval = usb_ep_enable(&udc->ep0in->ep);
+ if (retval)
+ return retval;
+ spin_lock_irqsave(&udc->lock, flags);
+
+ udc->driver = driver;
+ pm_runtime_get_sync(&udc->gadget.dev);
+ if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+ if (udc->vbus_active) {
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+ hw_device_reset(udc, USBMODE_CM_DC);
+ } else {
+ pm_runtime_put_sync(&udc->gadget.dev);
+ goto done;
+ }
+ }
+
+ retval = hw_device_state(udc, udc->ep0out->qh.dma);
+ if (retval)
+ pm_runtime_put_sync(&udc->gadget.dev);
+
+ done:
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return retval;
+}
+
+/**
+ * ci13xxx_stop: unregister a gadget driver
+ */
+static int ci13xxx_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+ udc->vbus_active) {
+ hw_device_state(udc, 0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
+ udc->driver = NULL;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ _gadget_stop_activity(&udc->gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+ pm_runtime_put(&udc->gadget.dev);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: udc interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(struct ci13xxx *udc)
+{
+ irqreturn_t retval;
+ u32 intr;
+
+ if (udc == NULL)
+ return IRQ_HANDLED;
+
+ spin_lock(&udc->lock);
+
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+ if (hw_read(udc, OP_USBMODE, USBMODE_CM) !=
+ USBMODE_CM_DC) {
+ spin_unlock(&udc->lock);
+ return IRQ_NONE;
+ }
+ }
+ intr = hw_test_and_clear_intr_active(udc);
+ dbg_interrupt(intr);
+
+ if (intr) {
+ /* order defines priority - do NOT change it */
+ if (USBi_URI & intr)
+ isr_reset_handler(udc);
+
+ if (USBi_PCI & intr) {
+ udc->gadget.speed = hw_port_is_high_speed(udc) ?
+ USB_SPEED_HIGH : USB_SPEED_FULL;
+ if (udc->suspended && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ udc->suspended = 0;
+ }
+ }
+
+ if (USBi_UI & intr)
+ isr_tr_complete_handler(udc);
+
+ if (USBi_SLI & intr) {
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+ udc->driver->suspend) {
+ udc->suspended = 1;
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+ retval = IRQ_HANDLED;
+ } else {
+ retval = IRQ_NONE;
+ }
+ spin_unlock(&udc->lock);
+
+ return retval;
+}
+
+/**
+ * udc_release: driver release function
+ * @dev: device
+ *
+ * Currently does nothing
+ */
+static void udc_release(struct device *dev)
+{
+}
+
+/**
+ * udc_start: initialize gadget role
+ * @udc: chipidea controller
+ */
+static int udc_start(struct ci13xxx *udc)
+{
+ struct device *dev = udc->dev;
+ int retval = 0;
+
+ if (!udc)
+ return -EINVAL;
+
+ spin_lock_init(&udc->lock);
+
+ udc->gadget.ops = &usb_gadget_ops;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ udc->gadget.is_otg = 0;
+ udc->gadget.name = udc->udc_driver->name;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.dma_mask = dev->dma_mask;
+ udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
+ udc->gadget.dev.parent = dev;
+ udc->gadget.dev.release = udc_release;
+
+ /* alloc resources */
+ udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+ sizeof(struct ci13xxx_qh),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->qh_pool == NULL)
+ return -ENOMEM;
+
+ udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+ sizeof(struct ci13xxx_td),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->td_pool == NULL) {
+ retval = -ENOMEM;
+ goto free_qh_pool;
+ }
+
+ retval = init_eps(udc);
+ if (retval)
+ goto free_pools;
+
+ udc->gadget.ep0 = &udc->ep0in->ep;
+
+ udc->transceiver = usb_get_transceiver();
+
+ if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+ if (udc->transceiver == NULL) {
+ retval = -ENODEV;
+ goto free_pools;
+ }
+ }
+
+ if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+ retval = hw_device_reset(udc, USBMODE_CM_DC);
+ if (retval)
+ goto put_transceiver;
+ }
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval) {
+ put_device(&udc->gadget.dev);
+ goto put_transceiver;
+ }
+
+ retval = dbg_create_files(&udc->gadget.dev);
+ if (retval)
+ goto unreg_device;
+
+ if (udc->transceiver) {
+ retval = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
+ if (retval)
+ goto remove_dbg;
+ }
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval)
+ goto remove_trans;
+
+ pm_runtime_no_callbacks(&udc->gadget.dev);
+ pm_runtime_enable(&udc->gadget.dev);
+
+ return retval;
+
+remove_trans:
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ usb_put_transceiver(udc->transceiver);
+ }
+
+ dev_err(dev, "error = %i\n", retval);
+remove_dbg:
+ dbg_remove_files(&udc->gadget.dev);
+unreg_device:
+ device_unregister(&udc->gadget.dev);
+put_transceiver:
+ if (udc->transceiver)
+ usb_put_transceiver(udc->transceiver);
+free_pools:
+ dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+ dma_pool_destroy(udc->qh_pool);
+ return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_stop(struct ci13xxx *udc)
+{
+ int i;
+
+ if (udc == NULL)
+ return;
+
+ usb_del_gadget_udc(&udc->gadget);
+
+ for (i = 0; i < udc->hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+ dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+ }
+
+ dma_pool_destroy(udc->td_pool);
+ dma_pool_destroy(udc->qh_pool);
+
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver->otg, NULL);
+ usb_put_transceiver(udc->transceiver);
+ }
+ dbg_remove_files(&udc->gadget.dev);
+ device_unregister(&udc->gadget.dev);
+ /* my kobject is dynamic, I swear! */
+ memset(&udc->gadget, 0, sizeof(udc->gadget));
+}
+
+/**
+ * ci_hdrc_gadget_init - initialize device related bits
+ * ci: the controller
+ *
+ * This function enables the gadget role, if the device is "device capable".
+ */
+int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+ struct ci_role_driver *rdrv;
+
+ if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
+ return -ENXIO;
+
+ rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = udc_start;
+ rdrv->stop = udc_stop;
+ rdrv->irq = udc_irq;
+ rdrv->name = "gadget";
+ ci->roles[CI_ROLE_GADGET] = rdrv;
+
+ return 0;
+}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
new file mode 100644
index 0000000..4ff2384d
--- /dev/null
+++ b/drivers/usb/chipidea/udc.h
@@ -0,0 +1,93 @@
+/*
+ * udc.h - ChipIdea UDC structures
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_UDC_H
+#define __DRIVERS_USB_CHIPIDEA_UDC_H
+
+#include <linux/list.h>
+
+#define CTRL_PAYLOAD_MAX 64
+#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */
+#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
+
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+ /* 0 */
+ u32 next;
+#define TD_TERMINATE BIT(0)
+#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
+ /* 1 */
+ u32 token;
+#define TD_STATUS (0x00FFUL << 0)
+#define TD_STATUS_TR_ERR BIT(3)
+#define TD_STATUS_DT_ERR BIT(5)
+#define TD_STATUS_HALTED BIT(6)
+#define TD_STATUS_ACTIVE BIT(7)
+#define TD_MULTO (0x0003UL << 10)
+#define TD_IOC BIT(15)
+#define TD_TOTAL_BYTES (0x7FFFUL << 16)
+ /* 2 */
+ u32 page[5];
+#define TD_CURR_OFFSET (0x0FFFUL << 0)
+#define TD_FRAME_NUM (0x07FFUL << 0)
+#define TD_RESERVED_MASK (0x0FFFUL << 0)
+} __attribute__ ((packed));
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+ /* 0 */
+ u32 cap;
+#define QH_IOS BIT(15)
+#define QH_MAX_PKT (0x07FFUL << 16)
+#define QH_ZLT BIT(29)
+#define QH_MULT (0x0003UL << 30)
+ /* 1 */
+ u32 curr;
+ /* 2 - 8 */
+ struct ci13xxx_td td;
+ /* 9 */
+ u32 RESERVED;
+ struct usb_ctrlrequest setup;
+} __attribute__ ((packed));
+
+/**
+ * struct ci13xxx_req - usb request representation
+ * @req: request structure for gadget drivers
+ * @queue: link to QH list
+ * @ptr: transfer descriptor for this request
+ * @dma: dma address for the transfer descriptor
+ * @zptr: transfer descriptor for the zero packet
+ * @zdma: dma address of the zero packet's transfer descriptor
+ */
+struct ci13xxx_req {
+ struct usb_request req;
+ struct list_head queue;
+ struct ci13xxx_td *ptr;
+ dma_addr_t dma;
+ struct ci13xxx_td *zptr;
+ dma_addr_t zdma;
+};
+
+#ifdef CONFIG_USB_CHIPIDEA_UDC
+
+int ci_hdrc_gadget_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+ return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b32ccb4..f2a120e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1664,6 +1664,7 @@ static struct usb_driver acm_driver = {
#ifdef CONFIG_PM
.supports_autosuspend = 1,
#endif
+ .disable_hub_initiated_lpm = 1,
};
/*
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 0bb2b32..ea8b304 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc)
static void cleanup(struct wdm_device *desc)
{
- spin_lock(&wdm_device_list_lock);
- list_del(&desc->device_list);
- spin_unlock(&wdm_device_list_lock);
kfree(desc->sbuf);
kfree(desc->inbuf);
kfree(desc->orq);
@@ -369,6 +366,7 @@ static ssize_t wdm_write
r = usb_autopm_get_interface(desc->intf);
if (r < 0) {
kfree(buf);
+ rv = usb_translate_errors(r);
goto outnp;
}
@@ -384,6 +382,7 @@ static ssize_t wdm_write
if (r < 0) {
kfree(buf);
+ rv = r;
goto out;
}
@@ -415,6 +414,7 @@ static ssize_t wdm_write
desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags);
dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
+ rv = usb_translate_errors(rv);
} else {
dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
req->wIndex);
@@ -530,11 +530,13 @@ static int wdm_flush(struct file *file, fl_owner_t id)
struct wdm_device *desc = file->private_data;
wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
- if (desc->werr < 0)
+
+ /* cannot dereference desc->intf if WDM_DISCONNECTING */
+ if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
dev_err(&desc->intf->dev, "Error in flush path: %d\n",
desc->werr);
- return desc->werr;
+ return usb_translate_errors(desc->werr);
}
static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
@@ -545,7 +547,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
spin_lock_irqsave(&desc->iuspin, flags);
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
- mask = POLLERR;
+ mask = POLLHUP | POLLERR;
spin_unlock_irqrestore(&desc->iuspin, flags);
goto desc_out;
}
@@ -596,6 +598,7 @@ static int wdm_open(struct inode *inode, struct file *file)
desc->count--;
dev_err(&desc->intf->dev,
"Error submitting int urb - %d\n", rv);
+ rv = usb_translate_errors(rv);
}
} else {
rv = 0;
@@ -621,10 +624,15 @@ static int wdm_release(struct inode *inode, struct file *file)
mutex_unlock(&desc->wlock);
if (!desc->count) {
- dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
- kill_urbs(desc);
- if (!test_bit(WDM_DISCONNECTING, &desc->flags))
+ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
+ kill_urbs(desc);
desc->manage_power(desc->intf, 0);
+ } else {
+ /* must avoid dev_printk here as desc->intf is invalid */
+ pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__);
+ cleanup(desc);
+ }
}
mutex_unlock(&wdm_mutex);
return 0;
@@ -771,6 +779,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
out:
return rv;
err:
+ spin_lock(&wdm_device_list_lock);
+ list_del(&desc->device_list);
+ spin_unlock(&wdm_device_list_lock);
cleanup(desc);
return rv;
}
@@ -896,8 +907,16 @@ static void wdm_disconnect(struct usb_interface *intf)
cancel_work_sync(&desc->rxwork);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
+
+ /* the desc->intf pointer used as list key is now invalid */
+ spin_lock(&wdm_device_list_lock);
+ list_del(&desc->device_list);
+ spin_unlock(&wdm_device_list_lock);
+
if (!desc->count)
cleanup(desc);
+ else
+ dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count);
mutex_unlock(&wdm_mutex);
}
@@ -1015,6 +1034,7 @@ static struct usb_driver wdm_driver = {
.post_reset = wdm_post_reset,
.id_table = wdm_ids,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(wdm_driver);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index a68c1a6..d4c47d5 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -172,27 +172,31 @@ struct usblp {
#ifdef DEBUG
static void usblp_dump(struct usblp *usblp)
{
+ struct device *dev = &usblp->intf->dev;
int p;
- dbg("usblp=0x%p", usblp);
- dbg("dev=0x%p", usblp->dev);
- dbg("present=%d", usblp->present);
- dbg("readbuf=0x%p", usblp->readbuf);
- dbg("readcount=%d", usblp->readcount);
- dbg("ifnum=%d", usblp->ifnum);
- for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
- dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
- dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
- dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
- }
- dbg("current_protocol=%d", usblp->current_protocol);
- dbg("minor=%d", usblp->minor);
- dbg("wstatus=%d", usblp->wstatus);
- dbg("rstatus=%d", usblp->rstatus);
- dbg("quirks=%d", usblp->quirks);
- dbg("used=%d", usblp->used);
- dbg("bidir=%d", usblp->bidir);
- dbg("device_id_string=\"%s\"",
+ dev_dbg(dev, "usblp=0x%p\n", usblp);
+ dev_dbg(dev, "dev=0x%p\n", usblp->dev);
+ dev_dbg(dev, "present=%d\n", usblp->present);
+ dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf);
+ dev_dbg(dev, "readcount=%d\n", usblp->readcount);
+ dev_dbg(dev, "ifnum=%d\n", usblp->ifnum);
+ for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
+ dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p,
+ usblp->protocol[p].alt_setting);
+ dev_dbg(dev, "protocol[%d].epwrite=%p\n", p,
+ usblp->protocol[p].epwrite);
+ dev_dbg(dev, "protocol[%d].epread=%p\n", p,
+ usblp->protocol[p].epread);
+ }
+ dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol);
+ dev_dbg(dev, "minor=%d\n", usblp->minor);
+ dev_dbg(dev, "wstatus=%d\n", usblp->wstatus);
+ dev_dbg(dev, "rstatus=%d\n", usblp->rstatus);
+ dev_dbg(dev, "quirks=%d\n", usblp->quirks);
+ dev_dbg(dev, "used=%d\n", usblp->used);
+ dev_dbg(dev, "bidir=%d\n", usblp->bidir);
+ dev_dbg(dev, "device_id_string=\"%s\"\n",
usblp->device_id_string ?
usblp->device_id_string + 2 :
(unsigned char *)"(null)");
@@ -262,7 +266,8 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
- dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
}
@@ -500,8 +505,9 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
- _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
+ dev_dbg(&usblp->intf->dev,
+ "usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd,
+ _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
@@ -594,7 +600,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d requested/got HP channel %ld/%d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d requested/got HP channel %ld/%d\n",
usblp->minor, arg, newChannel);
break;
@@ -614,7 +621,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d is bus=%d, device=%d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d is bus=%d, device=%d\n",
usblp->minor, twoints[0], twoints[1]);
break;
@@ -634,7 +642,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d is VID=0x%4.4X, PID=0x%4.4X\n",
usblp->minor, twoints[0], twoints[1]);
break;
@@ -987,7 +996,7 @@ static int usblp_submit_read(struct usblp *usblp)
usblp->rcomplete = 0;
spin_unlock_irqrestore(&usblp->lock, flags);
if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
- dbg("error submitting urb (%d)", rc);
+ dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);
spin_lock_irqsave(&usblp->lock, flags);
usblp->rstatus = rc;
usblp->rcomplete = 1;
@@ -1129,7 +1138,8 @@ static int usblp_probe(struct usb_interface *intf,
/* Analyze and pick initial alternate settings and endpoints. */
protocol = usblp_select_alts(usblp);
if (protocol < 0) {
- dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
+ dev_dbg(&intf->dev,
+ "incompatible printer-class device 0x%4.4X/0x%4.4X\n",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
retval = -ENODEV;
@@ -1158,14 +1168,14 @@ static int usblp_probe(struct usb_interface *intf,
retval = usb_register_dev(intf, &usblp_class);
if (retval) {
- printk(KERN_ERR "usblp: Not able to get a minor"
- " (base %u, slice default): %d\n",
- USBLP_MINOR_BASE, retval);
+ dev_err(&intf->dev,
+ "usblp: Not able to get a minor (base %u, slice default): %d\n",
+ USBLP_MINOR_BASE, retval);
goto abort_intfdata;
}
usblp->minor = intf->minor;
- printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
- "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
+ dev_info(&intf->dev,
+ "usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
usblp->ifnum,
usblp->protocol[usblp->current_protocol].alt_setting,
@@ -1302,7 +1312,8 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
usblp->bidir = (usblp->protocol[protocol].epread != NULL);
usblp->current_protocol = protocol;
- dbg("usblp%d set protocol %d", usblp->minor, protocol);
+ dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n",
+ usblp->minor, protocol);
return 0;
}
@@ -1315,7 +1326,8 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
if (err < 0) {
- dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d: error = %d reading IEEE-1284 Device ID string\n",
usblp->minor, err);
usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
return -EIO;
@@ -1331,7 +1343,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
length = USBLP_DEVICE_ID_SIZE - 1;
usblp->device_id_string[length] = '\0';
- dbg("usblp%d Device ID string [len=%d]=\"%s\"",
+ dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n",
usblp->minor, length, &usblp->device_id_string[2]);
return length;
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 18d02e3..9981984 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -27,58 +27,6 @@ config USB_ANNOUNCE_NEW_DEVICES
comment "Miscellaneous USB options"
depends on USB
-config USB_DEVICEFS
- bool "USB device filesystem (DEPRECATED)"
- depends on USB
- ---help---
- If you say Y here (and to "/proc file system support" in the "File
- systems" section, above), you will get a file /proc/bus/usb/devices
- which lists the devices currently connected to your USB bus or
- busses, and for every connected device a file named
- "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
- device number; the latter files can be used by user space programs
- to talk directly to the device. These files are "virtual", meaning
- they are generated on the fly and not stored on the hard drive.
-
- You may need to mount the usbfs file system to see the files, use
- mount -t usbfs none /proc/bus/usb
-
- For the format of the various /proc/bus/usb/ files, please read
- <file:Documentation/usb/proc_usb_info.txt>.
-
- Modern Linux systems do not use this.
-
- Usbfs entries are files and not character devices; usbfs can't
- handle Access Control Lists (ACL) which are the default way to
- grant access to USB devices for untrusted users of a desktop
- system.
-
- The usbfs functionality is replaced by real device-nodes managed by
- udev. These nodes lived in /dev/bus/usb and are used by libusb.
-
-config USB_DEVICE_CLASS
- bool "USB device class-devices (DEPRECATED)"
- depends on USB
- default y
- ---help---
- Userspace access to USB devices is granted by device-nodes exported
- directly from the usbdev in sysfs. Old versions of the driver
- core and udev needed additional class devices to export device nodes.
-
- These additional devices are difficult to handle in userspace, if
- information about USB interfaces must be available. One device
- contains the device node, the other device contains the interface
- data. Both devices are at the same level in sysfs (siblings) and one
- can't access the other. The device node created directly by the
- usb device is the parent device of the interface and therefore
- easily accessible from the interface event.
-
- This option provides backward compatibility for libusb device
- nodes (lsusb) when usbfs is not used, and the following udev rule
- doesn't exist:
- SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
- NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
-
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation"
depends on USB
@@ -125,7 +73,6 @@ config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
depends on USB_OTG || EXPERT
default y if USB_OTG
- default n if EXPERT
help
If you say Y here, the "otg_whitelist.h" file will be used as a
product whitelist, so USB peripherals not listed there will be
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 507a4e1..26059b9 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -9,6 +9,6 @@ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-$(CONFIG_PCI) += hcd-pci.o
-usbcore-$(CONFIG_USB_DEVICEFS) += inode.o
+usbcore-$(CONFIG_ACPI) += usb-acpi.o
obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8df4b76..e0f1079 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps)
static struct async *async_getpending(struct dev_state *ps,
void __user *userurb)
{
- unsigned long flags;
struct async *as;
- spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(as, &ps->async_pending, asynclist)
if (as->userurb == userurb) {
list_del_init(&as->asynclist);
- spin_unlock_irqrestore(&ps->lock, flags);
return as;
}
- spin_unlock_irqrestore(&ps->lock, flags);
+
return NULL;
}
@@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr)
__releases(ps->lock)
__acquires(ps->lock)
{
+ struct urb *urb;
struct async *as;
/* Mark all the pending URBs that match bulk_addr, up to but not
@@ -420,8 +418,11 @@ __acquires(ps->lock)
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_status == AS_UNLINK) {
as->bulk_status = 0; /* Only once */
+ urb = as->urb;
+ usb_get_urb(urb);
spin_unlock(&ps->lock); /* Allow completions */
- usb_unlink_urb(as->urb);
+ usb_unlink_urb(urb);
+ usb_put_urb(urb);
spin_lock(&ps->lock);
goto rescan;
}
@@ -472,6 +473,7 @@ static void async_completed(struct urb *urb)
static void destroy_async(struct dev_state *ps, struct list_head *list)
{
+ struct urb *urb;
struct async *as;
unsigned long flags;
@@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list)
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
+ urb = as->urb;
+ usb_get_urb(urb);
/* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
- usb_kill_urb(as->urb);
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
@@ -727,17 +732,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
-#ifdef CONFIG_USB_DEVICEFS
- /* procfs file */
- if (!dev) {
- dev = inode->i_private;
- if (dev && dev->usbfs_dentry &&
- dev->usbfs_dentry->d_inode == inode)
- usb_get_dev(dev);
- else
- dev = NULL;
- }
-#endif
mutex_unlock(&usbfs_mutex);
if (!dev)
@@ -1410,12 +1404,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
{
+ struct urb *urb;
struct async *as;
+ unsigned long flags;
+ spin_lock_irqsave(&ps->lock, flags);
as = async_getpending(ps, arg);
- if (!as)
+ if (!as) {
+ spin_unlock_irqrestore(&ps->lock, flags);
return -EINVAL;
- usb_kill_urb(as->urb);
+ }
+
+ urb = as->urb;
+ usb_get_urb(urb);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
+
return 0;
}
@@ -2062,44 +2068,13 @@ static void usbdev_remove(struct usb_device *udev)
}
}
-#ifdef CONFIG_USB_DEVICE_CLASS
-static struct class *usb_classdev_class;
-
-static int usb_classdev_add(struct usb_device *dev)
-{
- struct device *cldev;
-
- cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt,
- NULL, "usbdev%d.%d", dev->bus->busnum,
- dev->devnum);
- if (IS_ERR(cldev))
- return PTR_ERR(cldev);
- dev->usb_classdev = cldev;
- return 0;
-}
-
-static void usb_classdev_remove(struct usb_device *dev)
-{
- if (dev->usb_classdev)
- device_unregister(dev->usb_classdev);
-}
-
-#else
-#define usb_classdev_add(dev) 0
-#define usb_classdev_remove(dev) do {} while (0)
-
-#endif
-
static int usbdev_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
- if (usb_classdev_add(dev))
- return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
- usb_classdev_remove(dev);
usbdev_remove(dev);
break;
}
@@ -2129,21 +2104,6 @@ int __init usb_devio_init(void)
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)) {
- 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;
- goto out;
- }
- /* devices of this class shadow the major:minor of their parent
- * device, so clear ->dev_kobj to prevent adding duplicate entries
- * to /sys/dev
- */
- usb_classdev_class->dev_kobj = NULL;
-#endif
usb_register_notify(&usbdev_nb);
out:
return retval;
@@ -2156,9 +2116,6 @@ error_cdev:
void usb_devio_cleanup(void)
{
usb_unregister_notify(&usbdev_nb);
-#ifdef CONFIG_USB_DEVICE_CLASS
- class_destroy(usb_classdev_class);
-#endif
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9a56635..f536aeb 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -79,6 +79,30 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
}
EXPORT_SYMBOL_GPL(usb_store_new_id);
+ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
+{
+ struct usb_dynid *dynid;
+ size_t count = 0;
+
+ list_for_each_entry(dynid, &dynids->list, node)
+ if (dynid->id.bInterfaceClass != 0)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n",
+ dynid->id.idVendor, dynid->id.idProduct,
+ dynid->id.bInterfaceClass);
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n",
+ dynid->id.idVendor, dynid->id.idProduct);
+ return count;
+}
+EXPORT_SYMBOL_GPL(usb_show_dynids);
+
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
static ssize_t store_new_id(struct device_driver *driver,
const char *buf, size_t count)
{
@@ -86,7 +110,7 @@ static ssize_t store_new_id(struct device_driver *driver,
return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
}
-static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
/**
* store_remove_id - remove a USB device ID from this driver
@@ -127,7 +151,7 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
return retval;
return count;
}
-static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
static int usb_create_newid_files(struct usb_driver *usb_drv)
{
@@ -264,6 +288,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
+ int lpm_disable_error;
dev_dbg(dev, "%s\n", __func__);
@@ -300,6 +325,25 @@ static int usb_probe_interface(struct device *dev)
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
+ /* If the new driver doesn't allow hub-initiated LPM, and we can't
+ * disable hub-initiated LPM, then fail the probe.
+ *
+ * Otherwise, leaving LPM enabled should be harmless, because the
+ * endpoint intervals should remain the same, and the U1/U2 timeouts
+ * should remain the same.
+ *
+ * If we need to install alt setting 0 before probe, or another alt
+ * setting during probe, that should also be fine. usb_set_interface()
+ * will attempt to disable LPM, and fail if it can't disable it.
+ */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+ if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+ dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
+ __func__, driver->name);
+ error = lpm_disable_error;
+ goto err;
+ }
+
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
@@ -314,6 +358,11 @@ static int usb_probe_interface(struct device *dev)
goto err;
intf->condition = USB_INTERFACE_BOUND;
+
+ /* If the LPM disable succeeded, balance the ref counts. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
usb_autosuspend_device(udev);
return error;
@@ -337,7 +386,7 @@ static int usb_unbind_interface(struct device *dev)
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev;
- int error, r;
+ int error, r, lpm_disable_error;
intf->condition = USB_INTERFACE_UNBINDING;
@@ -345,6 +394,13 @@ static int usb_unbind_interface(struct device *dev)
udev = interface_to_usbdev(intf);
error = usb_autoresume_device(udev);
+ /* Hub-initiated LPM policy may change, so attempt to disable LPM until
+ * the driver is unbound. If LPM isn't disabled, that's fine because it
+ * wouldn't be enabled unless all the bound interfaces supported
+ * hub-initiated LPM.
+ */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+
/* Terminate all URBs for this interface unless the driver
* supports "soft" unbinding.
*/
@@ -378,6 +434,10 @@ static int usb_unbind_interface(struct device *dev)
intf->condition = USB_INTERFACE_UNBOUND;
intf->needs_remote_wakeup = 0;
+ /* Attempt to re-enable USB3 LPM, if the disable succeeded. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
@@ -418,17 +478,29 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
{
struct device *dev = &iface->dev;
+ struct usb_device *udev;
int retval = 0;
+ int lpm_disable_error;
if (dev->driver)
return -EBUSY;
+ udev = interface_to_usbdev(iface);
+
dev->driver = &driver->drvwrap.driver;
usb_set_intfdata(iface, priv);
iface->needs_binding = 0;
iface->condition = USB_INTERFACE_BOUND;
+ /* Disable LPM until this driver is bound. */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+ if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+ dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
+ __func__, driver->name);
+ return -ENOMEM;
+ }
+
/* Claimed interfaces are initially inactive (suspended) and
* runtime-PM-enabled, but only if the driver has autosuspend
* support. Otherwise they are marked active, to prevent the
@@ -447,6 +519,10 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (device_is_registered(dev))
retval = device_bind_driver(dev);
+ /* Attempt to re-enable USB3 LPM, if the disable was successful. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
return retval;
}
EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
@@ -726,16 +802,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
return -ENODEV;
}
-#ifdef CONFIG_USB_DEVICEFS
- /* If this is available, userspace programs can directly read
- * all the device descriptors we don't tell them about. Or
- * act as usermode drivers.
- */
- if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum))
- return -ENOMEM;
-#endif
-
/* per-device configurations are common */
if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
@@ -788,15 +854,13 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
retval = driver_register(&new_udriver->drvwrap.driver);
- if (!retval) {
+ if (!retval)
pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name);
- usbfs_update_special();
- } else {
+ else
printk(KERN_ERR "%s: error %d registering device "
" driver %s\n",
usbcore_name, retval, new_udriver->name);
- }
return retval;
}
@@ -815,7 +879,6 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver)
usbcore_name, udriver->name);
driver_unregister(&udriver->drvwrap.driver);
- usbfs_update_special();
}
EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
@@ -856,8 +919,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
if (retval)
goto out;
- usbfs_update_special();
-
retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
@@ -897,8 +958,6 @@ void usb_deregister(struct usb_driver *driver)
usb_remove_newid_files(driver);
driver_unregister(&driver->drvwrap.driver);
usb_free_dynids(driver);
-
- usbfs_update_special();
}
EXPORT_SYMBOL_GPL(usb_deregister);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index d95760d..e673b26 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -183,7 +183,7 @@ int usb_register_dev(struct usb_interface *intf,
if (retval)
return retval;
- dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
+ dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -239,7 +239,7 @@ void usb_deregister_dev(struct usb_interface *intf,
if (intf->minor == -1)
return;
- dbg ("removing %d minor", intf->minor);
+ dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 140d3e1..190b1ec7 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -138,7 +138,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x03, 0x00, /* __le16 idProduct; device 0x0003 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -159,7 +159,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -182,7 +182,7 @@ static const u8 usb11_rh_dev_descriptor [18] = {
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x01, 0x00, /* __le16 idProduct; device 0x0001 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -997,6 +997,15 @@ static int register_root_hub(struct usb_hcd *hcd)
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
+ if (usb_dev->speed == USB_SPEED_SUPER) {
+ retval = usb_get_bos_descriptor(usb_dev);
+ if (retval < 0) {
+ mutex_unlock(&usb_bus_list_lock);
+ dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
+ dev_name(&usb_dev->dev), retval);
+ return retval;
+ }
+ }
retval = usb_new_device (usb_dev);
if (retval) {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ec6c97d..04fb834 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -177,6 +177,228 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
+static int usb_device_supports_lpm(struct usb_device *udev)
+{
+ /* USB 2.1 (and greater) devices indicate LPM support through
+ * their USB 2.0 Extended Capabilities BOS descriptor.
+ */
+ if (udev->speed == USB_SPEED_HIGH) {
+ if (udev->bos->ext_cap &&
+ (USB_LPM_SUPPORT &
+ le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+ return 1;
+ return 0;
+ }
+
+ /* All USB 3.0 must support LPM, but we need their max exit latency
+ * information from the SuperSpeed Extended Capabilities BOS descriptor.
+ */
+ if (!udev->bos->ss_cap) {
+ dev_warn(&udev->dev, "No LPM exit latency info found. "
+ "Power management will be impacted.\n");
+ return 0;
+ }
+ if (udev->parent->lpm_capable)
+ return 1;
+
+ dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. "
+ "Power management will be impacted.\n");
+ return 0;
+}
+
+/*
+ * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
+ * either U1 or U2.
+ */
+static void usb_set_lpm_mel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency)
+{
+ unsigned int total_mel;
+ unsigned int device_mel;
+ unsigned int hub_mel;
+
+ /*
+ * Calculate the time it takes to transition all links from the roothub
+ * to the parent hub into U0. The parent hub must then decode the
+ * packet (hub header decode latency) to figure out which port it was
+ * bound for.
+ *
+ * The Hub Header decode latency is expressed in 0.1us intervals (0x1
+ * means 0.1us). Multiply that by 100 to get nanoseconds.
+ */
+ total_mel = hub_lpm_params->mel +
+ (hub->descriptor->u.ss.bHubHdrDecLat * 100);
+
+ /*
+ * How long will it take to transition the downstream hub's port into
+ * U0? The greater of either the hub exit latency or the device exit
+ * latency.
+ *
+ * The BOS U1/U2 exit latencies are expressed in 1us intervals.
+ * Multiply that by 1000 to get nanoseconds.
+ */
+ device_mel = udev_exit_latency * 1000;
+ hub_mel = hub_exit_latency * 1000;
+ if (device_mel > hub_mel)
+ total_mel += device_mel;
+ else
+ total_mel += hub_mel;
+
+ udev_lpm_params->mel = total_mel;
+}
+
+/*
+ * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
+ * a transition from either U1 or U2.
+ */
+static void usb_set_lpm_pel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency,
+ unsigned int port_to_port_exit_latency)
+{
+ unsigned int first_link_pel;
+ unsigned int hub_pel;
+
+ /*
+ * First, the device sends an LFPS to transition the link between the
+ * device and the parent hub into U0. The exit latency is the bigger of
+ * the device exit latency or the hub exit latency.
+ */
+ if (udev_exit_latency > hub_exit_latency)
+ first_link_pel = udev_exit_latency * 1000;
+ else
+ first_link_pel = hub_exit_latency * 1000;
+
+ /*
+ * When the hub starts to receive the LFPS, there is a slight delay for
+ * it to figure out that one of the ports is sending an LFPS. Then it
+ * will forward the LFPS to its upstream link. The exit latency is the
+ * delay, plus the PEL that we calculated for this hub.
+ */
+ hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
+
+ /*
+ * According to figure C-7 in the USB 3.0 spec, the PEL for this device
+ * is the greater of the two exit latencies.
+ */
+ if (first_link_pel > hub_pel)
+ udev_lpm_params->pel = first_link_pel;
+ else
+ udev_lpm_params->pel = hub_pel;
+}
+
+/*
+ * Set the System Exit Latency (SEL) to indicate the total worst-case time from
+ * when a device initiates a transition to U0, until when it will receive the
+ * first packet from the host controller.
+ *
+ * Section C.1.5.1 describes the four components to this:
+ * - t1: device PEL
+ * - t2: time for the ERDY to make it from the device to the host.
+ * - t3: a host-specific delay to process the ERDY.
+ * - t4: time for the packet to make it from the host to the device.
+ *
+ * t3 is specific to both the xHCI host and the platform the host is integrated
+ * into. The Intel HW folks have said it's negligible, FIXME if a different
+ * vendor says otherwise.
+ */
+static void usb_set_lpm_sel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params)
+{
+ struct usb_device *parent;
+ unsigned int num_hubs;
+ unsigned int total_sel;
+
+ /* t1 = device PEL */
+ total_sel = udev_lpm_params->pel;
+ /* How many external hubs are in between the device & the root port. */
+ for (parent = udev->parent, num_hubs = 0; parent->parent;
+ parent = parent->parent)
+ num_hubs++;
+ /* t2 = 2.1us + 250ns * (num_hubs - 1) */
+ if (num_hubs > 0)
+ total_sel += 2100 + 250 * (num_hubs - 1);
+
+ /* t4 = 250ns * num_hubs */
+ total_sel += 250 * num_hubs;
+
+ udev_lpm_params->sel = total_sel;
+}
+
+static void usb_set_lpm_parameters(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+ unsigned int port_to_port_delay;
+ unsigned int udev_u1_del;
+ unsigned int udev_u2_del;
+ unsigned int hub_u1_del;
+ unsigned int hub_u2_del;
+
+ if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+ return;
+
+ hub = hdev_to_hub(udev->parent);
+ /* It doesn't take time to transition the roothub into U0, since it
+ * doesn't have an upstream link.
+ */
+ if (!hub)
+ return;
+
+ udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
+ udev_u2_del = udev->bos->ss_cap->bU2DevExitLat;
+ hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
+ hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat;
+
+ usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del);
+
+ usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del);
+
+ /*
+ * Appendix C, section C.2.2.2, says that there is a slight delay from
+ * when the parent hub notices the downstream port is trying to
+ * transition to U0 to when the hub initiates a U0 transition on its
+ * upstream port. The section says the delays are tPort2PortU1EL and
+ * tPort2PortU2EL, but it doesn't define what they are.
+ *
+ * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
+ * about the same delays. Use the maximum delay calculations from those
+ * sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For
+ * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I
+ * assume the device exit latencies they are talking about are the hub
+ * exit latencies.
+ *
+ * What do we do if the U2 exit latency is less than the U1 exit
+ * latency? It's possible, although not likely...
+ */
+ port_to_port_delay = 1;
+
+ usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del,
+ port_to_port_delay);
+
+ if (hub_u2_del > hub_u1_del)
+ port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
+ else
+ port_to_port_delay = 1 + hub_u1_del;
+
+ usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del,
+ port_to_port_delay);
+
+ /* Now that we've got PEL, calculate SEL. */
+ usb_set_lpm_sel(udev, &udev->u1_params);
+ usb_set_lpm_sel(udev, &udev->u2_params);
+}
+
/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data)
{
@@ -2480,6 +2702,12 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
+ if (usb_unlocked_disable_lpm(udev)) {
+ dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
+ __func__);
+ return -ENOMEM;
+ }
+
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = set_port_feature(hub->hdev,
@@ -2499,6 +2727,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
NULL, 0,
USB_CTRL_SET_TIMEOUT);
+ /* Try to enable USB2 hardware LPM again */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
+
+ /* Try to enable USB3 LPM again */
+ usb_unlocked_enable_lpm(udev);
+
/* System sleep transitions should never fail */
if (!PMSG_IS_AUTO(msg))
status = 0;
@@ -2696,6 +2931,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
/* Try to enable USB2 hardware LPM */
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
+
+ /* Try to enable USB3 LPM */
+ usb_unlocked_enable_lpm(udev);
}
return status;
@@ -2824,11 +3062,429 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+static const char * const usb3_lpm_names[] = {
+ "U0",
+ "U1",
+ "U2",
+ "U3",
+};
+
+/*
+ * Send a Set SEL control transfer to the device, prior to enabling
+ * device-initiated U1 or U2. This lets the device know the exit latencies from
+ * the time the device initiates a U1 or U2 exit, to the time it will receive a
+ * packet from the host.
+ *
+ * This function will fail if the SEL or PEL values for udev are greater than
+ * the maximum allowed values for the link state to be enabled.
+ */
+static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
+{
+ struct usb_set_sel_req *sel_values;
+ unsigned long long u1_sel;
+ unsigned long long u1_pel;
+ unsigned long long u2_sel;
+ unsigned long long u2_pel;
+ int ret;
+
+ /* Convert SEL and PEL stored in ns to us */
+ u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+ u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+
+ /*
+ * Make sure that the calculated SEL and PEL values for the link
+ * state we're enabling aren't bigger than the max SEL/PEL
+ * value that will fit in the SET SEL control transfer.
+ * Otherwise the device would get an incorrect idea of the exit
+ * latency for the link state, and could start a device-initiated
+ * U1/U2 when the exit latencies are too high.
+ */
+ if ((state == USB3_LPM_U1 &&
+ (u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
+ u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
+ (state == USB3_LPM_U2 &&
+ (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
+ u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
+ dev_dbg(&udev->dev, "Device-initiated %s disabled due "
+ "to long SEL %llu ms or PEL %llu ms\n",
+ usb3_lpm_names[state], u1_sel, u1_pel);
+ return -EINVAL;
+ }
+
+ /*
+ * If we're enabling device-initiated LPM for one link state,
+ * but the other link state has a too high SEL or PEL value,
+ * just set those values to the max in the Set SEL request.
+ */
+ if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ /*
+ * usb_enable_lpm() can be called as part of a failed device reset,
+ * which may be initiated by an error path of a mass storage driver.
+ * Therefore, use GFP_NOIO.
+ */
+ sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
+ if (!sel_values)
+ return -ENOMEM;
+
+ sel_values->u1_sel = u1_sel;
+ sel_values->u1_pel = u1_pel;
+ sel_values->u2_sel = cpu_to_le16(u2_sel);
+ sel_values->u2_pel = cpu_to_le16(u2_pel);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_SEL,
+ USB_RECIP_DEVICE,
+ 0, 0,
+ sel_values, sizeof *(sel_values),
+ USB_CTRL_SET_TIMEOUT);
+ kfree(sel_values);
+ return ret;
+}
+
+/*
+ * Enable or disable device-initiated U1 or U2 transitions.
+ */
+static int usb_set_device_initiated_lpm(struct usb_device *udev,
+ enum usb3_link_state state, bool enable)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_DEVICE_U1_ENABLE;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_DEVICE_U2_ENABLE;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
+ __func__, enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ if (udev->state != USB_STATE_CONFIGURED) {
+ dev_dbg(&udev->dev, "%s: Can't %s %s state "
+ "for unconfigured device.\n",
+ __func__, enable ? "enable" : "disable",
+ usb3_lpm_names[state]);
+ return 0;
+ }
+
+ if (enable) {
+ /*
+ * First, let the device know about the exit latencies
+ * associated with the link state we're about to enable.
+ */
+ ret = usb_req_set_sel(udev, state);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Set SEL for device-initiated "
+ "%s failed.\n", usb3_lpm_names[state]);
+ return -EBUSY;
+ }
+ /*
+ * Now send the control transfer to enable device-initiated LPM
+ * for either U1 or U2.
+ */
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ }
+ if (ret < 0) {
+ dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
+ enable ? "Enable" : "Disable",
+ usb3_lpm_names[state]);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static int usb_set_lpm_timeout(struct usb_device *udev,
+ enum usb3_link_state state, int timeout)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_PORT_FEAT_U1_TIMEOUT;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_PORT_FEAT_U2_TIMEOUT;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
+ timeout != USB3_LPM_DEVICE_INITIATED) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
+ "which is a reserved value.\n",
+ usb3_lpm_names[state], timeout);
+ return -EINVAL;
+ }
+
+ ret = set_port_feature(udev->parent,
+ USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
+ feature);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
+ "error code %i\n", usb3_lpm_names[state],
+ timeout, ret);
+ return -EBUSY;
+ }
+ if (state == USB3_LPM_U1)
+ udev->u1_params.timeout = timeout;
+ else
+ udev->u2_params.timeout = timeout;
+ return 0;
+}
+
+/*
+ * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
+ * U1/U2 entry.
+ *
+ * We will attempt to enable U1 or U2, but there are no guarantees that the
+ * control transfers to set the hub timeout or enable device-initiated U1/U2
+ * will be successful.
+ *
+ * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
+ * driver know about it. If that call fails, it should be harmless, and just
+ * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
+ */
+static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ int timeout;
+
+ /* We allow the host controller to set the U1/U2 timeout internally
+ * first, so that it can change its schedule to account for the
+ * additional latency to send data to a device in a lower power
+ * link state.
+ */
+ timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
+
+ /* xHCI host controller doesn't want to enable this LPM state. */
+ if (timeout == 0)
+ return;
+
+ if (timeout < 0) {
+ dev_warn(&udev->dev, "Could not enable %s link state, "
+ "xHCI error %i.\n", usb3_lpm_names[state],
+ timeout);
+ return;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, timeout))
+ /* If we can't set the parent hub U1/U2 timeout,
+ * device-initiated LPM won't be allowed either, so let the xHCI
+ * host know that this link state won't be enabled.
+ */
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+
+ /* Only a configured device will accept the Set Feature U1/U2_ENABLE */
+ else if (udev->actconfig)
+ usb_set_device_initiated_lpm(udev, state, true);
+
+}
+
+/*
+ * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
+ * U1/U2 entry.
+ *
+ * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
+ * If zero is returned, the parent will not allow the link to go into U1/U2.
+ *
+ * If zero is returned, device-initiated U1/U2 entry may still be enabled, but
+ * it won't have an effect on the bus link state because the parent hub will
+ * still disallow device-initiated U1/U2 entry.
+ *
+ * If zero is returned, the xHCI host controller may still think U1/U2 entry is
+ * possible. The result will be slightly more bus bandwidth will be taken up
+ * (to account for U1/U2 exit latency), but it should be harmless.
+ */
+static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_PORT_FEAT_U1_TIMEOUT;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_PORT_FEAT_U2_TIMEOUT;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, 0))
+ return -EBUSY;
+
+ usb_set_device_initiated_lpm(udev, state, false);
+
+ if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
+ dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
+ "bus schedule bandwidth may be impacted.\n",
+ usb3_lpm_names[state]);
+ return 0;
+}
+
+/*
+ * Disable hub-initiated and device-initiated U1 and U2 entry.
+ * Caller must own the bandwidth_mutex.
+ *
+ * This will call usb_enable_lpm() on failure, which will decrement
+ * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
+ */
+int usb_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ if (!udev || !udev->parent ||
+ udev->speed != USB_SPEED_SUPER ||
+ !udev->lpm_capable)
+ return 0;
+
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
+ return 0;
+
+ udev->lpm_disable_count++;
+ if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0))
+ return 0;
+
+ /* If LPM is enabled, attempt to disable it. */
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
+ goto enable_lpm;
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
+ goto enable_lpm;
+
+ return 0;
+
+enable_lpm:
+ usb_enable_lpm(udev);
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret;
+
+ if (!hcd)
+ return -EINVAL;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ ret = usb_disable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+/*
+ * Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The
+ * xHCI host policy may prevent U1 or U2 from being enabled.
+ *
+ * Other callers may have disabled link PM, so U1 and U2 entry will be disabled
+ * until the lpm_disable_count drops to zero. Caller must own the
+ * bandwidth_mutex.
+ */
+void usb_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ if (!udev || !udev->parent ||
+ udev->speed != USB_SPEED_SUPER ||
+ !udev->lpm_capable)
+ return;
+
+ udev->lpm_disable_count--;
+ hcd = bus_to_hcd(udev->bus);
+ /* Double check that we can both enable and disable LPM.
+ * Device must be configured to accept set feature U1/U2 timeout.
+ */
+ if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
+ !hcd->driver->disable_usb3_lpm_timeout)
+ return;
+
+ if (udev->lpm_disable_count > 0)
+ return;
+
+ usb_enable_link_state(hcd, udev, USB3_LPM_U1);
+ usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+}
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
+void usb_unlocked_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!hcd)
+ return;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ usb_enable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+
#else /* CONFIG_PM */
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
+
+int usb_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+void usb_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+void usb_unlocked_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
#endif
@@ -3208,9 +3864,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(udev);
if (!retval) {
- if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
- le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
- udev->lpm_capable = 1;
+ udev->lpm_capable = usb_device_supports_lpm(udev);
+ usb_set_lpm_parameters(udev);
}
}
@@ -4042,11 +4697,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
goto done;
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM while we reset the device and reinstall the alt settings.
+ * Device-initiated LPM settings, and system exit latency settings are
+ * cleared when the device is reset, so we have to set them up again.
+ */
+ ret = usb_disable_lpm(udev);
+ if (ret) {
+ dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ goto done;
+ }
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
dev_warn(&udev->dev,
"Busted HC? Not enough HCD resources for "
"old configuration.\n");
+ usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@@ -4058,6 +4724,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
udev->actconfig->desc.bConfigurationValue, ret);
+ usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@@ -4096,10 +4763,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
desc->bInterfaceNumber,
desc->bAlternateSetting,
ret);
+ usb_unlocked_enable_lpm(udev);
goto re_enumerate;
}
}
+ /* Now that the alt settings are re-installed, enable LPM. */
+ usb_unlocked_enable_lpm(udev);
done:
return 0;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
deleted file mode 100644
index d2b9af5..0000000
--- a/drivers/usb/core/inode.c
+++ /dev/null
@@ -1,748 +0,0 @@
-/*****************************************************************************/
-
-/*
- * inode.c -- Inode/Dentry functions for the USB device file system.
- *
- * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Copyright (C) 2001,2002,2004 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- * 0.1 04.01.2000 Created
- * 0.2 10.12.2001 converted to use the vfs layer better
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/usb.h>
-#include <linux/namei.h>
-#include <linux/usbdevice_fs.h>
-#include <linux/parser.h>
-#include <linux/notifier.h>
-#include <linux/seq_file.h>
-#include <linux/usb/hcd.h>
-#include <asm/byteorder.h>
-#include "usb.h"
-
-#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
-#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
-#define USBFS_DEFAULT_LISTMODE S_IRUGO
-
-static const struct file_operations default_file_operations;
-static struct vfsmount *usbfs_mount;
-static int usbfs_mount_count; /* = 0 */
-
-static struct dentry *devices_usbfs_dentry;
-static int num_buses; /* = 0 */
-
-static uid_t devuid; /* = 0 */
-static uid_t busuid; /* = 0 */
-static uid_t listuid; /* = 0 */
-static gid_t devgid; /* = 0 */
-static gid_t busgid; /* = 0 */
-static gid_t listgid; /* = 0 */
-static umode_t devmode = USBFS_DEFAULT_DEVMODE;
-static umode_t busmode = USBFS_DEFAULT_BUSMODE;
-static umode_t listmode = USBFS_DEFAULT_LISTMODE;
-
-static int usbfs_show_options(struct seq_file *seq, struct dentry *root)
-{
- if (devuid != 0)
- seq_printf(seq, ",devuid=%u", devuid);
- if (devgid != 0)
- seq_printf(seq, ",devgid=%u", devgid);
- if (devmode != USBFS_DEFAULT_DEVMODE)
- seq_printf(seq, ",devmode=%o", devmode);
- if (busuid != 0)
- seq_printf(seq, ",busuid=%u", busuid);
- if (busgid != 0)
- seq_printf(seq, ",busgid=%u", busgid);
- if (busmode != USBFS_DEFAULT_BUSMODE)
- seq_printf(seq, ",busmode=%o", busmode);
- if (listuid != 0)
- seq_printf(seq, ",listuid=%u", listuid);
- if (listgid != 0)
- seq_printf(seq, ",listgid=%u", listgid);
- if (listmode != USBFS_DEFAULT_LISTMODE)
- seq_printf(seq, ",listmode=%o", listmode);
-
- return 0;
-}
-
-enum {
- Opt_devuid, Opt_devgid, Opt_devmode,
- Opt_busuid, Opt_busgid, Opt_busmode,
- Opt_listuid, Opt_listgid, Opt_listmode,
- Opt_err,
-};
-
-static const match_table_t tokens = {
- {Opt_devuid, "devuid=%u"},
- {Opt_devgid, "devgid=%u"},
- {Opt_devmode, "devmode=%o"},
- {Opt_busuid, "busuid=%u"},
- {Opt_busgid, "busgid=%u"},
- {Opt_busmode, "busmode=%o"},
- {Opt_listuid, "listuid=%u"},
- {Opt_listgid, "listgid=%u"},
- {Opt_listmode, "listmode=%o"},
- {Opt_err, NULL}
-};
-
-static int parse_options(struct super_block *s, char *data)
-{
- char *p;
- int option;
-
- /* (re)set to defaults. */
- devuid = 0;
- busuid = 0;
- listuid = 0;
- devgid = 0;
- busgid = 0;
- listgid = 0;
- devmode = USBFS_DEFAULT_DEVMODE;
- busmode = USBFS_DEFAULT_BUSMODE;
- listmode = USBFS_DEFAULT_LISTMODE;
-
- while ((p = strsep(&data, ",")) != NULL) {
- substring_t args[MAX_OPT_ARGS];
- int token;
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case Opt_devuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- devuid = option;
- break;
- case Opt_devgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- devgid = option;
- break;
- case Opt_devmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- devmode = option & S_IRWXUGO;
- break;
- case Opt_busuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- busuid = option;
- break;
- case Opt_busgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- busgid = option;
- break;
- case Opt_busmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- busmode = option & S_IRWXUGO;
- break;
- case Opt_listuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- listuid = option;
- break;
- case Opt_listgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- listgid = option;
- break;
- case Opt_listmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- listmode = option & S_IRWXUGO;
- break;
- default:
- printk(KERN_ERR "usbfs: unrecognised mount option "
- "\"%s\" or missing value\n", p);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static void update_special(struct dentry *special)
-{
- special->d_inode->i_uid = listuid;
- special->d_inode->i_gid = listgid;
- special->d_inode->i_mode = S_IFREG | listmode;
-}
-
-static void update_dev(struct dentry *dev)
-{
- dev->d_inode->i_uid = devuid;
- dev->d_inode->i_gid = devgid;
- dev->d_inode->i_mode = S_IFREG | devmode;
-}
-
-static void update_bus(struct dentry *bus)
-{
- struct dentry *dev = NULL;
-
- bus->d_inode->i_uid = busuid;
- bus->d_inode->i_gid = busgid;
- bus->d_inode->i_mode = S_IFDIR | busmode;
-
- mutex_lock(&bus->d_inode->i_mutex);
-
- list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
- if (dev->d_inode)
- update_dev(dev);
-
- mutex_unlock(&bus->d_inode->i_mutex);
-}
-
-static void update_sb(struct super_block *sb)
-{
- struct dentry *root = sb->s_root;
- struct dentry *bus = NULL;
-
- if (!root)
- return;
-
- mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
-
- list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
- if (bus->d_inode) {
- switch (S_IFMT & bus->d_inode->i_mode) {
- case S_IFDIR:
- update_bus(bus);
- break;
- case S_IFREG:
- update_special(bus);
- break;
- default:
- printk(KERN_WARNING "usbfs: Unknown node %s "
- "mode %x found on remount!\n",
- bus->d_name.name, bus->d_inode->i_mode);
- break;
- }
- }
- }
-
- mutex_unlock(&root->d_inode->i_mutex);
-}
-
-static int remount(struct super_block *sb, int *flags, char *data)
-{
- /* If this is not a real mount,
- * i.e. it's a simple_pin_fs from create_special_files,
- * then ignore it.
- */
- if (*flags & MS_KERNMOUNT)
- return 0;
-
- if (parse_options(sb, data)) {
- printk(KERN_WARNING "usbfs: mount parameter error.\n");
- return -EINVAL;
- }
-
- if (usbfs_mount)
- update_sb(usbfs_mount->mnt_sb);
-
- return 0;
-}
-
-static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev)
-{
- struct inode *inode = new_inode(sb);
-
- if (inode) {
- inode->i_ino = get_next_ino();
- inode_init_owner(inode, NULL, mode);
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- switch (mode & S_IFMT) {
- default:
- init_special_inode(inode, mode, dev);
- break;
- case S_IFREG:
- inode->i_fop = &default_file_operations;
- break;
- case S_IFDIR:
- inode->i_op = &simple_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
-
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
- break;
- }
- }
- return inode;
-}
-
-/* SMP-safe */
-static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode,
- dev_t dev)
-{
- struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
- int error = -EPERM;
-
- if (dentry->d_inode)
- return -EEXIST;
-
- if (inode) {
- d_instantiate(dentry, inode);
- dget(dentry);
- error = 0;
- }
- return error;
-}
-
-static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
- int res;
-
- mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
- res = usbfs_mknod (dir, dentry, mode, 0);
- if (!res)
- inc_nlink(dir);
- return res;
-}
-
-static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
- mode = (mode & S_IALLUGO) | S_IFREG;
- return usbfs_mknod (dir, dentry, mode, 0);
-}
-
-static inline int usbfs_positive (struct dentry *dentry)
-{
- return dentry->d_inode && !d_unhashed(dentry);
-}
-
-static int usbfs_empty (struct dentry *dentry)
-{
- struct list_head *list;
-
- spin_lock(&dentry->d_lock);
- list_for_each(list, &dentry->d_subdirs) {
- struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
-
- spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
- if (usbfs_positive(de)) {
- spin_unlock(&de->d_lock);
- spin_unlock(&dentry->d_lock);
- return 0;
- }
- spin_unlock(&de->d_lock);
- }
- spin_unlock(&dentry->d_lock);
- return 1;
-}
-
-static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
- mutex_lock(&inode->i_mutex);
- drop_nlink(dentry->d_inode);
- dput(dentry);
- mutex_unlock(&inode->i_mutex);
- d_delete(dentry);
- return 0;
-}
-
-static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
- int error = -ENOTEMPTY;
- struct inode * inode = dentry->d_inode;
-
- mutex_lock(&inode->i_mutex);
- dentry_unhash(dentry);
- if (usbfs_empty(dentry)) {
- dont_mount(dentry);
- drop_nlink(dentry->d_inode);
- drop_nlink(dentry->d_inode);
- dput(dentry);
- inode->i_flags |= S_DEAD;
- drop_nlink(dir);
- error = 0;
- }
- mutex_unlock(&inode->i_mutex);
- if (!error)
- d_delete(dentry);
- return error;
-}
-
-
-/* default file operations */
-static ssize_t default_read_file (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t default_write_file (struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return count;
-}
-
-static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
-{
- loff_t retval = -EINVAL;
-
- mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
- switch(orig) {
- case 0:
- if (offset > 0) {
- file->f_pos = offset;
- retval = file->f_pos;
- }
- break;
- case 1:
- if ((offset + file->f_pos) > 0) {
- file->f_pos += offset;
- retval = file->f_pos;
- }
- break;
- default:
- break;
- }
- mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
- return retval;
-}
-
-static const struct file_operations default_file_operations = {
- .read = default_read_file,
- .write = default_write_file,
- .open = simple_open,
- .llseek = default_file_lseek,
-};
-
-static const struct super_operations usbfs_ops = {
- .statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
- .remount_fs = remount,
- .show_options = usbfs_show_options,
-};
-
-static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct inode *inode;
-
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = USBDEVICE_SUPER_MAGIC;
- sb->s_op = &usbfs_ops;
- sb->s_time_gran = 1;
- inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
- sb->s_root = d_make_root(inode);
- if (!sb->s_root) {
- dbg("%s: could not get root dentry!",__func__);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * fs_create_by_name - create a file, given a name
- * @name: name of file
- * @mode: type of file
- * @parent: dentry of directory to create it in
- * @dentry: resulting dentry of file
- *
- * This function handles both regular files and directories.
- */
-static int fs_create_by_name (const char *name, umode_t mode,
- struct dentry *parent, struct dentry **dentry)
-{
- int error = 0;
-
- /* If the parent is not specified, we create it in the root.
- * We need the root dentry to do this, which is in the super
- * block. A pointer to that is in the struct vfsmount that we
- * have around.
- */
- if (!parent ) {
- if (usbfs_mount)
- parent = usbfs_mount->mnt_root;
- }
-
- if (!parent) {
- dbg("Ah! can not find a parent!");
- return -EFAULT;
- }
-
- *dentry = NULL;
- mutex_lock(&parent->d_inode->i_mutex);
- *dentry = lookup_one_len(name, parent, strlen(name));
- if (!IS_ERR(*dentry)) {
- if (S_ISDIR(mode))
- error = usbfs_mkdir (parent->d_inode, *dentry, mode);
- else
- error = usbfs_create (parent->d_inode, *dentry, mode);
- } else
- error = PTR_ERR(*dentry);
- mutex_unlock(&parent->d_inode->i_mutex);
-
- return error;
-}
-
-static struct dentry *fs_create_file (const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops,
- uid_t uid, gid_t gid)
-{
- struct dentry *dentry;
- int error;
-
- dbg("creating file '%s'",name);
-
- error = fs_create_by_name (name, mode, parent, &dentry);
- if (error) {
- dentry = NULL;
- } else {
- if (dentry->d_inode) {
- if (data)
- dentry->d_inode->i_private = data;
- if (fops)
- dentry->d_inode->i_fop = fops;
- dentry->d_inode->i_uid = uid;
- dentry->d_inode->i_gid = gid;
- }
- }
-
- return dentry;
-}
-
-static void fs_remove_file (struct dentry *dentry)
-{
- struct dentry *parent = dentry->d_parent;
-
- if (!parent || !parent->d_inode)
- return;
-
- mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT);
- if (usbfs_positive(dentry)) {
- if (dentry->d_inode) {
- if (S_ISDIR(dentry->d_inode->i_mode))
- usbfs_rmdir(parent->d_inode, dentry);
- else
- usbfs_unlink(parent->d_inode, dentry);
- dput(dentry);
- }
- }
- mutex_unlock(&parent->d_inode->i_mutex);
-}
-
-/* --------------------------------------------------------------------- */
-
-static struct dentry *usb_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_single(fs_type, flags, data, usbfs_fill_super);
-}
-
-static struct file_system_type usb_fs_type = {
- .owner = THIS_MODULE,
- .name = "usbfs",
- .mount = usb_mount,
- .kill_sb = kill_litter_super,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int create_special_files (void)
-{
- struct dentry *parent;
- int retval;
-
- /* create the devices special file */
- retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
- if (retval) {
- printk(KERN_ERR "Unable to get usbfs mount\n");
- goto exit;
- }
-
- parent = usbfs_mount->mnt_root;
- devices_usbfs_dentry = fs_create_file ("devices",
- listmode | S_IFREG, parent,
- NULL, &usbfs_devices_fops,
- listuid, listgid);
- if (devices_usbfs_dentry == NULL) {
- printk(KERN_ERR "Unable to create devices usbfs file\n");
- retval = -ENODEV;
- goto error_clean_mounts;
- }
-
- goto exit;
-
-error_clean_mounts:
- simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-exit:
- return retval;
-}
-
-static void remove_special_files (void)
-{
- if (devices_usbfs_dentry)
- fs_remove_file (devices_usbfs_dentry);
- devices_usbfs_dentry = NULL;
- simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-}
-
-void usbfs_update_special (void)
-{
- struct inode *inode;
-
- if (devices_usbfs_dentry) {
- inode = devices_usbfs_dentry->d_inode;
- if (inode)
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- }
-}
-
-static void usbfs_add_bus(struct usb_bus *bus)
-{
- struct dentry *parent;
- char name[8];
- int retval;
-
- /* create the special files if this is the first bus added */
- if (num_buses == 0) {
- retval = create_special_files();
- if (retval)
- return;
- }
- ++num_buses;
-
- sprintf (name, "%03d", bus->busnum);
-
- parent = usbfs_mount->mnt_root;
- bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
- bus, NULL, busuid, busgid);
- if (bus->usbfs_dentry == NULL) {
- printk(KERN_ERR "Error creating usbfs bus entry\n");
- return;
- }
-}
-
-static void usbfs_remove_bus(struct usb_bus *bus)
-{
- if (bus->usbfs_dentry) {
- fs_remove_file (bus->usbfs_dentry);
- bus->usbfs_dentry = NULL;
- }
-
- --num_buses;
- if (num_buses <= 0) {
- remove_special_files();
- num_buses = 0;
- }
-}
-
-static void usbfs_add_device(struct usb_device *dev)
-{
- char name[8];
- int i;
- int i_size;
-
- sprintf (name, "%03d", dev->devnum);
- dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
- dev->bus->usbfs_dentry, dev,
- &usbdev_file_operations,
- devuid, devgid);
- if (dev->usbfs_dentry == NULL) {
- printk(KERN_ERR "Error creating usbfs device entry\n");
- return;
- }
-
- /* Set the size of the device's file to be
- * equal to the size of the device descriptors. */
- i_size = sizeof (struct usb_device_descriptor);
- for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
- struct usb_config_descriptor *config =
- (struct usb_config_descriptor *)dev->rawdescriptors[i];
- i_size += le16_to_cpu(config->wTotalLength);
- }
- if (dev->usbfs_dentry->d_inode)
- dev->usbfs_dentry->d_inode->i_size = i_size;
-}
-
-static void usbfs_remove_device(struct usb_device *dev)
-{
- if (dev->usbfs_dentry) {
- fs_remove_file (dev->usbfs_dentry);
- dev->usbfs_dentry = NULL;
- }
-}
-
-static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
-{
- switch (action) {
- case USB_DEVICE_ADD:
- usbfs_add_device(dev);
- break;
- case USB_DEVICE_REMOVE:
- usbfs_remove_device(dev);
- break;
- case USB_BUS_ADD:
- usbfs_add_bus(dev);
- break;
- case USB_BUS_REMOVE:
- usbfs_remove_bus(dev);
- }
-
- usbfs_update_special();
- usbfs_conn_disc_event();
- return NOTIFY_OK;
-}
-
-static struct notifier_block usbfs_nb = {
- .notifier_call = usbfs_notify,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct proc_dir_entry *usbdir = NULL;
-
-int __init usbfs_init(void)
-{
- int retval;
-
- retval = register_filesystem(&usb_fs_type);
- if (retval)
- return retval;
-
- usb_register_notify(&usbfs_nb);
-
- /* create mount point for usbfs */
- usbdir = proc_mkdir("bus/usb", NULL);
-
- return 0;
-}
-
-void usbfs_cleanup(void)
-{
- usb_unregister_notify(&usbfs_nb);
- unregister_filesystem(&usb_fs_type);
- if (usbdir)
- remove_proc_entry("bus/usb", NULL);
-}
-
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ca717da..b548cf1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* Remove the current alt setting and add the new alt setting.
*/
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new alt setting is installed,
+ * so that the xHCI driver can recalculate the U1/U2 timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
if (ret < 0) {
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
alternate);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
} else if (ret < 0) {
/* Re-instate the old alt setting */
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
iface->cur_altsetting = alt;
+ /* Now that the interface is installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+
/* If the interface only has one altsetting and the device didn't
* accept the request, we attempt to carry out the equivalent action
* by manually clearing the HALT feature for each endpoint in the
@@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev)
config = dev->actconfig;
retval = 0;
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the configuration is reset, so
+ * that the xHCI driver can recalculate the U1/U2 timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
/* Make sure we have enough bandwidth for each alternate setting 0 */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
struct usb_interface *intf = config->interface[i];
@@ -1465,6 +1486,7 @@ reset_old_alts:
usb_hcd_alloc_bandwidth(dev, NULL,
alt, intf->cur_altsetting);
}
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return retval;
}
@@ -1502,6 +1524,8 @@ reset_old_alts:
create_intf_ep_devs(intf);
}
}
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
return 0;
}
EXPORT_SYMBOL_GPL(usb_reset_configuration);
@@ -1763,8 +1787,18 @@ free_interfaces:
* this call fails, the device state is unchanged.
*/
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new configuration is
+ * installed, so that the xHCI driver can recalculate the U1/U2
+ * timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@@ -1784,6 +1818,7 @@ free_interfaces:
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@@ -1838,6 +1873,9 @@ free_interfaces:
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 4c65eb6..32d3adc 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -123,6 +123,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Guillemot Webcam Hercules Dualpix Exchange*/
{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Midiman M-Audio Keystation 88es */
+ { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 566d9f9..9a56e3a 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
return (value < 0) ? value : count;
}
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
show_bConfigurationValue, set_bConfigurationValue);
/* String fields */
@@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev,
return result < 0? result : size;
}
-static DEVICE_ATTR(authorized, 0644,
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
usb_dev_authorized_show, usb_dev_authorized_store);
/* "Safely remove a device" */
@@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev,
usb_unlock_device(udev);
return rc;
}
-static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
static struct attribute *dev_attrs[] = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index cd9b3a2..9d912bf 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -681,6 +681,27 @@ void usb_unpoison_urb(struct urb *urb)
EXPORT_SYMBOL_GPL(usb_unpoison_urb);
/**
+ * usb_block_urb - reliably prevent further use of an URB
+ * @urb: pointer to URB to be blocked, may be NULL
+ *
+ * After the routine has run, 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.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ */
+void usb_block_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+
+ atomic_inc(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_block_urb);
+
+/**
* usb_kill_anchored_urbs - cancel transfer requests en masse
* @anchor: anchor the requests are bound to
*
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
new file mode 100644
index 0000000..8947b20
--- /dev/null
+++ b/drivers/usb/core/usb-acpi.c
@@ -0,0 +1,117 @@
+/*
+ * USB-ACPI glue code
+ *
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <acpi/acpi_bus.h>
+
+#include "usb.h"
+
+static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *upc;
+ int ret = 0;
+
+ status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ upc = buffer.pointer;
+
+ if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
+ || upc->package.count != 4) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (upc->package.elements[0].integer.value)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+
+out:
+ kfree(upc);
+ return ret;
+}
+
+static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_pld pld;
+
+ status = acpi_get_physical_device_location(handle, &pld);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if (pld.user_visible)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+
+ return 0;
+}
+
+static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct usb_device *udev;
+ struct device *parent;
+ acpi_handle *parent_handle;
+
+ if (!is_usb_device(dev))
+ return -ENODEV;
+
+ udev = to_usb_device(dev);
+ parent = dev->parent;
+ parent_handle = DEVICE_ACPI_HANDLE(parent);
+
+ if (!parent_handle)
+ return -ENODEV;
+
+ *handle = acpi_get_child(parent_handle, udev->portnum);
+
+ if (!*handle)
+ return -ENODEV;
+
+ /*
+ * PLD will tell us whether a port is removable to the user or
+ * not. If we don't get an answer from PLD (it's not present
+ * or it's malformed) then try to infer it from UPC. If a
+ * device isn't connectable then it's probably not removable.
+ */
+ if (usb_acpi_check_pld(udev, *handle) != 0)
+ usb_acpi_check_upc(udev, *handle);
+
+ return 0;
+}
+
+static struct acpi_bus_type usb_acpi_bus = {
+ .bus = &usb_bus_type,
+ .find_bridge = NULL,
+ .find_device = usb_acpi_find_device,
+};
+
+int usb_acpi_register(void)
+{
+ return register_acpi_bus_type(&usb_acpi_bus);
+}
+
+void usb_acpi_unregister(void)
+{
+ unregister_acpi_bus_type(&usb_acpi_bus);
+}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c74ba7b..25d0c61 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1015,6 +1015,7 @@ static int __init usb_init(void)
if (retval)
goto out;
+ usb_acpi_register();
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
@@ -1030,9 +1031,6 @@ static int __init usb_init(void)
retval = usb_devio_init();
if (retval)
goto usb_devio_init_failed;
- retval = usbfs_init();
- if (retval)
- goto fs_init_failed;
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
@@ -1042,8 +1040,6 @@ static int __init usb_init(void)
usb_hub_cleanup();
hub_init_failed:
- usbfs_cleanup();
-fs_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
@@ -1054,6 +1050,7 @@ major_init_failed:
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
+ usb_acpi_unregister();
usb_debugfs_cleanup();
out:
return retval;
@@ -1070,12 +1067,12 @@ static void __exit usb_exit(void)
usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
- usbfs_cleanup();
usb_deregister(&usbfs_driver);
usb_devio_cleanup();
usb_hub_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
+ usb_acpi_unregister();
usb_debugfs_cleanup();
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 71648dc..5c5c538 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
+#ifdef CONFIG_ACPI
+extern int usb_acpi_register(void);
+extern void usb_acpi_unregister(void);
+#else
+static inline int usb_acpi_register(void) { return 0; };
+static inline void usb_acpi_unregister(void) { };
+#endif
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..d13c60f4 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -4,7 +4,7 @@ config USB_DWC3
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
- select USB_XHCI_PLATFORM
+ select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d84..1040bdb 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -410,7 +410,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
- int irq;
void __iomem *regs;
void *mem;
@@ -425,15 +424,28 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- dev_err(dev, "missing resource\n");
+ dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
+ dwc->xhci_resources[1] = *res;
- dwc->res = res;
-
- res = devm_request_mem_region(dev, res->start, resource_size(res),
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+ dwc->xhci_resources[0] = *res;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
+
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+ resource_size(res) - DWC3_GLOBALS_REGS_START,
dev_name(dev));
if (!res) {
dev_err(dev, "can't request mem region\n");
@@ -446,19 +458,12 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
return -ENOMEM;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "missing IRQ\n");
- return -ENODEV;
- }
-
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
- dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b..f69c877 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -51,7 +51,9 @@
#include <linux/usb/gadget.h>
/* Global constants */
+#define DWC3_EP0_BOUNCE_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
+#define DWC3_XHCI_RESOURCES_NUM 2
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
#define DWC3_EVENT_TYPE_MASK 0xfe
@@ -75,6 +77,16 @@
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START 0x0
+#define DWC3_XHCI_REGS_END 0x7fff
+#define DWC3_GLOBALS_REGS_START 0xc100
+#define DWC3_GLOBALS_REGS_END 0xc6ff
+#define DWC3_DEVICE_REGS_START 0xc700
+#define DWC3_DEVICE_REGS_END 0xcbff
+#define DWC3_OTG_REGS_START 0xcc00
+#define DWC3_OTG_REGS_END 0xccff
+
/* Global Registers */
#define DWC3_GSBUSCFG0 0xc100
#define DWC3_GSBUSCFG1 0xc104
@@ -183,6 +195,7 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
/* Device Configuration Register */
+#define DWC3_DCFG_LPM_CAP (1 << 22)
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -272,12 +285,14 @@
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
+#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1)
+#define DWC3_DGCMD_CMDACT (1 << 10)
+
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
-#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8)
@@ -361,7 +376,6 @@ struct dwc3_ep {
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
- const struct usb_endpoint_descriptor *desc;
const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc;
@@ -561,6 +575,11 @@ struct dwc3_request {
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
+ * @isoch_delay: wValue from Set Isochronous Delay request;
+ * @u2sel: parameter from Set SEL request.
+ * @u2pel: parameter from Set SEL request.
+ * @u1sel: parameter from Set SEL request.
+ * @u1pel: parameter from Set SEL request.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@@ -583,7 +602,7 @@ struct dwc3 {
struct device *dev;
struct platform_device *xhci;
- struct resource *res;
+ struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +613,6 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
- int irq;
-
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -609,6 +626,10 @@ struct dwc3 {
#define DWC3_REVISION_185A 0x5533185a
#define DWC3_REVISION_188A 0x5533188a
#define DWC3_REVISION_190A 0x5533190a
+#define DWC3_REVISION_200A 0x5533200a
+#define DWC3_REVISION_202A 0x5533202a
+#define DWC3_REVISION_210A 0x5533210a
+#define DWC3_REVISION_220A 0x5533220a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -625,7 +646,14 @@ struct dwc3 {
enum dwc3_link_state link_state;
enum dwc3_device_state dev_state;
+ u16 isoch_delay;
+ u16 u2sel;
+ u16 u2pel;
+ u8 u1sel;
+ u8 u1pel;
+
u8 speed;
+
void *mem;
struct dwc3_hwparams hwparams;
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0e..479dc04 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
#include <linux/of.h>
#include "core.h"
-#include "io.h"
/*
* All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@ struct dwc3_omap {
u32 dma_status:1;
};
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel(value, base + offset);
+}
+
+
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
@@ -150,7 +160,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
spin_lock(&omap->lock);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
spin_unlock(&omap->lock);
@@ -270,7 +280,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
omap->base = base;
omap->dwc3 = dwc3;
- reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
}
}
- dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
- reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
- dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
@@ -318,7 +328,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 3584a16..9e8a3dc 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -179,7 +179,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int ret;
spin_lock_irqsave(&dwc->lock, flags);
- if (!dep->desc) {
+ if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, dep->name);
ret = -ESHUTDOWN;
@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
{
struct dwc3_ep *dep;
u32 recip;
+ u32 reg;
u16 usb_status = 0;
__le16 *response_pkt;
@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
/*
- * We are self-powered. U1/U2/LTM will be set later
- * once we handle this states. RemoteWakeup is 0 on SS
+ * LTM will be set once we know how to set this in HW.
*/
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+
+ if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (reg & DWC3_DCTL_INITU1ENA)
+ usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
+ if (reg & DWC3_DCTL_INITU2ENA)
+ usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+ }
+
break;
case USB_RECIP_INTERFACE:
@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip;
u32 wValue;
u32 wIndex;
+ u32 reg;
int ret;
wValue = le16_to_cpu(ctrl->wValue);
@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
+ switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
/*
* 9.4.1 says only only for SS, in AddressState only for
* default control pipe
*/
- switch (wValue) {
case USB_DEVICE_U1_ENABLE:
- case USB_DEVICE_U2_ENABLE:
- case USB_DEVICE_LTM_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
- }
- /* XXX add U[12] & LTM */
- switch (wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- break;
- case USB_DEVICE_U1_ENABLE:
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU1ENA;
+ else
+ reg &= ~DWC3_DCTL_INITU1ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
+
case USB_DEVICE_U2_ENABLE:
+ if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ return -EINVAL;
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU2ENA;
+ else
+ reg &= ~DWC3_DCTL_INITU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
+
case USB_DEVICE_LTM_ENABLE:
+ return -EINVAL;
break;
case USB_DEVICE_TEST_MODE:
@@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return ret;
}
+static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ u32 param = 0;
+ u32 reg;
+
+ struct timing {
+ u8 u1sel;
+ u8 u1pel;
+ u16 u2sel;
+ u16 u2pel;
+ } __packed timing;
+
+ int ret;
+
+ memcpy(&timing, req->buf, sizeof(timing));
+
+ dwc->u1sel = timing.u1sel;
+ dwc->u1pel = timing.u1pel;
+ dwc->u2sel = timing.u2sel;
+ dwc->u2pel = timing.u2pel;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (reg & DWC3_DCTL_INITU2ENA)
+ param = dwc->u2pel;
+ if (reg & DWC3_DCTL_INITU1ENA)
+ param = dwc->u1pel;
+
+ /*
+ * According to Synopsys Databook, if parameter is
+ * greater than 125, a value of zero should be
+ * programmed in the register.
+ */
+ if (param > 125)
+ param = 0;
+
+ /* now that we have the time, issue DGCMD Set Sel */
+ ret = dwc3_send_gadget_generic_command(dwc,
+ DWC3_DGCMD_SET_PERIODIC_PAR, param);
+ WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ struct dwc3_ep *dep;
+ u16 wLength;
+ u16 wValue;
+
+ if (dwc->dev_state == DWC3_DEFAULT_STATE)
+ return -EINVAL;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wLength = le16_to_cpu(ctrl->wLength);
+
+ if (wLength != 6) {
+ dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
+ wLength);
+ return -EINVAL;
+ }
+
+ /*
+ * To handle Set SEL we need to receive 6 bytes from Host. So let's
+ * queue a usb_request for 6 bytes.
+ *
+ * Remember, though, this controller can't handle non-wMaxPacketSize
+ * aligned transfers on the OUT direction, so we queue a request for
+ * wMaxPacketSize instead.
+ */
+ dep = dwc->eps[0];
+ dwc->ep0_usb_req.dep = dep;
+ dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
+ dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+ dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
+
+ return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wLength = le16_to_cpu(ctrl->wLength);
+ wIndex = le16_to_cpu(ctrl->wIndex);
+
+ if (wIndex || wLength)
+ return -EINVAL;
+
+ /*
+ * REVISIT It's unclear from Databook what to do with this
+ * value. For now, just cache it.
+ */
+ dwc->isoch_delay = wValue;
+
+ return 0;
+}
+
static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
int ret;
@@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
ret = dwc3_ep0_set_config(dwc, ctrl);
break;
+ case USB_REQ_SET_SEL:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
+ ret = dwc3_ep0_set_sel(dwc, ctrl);
+ break;
+ case USB_REQ_SET_ISOCH_DELAY:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+ ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+ break;
default:
dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe97..3df1a19 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -178,8 +178,8 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
- if (usb_endpoint_xfer_bulk(dep->desc)
- || usb_endpoint_xfer_isoc(dep->desc))
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
+ || usb_endpoint_xfer_isoc(dep->endpoint.desc))
mult = 3;
/*
@@ -229,7 +229,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
* completed (not the LINK TRB).
*/
if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->desc))
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->busy_slot++;
}
list_del(&req->list);
@@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
}
}
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
+{
+ u32 timeout = 500;
+ u32 reg;
+
+ dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+ dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+ if (!(reg & DWC3_DGCMD_CMDACT)) {
+ dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ DWC3_DGCMD_STATUS(reg));
+ return 0;
+ }
+
+ /*
+ * We can't sleep here, because it's also called from
+ * interrupt context.
+ */
+ timeout--;
+ if (!timeout)
+ return -ETIMEDOUT;
+ udelay(1);
+ } while (1);
+}
+
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
@@ -470,7 +497,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
if (ret)
return ret;
- dep->desc = desc;
+ dep->endpoint.desc = desc;
dep->comp_desc = comp_desc;
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
@@ -533,7 +560,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
dep->stream_capable = false;
- dep->desc = NULL;
dep->endpoint.desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
@@ -694,7 +720,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
/* Skip the LINK-TRB on ISOC */
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->desc))
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
return;
if (!req->trb) {
@@ -707,7 +733,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
- switch (usb_endpoint_type(dep->desc)) {
+ switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
@@ -732,7 +758,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
} else {
@@ -743,7 +769,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl |= DWC3_TRB_CTRL_LST;
}
- if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
@@ -771,7 +797,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
/* Can't wrap around on a non-isoc EP since there's no link TRB */
- if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
if (trbs_left > max)
trbs_left = max;
@@ -797,7 +823,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
* processed from the first TRB until the last one. Since we
* don't wrap around we have to start at the beginning.
*/
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dep->busy_slot = 1;
dep->free_slot = 1;
} else {
@@ -807,7 +833,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
}
/* The last TRB is a link TRB, not used for xfer */
- if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
return;
list_for_each_entry_safe(req, n, &dep->request_list, list) {
@@ -930,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
}
dep->flags |= DWC3_EP_BUSY;
- dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
- dep->number);
- WARN_ON_ONCE(!dep->res_trans_idx);
+ if (start_new) {
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+ WARN_ON_ONCE(!dep->res_trans_idx);
+ }
return 0;
}
@@ -967,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
list_add_tail(&req->list, &dep->request_list);
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+
/*
- * There is one special case: XferNotReady with
- * empty list of requests. We need to kick the
- * transfer here in that situation, otherwise
- * we will be NAKing forever.
+ * There are two special cases:
+ *
+ * 1. XferNotReady with empty list of requests. We need to kick the
+ * transfer here in that situation, otherwise we will be NAKing
+ * forever. If we get XferNotReady before gadget driver has a
+ * chance to queue a request, we will ACK the IRQ but won't be
+ * able to receive the data until the next request is queued.
+ * The following code is handling exactly that.
*
- * If we get XferNotReady before gadget driver
- * has a chance to queue a request, we will ACK
- * the IRQ but won't be able to receive the data
- * until the next request is queued. The following
- * code is handling exactly that.
+ * 2. XferInProgress on Isoc EP with an active transfer. We need to
+ * kick the transfer here after queuing a request, otherwise the
+ * core may not see the modified TRB(s).
*/
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
- int ret;
- int start_trans;
+ int ret;
+ int start_trans = 1;
+ u8 trans_idx = dep->res_trans_idx;
- start_trans = 1;
- if (usb_endpoint_xfer_isoc(dep->desc) &&
- (dep->flags & DWC3_EP_BUSY))
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ (dep->flags & DWC3_EP_BUSY)) {
start_trans = 0;
+ WARN_ON_ONCE(!trans_idx);
+ } else {
+ trans_idx = 0;
+ }
- ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+ ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
@@ -1011,7 +1048,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
int ret;
- if (!dep->desc) {
+ if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, ep->name);
return -ESHUTDOWN;
@@ -1125,7 +1162,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
spin_lock_irqsave(&dwc->lock, flags);
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
ret = -EINVAL;
goto out;
@@ -1356,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g,
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
- reg |= dwc->maximum_speed;
+
+ /**
+ * WORKAROUND: DWC3 revision < 2.20a have an issue
+ * which would cause metastability state on Run/Stop
+ * bit if we try to force the IP to USB2-only mode.
+ *
+ * Because of that, we cannot configure the IP to any
+ * speed other than the SuperSpeed
+ *
+ * Refers to:
+ *
+ * STAR#9000525659: Clock Domain Crossing on DCTL in
+ * USB 2.0 Mode
+ */
+ if (dwc->revision < DWC3_REVISION_220A)
+ reg |= DWC3_DCFG_SUPERSPEED;
+ else
+ reg |= dwc->maximum_speed;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc->start_config_issued = false;
@@ -1681,7 +1735,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
case DWC3_DEPEVT_XFERCOMPLETE:
dep->res_trans_idx = 0;
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
dep->name);
return;
@@ -1690,7 +1744,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
break;
case DWC3_DEPEVT_XFERINPROGRESS:
- if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
dep->name);
return;
@@ -1699,7 +1753,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
break;
case DWC3_DEPEVT_XFERNOTREADY:
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dwc3_gadget_start_isoc(dwc, dep, event);
} else {
int ret;
@@ -1720,7 +1774,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
break;
case DWC3_DEPEVT_STREAMEVT:
- if (!usb_endpoint_xfer_bulk(dep->desc)) {
+ if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
dep->name);
return;
@@ -1916,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+ reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->test_mode = false;
@@ -2263,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err1;
}
- dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
- GFP_KERNEL);
+ dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
@@ -2272,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
- 512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+ DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
+ GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
@@ -2313,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err5;
}
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg |= DWC3_DCFG_LPM_CAP;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
/* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN |
@@ -2351,8 +2414,8 @@ err5:
dwc3_gadget_free_endpoints(dwc);
err4:
- dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
- dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
err3:
kfree(dwc->setup_buf);
@@ -2381,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
- dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
kfree(dwc->setup_buf);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..95ef6a2 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18..56a6234 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -39,15 +39,6 @@
#include "core.h"
-static struct resource generic_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_MEM,
- },
-};
-
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
@@ -68,14 +59,8 @@ int dwc3_host_init(struct dwc3 *dwc)
dwc->xhci = xhci;
- /* setup resources */
- generic_resources[0].start = dwc->irq;
-
- generic_resources[1].start = dwc->res->start;
- generic_resources[1].end = dwc->res->start + 0x7fff;
-
- ret = platform_device_add_resources(xhci, generic_resources,
- ARRAY_SIZE(generic_resources));
+ ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+ DWC3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561..a50f76b 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
#include <linux/io.h>
+#include "core.h"
+
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
- return readl(base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ return readl(base + (offset - DWC3_GLOBALS_REGS_START));
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
- writel(value, base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 2633f75..bddc8fd 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -123,13 +123,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
# - discrete ones (including all PCI-only controllers)
# - debug/dummy gadget+hcd is last.
#
-choice
- prompt "USB Peripheral Controller"
- help
- A USB device uses a controller to talk to its host.
- Systems should have only one such upstream link.
- Many controller drivers are platform-specific; these
- often need board-specific hooks.
+menu "USB Peripheral Controller"
#
# Integrated controllers
@@ -147,6 +141,17 @@ config USB_AT91
dynamically linked module called "at91_udc" and force all
gadget drivers to also be dynamically linked.
+config USB_LPC32XX
+ tristate "LPC32XX USB Peripheral Controller"
+ depends on ARCH_LPC32XX
+ select USB_ISP1301
+ help
+ This option selects the USB device controller in the LPC32xx SoC.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "lpc32xx_udc" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_ATMEL_USBA
tristate "Atmel USBA"
select USB_GADGET_DUALSPEED
@@ -161,7 +166,7 @@ config USB_FSL_USB2
select USB_GADGET_DUALSPEED
select USB_FSL_MPH_DR_OF if OF
help
- Some of Freescale PowerPC processors have a High Speed
+ Some of Freescale PowerPC and i.MX processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
The number of programmable endpoints is different through
@@ -373,18 +378,6 @@ config USB_FSL_QE
Set CONFIG_USB_GADGET to "m" to build this driver as a
dynamically linked module called "fsl_qe_udc".
-config USB_CI13XXX_PCI
- tristate "MIPS USB CI13xxx PCI UDC"
- depends on PCI
- select USB_GADGET_DUALSPEED
- help
- MIPS USB IP core family device controller
- Currently it only supports IP part number CI13412
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "ci13xxx_udc" and force all
- gadget drivers to also be dynamically linked.
-
config USB_NET2272
tristate "PLX NET2272"
select USB_GADGET_DUALSPEED
@@ -438,22 +431,6 @@ config USB_GOKU
dynamically linked module called "goku_udc" and to force all
gadget drivers to also be dynamically linked.
-config USB_LANGWELL
- tristate "Intel Langwell USB Device Controller"
- depends on PCI
- depends on !PHYS_ADDR_T_64BIT
- select USB_GADGET_DUALSPEED
- help
- Intel Langwell USB Device Controller is a High-Speed USB
- On-The-Go device controller.
-
- The number of programmable endpoints is different through
- controller revision.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "langwell_udc" and force all
- gadget drivers to also be dynamically linked.
-
config USB_EG20T
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
depends on PCI
@@ -477,23 +454,6 @@ config USB_EG20T
ML7213/ML7831 is companion chip for Intel Atom E6xx series.
ML7213/ML7831 is completely compatible for Intel EG20T PCH.
-config USB_CI13XXX_MSM
- tristate "MIPS USB CI13xxx for MSM"
- depends on ARCH_MSM
- select USB_GADGET_DUALSPEED
- select USB_MSM_OTG
- help
- MSM SoC has chipidea USB controller. This driver uses
- ci13xxx_udc core.
- This driver depends on OTG driver for PHY initialization,
- clock management, powering up VBUS, and power management.
- This driver is not supported on boards like trout which
- has an external PHY.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "ci13xxx_msm" and force all
- gadget drivers to also be dynamically linked.
-
#
# LAST -- dummy/emulated controller
#
@@ -525,7 +485,7 @@ config USB_DUMMY_HCD
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default.
-endchoice
+endmenu
# Selected by UDC drivers that support high-speed operation.
config USB_GADGET_DUALSPEED
@@ -798,6 +758,16 @@ config USB_MASS_STORAGE
Say "y" to link the driver statically, or "m" to build
a dynamically linked module called "g_mass_storage".
+config USB_GADGET_TARGET
+ tristate "USB Gadget Target Fabric Module"
+ depends on TARGET_CORE
+ help
+ This fabric is an USB gadget. Two USB protocols are supported that is
+ BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
+ advertised on alternative interface 0 (primary) and UAS is on
+ alternative interface 1. Both protocols can work on USB2.0 and USB3.0.
+ UAS utilizes the USB 3.0 feature called streams support.
+
config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
help
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index b7f6eef..1811513 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -22,14 +22,12 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
-obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
-obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
+obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
-obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
#
@@ -52,6 +50,7 @@ g_nokia-y := nokia.o
g_webcam-y := webcam.o
g_ncm-y := ncm.o
g_acm_ms-y := acm_ms.o
+g_tcm_usb_gadget-y := tcm_usb_gadget.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -71,3 +70,4 @@ obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
+obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 7777927..187d211 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -333,7 +333,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
return -ESHUTDOWN;
spin_lock_irqsave(&dev->lock, iflags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
@@ -442,7 +442,6 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
u32 tmp;
VDBG(ep->dev, "ep-%d reset\n", ep->num);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.ops = &udc_ep_ops;
INIT_LIST_HEAD(&ep->queue);
@@ -489,7 +488,7 @@ static int udc_ep_disable(struct usb_ep *usbep)
return -EINVAL;
ep = container_of(usbep, struct udc_ep, ep);
- if (usbep->name == ep0_string || !ep->desc)
+ if (usbep->name == ep0_string || !ep->ep.desc)
return -EINVAL;
DBG(ep->dev, "Disable ep-%d\n", ep->num);
@@ -1066,7 +1065,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
return -EINVAL;
ep = container_of(usbep, struct udc_ep, ep);
- if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
return -EINVAL;
VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
@@ -1257,7 +1256,7 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
unsigned long iflags;
ep = container_of(usbep, struct udc_ep, ep);
- if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0
&& ep->num != UDC_EP0OUT_IX)))
return -EINVAL;
@@ -1317,7 +1316,7 @@ udc_set_halt(struct usb_ep *usbep, int halt)
pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
ep = container_of(usbep, struct udc_ep, ep);
- if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
return -EINVAL;
if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
@@ -1539,7 +1538,7 @@ static void udc_setup_endpoints(struct udc *dev)
* disabling ep interrupts when ENUM interrupt occurs but ep is
* not enabled by gadget driver
*/
- if (!ep->desc)
+ if (!ep->ep.desc)
ep_init(dev->regs, ep);
if (use_dma) {
@@ -3402,19 +3401,7 @@ static struct pci_driver udc_pci_driver = {
.remove = udc_pci_remove,
};
-/* Inits driver */
-static int __init init(void)
-{
- return pci_register_driver(&udc_pci_driver);
-}
-module_init(init);
-
-/* Cleans driver */
-static void __exit cleanup(void)
-{
- pci_unregister_driver(&udc_pci_driver);
-}
-module_exit(cleanup);
+module_pci_driver(udc_pci_driver);
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
MODULE_AUTHOR("Thomas Dahlmann");
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index f87e29c..14af87d 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -512,7 +512,6 @@ struct udc_ep {
/* queue for requests */
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
unsigned halted;
unsigned cancel_transfer;
unsigned num : 5,
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9d7bcd9..1a4430f 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -212,7 +212,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
if (udc->enabled && udc->vbus) {
proc_ep_show(s, &udc->ep[0]);
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc)
+ if (ep->ep.desc)
proc_ep_show(s, ep);
}
}
@@ -475,7 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
unsigned long flags;
if (!_ep || !ep
- || !desc || ep->desc
+ || !desc || ep->ep.desc
|| _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| (maxpacket = usb_endpoint_maxp(desc)) == 0
@@ -530,7 +530,7 @@ ok:
tmp |= AT91_UDP_EPEDS;
__raw_writel(tmp, ep->creg);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->ep.maxpacket = maxpacket;
/*
@@ -558,7 +558,6 @@ static int at91_ep_disable (struct usb_ep * _ep)
nuke(ep, -ESHUTDOWN);
/* restore the endpoint's pristine config */
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.maxpacket = ep->maxpacket;
@@ -618,7 +617,7 @@ static int at91_ep_queue(struct usb_ep *_ep,
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+ if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) {
DBG("invalid ep\n");
return -EINVAL;
}
@@ -833,7 +832,7 @@ static void udc_reinit(struct at91_udc *udc)
if (i != 0)
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 0;
ep->fifo_bank = 0;
ep->ep.maxpacket = ep->maxpacket;
@@ -978,18 +977,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
return 0;
}
-static int at91_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int at91_stop(struct usb_gadget_driver *driver);
-
+static int at91_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops at91_udc_ops = {
.get_frame = at91_get_frame,
.wakeup = at91_wakeup,
.set_selfpowered = at91_set_selfpowered,
.vbus_session = at91_vbus_session,
.pullup = at91_pullup,
- .start = at91_start,
- .stop = at91_stop,
+ .udc_start = at91_start,
+ .udc_stop = at91_stop,
/*
* VBUS-powered devices may also also want to support bigger
@@ -1172,7 +1171,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
| USB_REQ_GET_STATUS:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
- if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
+ if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
goto stall;
if (tmp) {
@@ -1197,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
ep = &udc->ep[tmp];
if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
- if (!ep->desc || ep->is_iso)
+ if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
@@ -1218,7 +1217,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
goto stall;
if (tmp == 0)
goto succeed;
- if (!ep->desc || ep->is_iso)
+ if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
@@ -1627,66 +1626,34 @@ static void at91_vbus_timer(unsigned long data)
schedule_work(&udc->vbus_timer_work);
}
-static int at91_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int at91_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct at91_udc *udc = &controller;
- int retval;
- unsigned long flags;
-
- if (!driver
- || driver->max_speed < USB_SPEED_FULL
- || !bind
- || !driver->setup) {
- DBG("bad parameter.\n");
- return -EINVAL;
- }
-
- if (udc->driver) {
- DBG("UDC already has a gadget driver\n");
- return -EBUSY;
- }
+ struct at91_udc *udc;
+ udc = container_of(gadget, struct at91_udc, gadget);
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
dev_set_drvdata(&udc->gadget.dev, &driver->driver);
udc->enabled = 1;
udc->selfpowered = 1;
- retval = bind(&udc->gadget);
- if (retval) {
- DBG("bind() returned %d\n", retval);
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- dev_set_drvdata(&udc->gadget.dev, NULL);
- udc->enabled = 0;
- udc->selfpowered = 0;
- return retval;
- }
-
- spin_lock_irqsave(&udc->lock, flags);
- pullup(udc, 1);
- spin_unlock_irqrestore(&udc->lock, flags);
-
DBG("bound to %s\n", driver->driver.name);
return 0;
}
-static int at91_stop(struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct at91_udc *udc = &controller;
+ struct at91_udc *udc;
unsigned long flags;
- if (!driver || driver != udc->driver || !driver->unbind)
- return -EINVAL;
-
+ udc = container_of(gadget, struct at91_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
udc->enabled = 0;
at91_udp_write(udc, AT91_UDP_IDR, ~0);
- pullup(udc, 0);
spin_unlock_irqrestore(&udc->lock, flags);
- driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
dev_set_drvdata(&udc->gadget.dev, NULL);
udc->driver = NULL;
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 3c0315b..e647d1c 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -105,9 +105,6 @@ struct at91_ep {
unsigned is_in:1;
unsigned is_iso:1;
unsigned fifo_bank:1;
-
- const struct usb_endpoint_descriptor
- *desc;
};
/*
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 9f98508..e23bf79 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -599,13 +599,13 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
spin_lock_irqsave(&ep->udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
spin_unlock_irqrestore(&ep->udc->lock, flags);
DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
return -EBUSY;
}
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->ep.maxpacket = maxpacket;
usba_ep_writel(ep, CFG, ept_cfg);
@@ -647,7 +647,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&udc->lock, flags);
- if (!ep->desc) {
+ if (!ep->ep.desc) {
spin_unlock_irqrestore(&udc->lock, flags);
/* REVISIT because this driver disables endpoints in
* reset_all_endpoints() before calling disconnect(),
@@ -658,7 +658,6 @@ static int usba_ep_disable(struct usb_ep *_ep)
ep->ep.name);
return -EINVAL;
}
- ep->desc = NULL;
ep->ep.desc = NULL;
list_splice_init(&ep->queue, &req_list);
@@ -752,7 +751,7 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
*/
ret = -ESHUTDOWN;
spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
if (list_empty(&ep->queue))
submit_request(ep, req);
@@ -776,7 +775,8 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
ep->ep.name, req, _req->length);
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN ||
+ !ep->ep.desc)
return -ESHUTDOWN;
req->submitted = 0;
@@ -792,7 +792,7 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* May have received a reset since last time we checked */
ret = -ESHUTDOWN;
spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
list_add_tail(&req->queue, &ep->queue);
if ((!ep_is_control(ep) && ep->is_in) ||
@@ -905,7 +905,7 @@ static int usba_ep_set_halt(struct usb_ep *_ep, int value)
DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
value ? "set" : "clear");
- if (!ep->desc) {
+ if (!ep->ep.desc) {
DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
ep->ep.name);
return -ENODEV;
@@ -1008,16 +1008,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
return 0;
}
-static int atmel_usba_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int atmel_usba_stop(struct usb_gadget_driver *driver);
-
+static int atmel_usba_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int atmel_usba_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered,
- .start = atmel_usba_start,
- .stop = atmel_usba_stop,
+ .udc_start = atmel_usba_start,
+ .udc_stop = atmel_usba_stop,
};
static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1071,7 +1071,7 @@ static void reset_all_endpoints(struct usba_udc *udc)
* FIXME remove this code ... and retest thoroughly.
*/
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
+ if (ep->ep.desc) {
spin_unlock(&udc->lock);
usba_ep_disable(&ep->ep);
spin_lock(&udc->lock);
@@ -1089,9 +1089,9 @@ static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
u8 bEndpointAddress;
- if (!ep->desc)
+ if (!ep->ep.desc)
continue;
- bEndpointAddress = ep->desc->bEndpointAddress;
+ bEndpointAddress = ep->ep.desc->bEndpointAddress;
if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
continue;
if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
@@ -1727,7 +1727,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
usb_speed_string(udc->gadget.speed));
ep0 = &usba_ep[0];
- ep0->desc = &usba_ep0_desc;
+ ep0->ep.desc = &usba_ep0_desc;
ep0->state = WAIT_FOR_SETUP;
usba_ep_writel(ep0, CFG,
(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
@@ -1795,21 +1795,13 @@ out:
return IRQ_HANDLED;
}
-static int atmel_usba_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int atmel_usba_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usba_udc *udc = &the_udc;
+ struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
- int ret;
-
- if (!udc->pdev)
- return -ENODEV;
spin_lock_irqsave(&udc->lock, flags);
- if (udc->driver) {
- spin_unlock_irqrestore(&udc->lock, flags);
- return -EBUSY;
- }
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver;
@@ -1819,13 +1811,6 @@ static int atmel_usba_start(struct usb_gadget_driver *driver,
clk_enable(udc->pclk);
clk_enable(udc->hclk);
- ret = bind(&udc->gadget);
- if (ret) {
- DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
- driver->driver.name, ret);
- goto err_driver_bind;
- }
-
DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
udc->vbus_prev = 0;
@@ -1842,23 +1827,14 @@ static int atmel_usba_start(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
-
-err_driver_bind:
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- return ret;
}
-static int atmel_usba_stop(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usba_udc *udc = &the_udc;
+ struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
- if (!udc->pdev)
- return -ENODEV;
- if (driver != udc->driver || !driver->unbind)
- return -EINVAL;
-
if (gpio_is_valid(udc->vbus_pin))
disable_irq(gpio_to_irq(udc->vbus_pin));
@@ -1871,10 +1847,6 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver)
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- if (udc->driver->disconnect)
- udc->driver->disconnect(&udc->gadget);
-
- driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 88a2e07..9791259 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -280,7 +280,6 @@ struct usba_ep {
struct usba_udc *udc;
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
u16 fifo_size;
u8 nr_banks;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
deleted file mode 100644
index 243ef1a..0000000
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ /dev/null
@@ -1,2996 +0,0 @@
-/*
- * ci13xxx_udc.c - MIPS USB IP core family device controller
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Description: MIPS USB IP core family device controller
- * Currently it only supports IP part number CI13412
- *
- * This driver is composed of several blocks:
- * - HW: hardware interface
- * - DBG: debug facilities (optional)
- * - UTIL: utilities
- * - ISR: interrupts handling
- * - ENDPT: endpoint operations (Gadget API)
- * - GADGET: gadget operations (Gadget API)
- * - BUS: bus glue code, bus abstraction layer
- *
- * Compile Options
- * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
- * - STALL_IN: non-empty bulk-in pipes cannot be halted
- * if defined mass storage compliance succeeds but with warnings
- * => case 4: Hi > Dn
- * => case 5: Hi > Di
- * => case 8: Hi <> Do
- * if undefined usbtest 13 fails
- * - TRACE: enable function tracing (depends on DEBUG)
- *
- * Main Features
- * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
- * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
- * - Normal & LPM support
- *
- * USBTEST Report
- * - OK: 0-12, 13 (STALL_IN defined) & 14
- * - Not Supported: 15 & 16 (ISO)
- *
- * TODO List
- * - OTG
- * - Isochronous & Interrupt Traffic
- * - Handle requests which spawns into several TDs
- * - GET_STATUS(device) - always reports 0
- * - Gadget API (majority of optional features)
- * - Suspend & Remote Wakeup
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-
-#include "ci13xxx_udc.h"
-
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-/* ctrl register bank access */
-static DEFINE_SPINLOCK(udc_lock);
-
-/* control endpoint description */
-static const struct usb_endpoint_descriptor
-ctrl_endpt_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-static const struct usb_endpoint_descriptor
-ctrl_endpt_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-/* UDC descriptor */
-static struct ci13xxx *_udc;
-
-/* Interrupt statistics */
-#define ISR_MASK 0x1F
-static struct {
- u32 test;
- u32 ui;
- u32 uei;
- u32 pci;
- u32 uri;
- u32 sli;
- u32 none;
- struct {
- u32 cnt;
- u32 buf[ISR_MASK+1];
- u32 idx;
- } hndl;
-} isr_statistics;
-
-/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static int ffs_nr(u32 x)
-{
- int n = ffs(x);
-
- return n ? n-1 : 32;
-}
-
-/******************************************************************************
- * HW block
- *****************************************************************************/
-/* register bank descriptor */
-static struct {
- unsigned lpm; /* is LPM? */
- void __iomem *abs; /* bus map offset */
- void __iomem *cap; /* bus map offset + CAP offset + CAP data */
- size_t size; /* bank size */
-} hw_bank;
-
-/* MSM specific */
-#define ABS_AHBBURST (0x0090UL)
-#define ABS_AHBMODE (0x0098UL)
-/* UDC register map */
-#define ABS_CAPLENGTH (0x100UL)
-#define ABS_HCCPARAMS (0x108UL)
-#define ABS_DCCPARAMS (0x124UL)
-#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL)
-/* offset to CAPLENTGH (addr + data) */
-#define CAP_USBCMD (0x000UL)
-#define CAP_USBSTS (0x004UL)
-#define CAP_USBINTR (0x008UL)
-#define CAP_DEVICEADDR (0x014UL)
-#define CAP_ENDPTLISTADDR (0x018UL)
-#define CAP_PORTSC (0x044UL)
-#define CAP_DEVLC (0x084UL)
-#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL)
-#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
-#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL)
-#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL)
-#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL)
-#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
-#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL)
-#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
-
-/* maximum number of enpoints: valid only after hw_device_reset() */
-static unsigned hw_ep_max;
-
-/**
- * hw_ep_bit: calculates the bit number
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns bit number
- */
-static inline int hw_ep_bit(int num, int dir)
-{
- return num + (dir ? 16 : 0);
-}
-
-static int ep_to_bit(int n)
-{
- int fill = 16 - hw_ep_max / 2;
-
- if (n >= hw_ep_max / 2)
- n += fill;
-
- return n;
-}
-
-/**
- * hw_aread: reads from register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_aread(u32 addr, u32 mask)
-{
- return ioread32(addr + hw_bank.abs) & mask;
-}
-
-/**
- * hw_awrite: writes to register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_awrite(u32 addr, u32 mask, u32 data)
-{
- iowrite32(hw_aread(addr, ~mask) | (data & mask),
- addr + hw_bank.abs);
-}
-
-/**
- * hw_cread: reads from register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_cread(u32 addr, u32 mask)
-{
- return ioread32(addr + hw_bank.cap) & mask;
-}
-
-/**
- * hw_cwrite: writes to register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_cwrite(u32 addr, u32 mask, u32 data)
-{
- iowrite32(hw_cread(addr, ~mask) | (data & mask),
- addr + hw_bank.cap);
-}
-
-/**
- * hw_ctest_and_clear: tests & clears register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_clear(u32 addr, u32 mask)
-{
- u32 reg = hw_cread(addr, mask);
-
- iowrite32(reg, addr + hw_bank.cap);
- return reg;
-}
-
-/**
- * hw_ctest_and_write: tests & writes register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
-{
- u32 reg = hw_cread(addr, ~0);
-
- iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
- return (reg & mask) >> ffs_nr(mask);
-}
-
-static int hw_device_init(void __iomem *base)
-{
- u32 reg;
-
- /* bank is a module variable */
- hw_bank.abs = base;
-
- hw_bank.cap = hw_bank.abs;
- hw_bank.cap += ABS_CAPLENGTH;
- hw_bank.cap += ioread8(hw_bank.cap);
-
- reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
- hw_bank.lpm = reg;
- hw_bank.size = hw_bank.cap - hw_bank.abs;
- hw_bank.size += CAP_LAST;
- hw_bank.size /= sizeof(u32);
-
- reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
- hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
-
- if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
- return -ENODEV;
-
- /* setup lock mode ? */
-
- /* ENDPTSETUPSTAT is '0' by default */
-
- /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
-
- return 0;
-}
-/**
- * hw_device_reset: resets chip (execute without interruption)
- * @base: register base address
- *
- * This function returns an error code
- */
-static int hw_device_reset(struct ci13xxx *udc)
-{
- /* should flush & stop before reset */
- hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
- hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
-
- hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
- while (hw_cread(CAP_USBCMD, USBCMD_RST))
- udelay(10); /* not RTOS friendly */
-
-
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_RESET_EVENT);
-
- if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
- hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
- /* USBMODE should be configured step by step */
- hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
- hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
- hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */
-
- if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
- pr_err("cannot enter in device mode");
- pr_err("lpm = %i", hw_bank.lpm);
- return -ENODEV;
- }
-
- return 0;
-}
-
-/**
- * hw_device_state: enables/disables interrupts & starts/stops device (execute
- * without interruption)
- * @dma: 0 => disable, !0 => enable and set dma engine
- *
- * This function returns an error code
- */
-static int hw_device_state(u32 dma)
-{
- if (dma) {
- hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
- /* interrupt, error, port change, reset, sleep/suspend */
- hw_cwrite(CAP_USBINTR, ~0,
- USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
- hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
- } else {
- hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
- hw_cwrite(CAP_USBINTR, ~0, 0);
- }
- return 0;
-}
-
-/**
- * hw_ep_flush: flush endpoint fifo (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_flush(int num, int dir)
-{
- int n = hw_ep_bit(num, dir);
-
- do {
- /* flush any pending transfer */
- hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
- cpu_relax();
- } while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
-
- return 0;
-}
-
-/**
- * hw_ep_disable: disables endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_disable(int num, int dir)
-{
- hw_ep_flush(num, dir);
- hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
- dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
- return 0;
-}
-
-/**
- * hw_ep_enable: enables endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @type: endpoint type
- *
- * This function returns an error code
- */
-static int hw_ep_enable(int num, int dir, int type)
-{
- u32 mask, data;
-
- if (dir) {
- mask = ENDPTCTRL_TXT; /* type */
- data = type << ffs_nr(mask);
-
- mask |= ENDPTCTRL_TXS; /* unstall */
- mask |= ENDPTCTRL_TXR; /* reset data toggle */
- data |= ENDPTCTRL_TXR;
- mask |= ENDPTCTRL_TXE; /* enable */
- data |= ENDPTCTRL_TXE;
- } else {
- mask = ENDPTCTRL_RXT; /* type */
- data = type << ffs_nr(mask);
-
- mask |= ENDPTCTRL_RXS; /* unstall */
- mask |= ENDPTCTRL_RXR; /* reset data toggle */
- data |= ENDPTCTRL_RXR;
- mask |= ENDPTCTRL_RXE; /* enable */
- data |= ENDPTCTRL_RXE;
- }
- hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
- return 0;
-}
-
-/**
- * hw_ep_get_halt: return endpoint halt status
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns 1 if endpoint halted
- */
-static int hw_ep_get_halt(int num, int dir)
-{
- u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
-
- return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
-}
-
-/**
- * hw_test_and_clear_setup_status: test & clear setup status (execute without
- * interruption)
- * @n: endpoint number
- *
- * This function returns setup status
- */
-static int hw_test_and_clear_setup_status(int n)
-{
- n = ep_to_bit(n);
- return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
-}
-
-/**
- * hw_ep_prime: primes endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @is_ctrl: true if control endpoint
- *
- * This function returns an error code
- */
-static int hw_ep_prime(int num, int dir, int is_ctrl)
-{
- int n = hw_ep_bit(num, dir);
-
- if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
- return -EAGAIN;
-
- hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
-
- while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- cpu_relax();
- if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
- return -EAGAIN;
-
- /* status shoult be tested according with manual but it doesn't work */
- return 0;
-}
-
-/**
- * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
- * without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @value: true => stall, false => unstall
- *
- * This function returns an error code
- */
-static int hw_ep_set_halt(int num, int dir, int value)
-{
- if (value != 0 && value != 1)
- return -EINVAL;
-
- do {
- u32 addr = CAP_ENDPTCTRL + num * sizeof(u32);
- u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
- u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
-
- /* data toggle - reserved for EP0 but it's in ESS */
- hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
-
- } while (value != hw_ep_get_halt(num, dir));
-
- return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_cwrite(CAP_USBINTR, BIT(n), 0);
- hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
- return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
- hw_cwrite(CAP_USBINTR, BIT(n), BIT(n));
- hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
- hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
- return 0;
-}
-
-/**
- * hw_is_port_high_speed: test if port is high speed
- *
- * This function returns true if high speed port
- */
-static int hw_port_is_high_speed(void)
-{
- return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
- hw_cread(CAP_PORTSC, PORTSC_HSP);
-}
-
-/**
- * hw_port_test_get: reads port test mode value
- *
- * This function returns port test mode value
- */
-static u8 hw_port_test_get(void)
-{
- return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
-}
-
-/**
- * hw_port_test_set: writes port test mode (execute without interruption)
- * @mode: new value
- *
- * This function returns an error code
- */
-static int hw_port_test_set(u8 mode)
-{
- const u8 TEST_MODE_MAX = 7;
-
- if (mode > TEST_MODE_MAX)
- return -EINVAL;
-
- hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
- return 0;
-}
-
-/**
- * hw_read_intr_enable: returns interrupt enable register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_enable(void)
-{
- return hw_cread(CAP_USBINTR, ~0);
-}
-
-/**
- * hw_read_intr_status: returns interrupt status register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_status(void)
-{
- return hw_cread(CAP_USBSTS, ~0);
-}
-
-/**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf: destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
- */
-static size_t hw_register_read(u32 *buf, size_t size)
-{
- unsigned i;
-
- if (size > hw_bank.size)
- size = hw_bank.size;
-
- for (i = 0; i < size; i++)
- buf[i] = hw_aread(i * sizeof(u32), ~0);
-
- return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(u16 addr, u32 data)
-{
- /* align */
- addr /= sizeof(u32);
-
- if (addr >= hw_bank.size)
- return -EINVAL;
-
- /* align */
- addr *= sizeof(u32);
-
- hw_awrite(addr, ~0, data);
- return 0;
-}
-
-/**
- * hw_test_and_clear_complete: test & clear complete status (execute without
- * interruption)
- * @n: endpoint number
- *
- * This function returns complete status
- */
-static int hw_test_and_clear_complete(int n)
-{
- n = ep_to_bit(n);
- return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
-}
-
-/**
- * hw_test_and_clear_intr_active: test & clear active interrupts (execute
- * without interruption)
- *
- * This function returns active interrutps
- */
-static u32 hw_test_and_clear_intr_active(void)
-{
- u32 reg = hw_read_intr_status() & hw_read_intr_enable();
-
- hw_cwrite(CAP_USBSTS, ~0, reg);
- return reg;
-}
-
-/**
- * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
- * interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_clear_setup_guard(void)
-{
- return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
-}
-
-/**
- * hw_test_and_set_setup_guard: test & set setup guard (execute without
- * interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_set_setup_guard(void)
-{
- return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
-}
-
-/**
- * hw_usb_set_address: configures USB address (execute without interruption)
- * @value: new USB address
- *
- * This function returns an error code
- */
-static int hw_usb_set_address(u8 value)
-{
- /* advance */
- hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
- value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
- return 0;
-}
-
-/**
- * hw_usb_reset: restart device after a bus reset (execute without
- * interruption)
- *
- * This function returns an error code
- */
-static int hw_usb_reset(void)
-{
- hw_usb_set_address(0);
-
- /* ESS flushes only at end?!? */
- hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */
-
- /* clear setup token semaphores */
- hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */
-
- /* clear complete status */
- hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
-
- /* wait until all bits cleared */
- while (hw_cread(CAP_ENDPTPRIME, ~0))
- udelay(10); /* not RTOS friendly */
-
- /* reset all endpoints ? */
-
- /* reset internal status and wait for further instructions
- no need to verify the port reset status (ESS does it) */
-
- return 0;
-}
-
-/******************************************************************************
- * DBG block
- *****************************************************************************/
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget *gadget = &udc->gadget;
- int n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
- gadget->speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
- gadget->max_speed);
- /* TODO: Scheduled for removal in 3.8. */
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
- gadget_is_dualspeed(gadget));
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
- gadget->is_otg);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
- gadget->is_a_peripheral);
- n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
- gadget->b_hnp_enable);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
- gadget->a_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
- gadget->a_alt_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
- (gadget->name ? gadget->name : ""));
-
- return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget_driver *driver = udc->driver;
- int n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- if (driver == NULL)
- return scnprintf(buf, PAGE_SIZE,
- "There is no gadget attached!\n");
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
- (driver->function ? driver->function : ""));
- n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
- driver->max_speed);
-
- return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG 64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX 128UL
-
-/* Event buffer descriptor */
-static struct {
- char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
- unsigned idx; /* index */
- unsigned tty; /* print to console? */
- rwlock_t lck; /* lock */
-} dbg_data = {
- .idx = 0,
- .tty = 0,
- .lck = __RW_LOCK_UNLOCKED(lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
- *idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
- *idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print: prints the common part of the event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- * @extra: extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
- struct timeval tval;
- unsigned int stamp;
- unsigned long flags;
-
- write_lock_irqsave(&dbg_data.lck, flags);
-
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
- stamp = stamp * 1000000 + tval.tv_usec;
-
- scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-
- dbg_inc(&dbg_data.idx);
-
- write_unlock_irqrestore(&dbg_data.lck, flags);
-
- if (dbg_data.tty != 0)
- pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr: endpoint address
- * @td: transfer descriptor
- * @status: status
- */
-static void dbg_done(u8 addr, const u32 token, int status)
-{
- char msg[DBG_DATA_MSG];
-
- scnprintf(msg, sizeof(msg), "%d %02X",
- (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
- (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
- dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- */
-static void dbg_event(u8 addr, const char *name, int status)
-{
- if (name != NULL)
- dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr: endpoint address
- * @req: USB request
- * @status: status
- */
-static void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%d %d", !req->no_interrupt, req->length);
- dbg_print(addr, "QUEUE", status, msg);
- }
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req: setup request
- */
-static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%02X %02X %04X %04X %d", req->bRequestType,
- req->bRequest, le16_to_cpu(req->wValue),
- le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
- dbg_print(addr, "SETUP", 0, msg);
- }
-}
-
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- unsigned long flags;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- read_lock_irqsave(&dbg_data.lck, flags);
-
- i = dbg_data.idx;
- for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
- n += strlen(dbg_data.buf[i]);
- if (n >= PAGE_SIZE) {
- n -= strlen(dbg_data.buf[i]);
- break;
- }
- }
- for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
- j += scnprintf(buf + j, PAGE_SIZE - j,
- "%s", dbg_data.buf[i]);
-
- read_unlock_irqrestore(&dbg_data.lck, flags);
-
- return n;
-}
-
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned tty;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
- dev_err(dev, "<1|0>: enable|disable console log\n");
- goto done;
- }
-
- dbg_data.tty = tty;
- dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
- return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
-
-/**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
- */
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- u32 intr;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
-
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "status = %08x\n", hw_read_intr_status());
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "enable = %08x\n", hw_read_intr_enable());
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
- isr_statistics.test);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
- isr_statistics.ui);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
- isr_statistics.uei);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
- isr_statistics.pci);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
- isr_statistics.uri);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
- isr_statistics.sli);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
- isr_statistics.none);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
- isr_statistics.hndl.cnt);
-
- for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
- i &= ISR_MASK;
- intr = isr_statistics.hndl.buf[i];
-
- if (USBi_UI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
- intr &= ~USBi_UI;
- if (USBi_UEI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
- intr &= ~USBi_UEI;
- if (USBi_PCI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
- intr &= ~USBi_PCI;
- if (USBi_URI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
- intr &= ~USBi_URI;
- if (USBi_SLI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
- intr &= ~USBi_SLI;
- if (intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
- if (isr_statistics.hndl.buf[i])
- n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
- }
-
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- * (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned en, bit;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
- dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (en) {
- if (hw_intr_force(bit))
- dev_err(dev, "invalid bit number\n");
- else
- isr_statistics.test++;
- } else {
- if (hw_intr_clear(bit))
- dev_err(dev, "invalid bit number\n");
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
-
-/**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t show_port_test(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- mode = hw_port_test_get();
- spin_unlock_irqrestore(udc->lock, flags);
-
- return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
-}
-
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &mode) != 1) {
- dev_err(dev, "<mode>: set port test mode");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (hw_port_test_set(mode))
- dev_err(dev, "invalid mode\n");
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
- show_port_test, store_port_test);
-
-/**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
- */
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- for (i = 0; i < hw_ep_max/2; i++) {
- struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
- struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: RX=%08X TX=%08X\n",
- i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
- for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X %08X\n", j,
- *((u32 *)mEpRx->qh.ptr + j),
- *((u32 *)mEpTx->qh.ptr + j));
- }
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
-
-/**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
- */
-#define DUMP_ENTRIES 512
-static ssize_t show_registers(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- u32 *dump;
- unsigned i, k, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
- if (!dump) {
- dev_err(dev, "%s: out of memory\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- k = hw_register_read(dump, DUMP_ENTRIES);
- spin_unlock_irqrestore(udc->lock, flags);
-
- for (i = 0; i < k; i++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "reg[0x%04X] = 0x%08X\n",
- i * (unsigned)sizeof(u32), dump[i]);
- }
- kfree(dump);
-
- return n;
-}
-
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long addr, data, flags;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%li %li", &addr, &data) != 2) {
- dev_err(dev, "<addr> <data>: write data to register address");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (hw_register_write(addr, data))
- dev_err(dev, "invalid address range\n");
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
- show_registers, store_registers);
-
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- for (i = 0; i < hw_ep_max; i++)
- list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
- {
- req = list_entry(ptr, struct ci13xxx_req, queue);
-
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: TD=%08X %s\n",
- i % hw_ep_max/2, (u32)req->dma,
- ((i < hw_ep_max/2) ? "RX" : "TX"));
-
- for (j = 0; j < qSize; j++)
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
-
-/**
- * dbg_create_files: initializes the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_create_files(struct device *dev)
-{
- int retval = 0;
-
- if (dev == NULL)
- return -EINVAL;
- retval = device_create_file(dev, &dev_attr_device);
- if (retval)
- goto done;
- retval = device_create_file(dev, &dev_attr_driver);
- if (retval)
- goto rm_device;
- retval = device_create_file(dev, &dev_attr_events);
- if (retval)
- goto rm_driver;
- retval = device_create_file(dev, &dev_attr_inters);
- if (retval)
- goto rm_events;
- retval = device_create_file(dev, &dev_attr_port_test);
- if (retval)
- goto rm_inters;
- retval = device_create_file(dev, &dev_attr_qheads);
- if (retval)
- goto rm_port_test;
- retval = device_create_file(dev, &dev_attr_registers);
- if (retval)
- goto rm_qheads;
- retval = device_create_file(dev, &dev_attr_requests);
- if (retval)
- goto rm_registers;
- return 0;
-
- rm_registers:
- device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
- device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
- device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
- device_remove_file(dev, &dev_attr_inters);
- rm_events:
- device_remove_file(dev, &dev_attr_events);
- rm_driver:
- device_remove_file(dev, &dev_attr_driver);
- rm_device:
- device_remove_file(dev, &dev_attr_device);
- done:
- return retval;
-}
-
-/**
- * dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_remove_files(struct device *dev)
-{
- if (dev == NULL)
- return -EINVAL;
- device_remove_file(dev, &dev_attr_requests);
- device_remove_file(dev, &dev_attr_registers);
- device_remove_file(dev, &dev_attr_qheads);
- device_remove_file(dev, &dev_attr_port_test);
- device_remove_file(dev, &dev_attr_inters);
- device_remove_file(dev, &dev_attr_events);
- device_remove_file(dev, &dev_attr_driver);
- device_remove_file(dev, &dev_attr_device);
- return 0;
-}
-
-/******************************************************************************
- * UTIL block
- *****************************************************************************/
-/**
- * _usb_addr: calculates endpoint address from direction & number
- * @ep: endpoint
- */
-static inline u8 _usb_addr(struct ci13xxx_ep *ep)
-{
- return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
-}
-
-/**
- * _hardware_queue: configures a request at hardware level
- * @gadget: gadget
- * @mEp: endpoint
- *
- * This function returns an error code
- */
-static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
- unsigned i;
- int ret = 0;
- unsigned length = mReq->req.length;
-
- trace("%p, %p", mEp, mReq);
-
- /* don't queue twice */
- if (mReq->req.status == -EALREADY)
- return -EALREADY;
-
- mReq->req.status = -EALREADY;
- if (length && mReq->req.dma == DMA_ADDR_INVALID) {
- mReq->req.dma = \
- dma_map_single(mEp->device, mReq->req.buf,
- length, mEp->dir ? DMA_TO_DEVICE :
- DMA_FROM_DEVICE);
- if (mReq->req.dma == 0)
- return -ENOMEM;
-
- mReq->map = 1;
- }
-
- if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
- mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
- &mReq->zdma);
- if (mReq->zptr == NULL) {
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma,
- length, mEp->dir ? DMA_TO_DEVICE :
- DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
- return -ENOMEM;
- }
- memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
- if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
- }
- /*
- * TD configuration
- * TODO - handle requests which spawns into several TDs
- */
- memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
- if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
- } else {
- mReq->ptr->next = TD_TERMINATE;
- if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
- }
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
-
- if (!list_empty(&mEp->qh.queue)) {
- struct ci13xxx_req *mReqPrev;
- int n = hw_ep_bit(mEp->num, mEp->dir);
- int tmp_stat;
-
- mReqPrev = list_entry(mEp->qh.queue.prev,
- struct ci13xxx_req, queue);
- if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
- else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
- wmb();
- if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- goto done;
- do {
- hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
- tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
- } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
- hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
- if (tmp_stat)
- goto done;
- }
-
- /* QH configuration */
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
- mEp->qh.ptr->cap |= QH_ZLT;
-
- wmb(); /* synchronize before ep prime */
-
- ret = hw_ep_prime(mEp->num, mEp->dir,
- mEp->type == USB_ENDPOINT_XFER_CONTROL);
-done:
- return ret;
-}
-
-/**
- * _hardware_dequeue: handles a request at hardware level
- * @gadget: gadget
- * @mEp: endpoint
- *
- * This function returns an error code
- */
-static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
- trace("%p, %p", mEp, mReq);
-
- if (mReq->req.status != -EALREADY)
- return -EINVAL;
-
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
- return -EBUSY;
-
- if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
- return -EBUSY;
- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
- mReq->zptr = NULL;
- }
-
- mReq->req.status = 0;
-
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
- mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
-
- mReq->req.status = mReq->ptr->token & TD_STATUS;
- if ((TD_STATUS_HALTED & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
-
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
- mReq->req.actual = mReq->req.length - mReq->req.actual;
- mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
-
- return mReq->req.actual;
-}
-
-/**
- * _ep_nuke: dequeues all endpoint requests
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int _ep_nuke(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- trace("%p", mEp);
-
- if (mEp == NULL)
- return -EINVAL;
-
- hw_ep_flush(mEp->num, mEp->dir);
-
- while (!list_empty(&mEp->qh.queue)) {
-
- /* pop oldest request */
- struct ci13xxx_req *mReq = \
- list_entry(mEp->qh.queue.next,
- struct ci13xxx_req, queue);
- list_del_init(&mReq->queue);
- mReq->req.status = -ESHUTDOWN;
-
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
- }
- return 0;
-}
-
-/**
- * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
- * @gadget: gadget
- *
- * This function returns an error code
- */
-static int _gadget_stop_activity(struct usb_gadget *gadget)
-{
- struct usb_ep *ep;
- struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
- unsigned long flags;
-
- trace("%p", gadget);
-
- if (gadget == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(udc->lock, flags);
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->remote_wakeup = 0;
- udc->suspended = 0;
- spin_unlock_irqrestore(udc->lock, flags);
-
- /* flush all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_fifo_flush(ep);
- }
- usb_ep_fifo_flush(&udc->ep0out.ep);
- usb_ep_fifo_flush(&udc->ep0in.ep);
-
- udc->driver->disconnect(gadget);
-
- /* make sure to disable all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_disable(ep);
- }
-
- if (udc->status != NULL) {
- usb_ep_free_request(&udc->ep0in.ep, udc->status);
- udc->status = NULL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- * ISR block
- *****************************************************************************/
-/**
- * isr_reset_handler: USB reset interrupt handler
- * @udc: UDC device
- *
- * This function resets USB engine after a bus reset occurred
- */
-static void isr_reset_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
- int retval;
-
- trace("%p", udc);
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
-
- dbg_event(0xFF, "BUS RST", 0);
-
- spin_unlock(udc->lock);
- retval = _gadget_stop_activity(&udc->gadget);
- if (retval)
- goto done;
-
- retval = hw_usb_reset();
- if (retval)
- goto done;
-
- udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
- if (udc->status == NULL)
- retval = -ENOMEM;
-
- spin_lock(udc->lock);
-
- done:
- if (retval)
- err("error: %i", retval);
-}
-
-/**
- * isr_get_status_complete: get_status request complete function
- * @ep: endpoint
- * @req: request handled
- *
- * Caller must release lock
- */
-static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL) {
- err("EINVAL");
- return;
- }
-
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
-/**
- * isr_get_status_response: get_status request response
- * @udc: udc struct
- * @setup: setup request packet
- *
- * This function returns an error code
- */
-static int isr_get_status_response(struct ci13xxx *udc,
- struct usb_ctrlrequest *setup)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- struct ci13xxx_ep *mEp = &udc->ep0in;
- struct usb_request *req = NULL;
- gfp_t gfp_flags = GFP_ATOMIC;
- int dir, num, retval;
-
- trace("%p, %p", mEp, setup);
-
- if (mEp == NULL || setup == NULL)
- return -EINVAL;
-
- spin_unlock(mEp->lock);
- req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
- spin_lock(mEp->lock);
- if (req == NULL)
- return -ENOMEM;
-
- req->complete = isr_get_status_complete;
- req->length = 2;
- req->buf = kzalloc(req->length, gfp_flags);
- if (req->buf == NULL) {
- retval = -ENOMEM;
- goto err_free_req;
- }
-
- if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- /* Assume that device is bus powered for now. */
- *((u16 *)req->buf) = _udc->remote_wakeup << 1;
- retval = 0;
- } else if ((setup->bRequestType & USB_RECIP_MASK) \
- == USB_RECIP_ENDPOINT) {
- dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
- TX : RX;
- num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
- *((u16 *)req->buf) = hw_ep_get_halt(num, dir);
- }
- /* else do nothing; reserved for future use */
-
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
- if (retval)
- goto err_free_buf;
-
- return 0;
-
- err_free_buf:
- kfree(req->buf);
- err_free_req:
- spin_unlock(mEp->lock);
- usb_ep_free_request(&mEp->ep, req);
- spin_lock(mEp->lock);
- return retval;
-}
-
-/**
- * isr_setup_status_complete: setup_status request complete function
- * @ep: endpoint
- * @req: request handled
- *
- * Caller must release lock. Put the port in test mode if test mode
- * feature is selected.
- */
-static void
-isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx *udc = req->context;
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- spin_lock_irqsave(udc->lock, flags);
- if (udc->test_mode)
- hw_port_test_set(udc->test_mode);
- spin_unlock_irqrestore(udc->lock, flags);
-}
-
-/**
- * isr_setup_status_phase: queues the status phase of a setup transation
- * @udc: udc struct
- *
- * This function returns an error code
- */
-static int isr_setup_status_phase(struct ci13xxx *udc)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- int retval;
- struct ci13xxx_ep *mEp;
-
- trace("%p", udc);
-
- mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
- udc->status->context = udc;
- udc->status->complete = isr_setup_status_complete;
-
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
-
- return retval;
-}
-
-/**
- * isr_tr_complete_low: transaction complete low level handler
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- struct ci13xxx_req *mReq, *mReqTemp;
- struct ci13xxx_ep *mEpTemp = mEp;
- int uninitialized_var(retval);
-
- trace("%p", mEp);
-
- if (list_empty(&mEp->qh.queue))
- return -EINVAL;
-
- list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
- queue) {
- retval = _hardware_dequeue(mEp, mReq);
- if (retval < 0)
- break;
- list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
- mReq->req.length)
- mEpTemp = &_udc->ep0in;
- mReq->req.complete(&mEpTemp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
- }
-
- if (retval == -EBUSY)
- retval = 0;
- if (retval < 0)
- dbg_event(_usb_addr(mEp), "DONE", retval);
-
- return retval;
-}
-
-/**
- * isr_tr_complete_handler: transaction complete interrupt handler
- * @udc: UDC descriptor
- *
- * This function handles traffic events
- */
-static void isr_tr_complete_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
- unsigned i;
- u8 tmode = 0;
-
- trace("%p", udc);
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
-
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
- int type, num, dir, err = -EINVAL;
- struct usb_ctrlrequest req;
-
- if (mEp->desc == NULL)
- continue; /* not configured */
-
- if (hw_test_and_clear_complete(i)) {
- err = isr_tr_complete_low(mEp);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (err > 0) /* needs status phase */
- err = isr_setup_status_phase(udc);
- if (err < 0) {
- dbg_event(_usb_addr(mEp),
- "ERROR", err);
- spin_unlock(udc->lock);
- if (usb_ep_set_halt(&mEp->ep))
- err("error: ep_set_halt");
- spin_lock(udc->lock);
- }
- }
- }
-
- if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
- !hw_test_and_clear_setup_status(i))
- continue;
-
- if (i != 0) {
- warn("ctrl traffic received at endpoint");
- continue;
- }
-
- /*
- * Flush data and handshake transactions of previous
- * setup packet.
- */
- _ep_nuke(&udc->ep0out);
- _ep_nuke(&udc->ep0in);
-
- /* read_setup_packet */
- do {
- hw_test_and_set_setup_guard();
- memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
- } while (!hw_test_and_clear_setup_guard());
-
- type = req.bRequestType;
-
- udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
-
- dbg_setup(_usb_addr(mEp), &req);
-
- switch (req.bRequest) {
- case USB_REQ_CLEAR_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += hw_ep_max/2;
- if (!udc->ci13xxx_ep[num].wedge) {
- spin_unlock(udc->lock);
- err = usb_ep_clear_halt(
- &udc->ci13xxx_ep[num].ep);
- spin_lock(udc->lock);
- if (err)
- break;
- }
- err = isr_setup_status_phase(udc);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
- le16_to_cpu(req.wValue) ==
- USB_DEVICE_REMOTE_WAKEUP) {
- if (req.wLength != 0)
- break;
- udc->remote_wakeup = 0;
- err = isr_setup_status_phase(udc);
- } else {
- goto delegate;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
- type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
- type != (USB_DIR_IN|USB_RECIP_INTERFACE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 2 ||
- le16_to_cpu(req.wValue) != 0)
- break;
- err = isr_get_status_response(udc, &req);
- break;
- case USB_REQ_SET_ADDRESS:
- if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 0 ||
- le16_to_cpu(req.wIndex) != 0)
- break;
- err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
- if (err)
- break;
- err = isr_setup_status_phase(udc);
- break;
- case USB_REQ_SET_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += hw_ep_max/2;
-
- spin_unlock(udc->lock);
- err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
- spin_lock(udc->lock);
- if (!err)
- isr_setup_status_phase(udc);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
- if (req.wLength != 0)
- break;
- switch (le16_to_cpu(req.wValue)) {
- case USB_DEVICE_REMOTE_WAKEUP:
- udc->remote_wakeup = 1;
- err = isr_setup_status_phase(udc);
- break;
- case USB_DEVICE_TEST_MODE:
- tmode = le16_to_cpu(req.wIndex) >> 8;
- switch (tmode) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- udc->test_mode = tmode;
- err = isr_setup_status_phase(
- udc);
- break;
- default:
- break;
- }
- default:
- goto delegate;
- }
- } else {
- goto delegate;
- }
- break;
- default:
-delegate:
- if (req.wLength == 0) /* no data phase */
- udc->ep0_dir = TX;
-
- spin_unlock(udc->lock);
- err = udc->driver->setup(&udc->gadget, &req);
- spin_lock(udc->lock);
- break;
- }
-
- if (err < 0) {
- dbg_event(_usb_addr(mEp), "ERROR", err);
-
- spin_unlock(udc->lock);
- if (usb_ep_set_halt(&mEp->ep))
- err("error: ep_set_halt");
- spin_lock(udc->lock);
- }
- }
-}
-
-/******************************************************************************
- * ENDPT block
- *****************************************************************************/
-/**
- * ep_enable: configure endpoint, making it usable
- *
- * Check usb_ep_enable() at "usb_gadget.h" for details
- */
-static int ep_enable(struct usb_ep *ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int retval = 0;
- unsigned long flags;
-
- trace("%p, %p", ep, desc);
-
- if (ep == NULL || desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- /* only internal SW should enable ctrl endpts */
-
- mEp->desc = desc;
-
- if (!list_empty(&mEp->qh.queue))
- warn("enabling a non-empty endpoint!");
-
- mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
- mEp->num = usb_endpoint_num(desc);
- mEp->type = usb_endpoint_type(desc);
-
- mEp->ep.maxpacket = usb_endpoint_maxp(desc);
-
- dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
- mEp->qh.ptr->cap = 0;
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
- else
- mEp->qh.ptr->cap &= ~QH_ZLT;
-
- mEp->qh.ptr->cap |=
- (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
-
- /*
- * Enable endpoints in the HW other than ep0 as ep0
- * is always enabled
- */
- if (mEp->num)
- retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_disable: endpoint is no longer usable
- *
- * Check usb_ep_disable() at "usb_gadget.h" for details
- */
-static int ep_disable(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int direction, retval = 0;
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL)
- return -EINVAL;
- else if (mEp->desc == NULL)
- return -EBUSY;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- /* only internal SW should disable ctrl endpts */
-
- direction = mEp->dir;
- do {
- dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
- retval |= _ep_nuke(mEp);
- retval |= hw_ep_disable(mEp->num, mEp->dir);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
-
- } while (mEp->dir != direction);
-
- mEp->desc = NULL;
- mEp->ep.desc = NULL;
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_alloc_request: allocate a request object to use with this endpoint
- *
- * Check usb_ep_alloc_request() at "usb_gadget.h" for details
- */
-static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = NULL;
-
- trace("%p, %i", ep, gfp_flags);
-
- if (ep == NULL) {
- err("EINVAL");
- return NULL;
- }
-
- mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
- if (mReq != NULL) {
- INIT_LIST_HEAD(&mReq->queue);
- mReq->req.dma = DMA_ADDR_INVALID;
-
- mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
- &mReq->dma);
- if (mReq->ptr == NULL) {
- kfree(mReq);
- mReq = NULL;
- }
- }
-
- dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
- return (mReq == NULL) ? NULL : &mReq->req;
-}
-
-/**
- * ep_free_request: frees a request object
- *
- * Check usb_ep_free_request() at "usb_gadget.h" for details
- */
-static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL) {
- err("EINVAL");
- return;
- } else if (!list_empty(&mReq->queue)) {
- err("EBUSY");
- return;
- }
-
- spin_lock_irqsave(mEp->lock, flags);
-
- if (mReq->ptr)
- dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
- kfree(mReq);
-
- dbg_event(_usb_addr(mEp), "FREE", 0);
-
- spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * ep_queue: queues (submits) an I/O request to an endpoint
- *
- * Check usb_ep_queue()* at usb_gadget.h" for details
- */
-static int ep_queue(struct usb_ep *ep, struct usb_request *req,
- gfp_t __maybe_unused gfp_flags)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- int retval = 0;
- unsigned long flags;
-
- trace("%p, %p, %X", ep, req, gfp_flags);
-
- if (ep == NULL || req == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (_udc->ep0_dir == RX) ?
- &_udc->ep0out : &_udc->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- warn("endpoint ctrl %X nuked", _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- err("request already in queue");
- goto done;
- }
-
- if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
- req->length = (4 * CI13XXX_PAGE_SIZE);
- retval = -EMSGSIZE;
- warn("request length truncated");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
-
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
- *
- * Check usb_ep_dequeue() at "usb_gadget.h" for details
- */
-static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
- mEp->desc == NULL || list_empty(&mReq->queue) ||
- list_empty(&mEp->qh.queue))
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
- hw_ep_flush(mEp->num, mEp->dir);
-
- /* pop request */
- list_del_init(&mReq->queue);
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
- mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
- req->status = -ECONNRESET;
-
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return 0;
-}
-
-/**
- * ep_set_halt: sets the endpoint halt feature
- *
- * Check usb_ep_set_halt() at "usb_gadget.h" for details
- */
-static int ep_set_halt(struct usb_ep *ep, int value)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int direction, retval = 0;
- unsigned long flags;
-
- trace("%p, %i", ep, value);
-
- if (ep == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
-#ifndef STALL_IN
- /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
- if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
- !list_empty(&mEp->qh.queue)) {
- spin_unlock_irqrestore(mEp->lock, flags);
- return -EAGAIN;
- }
-#endif
-
- direction = mEp->dir;
- do {
- dbg_event(_usb_addr(mEp), "HALT", value);
- retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
-
- if (!value)
- mEp->wedge = 0;
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
-
- } while (mEp->dir != direction);
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_set_wedge: sets the halt feature and ignores clear requests
- *
- * Check usb_ep_set_wedge() at "usb_gadget.h" for details
- */
-static int ep_set_wedge(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "WEDGE", 0);
- mEp->wedge = 1;
-
- spin_unlock_irqrestore(mEp->lock, flags);
-
- return usb_ep_set_halt(ep);
-}
-
-/**
- * ep_fifo_flush: flushes contents of a fifo
- *
- * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
- */
-static void ep_fifo_flush(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL) {
- err("%02X: -EINVAL", _usb_addr(mEp));
- return;
- }
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "FFLUSH", 0);
- hw_ep_flush(mEp->num, mEp->dir);
-
- spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * Endpoint-specific part of the API to the USB controller hardware
- * Check "usb_gadget.h" for details
- */
-static const struct usb_ep_ops usb_ep_ops = {
- .enable = ep_enable,
- .disable = ep_disable,
- .alloc_request = ep_alloc_request,
- .free_request = ep_free_request,
- .queue = ep_queue,
- .dequeue = ep_dequeue,
- .set_halt = ep_set_halt,
- .set_wedge = ep_set_wedge,
- .fifo_flush = ep_fifo_flush,
-};
-
-/******************************************************************************
- * GADGET block
- *****************************************************************************/
-static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
- unsigned long flags;
- int gadget_ready = 0;
-
- if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
- return -EOPNOTSUPP;
-
- spin_lock_irqsave(udc->lock, flags);
- udc->vbus_active = is_active;
- if (udc->driver)
- gadget_ready = 1;
- spin_unlock_irqrestore(udc->lock, flags);
-
- if (gadget_ready) {
- if (is_active) {
- pm_runtime_get_sync(&_gadget->dev);
- hw_device_reset(udc);
- hw_device_state(udc->ep0out.qh.dma);
- } else {
- hw_device_state(0);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
- _gadget_stop_activity(&udc->gadget);
- pm_runtime_put_sync(&_gadget->dev);
- }
- }
-
- return 0;
-}
-
-static int ci13xxx_wakeup(struct usb_gadget *_gadget)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
- unsigned long flags;
- int ret = 0;
-
- trace();
-
- spin_lock_irqsave(udc->lock, flags);
- if (!udc->remote_wakeup) {
- ret = -EOPNOTSUPP;
- trace("remote wakeup feature is not enabled\n");
- goto out;
- }
- if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
- ret = -EINVAL;
- trace("port is not suspended\n");
- goto out;
- }
- hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
-out:
- spin_unlock_irqrestore(udc->lock, flags);
- return ret;
-}
-
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
-
- if (udc->transceiver)
- return usb_phy_set_power(udc->transceiver, mA);
- return -ENOTSUPP;
-}
-
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int ci13xxx_stop(struct usb_gadget_driver *driver);
-/**
- * Device operations part of the API to the USB controller hardware,
- * which don't involve endpoints (or i/o)
- * Check "usb_gadget.h" for details
- */
-static const struct usb_gadget_ops usb_gadget_ops = {
- .vbus_session = ci13xxx_vbus_session,
- .wakeup = ci13xxx_wakeup,
- .vbus_draw = ci13xxx_vbus_draw,
- .start = ci13xxx_start,
- .stop = ci13xxx_stop,
-};
-
-/**
- * ci13xxx_start: register a gadget driver
- * @driver: the driver being registered
- * @bind: the driver's bind callback
- *
- * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
- * Interrupts are enabled here.
- */
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
-{
- struct ci13xxx *udc = _udc;
- unsigned long flags;
- int i, j;
- int retval = -ENOMEM;
-
- trace("%p", driver);
-
- if (driver == NULL ||
- bind == NULL ||
- driver->setup == NULL ||
- driver->disconnect == NULL)
- return -EINVAL;
- else if (udc == NULL)
- return -ENODEV;
- else if (udc->driver != NULL)
- return -EBUSY;
-
- /* alloc resources */
- udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
- sizeof(struct ci13xxx_qh),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->qh_pool == NULL)
- return -ENOMEM;
-
- udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
- sizeof(struct ci13xxx_td),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->td_pool == NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- return -ENOMEM;
- }
-
- spin_lock_irqsave(udc->lock, flags);
-
- info("hw_ep_max = %d", hw_ep_max);
-
- udc->gadget.dev.driver = NULL;
-
- retval = 0;
- for (i = 0; i < hw_ep_max/2; i++) {
- for (j = RX; j <= TX; j++) {
- int k = i + j * hw_ep_max/2;
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
-
- scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
- (j == TX) ? "in" : "out");
-
- mEp->lock = udc->lock;
- mEp->device = &udc->gadget.dev;
- mEp->td_pool = udc->td_pool;
-
- mEp->ep.name = mEp->name;
- mEp->ep.ops = &usb_ep_ops;
- mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
-
- INIT_LIST_HEAD(&mEp->qh.queue);
- spin_unlock_irqrestore(udc->lock, flags);
- mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
- &mEp->qh.dma);
- spin_lock_irqsave(udc->lock, flags);
- if (mEp->qh.ptr == NULL)
- retval = -ENOMEM;
- else
- memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
-
- /* skip ep0 out and in endpoints */
- if (i == 0)
- continue;
-
- list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
- }
- }
- if (retval)
- goto done;
- spin_unlock_irqrestore(udc->lock, flags);
- udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
- retval = usb_ep_enable(&udc->ep0out.ep);
- if (retval)
- return retval;
-
- udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
- retval = usb_ep_enable(&udc->ep0in.ep);
- if (retval)
- return retval;
- spin_lock_irqsave(udc->lock, flags);
-
- udc->gadget.ep0 = &udc->ep0in.ep;
- /* bind gadget */
- driver->driver.bus = NULL;
- udc->gadget.dev.driver = &driver->driver;
-
- spin_unlock_irqrestore(udc->lock, flags);
- retval = bind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
-
- if (retval) {
- udc->gadget.dev.driver = NULL;
- goto done;
- }
-
- udc->driver = driver;
- pm_runtime_get_sync(&udc->gadget.dev);
- if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
- if (udc->vbus_active) {
- if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
- hw_device_reset(udc);
- } else {
- pm_runtime_put_sync(&udc->gadget.dev);
- goto done;
- }
- }
-
- retval = hw_device_state(udc->ep0out.qh.dma);
- if (retval)
- pm_runtime_put_sync(&udc->gadget.dev);
-
- done:
- spin_unlock_irqrestore(udc->lock, flags);
- return retval;
-}
-
-/**
- * ci13xxx_stop: unregister a gadget driver
- *
- * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
- */
-static int ci13xxx_stop(struct usb_gadget_driver *driver)
-{
- struct ci13xxx *udc = _udc;
- unsigned long i, flags;
-
- trace("%p", driver);
-
- if (driver == NULL ||
- driver->unbind == NULL ||
- driver->setup == NULL ||
- driver->disconnect == NULL ||
- driver != udc->driver)
- return -EINVAL;
-
- spin_lock_irqsave(udc->lock, flags);
-
- if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
- udc->vbus_active) {
- hw_device_state(0);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
- spin_unlock_irqrestore(udc->lock, flags);
- _gadget_stop_activity(&udc->gadget);
- spin_lock_irqsave(udc->lock, flags);
- pm_runtime_put(&udc->gadget.dev);
- }
-
- /* unbind gadget */
- spin_unlock_irqrestore(udc->lock, flags);
- driver->unbind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
-
- udc->gadget.dev.driver = NULL;
-
- /* free resources */
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-
- if (!list_empty(&mEp->ep.ep_list))
- list_del_init(&mEp->ep.ep_list);
-
- if (mEp->qh.ptr != NULL)
- dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
- }
-
- udc->gadget.ep0 = NULL;
- udc->driver = NULL;
-
- spin_unlock_irqrestore(udc->lock, flags);
-
- if (udc->td_pool != NULL) {
- dma_pool_destroy(udc->td_pool);
- udc->td_pool = NULL;
- }
- if (udc->qh_pool != NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- * BUS block
- *****************************************************************************/
-/**
- * udc_irq: global interrupt handler
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * It locks access to registers
- */
-static irqreturn_t udc_irq(void)
-{
- struct ci13xxx *udc = _udc;
- irqreturn_t retval;
- u32 intr;
-
- trace();
-
- if (udc == NULL) {
- err("ENODEV");
- return IRQ_HANDLED;
- }
-
- spin_lock(udc->lock);
-
- if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
- if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
- USBMODE_CM_DEVICE) {
- spin_unlock(udc->lock);
- return IRQ_NONE;
- }
- }
- intr = hw_test_and_clear_intr_active();
- if (intr) {
- isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
- isr_statistics.hndl.idx &= ISR_MASK;
- isr_statistics.hndl.cnt++;
-
- /* order defines priority - do NOT change it */
- if (USBi_URI & intr) {
- isr_statistics.uri++;
- isr_reset_handler(udc);
- }
- if (USBi_PCI & intr) {
- isr_statistics.pci++;
- udc->gadget.speed = hw_port_is_high_speed() ?
- USB_SPEED_HIGH : USB_SPEED_FULL;
- if (udc->suspended && udc->driver->resume) {
- spin_unlock(udc->lock);
- udc->driver->resume(&udc->gadget);
- spin_lock(udc->lock);
- udc->suspended = 0;
- }
- }
- if (USBi_UEI & intr)
- isr_statistics.uei++;
- if (USBi_UI & intr) {
- isr_statistics.ui++;
- isr_tr_complete_handler(udc);
- }
- if (USBi_SLI & intr) {
- if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
- udc->driver->suspend) {
- udc->suspended = 1;
- spin_unlock(udc->lock);
- udc->driver->suspend(&udc->gadget);
- spin_lock(udc->lock);
- }
- isr_statistics.sli++;
- }
- retval = IRQ_HANDLED;
- } else {
- isr_statistics.none++;
- retval = IRQ_NONE;
- }
- spin_unlock(udc->lock);
-
- return retval;
-}
-
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
- trace("%p", dev);
-
- if (dev == NULL)
- err("EINVAL");
-}
-
-/**
- * udc_probe: parent probe must call this to initialize UDC
- * @dev: parent device
- * @regs: registers base address
- * @name: driver name
- *
- * This function returns an error code
- * No interrupts active, the IRQ has not been requested yet
- * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
- */
-static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
- void __iomem *regs)
-{
- struct ci13xxx *udc;
- int retval = 0;
-
- trace("%p, %p, %p", dev, regs, driver->name);
-
- if (dev == NULL || regs == NULL || driver == NULL ||
- driver->name == NULL)
- return -EINVAL;
-
- udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
- if (udc == NULL)
- return -ENOMEM;
-
- udc->lock = &udc_lock;
- udc->regs = regs;
- udc->udc_driver = driver;
-
- udc->gadget.ops = &usb_gadget_ops;
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->gadget.max_speed = USB_SPEED_HIGH;
- udc->gadget.is_otg = 0;
- udc->gadget.name = driver->name;
-
- INIT_LIST_HEAD(&udc->gadget.ep_list);
- udc->gadget.ep0 = NULL;
-
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.dma_mask = dev->dma_mask;
- udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- udc->gadget.dev.parent = dev;
- udc->gadget.dev.release = udc_release;
-
- retval = hw_device_init(regs);
- if (retval < 0)
- goto free_udc;
-
- udc->transceiver = usb_get_transceiver();
-
- if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
- if (udc->transceiver == NULL) {
- retval = -ENODEV;
- goto free_udc;
- }
- }
-
- if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
- retval = hw_device_reset(udc);
- if (retval)
- goto put_transceiver;
- }
-
- retval = device_register(&udc->gadget.dev);
- if (retval) {
- put_device(&udc->gadget.dev);
- goto put_transceiver;
- }
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- retval = dbg_create_files(&udc->gadget.dev);
-#endif
- if (retval)
- goto unreg_device;
-
- if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver->otg,
- &udc->gadget);
- if (retval)
- goto remove_dbg;
- }
-
- retval = usb_add_gadget_udc(dev, &udc->gadget);
- if (retval)
- goto remove_trans;
-
- pm_runtime_no_callbacks(&udc->gadget.dev);
- pm_runtime_enable(&udc->gadget.dev);
-
- _udc = udc;
- return retval;
-
-remove_trans:
- if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
- }
-
- err("error = %i", retval);
-remove_dbg:
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- dbg_remove_files(&udc->gadget.dev);
-#endif
-unreg_device:
- device_unregister(&udc->gadget.dev);
-put_transceiver:
- if (udc->transceiver)
- usb_put_transceiver(udc->transceiver);
-free_udc:
- kfree(udc);
- _udc = NULL;
- return retval;
-}
-
-/**
- * udc_remove: parent remove must call this to remove UDC
- *
- * No interrupts active, the IRQ has been released
- */
-static void udc_remove(void)
-{
- struct ci13xxx *udc = _udc;
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
- usb_del_gadget_udc(&udc->gadget);
-
- if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
- }
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- dbg_remove_files(&udc->gadget.dev);
-#endif
- device_unregister(&udc->gadget.dev);
-
- kfree(udc);
- _udc = NULL;
-}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
deleted file mode 100644
index 0d31af5..0000000
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Description: MIPS USB IP core family device controller
- * Structures, registers and logging macros
- */
-
-#ifndef _CI13XXX_h_
-#define _CI13XXX_h_
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
-#define ENDPT_MAX (32)
-#define CTRL_PAYLOAD_MAX (64)
-#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
-#define TX (1) /* similar to USB_DIR_IN but can be used as an index */
-
-/******************************************************************************
- * STRUCTURES
- *****************************************************************************/
-/* DMA layout of transfer descriptors */
-struct ci13xxx_td {
- /* 0 */
- u32 next;
-#define TD_TERMINATE BIT(0)
-#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
- /* 1 */
- u32 token;
-#define TD_STATUS (0x00FFUL << 0)
-#define TD_STATUS_TR_ERR BIT(3)
-#define TD_STATUS_DT_ERR BIT(5)
-#define TD_STATUS_HALTED BIT(6)
-#define TD_STATUS_ACTIVE BIT(7)
-#define TD_MULTO (0x0003UL << 10)
-#define TD_IOC BIT(15)
-#define TD_TOTAL_BYTES (0x7FFFUL << 16)
- /* 2 */
- u32 page[5];
-#define TD_CURR_OFFSET (0x0FFFUL << 0)
-#define TD_FRAME_NUM (0x07FFUL << 0)
-#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed));
-
-/* DMA layout of queue heads */
-struct ci13xxx_qh {
- /* 0 */
- u32 cap;
-#define QH_IOS BIT(15)
-#define QH_MAX_PKT (0x07FFUL << 16)
-#define QH_ZLT BIT(29)
-#define QH_MULT (0x0003UL << 30)
- /* 1 */
- u32 curr;
- /* 2 - 8 */
- struct ci13xxx_td td;
- /* 9 */
- u32 RESERVED;
- struct usb_ctrlrequest setup;
-} __attribute__ ((packed));
-
-/* Extension of usb_request */
-struct ci13xxx_req {
- struct usb_request req;
- unsigned map;
- struct list_head queue;
- struct ci13xxx_td *ptr;
- dma_addr_t dma;
- struct ci13xxx_td *zptr;
- dma_addr_t zdma;
-};
-
-/* Extension of usb_ep */
-struct ci13xxx_ep {
- struct usb_ep ep;
- const struct usb_endpoint_descriptor *desc;
- u8 dir;
- u8 num;
- u8 type;
- char name[16];
- struct {
- struct list_head queue;
- struct ci13xxx_qh *ptr;
- dma_addr_t dma;
- } qh;
- int wedge;
-
- /* global resources */
- spinlock_t *lock;
- struct device *device;
- struct dma_pool *td_pool;
-};
-
-struct ci13xxx;
-struct ci13xxx_udc_driver {
- const char *name;
- unsigned long flags;
-#define CI13XXX_REGS_SHARED BIT(0)
-#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
-#define CI13XXX_PULLUP_ON_VBUS BIT(2)
-#define CI13XXX_DISABLE_STREAMING BIT(3)
-
-#define CI13XXX_CONTROLLER_RESET_EVENT 0
-#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
- void (*notify_event) (struct ci13xxx *udc, unsigned event);
-};
-
-/* CI13XXX UDC descriptor & global resources */
-struct ci13xxx {
- spinlock_t *lock; /* ctrl register bank access */
- void __iomem *regs; /* registers address space */
-
- struct dma_pool *qh_pool; /* DMA pool for queue heads */
- struct dma_pool *td_pool; /* DMA pool for transfer descs */
- struct usb_request *status; /* ep0 status request */
-
- struct usb_gadget gadget; /* USB slave device */
- struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
- u32 ep0_dir; /* ep0 direction */
-#define ep0out ci13xxx_ep[0]
-#define ep0in ci13xxx_ep[hw_ep_max / 2]
- u8 remote_wakeup; /* Is remote wakeup feature
- enabled by the host? */
- u8 suspended; /* suspended by the host */
- u8 test_mode; /* the selected test mode */
-
- struct usb_gadget_driver *driver; /* 3rd party gadget driver */
- struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
- int vbus_active; /* is VBUS active */
- struct usb_phy *transceiver; /* Transceiver struct */
-};
-
-/******************************************************************************
- * REGISTERS
- *****************************************************************************/
-/* register size */
-#define REG_BITS (32)
-
-/* HCCPARAMS */
-#define HCCPARAMS_LEN BIT(17)
-
-/* DCCPARAMS */
-#define DCCPARAMS_DEN (0x1F << 0)
-#define DCCPARAMS_DC BIT(7)
-
-/* TESTMODE */
-#define TESTMODE_FORCE BIT(0)
-
-/* USBCMD */
-#define USBCMD_RS BIT(0)
-#define USBCMD_RST BIT(1)
-#define USBCMD_SUTW BIT(13)
-#define USBCMD_ATDTW BIT(14)
-
-/* USBSTS & USBINTR */
-#define USBi_UI BIT(0)
-#define USBi_UEI BIT(1)
-#define USBi_PCI BIT(2)
-#define USBi_URI BIT(6)
-#define USBi_SLI BIT(8)
-
-/* DEVICEADDR */
-#define DEVICEADDR_USBADRA BIT(24)
-#define DEVICEADDR_USBADR (0x7FUL << 25)
-
-/* PORTSC */
-#define PORTSC_FPR BIT(6)
-#define PORTSC_SUSP BIT(7)
-#define PORTSC_HSP BIT(9)
-#define PORTSC_PTC (0x0FUL << 16)
-
-/* DEVLC */
-#define DEVLC_PSPD (0x03UL << 25)
-#define DEVLC_PSPD_HS (0x02UL << 25)
-
-/* USBMODE */
-#define USBMODE_CM (0x03UL << 0)
-#define USBMODE_CM_IDLE (0x00UL << 0)
-#define USBMODE_CM_DEVICE (0x02UL << 0)
-#define USBMODE_CM_HOST (0x03UL << 0)
-#define USBMODE_SLOM BIT(3)
-#define USBMODE_SDIS BIT(4)
-
-/* ENDPTCTRL */
-#define ENDPTCTRL_RXS BIT(0)
-#define ENDPTCTRL_RXT (0x03UL << 2)
-#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
-#define ENDPTCTRL_RXE BIT(7)
-#define ENDPTCTRL_TXS BIT(16)
-#define ENDPTCTRL_TXT (0x03UL << 18)
-#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
-#define ENDPTCTRL_TXE BIT(23)
-
-/******************************************************************************
- * LOGGING
- *****************************************************************************/
-#define ci13xxx_printk(level, format, args...) \
-do { \
- if (_udc == NULL) \
- printk(level "[%s] " format "\n", __func__, ## args); \
- else \
- dev_printk(level, _udc->gadget.dev.parent, \
- "[%s] " format "\n", __func__, ## args); \
-} while (0)
-
-#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args)
-#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args)
-#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args)
-
-#ifdef TRACE
-#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args)
-#define dbg_trace(format, args...) dev_dbg(dev, format, ##args)
-#else
-#define trace(format, args...) do {} while (0)
-#define dbg_trace(format, args...) do {} while (0)
-#endif
-
-#endif /* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index baaebf2..390749b 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -40,27 +40,27 @@ static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
*/
static ushort idVendor;
-module_param(idVendor, ushort, 0);
+module_param(idVendor, ushort, 0644);
MODULE_PARM_DESC(idVendor, "USB Vendor ID");
static ushort idProduct;
-module_param(idProduct, ushort, 0);
+module_param(idProduct, ushort, 0644);
MODULE_PARM_DESC(idProduct, "USB Product ID");
static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0);
+module_param(bcdDevice, ushort, 0644);
MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
static char *iManufacturer;
-module_param(iManufacturer, charp, 0);
+module_param(iManufacturer, charp, 0644);
MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
static char *iProduct;
-module_param(iProduct, charp, 0);
+module_param(iProduct, charp, 0644);
MODULE_PARM_DESC(iProduct, "USB Product string");
static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0);
+module_param(iSerialNumber, charp, 0644);
MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
static char composite_manufacturer[50];
@@ -734,9 +734,23 @@ int usb_add_config(struct usb_composite_dev *cdev,
INIT_LIST_HEAD(&config->functions);
config->next_interface_id = 0;
+ memset(config->interface, 0, sizeof(config->interface));
status = bind(config);
if (status < 0) {
+ while (!list_empty(&config->functions)) {
+ struct usb_function *f;
+
+ f = list_first_entry(&config->functions,
+ struct usb_function, list);
+ list_del(&f->list);
+ if (f->unbind) {
+ DBG(cdev, "unbind function '%s'/%p\n",
+ f->name, f);
+ f->unbind(config, f);
+ /* may free memory for "f" */
+ }
+ }
list_del(&config->list);
config->cdev = NULL;
} else {
@@ -774,6 +788,53 @@ done:
return status;
}
+static void remove_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *config)
+{
+ while (!list_empty(&config->functions)) {
+ struct usb_function *f;
+
+ f = list_first_entry(&config->functions,
+ struct usb_function, list);
+ list_del(&f->list);
+ if (f->unbind) {
+ DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+ f->unbind(config, f);
+ /* may free memory for "f" */
+ }
+ }
+ list_del(&config->list);
+ if (config->unbind) {
+ DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+ config->unbind(config);
+ /* may free memory for "c" */
+ }
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void usb_remove_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *config)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+
+ if (cdev->config == config)
+ reset_config(cdev);
+
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ remove_config(cdev, config);
+}
+
/*-------------------------------------------------------------------------*/
/* We support strings in multiple languages ... string descriptor zero
@@ -785,7 +846,7 @@ done:
static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
{
const struct usb_gadget_strings *s;
- u16 language;
+ __le16 language;
__le16 *tmp;
while (*sp) {
@@ -877,7 +938,7 @@ static int get_string(struct usb_composite_dev *cdev,
else if (cdev->product_override == id)
str = iProduct ?: composite->iProduct;
else if (cdev->serial_override == id)
- str = iSerialNumber;
+ str = iSerialNumber ?: composite->iSerialNumber;
else
str = NULL;
if (str) {
@@ -1328,28 +1389,9 @@ composite_unbind(struct usb_gadget *gadget)
while (!list_empty(&cdev->configs)) {
struct usb_configuration *c;
-
c = list_first_entry(&cdev->configs,
struct usb_configuration, list);
- while (!list_empty(&c->functions)) {
- struct usb_function *f;
-
- f = list_first_entry(&c->functions,
- struct usb_function, list);
- list_del(&f->list);
- if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n",
- f->name, f);
- f->unbind(c, f);
- /* may free memory for "f" */
- }
- }
- list_del(&c->list);
- if (c->unbind) {
- DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
- c->unbind(c);
- /* may free memory for "c" */
- }
+ remove_config(cdev, c);
}
if (composite->unbind)
composite->unbind(cdev);
@@ -1431,10 +1473,16 @@ static int composite_bind(struct usb_gadget *gadget)
/* standardized runtime overrides for device ID data */
if (idVendor)
cdev->desc.idVendor = cpu_to_le16(idVendor);
+ else
+ idVendor = le16_to_cpu(cdev->desc.idVendor);
if (idProduct)
cdev->desc.idProduct = cpu_to_le16(idProduct);
+ else
+ idProduct = le16_to_cpu(cdev->desc.idProduct);
if (bcdDevice)
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+ else
+ bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
/* string overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
@@ -1455,7 +1503,8 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->product_override =
override_id(cdev, &cdev->desc.iProduct);
- if (iSerialNumber)
+ if (iSerialNumber ||
+ (!cdev->desc.iSerialNumber && composite->iSerialNumber))
cdev->serial_override =
override_id(cdev, &cdev->desc.iSerialNumber);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 170cbe8..b799106 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -595,14 +595,12 @@ static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
- struct dummy_ep *ep;
struct dummy_request *req;
- if (!_ep || !_req)
- return;
- ep = usb_ep_to_dummy_ep(_ep);
- if (!ep->desc && _ep->name != ep0name)
+ if (!_ep || !_req) {
+ WARN_ON(1);
return;
+ }
req = usb_request_to_dummy_request(_req);
WARN_ON(!list_empty(&req->queue));
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f52cb1a..dcd1c7f 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1031,6 +1031,12 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
+ union {
+ /* set by ffs_fs_mount(), read by ffs_sb_fill() */
+ void *private_data;
+ /* set by ffs_sb_fill(), read by ffs_fs_mount */
+ struct ffs_data *ffs_data;
+ };
};
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
@@ -1047,8 +1053,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
goto Enomem;
ffs->sb = sb;
- ffs->dev_name = data->dev_name;
+ ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL);
+ if (unlikely(!ffs->dev_name))
+ goto Enomem;
ffs->file_perms = data->perms;
+ ffs->private_data = data->private_data;
+
+ /* used by the caller of this function */
+ data->ffs_data = ffs;
sb->s_fs_info = ffs;
sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -1167,20 +1179,29 @@ ffs_fs_mount(struct file_system_type *t, int flags,
},
.root_mode = S_IFDIR | 0500,
};
+ struct dentry *rv;
int ret;
+ void *ffs_dev;
ENTER();
- ret = functionfs_check_dev_callback(dev_name);
- if (unlikely(ret < 0))
- return ERR_PTR(ret);
-
ret = ffs_fs_parse_opts(&data, opts);
if (unlikely(ret < 0))
return ERR_PTR(ret);
+ ffs_dev = functionfs_acquire_dev_callback(dev_name);
+ if (IS_ERR(ffs_dev))
+ return ffs_dev;
+
data.dev_name = dev_name;
- return mount_single(t, flags, &data, ffs_sb_fill);
+ data.private_data = ffs_dev;
+ rv = mount_nodev(t, flags, &data, ffs_sb_fill);
+
+ /* data.ffs_data is set by ffs_sb_fill */
+ if (IS_ERR(rv))
+ functionfs_release_dev_callback(data.ffs_data);
+
+ return rv;
}
static void
@@ -1189,8 +1210,10 @@ ffs_fs_kill_sb(struct super_block *sb)
ENTER();
kill_litter_super(sb);
- if (sb->s_fs_info)
+ if (sb->s_fs_info) {
+ functionfs_release_dev_callback(sb->s_fs_info);
ffs_data_put(sb->s_fs_info);
+ }
}
static struct file_system_type ffs_fs_type = {
@@ -1256,6 +1279,7 @@ static void ffs_data_put(struct ffs_data *ffs)
ffs_data_clear(ffs);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait));
+ kfree(ffs->dev_name);
kfree(ffs);
}
}
@@ -1473,8 +1497,22 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev,
static void ffs_func_free(struct ffs_function *func)
{
+ struct ffs_ep *ep = func->eps;
+ unsigned count = func->ffs->eps_count;
+ unsigned long flags;
+
ENTER();
+ /* cleanup after autoconfig */
+ spin_lock_irqsave(&func->ffs->eps_lock, flags);
+ do {
+ if (ep->ep && ep->req)
+ usb_ep_free_request(ep->ep, ep->req);
+ ep->req = NULL;
+ ++ep;
+ } while (--count);
+ spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
ffs_data_put(func->ffs);
kfree(func->eps);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index b211342..3b3932c 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -374,7 +374,7 @@ static int hidg_setup(struct usb_function *f,
break;
default:
- VDBG(cdev, "Unknown decriptor request 0x%x\n",
+ VDBG(cdev, "Unknown descriptor request 0x%x\n",
value >> 8);
goto stall;
break;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 2c0cd82..7275706 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -286,7 +286,7 @@ static void disable_loopback(struct f_loopback *loop)
struct usb_composite_dev *cdev;
cdev = loop->function.config->cdev;
- disable_endpoints(cdev, loop->in_ep, loop->out_ep);
+ disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
VDBG(cdev, "%s disabled\n", loop->function.name);
}
@@ -329,7 +329,7 @@ fail0:
* than 'buflen' bytes each.
*/
for (i = 0; i < qlen && result == 0; i++) {
- req = alloc_ep_req(ep);
+ req = alloc_ep_req(ep, 0);
if (req) {
req->complete = loopback_complete;
result = usb_ep_queue(ep, req, GFP_ATOMIC);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index cb8c162..f67b453 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3110,13 +3110,6 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
return rc;
}
-static inline int __deprecated __maybe_unused
-fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c,
- struct fsg_common *common)
-{
- return fsg_bind_config(cdev, c, common);
-}
-
/************************* Module parameters *************************/
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index d4f823f..b1681e4 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -71,6 +71,8 @@ struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
u8 ethaddr[ETH_ALEN];
+ u32 vendorID;
+ const char *manufacturer;
int config;
struct usb_ep *notify;
@@ -768,12 +770,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
-#if 0
-// FIXME
- if (rndis_set_param_vendor(rndis->config, vendorID,
- manufacturer))
- goto fail0;
-#endif
+ if (rndis->manufacturer && rndis->vendorID &&
+ rndis_set_param_vendor(rndis->config, rndis->vendorID,
+ rndis->manufacturer))
+ goto fail;
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
@@ -820,6 +820,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_deregister(rndis->config);
rndis_exit();
+ rndis_string_defs[0].id = 0;
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
@@ -840,20 +841,9 @@ static inline bool can_support_rndis(struct usb_configuration *c)
return true;
}
-/**
- * rndis_bind_config - add RNDIS network link to a configuration
- * @c: the configuration to support the network link
- * @ethaddr: a buffer in which the ethernet address of the host side
- * side of the link was recorded
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gether_setup(). Caller is also responsible
- * for calling @gether_cleanup() before module unload.
- */
int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer)
{
struct f_rndis *rndis;
int status;
@@ -898,6 +888,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
goto fail;
memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+ rndis->vendorID = vendorID;
+ rndis->manufacturer = manufacturer;
/* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0;
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 7aa7ac8..5c1b68b 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -51,6 +51,9 @@ struct f_sourcesink {
struct usb_ep *in_ep;
struct usb_ep *out_ep;
+ struct usb_ep *iso_in_ep;
+ struct usb_ep *iso_out_ep;
+ int cur_alt;
};
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -59,18 +62,45 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
}
static unsigned pattern;
-module_param(pattern, uint, 0);
-MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
+
+static unsigned isoc_interval = 4;
+module_param(isoc_interval, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_interval, "1 - 16");
+
+static unsigned isoc_maxpacket = 1024;
+module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+
+static unsigned isoc_mult;
+module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
+
+static unsigned isoc_maxburst;
+module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
/*-------------------------------------------------------------------------*/
-static struct usb_interface_descriptor source_sink_intf = {
- .bLength = sizeof source_sink_intf,
+static struct usb_interface_descriptor source_sink_intf_alt0 = {
+ .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- /* .iInterface = DYNAMIC */
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_interface_descriptor source_sink_intf_alt1 = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 4,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ /* .iInterface = DYNAMIC */
};
/* full speed support: */
@@ -91,10 +121,36 @@ static struct usb_endpoint_descriptor fs_sink_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
+static struct usb_endpoint_descriptor fs_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1023),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor fs_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1023),
+ .bInterval = 4,
+};
+
static struct usb_descriptor_header *fs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define FS_ALT_IFC_1_OFFSET 3
+ (struct usb_descriptor_header *) &fs_sink_desc,
+ (struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &fs_iso_sink_desc,
+ (struct usb_descriptor_header *) &fs_iso_source_desc,
NULL,
};
@@ -116,10 +172,34 @@ static struct usb_endpoint_descriptor hs_sink_desc = {
.wMaxPacketSize = cpu_to_le16(512),
};
+static struct usb_endpoint_descriptor hs_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor hs_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
static struct usb_descriptor_header *hs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define HS_ALT_IFC_1_OFFSET 3
+ (struct usb_descriptor_header *) &hs_source_desc,
+ (struct usb_descriptor_header *) &hs_sink_desc,
+ (struct usb_descriptor_header *) &hs_iso_source_desc,
+ (struct usb_descriptor_header *) &hs_iso_sink_desc,
NULL,
};
@@ -136,6 +216,7 @@ static struct usb_endpoint_descriptor ss_source_desc = {
struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
@@ -152,17 +233,64 @@ static struct usb_endpoint_descriptor ss_sink_desc = {
struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
+static struct usb_endpoint_descriptor ss_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {
+ .bLength = USB_DT_SS_EP_COMP_SIZE,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
+ .bLength = USB_DT_SS_EP_COMP_SIZE,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
+};
+
static struct usb_descriptor_header *ss_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &ss_source_desc,
(struct usb_descriptor_header *) &ss_source_comp_desc,
(struct usb_descriptor_header *) &ss_sink_desc,
(struct usb_descriptor_header *) &ss_sink_comp_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define SS_ALT_IFC_1_OFFSET 5
+ (struct usb_descriptor_header *) &ss_source_desc,
+ (struct usb_descriptor_header *) &ss_source_comp_desc,
+ (struct usb_descriptor_header *) &ss_sink_desc,
+ (struct usb_descriptor_header *) &ss_sink_comp_desc,
+ (struct usb_descriptor_header *) &ss_iso_source_desc,
+ (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
+ (struct usb_descriptor_header *) &ss_iso_sink_desc,
+ (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
NULL,
};
@@ -196,9 +324,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
id = usb_interface_id(c, f);
if (id < 0)
return id;
- source_sink_intf.bInterfaceNumber = id;
+ source_sink_intf_alt0.bInterfaceNumber = id;
+ source_sink_intf_alt1.bInterfaceNumber = id;
- /* allocate endpoints */
+ /* allocate bulk endpoints */
ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
if (!ss->in_ep) {
autoconf_fail:
@@ -213,12 +342,74 @@ autoconf_fail:
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */
+ /* sanity check the isoc module parameters */
+ if (isoc_interval < 1)
+ isoc_interval = 1;
+ if (isoc_interval > 16)
+ isoc_interval = 16;
+ if (isoc_mult > 2)
+ isoc_mult = 2;
+ if (isoc_maxburst > 15)
+ isoc_maxburst = 15;
+
+ /* fill in the FS isoc descriptors from the module parameters */
+ fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ fs_iso_source_desc.bInterval = isoc_interval;
+ fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ fs_iso_sink_desc.bInterval = isoc_interval;
+
+ /* allocate iso endpoints */
+ ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
+ if (!ss->iso_in_ep)
+ goto no_iso;
+ ss->iso_in_ep->driver_data = cdev; /* claim */
+
+ ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
+ if (ss->iso_out_ep) {
+ ss->iso_out_ep->driver_data = cdev; /* claim */
+ } else {
+ ss->iso_in_ep->driver_data = NULL;
+ ss->iso_in_ep = NULL;
+no_iso:
+ /*
+ * We still want to work even if the UDC doesn't have isoc
+ * endpoints, so null out the alt interface that contains
+ * them and continue.
+ */
+ fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
+ hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
+ ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
+ }
+
+ if (isoc_maxpacket > 1024)
+ isoc_maxpacket = 1024;
+
/* support high speed hardware */
if (gadget_is_dualspeed(c->cdev->gadget)) {
hs_source_desc.bEndpointAddress =
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
+
+ /*
+ * Fill in the HS isoc descriptors from the module parameters.
+ * We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+ hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
+ hs_iso_source_desc.bInterval = isoc_interval;
+ hs_iso_source_desc.bEndpointAddress =
+ fs_iso_source_desc.bEndpointAddress;
+
+ hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+ hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
+ hs_iso_sink_desc.bInterval = isoc_interval;
+ hs_iso_sink_desc.bEndpointAddress =
+ fs_iso_sink_desc.bEndpointAddress;
+
f->hs_descriptors = hs_source_sink_descs;
}
@@ -228,13 +419,39 @@ autoconf_fail:
fs_source_desc.bEndpointAddress;
ss_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
+
+ /*
+ * Fill in the SS isoc descriptors from the module parameters.
+ * We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+ ss_iso_source_desc.bInterval = isoc_interval;
+ ss_iso_source_comp_desc.bmAttributes = isoc_mult;
+ ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
+ ss_iso_source_comp_desc.wBytesPerInterval =
+ isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+ ss_iso_source_desc.bEndpointAddress =
+ fs_iso_source_desc.bEndpointAddress;
+
+ ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+ ss_iso_sink_desc.bInterval = isoc_interval;
+ ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
+ ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
+ ss_iso_sink_comp_desc.wBytesPerInterval =
+ isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+ ss_iso_sink_desc.bEndpointAddress =
+ fs_iso_sink_desc.bEndpointAddress;
+
f->ss_descriptors = ss_source_sink_descs;
}
- DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
+ DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
- f->name, ss->in_ep->name, ss->out_ep->name);
+ f->name, ss->in_ep->name, ss->out_ep->name,
+ ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
+ ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
return 0;
}
@@ -251,6 +468,9 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
u8 *buf = req->buf;
struct usb_composite_dev *cdev = ss->function.config->cdev;
+ if (pattern == 2)
+ return 0;
+
for (i = 0; i < req->actual; i++, buf++) {
switch (pattern) {
@@ -265,7 +485,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
* each usb transfer request should be. Resync is done
* with set_interface or set_config. (We *WANT* it to
* get quickly out of sync if controllers or their drivers
- * stutter for any reason, including buffer duplcation...)
+ * stutter for any reason, including buffer duplication...)
*/
case 1:
if (*buf == (u8)(i % 63))
@@ -292,21 +512,30 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
for (i = 0; i < req->length; i++)
*buf++ = (u8) (i % 63);
break;
+ case 2:
+ break;
}
}
static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct f_sourcesink *ss = ep->driver_data;
- struct usb_composite_dev *cdev = ss->function.config->cdev;
- int status = req->status;
+ struct usb_composite_dev *cdev;
+ struct f_sourcesink *ss = ep->driver_data;
+ int status = req->status;
+
+ /* driver_data will be null if ep has been disabled */
+ if (!ss)
+ return;
+
+ cdev = ss->function.config->cdev;
switch (status) {
case 0: /* normal completion? */
if (ep == ss->out_ep) {
check_read_data(ss, req);
- memset(req->buf, 0x55, req->length);
+ if (pattern != 2)
+ memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
break;
@@ -344,32 +573,57 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
}
}
-static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
+static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
+ bool is_iso, int speed)
{
struct usb_ep *ep;
struct usb_request *req;
- int status;
+ int i, size, status;
+
+ for (i = 0; i < 8; i++) {
+ if (is_iso) {
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ size = isoc_maxpacket * (isoc_mult + 1) *
+ (isoc_maxburst + 1);
+ break;
+ case USB_SPEED_HIGH:
+ size = isoc_maxpacket * (isoc_mult + 1);
+ break;
+ default:
+ size = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ break;
+ }
+ ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
+ req = alloc_ep_req(ep, size);
+ } else {
+ ep = is_in ? ss->in_ep : ss->out_ep;
+ req = alloc_ep_req(ep, 0);
+ }
- ep = is_in ? ss->in_ep : ss->out_ep;
- req = alloc_ep_req(ep);
- if (!req)
- return -ENOMEM;
+ if (!req)
+ return -ENOMEM;
- req->complete = source_sink_complete;
- if (is_in)
- reinit_write_data(ep, req);
- else
- memset(req->buf, 0x55, req->length);
+ req->complete = source_sink_complete;
+ if (is_in)
+ reinit_write_data(ep, req);
+ else if (pattern != 2)
+ memset(req->buf, 0x55, req->length);
- status = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (status) {
- struct usb_composite_dev *cdev;
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (status) {
+ struct usb_composite_dev *cdev;
- cdev = ss->function.config->cdev;
- ERROR(cdev, "start %s %s --> %d\n",
- is_in ? "IN" : "OUT",
- ep->name, status);
- free_ep_req(ep, req);
+ cdev = ss->function.config->cdev;
+ ERROR(cdev, "start %s%s %s --> %d\n",
+ is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+ ep->name, status);
+ free_ep_req(ep, req);
+ }
+
+ if (!is_iso)
+ break;
}
return status;
@@ -380,17 +634,20 @@ static void disable_source_sink(struct f_sourcesink *ss)
struct usb_composite_dev *cdev;
cdev = ss->function.config->cdev;
- disable_endpoints(cdev, ss->in_ep, ss->out_ep);
+ disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
+ ss->iso_out_ep);
VDBG(cdev, "%s disabled\n", ss->function.name);
}
static int
-enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
+enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
+ int alt)
{
int result = 0;
+ int speed = cdev->gadget->speed;
struct usb_ep *ep;
- /* one endpoint writes (sources) zeroes IN (to the host) */
+ /* one bulk endpoint writes (sources) zeroes IN (to the host) */
ep = ss->in_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
@@ -400,7 +657,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
return result;
ep->driver_data = ss;
- result = source_sink_start_ep(ss, true);
+ result = source_sink_start_ep(ss, true, false, speed);
if (result < 0) {
fail:
ep = ss->in_ep;
@@ -409,7 +666,7 @@ fail:
return result;
}
- /* one endpoint reads (sinks) anything OUT (from the host) */
+ /* one bulk endpoint reads (sinks) anything OUT (from the host) */
ep = ss->out_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
@@ -419,27 +676,82 @@ fail:
goto fail;
ep->driver_data = ss;
- result = source_sink_start_ep(ss, false);
+ result = source_sink_start_ep(ss, false, false, speed);
if (result < 0) {
+fail2:
+ ep = ss->out_ep;
usb_ep_disable(ep);
ep->driver_data = NULL;
goto fail;
}
- DBG(cdev, "%s enabled\n", ss->function.name);
+ if (alt == 0)
+ goto out;
+
+ /* one iso endpoint writes (sources) zeroes IN (to the host) */
+ ep = ss->iso_in_ep;
+ if (ep) {
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ goto fail2;
+ result = usb_ep_enable(ep);
+ if (result < 0)
+ goto fail2;
+ ep->driver_data = ss;
+
+ result = source_sink_start_ep(ss, true, true, speed);
+ if (result < 0) {
+fail3:
+ ep = ss->iso_in_ep;
+ if (ep) {
+ usb_ep_disable(ep);
+ ep->driver_data = NULL;
+ }
+ goto fail2;
+ }
+ }
+
+ /* one iso endpoint reads (sinks) anything OUT (from the host) */
+ ep = ss->iso_out_ep;
+ if (ep) {
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ goto fail3;
+ result = usb_ep_enable(ep);
+ if (result < 0)
+ goto fail3;
+ ep->driver_data = ss;
+
+ result = source_sink_start_ep(ss, false, true, speed);
+ if (result < 0) {
+ usb_ep_disable(ep);
+ ep->driver_data = NULL;
+ goto fail3;
+ }
+ }
+out:
+ ss->cur_alt = alt;
+
+ DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt);
return result;
}
static int sourcesink_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
- struct f_sourcesink *ss = func_to_ss(f);
- struct usb_composite_dev *cdev = f->config->cdev;
+ struct f_sourcesink *ss = func_to_ss(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
- /* we know alt is zero */
if (ss->in_ep->driver_data)
disable_source_sink(ss);
- return enable_source_sink(cdev, ss);
+ return enable_source_sink(cdev, ss, alt);
+}
+
+static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_sourcesink *ss = func_to_ss(f);
+
+ return ss->cur_alt;
}
static void sourcesink_disable(struct usb_function *f)
@@ -465,6 +777,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
ss->function.bind = sourcesink_bind;
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
+ ss->function.get_alt = sourcesink_get_alt;
ss->function.disable = sourcesink_disable;
status = usb_add_function(c, &ss->function);
@@ -536,7 +849,7 @@ unknown:
req->length = value;
value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
- ERROR(c->cdev, "source/sinkc response, err %d\n",
+ ERROR(c->cdev, "source/sink response, err %d\n",
value);
}
@@ -545,12 +858,12 @@ unknown:
}
static struct usb_configuration sourcesink_driver = {
- .label = "source/sink",
- .strings = sourcesink_strings,
- .setup = sourcesink_setup,
- .bConfigurationValue = 3,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- /* .iConfiguration = DYNAMIC */
+ .label = "source/sink",
+ .strings = sourcesink_strings,
+ .setup = sourcesink_setup,
+ .bConfigurationValue = 3,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ /* .iConfiguration = DYNAMIC */
};
/**
@@ -567,7 +880,8 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
return id;
strings_sourcesink[0].id = id;
- source_sink_intf.iInterface = id;
+ source_sink_intf_alt0.iInterface = id;
+ source_sink_intf_alt1.iInterface = id;
sourcesink_driver.iConfiguration = id;
/* support autoresume for remote wakeup testing */
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 877a2c4..51881f3 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -71,9 +71,6 @@ static struct usb_endpoint_descriptor qe_ep0_desc = {
.wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
};
-/* it is initialized in probe() */
-static struct qe_udc *udc_controller;
-
/********************************************************************
* Internal Used Function Start
********************************************************************/
@@ -188,8 +185,8 @@ 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;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
return 0;
}
@@ -450,13 +447,13 @@ static int qe_ep_rxbd_update(struct qe_ep *ep)
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->rxbuf_d = dma_map_single(ep->udc->gadget.dev.parent,
ep->rxbuffer,
size,
DMA_FROM_DEVICE);
ep->rxbufmap = 1;
} else {
- dma_sync_single_for_device(udc_controller->gadget.dev.parent,
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
ep->rxbufmap = 0;
@@ -489,10 +486,10 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num)
epparam = udc->ep_param[pipe_num];
usep = 0;
- logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ logepnum = (ep->ep.desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
usep |= (logepnum << USB_EPNUM_SHIFT);
- switch (ep->desc->bmAttributes & 0x03) {
+ switch (ep->ep.desc->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
usep |= USB_TRANS_BULK;
break;
@@ -644,7 +641,7 @@ static int qe_ep_init(struct qe_udc *udc,
/* initialize ep structure */
ep->ep.maxpacket = max;
ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
ep->init = 1;
@@ -698,14 +695,14 @@ en_done:
return -ENODEV;
}
-static inline void qe_usb_enable(void)
+static inline void qe_usb_enable(struct qe_udc *udc)
{
- setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+ setbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
}
-static inline void qe_usb_disable(void)
+static inline void qe_usb_disable(struct qe_udc *udc)
{
- clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+ clrbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
}
/*----------------------------------------------------------------------------*
@@ -1599,7 +1596,7 @@ static int qe_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct qe_ep, ep);
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+ if (!_ep || !desc || ep->ep.desc || _ep->name == ep_name[0] ||
(desc->bDescriptorType != USB_DT_ENDPOINT))
return -EINVAL;
@@ -1629,7 +1626,7 @@ static int qe_ep_disable(struct usb_ep *_ep)
ep = container_of(_ep, struct qe_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -1637,7 +1634,6 @@ static int qe_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&udc->lock, flags);
/* Nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->tx_req = NULL;
@@ -1656,13 +1652,13 @@ static int qe_ep_disable(struct usb_ep *_ep)
if (ep->dir != USB_DIR_IN) {
kfree(ep->rxframe);
if (ep->rxbufmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
+ dma_unmap_single(udc->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,
+ udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
}
@@ -1715,7 +1711,7 @@ static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req)
dev_dbg(udc->dev, "bad params\n");
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep_index(ep))) {
+ if (!_ep || (!ep->ep.desc && ep_index(ep))) {
dev_dbg(udc->dev, "bad ep\n");
return -EINVAL;
}
@@ -1826,7 +1822,7 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value)
struct qe_udc *udc;
ep = container_of(_ep, struct qe_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
@@ -1880,9 +1876,10 @@ static struct usb_ep_ops qe_ep_ops = {
/* Get the current frame number */
static int qe_get_frame(struct usb_gadget *gadget)
{
+ struct qe_udc *udc = container_of(gadget, struct qe_udc, gadget);
u16 tmp;
- tmp = in_be16(&udc_controller->usb_param->frame_n);
+ tmp = in_be16(&udc->usb_param->frame_n);
if (tmp & 0x8000)
tmp = tmp & 0x07ff;
else
@@ -1891,57 +1888,16 @@ static int qe_get_frame(struct usb_gadget *gadget)
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;
-}
-
-static int fsl_qe_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int fsl_qe_stop(struct usb_gadget_driver *driver);
+static int fsl_qe_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int fsl_qe_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
/* 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,
- .start = fsl_qe_start,
- .stop = fsl_qe_stop,
+ .udc_start = fsl_qe_start,
+ .udc_stop = fsl_qe_stop,
};
/*-------------------------------------------------------------------------
@@ -2015,7 +1971,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
u16 usep;
/* stall if endpoint doesn't exist */
- if (!target_ep->desc)
+ if (!target_ep->ep.desc)
goto stall;
usep = in_be16(&udc->usb_regs->usb_usep[pipe]);
@@ -2190,7 +2146,7 @@ static int reset_irq(struct qe_udc *udc)
if (udc->usb_state == USB_STATE_DEFAULT)
return 0;
- qe_usb_disable();
+ qe_usb_disable(udc);
out_8(&udc->usb_regs->usb_usadr, 0);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
@@ -2202,7 +2158,7 @@ static int reset_irq(struct qe_udc *udc)
udc->usb_state = USB_STATE_DEFAULT;
udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = USB_DIR_OUT;
- qe_usb_enable();
+ qe_usb_enable(udc);
return 0;
}
@@ -2327,92 +2283,65 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
/*-------------------------------------------------------------------------
Gadget driver probe and unregister.
--------------------------------------------------------------------------*/
-static int fsl_qe_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int fsl_qe_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- int retval;
- unsigned long flags = 0;
-
- /* standard operations */
- if (!udc_controller)
- return -ENODEV;
-
- if (!driver || driver->max_speed < USB_SPEED_FULL
- || !bind || !driver->disconnect || !driver->setup)
- return -EINVAL;
-
- if (udc_controller->driver)
- return -EBUSY;
+ struct qe_udc *udc;
+ unsigned long flags;
+ udc = container_of(gadget, struct qe_udc, gadget);
/* lock is needed but whether should use this lock or another */
- spin_lock_irqsave(&udc_controller->lock, flags);
+ spin_lock_irqsave(&udc->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 = driver->max_speed;
- spin_unlock_irqrestore(&udc_controller->lock, flags);
-
- retval = 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;
- }
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ udc->gadget.speed = driver->max_speed;
/* 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);
+ qe_usb_enable(udc);
+
+ out_be16(&udc->usb_regs->usb_usber, 0xffff);
+ out_be16(&udc->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = USB_DIR_OUT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name,
+ driver->driver.name);
return 0;
}
-static int fsl_qe_stop(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
+ struct qe_udc *udc;
struct qe_ep *loop_ep;
unsigned long flags;
- if (!udc_controller)
- return -ENODEV;
-
- if (!driver || driver != udc_controller->driver)
- return -EINVAL;
-
+ udc = container_of(gadget, struct qe_udc, gadget);
/* stop usb controller, disable intr */
- qe_usb_disable();
+ qe_usb_disable(udc);
/* in fact, no needed */
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->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)
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc->gadget.ep_list, ep.ep_list)
nuke(loop_ep, -ESHUTDOWN);
- spin_unlock_irqrestore(&udc_controller->lock, flags);
-
- /* report disconnect; the controller is already quiesced */
- driver->disconnect(&udc_controller->gadget);
+ spin_unlock_irqrestore(&udc->lock, flags);
- /* unbind gadget and unhook driver. */
- driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = NULL;
- udc_controller->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
- dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n",
+ dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
driver->driver.name);
return 0;
}
@@ -2502,7 +2431,7 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
ep->ep.ops = &qe_ep_ops;
ep->stopped = 1;
ep->ep.maxpacket = (unsigned short) ~0;
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->dir = 0xff;
ep->epnum = (u8)pipe_num;
ep->sent = 0;
@@ -2531,21 +2460,22 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
*----------------------------------------------------------------------*/
static void qe_udc_release(struct device *dev)
{
- int i = 0;
+ struct qe_udc *udc = container_of(dev, struct qe_udc, gadget.dev);
+ int i;
- complete(udc_controller->done);
- cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0]));
+ complete(udc->done);
+ cpm_muram_free(cpm_muram_offset(udc->ep_param[0]));
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- udc_controller->ep_param[i] = NULL;
+ udc->ep_param[i] = NULL;
- kfree(udc_controller);
- udc_controller = NULL;
+ kfree(udc);
}
/* Driver probe functions */
static const struct of_device_id qe_udc_match[];
static int __devinit qe_udc_probe(struct platform_device *ofdev)
{
+ struct qe_udc *udc;
const struct of_device_id *match;
struct device_node *np = ofdev->dev.of_node;
struct qe_ep *ep;
@@ -2562,44 +2492,44 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
return -ENODEV;
/* Initialize the udc structure including QH member and other member */
- udc_controller = qe_udc_config(ofdev);
- if (!udc_controller) {
+ udc = qe_udc_config(ofdev);
+ if (!udc) {
dev_err(&ofdev->dev, "failed to initialize\n");
return -ENOMEM;
}
- udc_controller->soc_type = (unsigned long)match->data;
- udc_controller->usb_regs = of_iomap(np, 0);
- if (!udc_controller->usb_regs) {
+ udc->soc_type = (unsigned long)match->data;
+ udc->usb_regs = of_iomap(np, 0);
+ if (!udc->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);
+ qe_udc_reg_init(udc);
/* here comes the stand operations for probe
* set the qe_udc->gadget.xxx */
- udc_controller->gadget.ops = &qe_gadget_ops;
+ udc->gadget.ops = &qe_gadget_ops;
/* gadget.ep0 is a pointer */
- udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+ udc->gadget.ep0 = &udc->eps[0].ep;
- INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
/* modify in register gadget process */
- udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
/* name: Identifies the controller hardware type. */
- udc_controller->gadget.name = driver_name;
+ udc->gadget.name = driver_name;
- device_initialize(&udc_controller->gadget.dev);
+ device_initialize(&udc->gadget.dev);
- dev_set_name(&udc_controller->gadget.dev, "gadget");
+ dev_set_name(&udc->gadget.dev, "gadget");
- udc_controller->gadget.dev.release = qe_udc_release;
- udc_controller->gadget.dev.parent = &ofdev->dev;
+ udc->gadget.dev.release = qe_udc_release;
+ udc->gadget.dev.parent = &ofdev->dev;
/* initialize qe_ep struct */
for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
@@ -2608,104 +2538,104 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
/* setup the qe_ep struct and link ep.ep.list
* into gadget.ep_list */
- qe_ep_config(udc_controller, (unsigned char)i);
+ qe_ep_config(udc, (unsigned char)i);
}
/* ep0 initialization in here */
- ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc);
+ ret = qe_ep_init(udc, 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_err(udc_controller->dev, "cannot alloc nullbuf\n");
+ udc->nullbuf = kzalloc(256, GFP_KERNEL);
+ if (udc->nullbuf == NULL) {
+ dev_err(udc->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) {
+ udc->statusbuf = kzalloc(2, GFP_KERNEL);
+ if (udc->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,
+ udc->nullp = virt_to_phys((void *)udc->nullbuf);
+ if (udc->nullp == DMA_ADDR_INVALID) {
+ udc->nullp = dma_map_single(
+ udc->gadget.dev.parent,
+ udc->nullbuf,
256,
DMA_TO_DEVICE);
- udc_controller->nullmap = 1;
+ udc->nullmap = 1;
} else {
- dma_sync_single_for_device(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_device(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet,
- (unsigned long)udc_controller);
+ tasklet_init(&udc->rx_tasklet, ep_rx_tasklet,
+ (unsigned long)udc);
/* request irq and disable DR */
- udc_controller->usb_irq = irq_of_parse_and_map(np, 0);
- if (!udc_controller->usb_irq) {
+ udc->usb_irq = irq_of_parse_and_map(np, 0);
+ if (!udc->usb_irq) {
ret = -EINVAL;
goto err_noirq;
}
- ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0,
- driver_name, udc_controller);
+ ret = request_irq(udc->usb_irq, qe_udc_irq, 0,
+ driver_name, udc);
if (ret) {
- dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
- udc_controller->usb_irq, ret);
+ dev_err(udc->dev, "cannot request irq %d err %d\n",
+ udc->usb_irq, ret);
goto err5;
}
- ret = device_add(&udc_controller->gadget.dev);
+ ret = device_add(&udc->gadget.dev);
if (ret)
goto err6;
- ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+ ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
if (ret)
goto err7;
- dev_info(udc_controller->dev,
+ dev_set_drvdata(&ofdev->dev, udc);
+ dev_info(udc->dev,
"%s USB controller initialized as device\n",
- (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
+ (udc->soc_type == PORT_QE) ? "QE" : "CPM");
return 0;
err7:
- device_unregister(&udc_controller->gadget.dev);
+ device_unregister(&udc->gadget.dev);
err6:
- free_irq(udc_controller->usb_irq, udc_controller);
+ free_irq(udc->usb_irq, udc);
err5:
- irq_dispose_mapping(udc_controller->usb_irq);
+ irq_dispose_mapping(udc->usb_irq);
err_noirq:
- if (udc_controller->nullmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ if (udc->nullmap) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
- udc_controller->nullp = DMA_ADDR_INVALID;
+ udc->nullp = DMA_ADDR_INVALID;
} else {
- dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- kfree(udc_controller->statusbuf);
+ kfree(udc->statusbuf);
err4:
- kfree(udc_controller->nullbuf);
+ kfree(udc->nullbuf);
err3:
- ep = &udc_controller->eps[0];
+ ep = &udc->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);
+ iounmap(udc->usb_regs);
err1:
- kfree(udc_controller);
- udc_controller = NULL;
+ kfree(udc);
return ret;
}
@@ -2723,44 +2653,41 @@ static int qe_udc_resume(struct platform_device *dev)
static int __devexit qe_udc_remove(struct platform_device *ofdev)
{
+ struct qe_udc *udc = dev_get_drvdata(&ofdev->dev);
struct qe_ep *ep;
unsigned int size;
-
DECLARE_COMPLETION(done);
- if (!udc_controller)
- return -ENODEV;
-
- usb_del_gadget_udc(&udc_controller->gadget);
+ usb_del_gadget_udc(&udc->gadget);
- udc_controller->done = &done;
- tasklet_disable(&udc_controller->rx_tasklet);
+ udc->done = &done;
+ tasklet_disable(&udc->rx_tasklet);
- if (udc_controller->nullmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ if (udc->nullmap) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
- udc_controller->nullp = DMA_ADDR_INVALID;
+ udc->nullp = DMA_ADDR_INVALID;
} else {
- dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- kfree(udc_controller->statusbuf);
- kfree(udc_controller->nullbuf);
+ kfree(udc->statusbuf);
+ kfree(udc->nullbuf);
- ep = &udc_controller->eps[0];
+ ep = &udc->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,
+ dma_unmap_single(udc->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,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
}
@@ -2768,14 +2695,14 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)
kfree(ep->rxbuffer);
kfree(ep->txframe);
- free_irq(udc_controller->usb_irq, udc_controller);
- irq_dispose_mapping(udc_controller->usb_irq);
+ free_irq(udc->usb_irq, udc);
+ irq_dispose_mapping(udc->usb_irq);
- tasklet_kill(&udc_controller->rx_tasklet);
+ tasklet_kill(&udc->rx_tasklet);
- iounmap(udc_controller->usb_regs);
+ iounmap(udc->usb_regs);
- device_unregister(&udc_controller->gadget.dev);
+ device_unregister(&udc->gadget.dev);
/* wait for release() of gadget.dev to free udc */
wait_for_completion(&done);
diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h
index 1da5fb0..4c07ca9 100644
--- a/drivers/usb/gadget/fsl_qe_udc.h
+++ b/drivers/usb/gadget/fsl_qe_udc.h
@@ -266,7 +266,6 @@ 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;
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 55abfb6..2831685 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc.
* All rights reserved.
*
* Author: Li Yang <leoli@freescale.com>
@@ -58,9 +58,8 @@ static const char driver_name[] = "fsl-usb2-udc";
static const char driver_desc[] = DRIVER_DESC;
static struct usb_dr_device *dr_regs;
-#ifndef CONFIG_ARCH_MXC
+
static struct usb_sys_interface *usb_sys_regs;
-#endif
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
@@ -244,10 +243,9 @@ static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp, portctrl, ep_num;
unsigned int max_no_of_ep;
-#ifndef CONFIG_ARCH_MXC
unsigned int ctrl;
-#endif
unsigned long timeout;
+
#define FSL_UDC_RESET_TIMEOUT 1000
/* Config PHY interface */
@@ -255,12 +253,32 @@ static int dr_controller_setup(struct fsl_udc *udc)
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ ctrl = __raw_readl(&usb_sys_regs->control);
+ ctrl &= ~USB_CTRL_UTMI_PHY_EN;
+ ctrl |= USB_CTRL_USB_EN;
+ __raw_writel(ctrl, &usb_sys_regs->control);
+ }
+ }
portctrl |= PORTSCX_PTS_ULPI;
break;
case FSL_USB2_PHY_UTMI_WIDE:
portctrl |= PORTSCX_PTW_16BIT;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ ctrl = __raw_readl(&usb_sys_regs->control);
+ ctrl |= (USB_CTRL_UTMI_PHY_EN |
+ USB_CTRL_USB_EN);
+ __raw_writel(ctrl, &usb_sys_regs->control);
+ mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
+ PHY CLK to become stable - 10ms*/
+ }
+ }
portctrl |= PORTSCX_PTS_UTMI;
break;
case FSL_USB2_PHY_SERIAL:
@@ -549,7 +567,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct fsl_ep, ep);
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| (desc->bDescriptorType != USB_DT_ENDPOINT))
return -EINVAL;
@@ -590,7 +608,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
spin_lock_irqsave(&udc->lock, flags);
ep->ep.maxpacket = max;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
/* Controller related setup */
@@ -614,7 +632,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
retval = 0;
VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
- ep->desc->bEndpointAddress & 0x0f,
+ ep->ep.desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN)
? "in" : "out", max);
en_done:
@@ -634,7 +652,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
int ep_num;
ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -657,7 +675,6 @@ static int fsl_ep_disable(struct usb_ep *_ep)
/* nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -736,6 +753,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
lastreq->tail->next_td_ptr =
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
+ /* Ensure dTD's next dtd pointer to be updated */
+ wmb();
/* Read prime bit, if 1 goto done */
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
return;
@@ -874,11 +893,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
VDBG("%s, bad params", __func__);
return -EINVAL;
}
- if (unlikely(!_ep || !ep->desc)) {
+ if (unlikely(!_ep || !ep->ep.desc)) {
VDBG("%s, bad ep", __func__);
return -EINVAL;
}
- if (usb_endpoint_xfer_isoc(ep->desc)) {
+ if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
}
@@ -1017,12 +1036,12 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct fsl_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
- if (usb_endpoint_xfer_isoc(ep->desc)) {
+ if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
status = -EOPNOTSUPP;
goto out;
}
@@ -1061,7 +1080,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
struct ep_queue_head *qh;
ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || (!ep->desc && ep_index(ep) != 0))
+ if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
return -ENODEV;
udc = (struct fsl_udc *)ep->udc;
@@ -1094,7 +1113,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep)
return;
} else {
ep = container_of(_ep, struct fsl_ep, ep);
- if (!ep->desc)
+ if (!ep->ep.desc)
return;
}
ep_num = ep_index(ep);
@@ -1349,7 +1368,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
/* stall if endpoint doesn't exist */
- if (!target_ep->desc)
+ if (!target_ep->ep.desc)
goto stall;
tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))
<< USB_ENDPOINT_HALT;
@@ -2259,7 +2278,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
}
/* other gadget->eplist ep */
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
+ if (ep->ep.desc) {
t = scnprintf(next, size,
"\nFor %s Maxpkt is 0x%x "
"index is 0x%x\n",
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index e651469..5cd7b7e 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -1,4 +1,12 @@
/*
+ * Copyright (C) 2004,2012 Freescale Semiconductor, Inc
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* Freescale USB device/endpoint management registers
*/
#ifndef __FSL_USB2_UDC_H
@@ -348,6 +356,9 @@ struct usb_sys_interface {
/* control Register Bit Masks */
#define USB_CTRL_IOENB 0x00000004
#define USB_CTRL_ULPI_INT0EN 0x00000001
+#define USB_CTRL_UTMI_PHY_EN 0x00000200
+#define USB_CTRL_USB_EN 0x00000004
+#define USB_CTRL_ULPI_PHY_CLK_SEL 0x00000400
/* Endpoint Queue Head data struct
* Rem: all the variables of qh are LittleEndian Mode
@@ -450,7 +461,6 @@ struct fsl_ep {
struct list_head queue;
struct fsl_udc *udc;
struct ep_queue_head *qh;
- const struct usb_endpoint_descriptor *desc;
struct usb_gadget *gadget;
char name[14];
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 5831cb4..cdd9454 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -203,7 +203,7 @@ static int config_ep(struct fusb300_ep *ep,
struct fusb300 *fusb300 = ep->fusb300;
struct fusb300_ep_info info;
- ep->desc = desc;
+ ep->ep.desc = desc;
info.interval = 0;
info.addrofs = 0;
@@ -443,7 +443,7 @@ static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* ep0 */
+ if (ep->ep.desc == NULL) /* ep0 */
ep0_queue(ep, req);
else if (request && !ep->stall)
enable_fifo_int(ep);
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index 92745bd..542cd83 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -650,7 +650,6 @@ struct fusb300_ep {
unsigned char epnum;
unsigned char type;
- const struct usb_endpoint_descriptor *desc;
};
struct fusb300 {
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index a85eaf4..d3ace90 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -67,6 +67,15 @@ MODULE_LICENSE("GPL");
#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
+#define GFS_MAX_DEVS 10
+
+struct gfs_ffs_obj {
+ const char *name;
+ bool mounted;
+ bool desc_ready;
+ struct ffs_data *ffs_data;
+};
+
static struct usb_device_descriptor gfs_dev_desc = {
.bLength = sizeof gfs_dev_desc,
.bDescriptorType = USB_DT_DEVICE,
@@ -78,12 +87,17 @@ static struct usb_device_descriptor gfs_dev_desc = {
.idProduct = cpu_to_le16(GFS_PRODUCT_ID),
};
+static char *func_names[GFS_MAX_DEVS];
+static unsigned int func_num;
+
module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644);
MODULE_PARM_DESC(bDeviceClass, "USB Device class");
module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
+module_param_array_named(functions, func_names, charp, &func_num, 0);
+MODULE_PARM_DESC(functions, "USB Functions list");
static const struct usb_descriptor_header *gfs_otg_desc[] = {
(const struct usb_descriptor_header *)
@@ -158,13 +172,34 @@ static struct usb_composite_driver gfs_driver = {
.iProduct = DRIVER_DESC,
};
-static struct ffs_data *gfs_ffs_data;
-static unsigned long gfs_registered;
+static DEFINE_MUTEX(gfs_lock);
+static unsigned int missing_funcs;
+static bool gfs_ether_setup;
+static bool gfs_registered;
+static bool gfs_single_func;
+static struct gfs_ffs_obj *ffs_tab;
static int __init gfs_init(void)
{
+ int i;
+
ENTER();
+ if (!func_num) {
+ gfs_single_func = true;
+ func_num = 1;
+ }
+
+ ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
+ if (!ffs_tab)
+ return -ENOMEM;
+
+ if (!gfs_single_func)
+ for (i = 0; i < func_num; i++)
+ ffs_tab[i].name = func_names[i];
+
+ missing_funcs = func_num;
+
return functionfs_init();
}
module_init(gfs_init);
@@ -172,63 +207,165 @@ module_init(gfs_init);
static void __exit gfs_exit(void)
{
ENTER();
+ mutex_lock(&gfs_lock);
- if (test_and_clear_bit(0, &gfs_registered))
+ if (gfs_registered)
usb_composite_unregister(&gfs_driver);
+ gfs_registered = false;
functionfs_cleanup();
+
+ mutex_unlock(&gfs_lock);
+ kfree(ffs_tab);
}
module_exit(gfs_exit);
+static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name)
+{
+ int i;
+
+ ENTER();
+
+ if (gfs_single_func)
+ return &ffs_tab[0];
+
+ for (i = 0; i < func_num; i++)
+ if (strcmp(ffs_tab[i].name, dev_name) == 0)
+ return &ffs_tab[i];
+
+ return NULL;
+}
+
static int functionfs_ready_callback(struct ffs_data *ffs)
{
+ struct gfs_ffs_obj *ffs_obj;
int ret;
ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (WARN_ON(ffs_obj->desc_ready)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->desc_ready = true;
+ ffs_obj->ffs_data = ffs;
- if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
- return -EBUSY;
+ if (--missing_funcs) {
+ ret = 0;
+ goto done;
+ }
+
+ if (gfs_registered) {
+ ret = -EBUSY;
+ goto done;
+ }
+ gfs_registered = true;
- gfs_ffs_data = ffs;
ret = usb_composite_probe(&gfs_driver, gfs_bind);
if (unlikely(ret < 0))
- clear_bit(0, &gfs_registered);
+ gfs_registered = false;
+
+done:
+ mutex_unlock(&gfs_lock);
return ret;
}
static void functionfs_closed_callback(struct ffs_data *ffs)
{
+ struct gfs_ffs_obj *ffs_obj;
+
ENTER();
+ mutex_lock(&gfs_lock);
- if (test_and_clear_bit(0, &gfs_registered))
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj)
+ goto done;
+
+ ffs_obj->desc_ready = false;
+ missing_funcs++;
+
+ if (gfs_registered)
usb_composite_unregister(&gfs_driver);
+ gfs_registered = false;
+
+done:
+ mutex_unlock(&gfs_lock);
}
-static int functionfs_check_dev_callback(const char *dev_name)
+static void *functionfs_acquire_dev_callback(const char *dev_name)
{
- return 0;
+ struct gfs_ffs_obj *ffs_dev;
+
+ ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_dev = gfs_find_dev(dev_name);
+ if (!ffs_dev) {
+ ffs_dev = ERR_PTR(-ENODEV);
+ goto done;
+ }
+
+ if (ffs_dev->mounted) {
+ ffs_dev = ERR_PTR(-EBUSY);
+ goto done;
+ }
+ ffs_dev->mounted = true;
+
+done:
+ mutex_unlock(&gfs_lock);
+ return ffs_dev;
}
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+ struct gfs_ffs_obj *ffs_dev;
+
+ ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_dev = ffs_data->private_data;
+ if (ffs_dev)
+ ffs_dev->mounted = false;
+
+ mutex_unlock(&gfs_lock);
+}
+
+/*
+ * It is assumed that gfs_bind is called from a context where gfs_lock is held
+ */
static int gfs_bind(struct usb_composite_dev *cdev)
{
int ret, i;
ENTER();
- if (WARN_ON(!gfs_ffs_data))
+ if (missing_funcs)
return -ENODEV;
ret = gether_setup(cdev->gadget, gfs_hostaddr);
if (unlikely(ret < 0))
goto error_quick;
+ gfs_ether_setup = true;
ret = usb_string_ids_tab(cdev, gfs_strings);
if (unlikely(ret < 0))
goto error;
- ret = functionfs_bind(gfs_ffs_data, cdev);
- if (unlikely(ret < 0))
- goto error;
+ for (i = func_num; --i; ) {
+ ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
+ if (unlikely(ret < 0)) {
+ while (++i < func_num)
+ functionfs_unbind(ffs_tab[i].ffs_data);
+ goto error;
+ }
+ }
for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
struct gfs_configuration *c = gfs_configurations + i;
@@ -246,16 +383,22 @@ static int gfs_bind(struct usb_composite_dev *cdev)
return 0;
error_unbind:
- functionfs_unbind(gfs_ffs_data);
+ for (i = 0; i < func_num; i++)
+ functionfs_unbind(ffs_tab[i].ffs_data);
error:
gether_cleanup();
error_quick:
- gfs_ffs_data = NULL;
+ gfs_ether_setup = false;
return ret;
}
+/*
+ * It is assumed that gfs_unbind is called from a context where gfs_lock is held
+ */
static int gfs_unbind(struct usb_composite_dev *cdev)
{
+ int i;
+
ENTER();
/*
@@ -266,22 +409,29 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
* from composite on orror recovery, but what you're gonna
* do...?
*/
- if (gfs_ffs_data) {
+ if (gfs_ether_setup)
gether_cleanup();
- functionfs_unbind(gfs_ffs_data);
- gfs_ffs_data = NULL;
- }
+ gfs_ether_setup = false;
+
+ for (i = func_num; --i; )
+ if (ffs_tab[i].ffs_data)
+ functionfs_unbind(ffs_tab[i].ffs_data);
return 0;
}
+/*
+ * It is assumed that gfs_do_config is called from a context where
+ * gfs_lock is held
+ */
static int gfs_do_config(struct usb_configuration *c)
{
struct gfs_configuration *gc =
container_of(c, struct gfs_configuration, c);
+ int i;
int ret;
- if (WARN_ON(!gfs_ffs_data))
+ if (missing_funcs)
return -ENODEV;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -295,9 +445,11 @@ static int gfs_do_config(struct usb_configuration *c)
return ret;
}
- ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
- if (unlikely(ret < 0))
- return ret;
+ for (i = 0; i < func_num; i++) {
+ ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
+ if (unlikely(ret < 0))
+ return ret;
+ }
/*
* After previous do_configs there may be some invalid
diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h
index e84b3c4..71ca193 100644
--- a/drivers/usb/gadget/g_zero.h
+++ b/drivers/usb/gadget/g_zero.h
@@ -13,10 +13,11 @@ extern unsigned buflen;
extern const struct usb_descriptor_header *otg_desc[];
/* common utilities */
-struct usb_request *alloc_ep_req(struct usb_ep *ep);
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
void free_ep_req(struct usb_ep *ep, struct usb_request *req);
void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out);
+ struct usb_ep *in, struct usb_ep *out,
+ struct usb_ep *iso_in, struct usb_ep *iso_out);
/* configuration-specific linkup */
int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index a8855d0..b8b3a34 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -37,6 +37,7 @@
#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name))
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
+#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name))
#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name))
#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name))
@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x31;
else if (gadget_is_dwc3(gadget))
return 0x32;
+ else if (gadget_is_lpc32xx(gadget))
+ return 0x33;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index e151d6b..b241e6c 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -102,7 +102,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
dev = ep->dev;
@@ -176,7 +176,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
command(ep->dev->regs, COMMAND_RESET, ep->num);
ep->ep.maxpacket = max;
ep->stopped = 0;
- ep->desc = desc;
+ ep->ep.desc = desc;
spin_unlock_irqrestore(&ep->dev->lock, flags);
DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name,
@@ -233,7 +233,6 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
}
ep->ep.maxpacket = MAX_FIFO_SIZE;
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->irqs = 0;
@@ -247,7 +246,7 @@ static int goku_ep_disable(struct usb_ep *_ep)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !ep->desc)
+ if (!_ep || !ep->ep.desc)
return -ENODEV;
dev = ep->dev;
if (dev->ep0state == EP0_SUSPEND)
@@ -722,7 +721,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|| !_req->buf || !list_empty(&req->queue)))
return -EINVAL;
ep = container_of(_ep, struct goku_ep, ep);
- if (unlikely(!_ep || (!ep->desc && ep->num != 0)))
+ if (unlikely(!_ep || (!ep->ep.desc && ep->num != 0)))
return -EINVAL;
dev = ep->dev;
if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
@@ -815,7 +814,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !_req || (!ep->desc && ep->num != 0))
+ if (!_ep || !_req || (!ep->ep.desc && ep->num != 0))
return -EINVAL;
dev = ep->dev;
if (!dev->driver)
@@ -896,7 +895,7 @@ static int goku_set_halt(struct usb_ep *_ep, int value)
return -EINVAL;
/* don't change EPxSTATUS_EP_INVALID to READY */
- } else if (!ep->desc) {
+ } else if (!ep->ep.desc) {
DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return -EINVAL;
}
@@ -955,7 +954,7 @@ static void goku_fifo_flush(struct usb_ep *_ep)
VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name);
/* don't change EPxSTATUS_EP_INVALID to READY */
- if (!ep->desc && ep->num != 0) {
+ if (!ep->ep.desc && ep->num != 0) {
DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return;
}
@@ -1152,7 +1151,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
struct goku_ep *ep = &dev->ep [i];
struct goku_request *req;
- if (i && !ep->desc)
+ if (i && !ep->ep.desc)
continue;
tmp = readl(ep->reg_status);
@@ -1473,7 +1472,8 @@ static void ep0_setup(struct goku_udc *dev)
case USB_RECIP_ENDPOINT:
tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
/* active endpoint */
- if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
+ if (tmp > 3 ||
+ (!dev->ep[tmp].ep.desc && tmp != 0))
goto stall;
if (ctrl.wIndex & cpu_to_le16(
USB_DIR_IN)) {
@@ -1895,14 +1895,4 @@ static struct pci_driver goku_pci_driver = {
/* FIXME add power management support */
};
-static int __init init (void)
-{
- return pci_register_driver (&goku_pci_driver);
-}
-module_init (init);
-
-static void __exit cleanup (void)
-{
- pci_unregister_driver (&goku_pci_driver);
-}
-module_exit (cleanup);
+module_pci_driver(goku_pci_driver);
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index e7e0c69..85cdce0 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -216,7 +216,6 @@ struct goku_ep {
/* analogous to a host-side qh */
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
u32 __iomem *reg_fifo;
u32 __iomem *reg_mode;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 8d1c75a..54034f8 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1237,14 +1237,15 @@ irq_handler_t intr_handler(int i)
*******************************************************************************
*/
-static int imx_udc_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int imx_udc_stop(struct usb_gadget_driver *driver);
+static int imx_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int imx_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops imx_udc_ops = {
- .get_frame = imx_udc_get_frame,
- .wakeup = imx_udc_wakeup,
- .start = imx_udc_start,
- .stop = imx_udc_stop,
+ .get_frame = imx_udc_get_frame,
+ .wakeup = imx_udc_wakeup,
+ .udc_start = imx_udc_start,
+ .udc_stop = imx_udc_stop,
};
static struct imx_udc_struct controller = {
@@ -1329,23 +1330,13 @@ static struct imx_udc_struct controller = {
* USB gadget driver functions
*******************************************************************************
*/
-static int imx_udc_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int imx_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct imx_udc_struct *imx_usb = &controller;
+ struct imx_udc_struct *imx_usb;
int retval;
- if (!driver
- || driver->max_speed < USB_SPEED_FULL
- || !bind
- || !driver->disconnect
- || !driver->setup)
- return -EINVAL;
- if (!imx_usb)
- return -ENODEV;
- if (imx_usb->driver)
- return -EBUSY;
-
+ imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
/* first hook up the driver ... */
imx_usb->driver = driver;
imx_usb->gadget.dev.driver = &driver->driver;
@@ -1353,14 +1344,6 @@ static int imx_udc_start(struct usb_gadget_driver *driver,
retval = device_add(&imx_usb->gadget.dev);
if (retval)
goto fail;
- retval = bind(&imx_usb->gadget);
- if (retval) {
- D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n",
- __func__, driver->driver.name, retval);
- device_del(&imx_usb->gadget.dev);
-
- goto fail;
- }
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
__func__, driver->driver.name);
@@ -1374,20 +1357,16 @@ fail:
return retval;
}
-static int imx_udc_stop(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct imx_udc_struct *imx_usb = &controller;
-
- if (!imx_usb)
- return -ENODEV;
- if (!driver || driver != imx_usb->driver || !driver->unbind)
- return -EINVAL;
+ struct imx_udc_struct *imx_usb = container_of(gadget,
+ struct imx_udc_struct, gadget);
udc_stop_activity(imx_usb, driver);
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
- driver->unbind(&imx_usb->gadget);
imx_usb->gadget.dev.driver = NULL;
imx_usb->driver = NULL;
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
deleted file mode 100644
index f9cedd5..0000000
--- a/drivers/usb/gadget/langwell_udc.c
+++ /dev/null
@@ -1,3434 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- */
-
-
-/* #undef DEBUG */
-/* #undef VERBOSE_DEBUG */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/pm.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <asm/unaligned.h>
-
-#include "langwell_udc.h"
-
-
-#define DRIVER_DESC "Intel Langwell USB Device Controller driver"
-#define DRIVER_VERSION "16 May 2009"
-
-static const char driver_name[] = "langwell_udc";
-static const char driver_desc[] = DRIVER_DESC;
-
-
-/* for endpoint 0 operations */
-static const struct usb_endpoint_descriptor
-langwell_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = EP0_MAX_PKT_SIZE,
-};
-
-
-/*-------------------------------------------------------------------------*/
-/* debugging */
-
-#ifdef VERBOSE_DEBUG
-static inline void print_all_registers(struct langwell_udc *dev)
-{
- int i;
-
- /* Capability Registers */
- dev_dbg(&dev->pdev->dev,
- "Capability Registers (offset: 0x%04x, length: 0x%08x)\n",
- CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs));
- dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n",
- readb(&dev->cap_regs->caplength));
- dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n",
- readw(&dev->cap_regs->hciversion));
- dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n",
- readl(&dev->cap_regs->hcsparams));
- dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n",
- readl(&dev->cap_regs->hccparams));
- dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n",
- readw(&dev->cap_regs->dciversion));
- dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n",
- readl(&dev->cap_regs->dccparams));
-
- /* Operational Registers */
- dev_dbg(&dev->pdev->dev,
- "Operational Registers (offset: 0x%04x, length: 0x%08x)\n",
- OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs));
- dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n",
- readl(&dev->op_regs->extsts));
- dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n",
- readl(&dev->op_regs->extintr));
- dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n",
- readl(&dev->op_regs->usbcmd));
- dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n",
- readl(&dev->op_regs->usbsts));
- dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n",
- readl(&dev->op_regs->usbintr));
- dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n",
- readl(&dev->op_regs->frindex));
- dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n",
- readl(&dev->op_regs->ctrldssegment));
- dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n",
- readl(&dev->op_regs->deviceaddr));
- dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n",
- readl(&dev->op_regs->endpointlistaddr));
- dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n",
- readl(&dev->op_regs->ttctrl));
- dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n",
- readl(&dev->op_regs->burstsize));
- dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n",
- readl(&dev->op_regs->txfilltuning));
- dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n",
- readl(&dev->op_regs->txttfilltuning));
- dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n",
- readl(&dev->op_regs->ic_usb));
- dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n",
- readl(&dev->op_regs->ulpi_viewport));
- dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n",
- readl(&dev->op_regs->configflag));
- dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n",
- readl(&dev->op_regs->portsc1));
- dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n",
- readl(&dev->op_regs->devlc));
- dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n",
- readl(&dev->op_regs->otgsc));
- dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n",
- readl(&dev->op_regs->usbmode));
- dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n",
- readl(&dev->op_regs->endptnak));
- dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n",
- readl(&dev->op_regs->endptnaken));
- dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n",
- readl(&dev->op_regs->endptsetupstat));
- dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n",
- readl(&dev->op_regs->endptprime));
- dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n",
- readl(&dev->op_regs->endptflush));
- dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n",
- readl(&dev->op_regs->endptstat));
- dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n",
- readl(&dev->op_regs->endptcomplete));
-
- for (i = 0; i < dev->ep_max / 2; i++) {
- dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n",
- i, readl(&dev->op_regs->endptctrl[i]));
- }
-}
-#else
-
-#define print_all_registers(dev) do { } while (0)
-
-#endif /* VERBOSE_DEBUG */
-
-
-/*-------------------------------------------------------------------------*/
-
-#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \
- USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc)))
-
-#define DIR_STRING(ep) (is_in(ep) ? "in" : "out")
-
-
-static char *type_string(const struct usb_endpoint_descriptor *desc)
-{
- switch (usb_endpoint_type(desc)) {
- case USB_ENDPOINT_XFER_BULK:
- return "bulk";
- case USB_ENDPOINT_XFER_ISOC:
- return "iso";
- case USB_ENDPOINT_XFER_INT:
- return "int";
- };
-
- return "control";
-}
-
-
-/* configure endpoint control registers */
-static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
- unsigned char is_in, unsigned char ep_type)
-{
- struct langwell_udc *dev;
- u32 endptctrl;
-
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in) { /* TX */
- if (ep_num)
- endptctrl |= EPCTRL_TXR;
- endptctrl |= EPCTRL_TXE;
- endptctrl |= ep_type << EPCTRL_TXT_SHIFT;
- } else { /* RX */
- if (ep_num)
- endptctrl |= EPCTRL_RXR;
- endptctrl |= EPCTRL_RXE;
- endptctrl |= ep_type << EPCTRL_RXT_SHIFT;
- }
-
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* reset ep0 dQH and endptctrl */
-static void ep0_reset(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 in and out */
- for (i = 0; i < 2; i++) {
- ep = &dev->ep[i];
- ep->dev = dev;
-
- /* ep0 dQH */
- ep->dqh = &dev->ep_dqh[i];
-
- /* configure ep0 endpoint capabilities in dQH */
- ep->dqh->dqh_ios = 1;
- ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE;
-
- /* enable ep0-in HW zero length termination select */
- if (is_in(ep))
- ep->dqh->dqh_zlt = 0;
- ep->dqh->dqh_mult = 0;
-
- ep->dqh->dtd_next = DTD_TERM;
-
- /* configure ep0 control registers */
- ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoints operations */
-
-/* configure endpoint, making it usable */
-static int langwell_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct langwell_udc *dev;
- struct langwell_ep *ep;
- u16 max = 0;
- unsigned long flags;
- int i, retval = 0;
- unsigned char zlt, ios = 0, mult = 0;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !desc || ep->desc
- || desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
-
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- max = usb_endpoint_maxp(desc);
-
- /*
- * disable HW zero length termination select
- * driver handles zero length packet through req->req.zero
- */
- zlt = 1;
-
- /*
- * sanity check type, direction, address, and then
- * initialize the endpoint capabilities fields in dQH
- */
- switch (usb_endpoint_type(desc)) {
- case USB_ENDPOINT_XFER_CONTROL:
- ios = 1;
- break;
- case USB_ENDPOINT_XFER_BULK:
- if ((dev->gadget.speed == USB_SPEED_HIGH
- && max != 512)
- || (dev->gadget.speed == USB_SPEED_FULL
- && max > 64)) {
- goto done;
- }
- break;
- case USB_ENDPOINT_XFER_INT:
- if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
- goto done;
-
- switch (dev->gadget.speed) {
- case USB_SPEED_HIGH:
- if (max <= 1024)
- break;
- case USB_SPEED_FULL:
- if (max <= 64)
- break;
- default:
- if (max <= 8)
- break;
- goto done;
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (strstr(ep->ep.name, "-bulk")
- || strstr(ep->ep.name, "-int"))
- goto done;
-
- switch (dev->gadget.speed) {
- case USB_SPEED_HIGH:
- if (max <= 1024)
- break;
- case USB_SPEED_FULL:
- if (max <= 1023)
- break;
- default:
- goto done;
- }
- /*
- * FIXME:
- * calculate transactions needed for high bandwidth iso
- */
- mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
- /* 3 transactions at most */
- if (mult > 3)
- goto done;
- break;
- default:
- goto done;
- }
-
- spin_lock_irqsave(&dev->lock, flags);
-
- ep->ep.maxpacket = max;
- ep->desc = desc;
- ep->stopped = 0;
- ep->ep_num = usb_endpoint_num(desc);
-
- /* ep_type */
- ep->ep_type = usb_endpoint_type(desc);
-
- /* configure endpoint control registers */
- ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type);
-
- /* configure endpoint capabilities in dQH */
- i = ep->ep_num * 2 + is_in(ep);
- ep->dqh = &dev->ep_dqh[i];
- ep->dqh->dqh_ios = ios;
- ep->dqh->dqh_mpl = cpu_to_le16(max);
- ep->dqh->dqh_zlt = zlt;
- ep->dqh->dqh_mult = mult;
- ep->dqh->dtd_next = DTD_TERM;
-
- dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n",
- _ep->name,
- ep->ep_num,
- DIR_STRING(ep),
- type_string(desc),
- max);
-
- spin_unlock_irqrestore(&dev->lock, flags);
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* retire a request */
-static void done(struct langwell_ep *ep, struct langwell_request *req,
- int status)
-{
- struct langwell_udc *dev = ep->dev;
- unsigned stopped = ep->stopped;
- struct langwell_dtd *curr_dtd, *next_dtd;
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* remove the req from ep->queue */
- list_del_init(&req->queue);
-
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- /* free dTD for the request */
- next_dtd = req->head;
- for (i = 0; i < req->dtd_count; i++) {
- curr_dtd = next_dtd;
- if (i != req->dtd_count - 1)
- next_dtd = curr_dtd->next_dtd_virt;
- dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
- }
-
- usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
-
- if (status != -ESHUTDOWN)
- dev_dbg(&dev->pdev->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(&dev->lock);
- /* complete routine from gadget driver */
- if (req->req.complete)
- req->req.complete(&ep->ep, &req->req);
-
- spin_lock(&dev->lock);
- ep->stopped = stopped;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void langwell_ep_fifo_flush(struct usb_ep *_ep);
-
-/* delete all endpoint requests, called with spinlock held */
-static void nuke(struct langwell_ep *ep, int status)
-{
- /* called with spinlock held */
- ep->stopped = 1;
-
- /* endpoint fifo flush */
- if (&ep->ep && ep->desc)
- langwell_ep_fifo_flush(&ep->ep);
-
- while (!list_empty(&ep->queue)) {
- struct langwell_request *req = NULL;
- req = list_entry(ep->queue.next, struct langwell_request,
- queue);
- done(ep, req, status);
- }
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint is no longer usable */
-static int langwell_ep_disable(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- unsigned long flags;
- struct langwell_udc *dev;
- int ep_num;
- u32 endptctrl;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* disable endpoint control register */
- ep_num = ep->ep_num;
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl &= ~EPCTRL_TXE;
- else
- endptctrl &= ~EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- /* nuke all pending requests (does flush) */
- nuke(ep, -ESHUTDOWN);
-
- ep->desc = NULL;
- ep->ep.desc = NULL;
- ep->stopped = 1;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-}
-
-
-/* allocate a request object to use with this endpoint */
-static struct usb_request *langwell_alloc_request(struct usb_ep *_ep,
- gfp_t gfp_flags)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req = NULL;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- req = kzalloc(sizeof(*req), gfp_flags);
- if (!req)
- return NULL;
-
- req->req.dma = DMA_ADDR_INVALID;
- INIT_LIST_HEAD(&req->queue);
-
- dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return &req->req;
-}
-
-
-/* free a request object */
-static void langwell_free_request(struct usb_ep *_ep,
- struct usb_request *_req)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req = NULL;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !_req)
- return;
-
- req = container_of(_req, struct langwell_request, req);
- WARN_ON(!list_empty(&req->queue));
-
- if (_req)
- kfree(req);
-
- dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* queue dTD and PRIME endpoint */
-static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
-{
- u32 bit_mask, usbcmd, endptstat, dtd_dma;
- u8 dtd_status;
- int i;
- struct langwell_dqh *dqh;
- struct langwell_udc *dev;
-
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- i = ep->ep_num * 2 + is_in(ep);
- dqh = &dev->ep_dqh[i];
-
- if (ep->ep_num)
- dev_vdbg(&dev->pdev->dev, "%s\n", ep->name);
- else
- /* ep0 */
- dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
-
- dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n",
- i, &(dev->ep_dqh[i]));
-
- bit_mask = is_in(ep) ?
- (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
-
- dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask);
-
- /* check if the pipe is empty */
- if (!(list_empty(&ep->queue))) {
- /* add dTD to the end of linked list */
- struct langwell_request *lastreq;
- lastreq = list_entry(ep->queue.prev,
- struct langwell_request, queue);
-
- lastreq->tail->dtd_next =
- cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK);
-
- /* read prime bit, if 1 goto out */
- if (readl(&dev->op_regs->endptprime) & bit_mask)
- goto out;
-
- do {
- /* set ATDTW bit in USBCMD */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd);
-
- /* read correct status bit */
- endptstat = readl(&dev->op_regs->endptstat) & bit_mask;
-
- } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW));
-
- /* write ATDTW bit to 0 */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd);
-
- if (endptstat)
- goto out;
- }
-
- /* write dQH next pointer and terminate bit to 0 */
- dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK;
- dqh->dtd_next = cpu_to_le32(dtd_dma);
-
- /* clear active and halt bit */
- dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED);
- dqh->dtd_status &= dtd_status;
- dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status);
-
- /* ensure that updates to the dQH will occur before priming */
- wmb();
-
- /* write 1 to endptprime register to PRIME endpoint */
- bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num);
- dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask);
- writel(bit_mask, &dev->op_regs->endptprime);
-out:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* fill in the dTD structure to build a transfer descriptor */
-static struct langwell_dtd *build_dtd(struct langwell_request *req,
- unsigned *length, dma_addr_t *dma, int *is_last)
-{
- u32 buf_ptr;
- struct langwell_dtd *dtd;
- struct langwell_udc *dev;
- int i;
-
- dev = req->ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* the maximum transfer length, up to 16k bytes */
- *length = min(req->req.length - req->req.actual,
- (unsigned)DTD_MAX_TRANSFER_LENGTH);
-
- /* create dTD dma_pool resource */
- dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma);
- if (dtd == NULL)
- return dtd;
- dtd->dtd_dma = *dma;
-
- /* initialize buffer page pointers */
- buf_ptr = (u32)(req->req.dma + req->req.actual);
- for (i = 0; i < 5; i++)
- dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE);
-
- req->req.actual += *length;
-
- /* fill in total bytes with transfer size */
- dtd->dtd_total = cpu_to_le16(*length);
- dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total);
-
- /* set is_last flag if req->req.zero is set or not */
- if (req->req.zero) {
- if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
- *is_last = 1;
- else
- *is_last = 0;
- } else if (req->req.length == req->req.actual) {
- *is_last = 1;
- } else
- *is_last = 0;
-
- if (*is_last == 0)
- dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n");
-
- /* set interrupt on complete bit for the last dTD */
- if (*is_last && !req->req.no_interrupt)
- dtd->dtd_ioc = 1;
-
- /* set multiplier override 0 for non-ISO and non-TX endpoint */
- dtd->dtd_multo = 0;
-
- /* set the active bit of status field to 1 */
- dtd->dtd_status = DTD_STS_ACTIVE;
- dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n",
- dtd->dtd_status);
-
- dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n",
- *length, (int)*dma);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return dtd;
-}
-
-
-/* generate dTD linked list for a request */
-static int req_to_dtd(struct langwell_request *req)
-{
- unsigned count;
- int is_last, is_first = 1;
- struct langwell_dtd *dtd, *last_dtd = NULL;
- struct langwell_udc *dev;
- dma_addr_t dma;
-
- dev = req->ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
- do {
- dtd = build_dtd(req, &count, &dma, &is_last);
- if (dtd == NULL)
- return -ENOMEM;
-
- if (is_first) {
- is_first = 0;
- req->head = dtd;
- } else {
- last_dtd->dtd_next = cpu_to_le32(dma);
- last_dtd->next_dtd_virt = dtd;
- }
- last_dtd = dtd;
- req->dtd_count++;
- } while (!is_last);
-
- /* set terminate bit to 1 for the last dTD */
- dtd->dtd_next = DTD_TERM;
-
- req->tail = dtd;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* queue (submits) an I/O requests to an endpoint */
-static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
- gfp_t gfp_flags)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- unsigned long flags;
- int is_iso = 0;
- int ret;
-
- /* always require a cpu-view buffer */
- req = container_of(_req, struct langwell_request, req);
- ep = container_of(_ep, struct langwell_ep, ep);
-
- if (!_req || !_req->complete || !_req->buf
- || !list_empty(&req->queue)) {
- return -EINVAL;
- }
-
- if (unlikely(!_ep || !ep->desc))
- return -EINVAL;
-
- dev = ep->dev;
- req->ep = ep;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (usb_endpoint_xfer_isoc(ep->desc)) {
- if (req->req.length > ep->ep.maxpacket)
- return -EMSGSIZE;
- is_iso = 1;
- }
-
- if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
- return -ESHUTDOWN;
-
- /* set up dma mapping */
- ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
- if (ret)
- return ret;
-
- dev_dbg(&dev->pdev->dev,
- "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
- _ep->name,
- _req, _req->length, _req->buf, (int)_req->dma);
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
- req->dtd_count = 0;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* build and put dTDs to endpoint queue */
- if (!req_to_dtd(req)) {
- queue_dtd(ep, req);
- } else {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ENOMEM;
- }
-
- /* update ep0 state */
- if (ep->ep_num == 0)
- dev->ep0_state = DATA_STATE_XMIT;
-
- if (likely(req != NULL)) {
- list_add_tail(&req->queue, &ep->queue);
- dev_vdbg(&dev->pdev->dev, "list_add_tail()\n");
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* dequeue (cancels, unlinks) an I/O request from an endpoint */
-static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req;
- unsigned long flags;
- int stopped, ep_num, retval = 0;
- u32 endptctrl;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc || !_req)
- return -EINVAL;
-
- if (!dev->driver)
- return -ESHUTDOWN;
-
- spin_lock_irqsave(&dev->lock, flags);
- stopped = ep->stopped;
-
- /* quiesce dma while we patch the queue */
- ep->stopped = 1;
- ep_num = ep->ep_num;
-
- /* disable endpoint control register */
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl &= ~EPCTRL_TXE;
- else
- endptctrl &= ~EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- /* make sure it's still queued on this endpoint */
- list_for_each_entry(req, &ep->queue, queue) {
- if (&req->req == _req)
- break;
- }
-
- if (&req->req != _req) {
- retval = -EINVAL;
- goto done;
- }
-
- /* queue head may be partially complete. */
- if (ep->queue.next == &req->queue) {
- dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name);
- _req->status = -ECONNRESET;
- langwell_ep_fifo_flush(&ep->ep);
-
- /* not the last request in endpoint queue */
- if (likely(ep->queue.next == &req->queue)) {
- struct langwell_dqh *dqh;
- struct langwell_request *next_req;
-
- dqh = ep->dqh;
- next_req = list_entry(req->queue.next,
- struct langwell_request, queue);
-
- /* point the dQH to the first dTD of next request */
- writel((u32) next_req->head, &dqh->dqh_current);
- }
- } else {
- struct langwell_request *prev_req;
-
- prev_req = list_entry(req->queue.prev,
- struct langwell_request, queue);
- writel(readl(&req->tail->dtd_next),
- &prev_req->tail->dtd_next);
- }
-
- done(ep, req, -ECONNRESET);
-
-done:
- /* enable endpoint again */
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl |= EPCTRL_TXE;
- else
- endptctrl |= EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- ep->stopped = stopped;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint set/clear halt */
-static void ep_set_halt(struct langwell_ep *ep, int value)
-{
- u32 endptctrl = 0;
- int ep_num;
- struct langwell_udc *dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- ep_num = ep->ep_num;
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-
- /* value: 1 - set halt, 0 - clear halt */
- if (value) {
- /* set the stall bit */
- if (is_in(ep))
- endptctrl |= EPCTRL_TXS;
- else
- endptctrl |= EPCTRL_RXS;
- } else {
- /* clear the stall bit and reset data toggle */
- if (is_in(ep)) {
- endptctrl &= ~EPCTRL_TXS;
- endptctrl |= EPCTRL_TXR;
- } else {
- endptctrl &= ~EPCTRL_RXS;
- endptctrl |= EPCTRL_RXR;
- }
- }
-
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* set the endpoint halt feature */
-static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- unsigned long flags;
- int retval = 0;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- if (usb_endpoint_xfer_isoc(ep->desc))
- return -EOPNOTSUPP;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /*
- * attempt to halt IN ep will fail if any transfer requests
- * are still queue
- */
- if (!list_empty(&ep->queue) && is_in(ep) && value) {
- /* IN endpoint FIFO holds bytes */
- dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name);
- retval = -EAGAIN;
- goto done;
- }
-
- /* endpoint set/clear halt */
- if (ep->ep_num) {
- ep_set_halt(ep, value);
- } else { /* endpoint 0 */
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
- }
-done:
- spin_unlock_irqrestore(&dev->lock, flags);
- dev_dbg(&dev->pdev->dev, "%s %s halt\n",
- _ep->name, value ? "set" : "clear");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* set the halt feature and ignores clear requests */
-static int langwell_ep_set_wedge(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return usb_ep_set_halt(_ep);
-}
-
-
-/* flush contents of a fifo */
-static void langwell_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- u32 flush_bit;
- unsigned long timeout;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc) {
- dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return;
- }
-
- dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n",
- _ep->name, DIR_STRING(ep));
-
- /* flush endpoint buffer */
- if (ep->ep_num == 0)
- flush_bit = (1 << 16) | 1;
- else if (is_in(ep))
- flush_bit = 1 << (ep->ep_num + 16); /* TX */
- else
- flush_bit = 1 << ep->ep_num; /* RX */
-
- /* wait until flush complete */
- timeout = jiffies + FLUSH_TIMEOUT;
- do {
- writel(flush_bit, &dev->op_regs->endptflush);
- while (readl(&dev->op_regs->endptflush)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "ep flush timeout\n");
- goto done;
- }
- cpu_relax();
- }
- } while (readl(&dev->op_regs->endptstat) & flush_bit);
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* endpoints operations structure */
-static const struct usb_ep_ops langwell_ep_ops = {
-
- /* configure endpoint, making it usable */
- .enable = langwell_ep_enable,
-
- /* endpoint is no longer usable */
- .disable = langwell_ep_disable,
-
- /* allocate a request object to use with this endpoint */
- .alloc_request = langwell_alloc_request,
-
- /* free a request object */
- .free_request = langwell_free_request,
-
- /* queue (submits) an I/O requests to an endpoint */
- .queue = langwell_ep_queue,
-
- /* dequeue (cancels, unlinks) an I/O request from an endpoint */
- .dequeue = langwell_ep_dequeue,
-
- /* set the endpoint halt feature */
- .set_halt = langwell_ep_set_halt,
-
- /* set the halt feature and ignores clear requests */
- .set_wedge = langwell_ep_set_wedge,
-
- /* flush contents of a fifo */
- .fifo_flush = langwell_ep_fifo_flush,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller usb_gadget_ops structure */
-
-/* returns the current frame number */
-static int langwell_get_frame(struct usb_gadget *_gadget)
-{
- struct langwell_udc *dev;
- u16 retval;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* enter or exit PHY low power state */
-static void langwell_phy_low_power(struct langwell_udc *dev, bool flag)
-{
- u32 devlc;
- u8 devlc_byte2;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
-
- if (flag)
- devlc |= LPM_PHCD;
- else
- devlc &= ~LPM_PHCD;
-
- /* FIXME: workaround for Langwell A1/A2/A3 sighting */
- devlc_byte2 = (devlc >> 16) & 0xff;
- writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
-
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev,
- "%s PHY low power suspend, devlc = 0x%08x\n",
- flag ? "enter" : "exit", devlc);
-}
-
-
-/* tries to wake up the host connected to this gadget */
-static int langwell_wakeup(struct usb_gadget *_gadget)
-{
- struct langwell_udc *dev;
- u32 portsc1;
- unsigned long flags;
-
- if (!_gadget)
- return 0;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* remote wakeup feature not enabled by host */
- if (!dev->remote_wakeup) {
- dev_info(&dev->pdev->dev, "remote wakeup is disabled\n");
- return -ENOTSUPP;
- }
-
- spin_lock_irqsave(&dev->lock, flags);
-
- portsc1 = readl(&dev->op_regs->portsc1);
- if (!(portsc1 & PORTS_SUSP)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
-
- /* LPM L1 to L0 or legacy remote wakeup */
- if (dev->lpm && dev->lpm_state == LPM_L1)
- dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n");
- else
- dev_info(&dev->pdev->dev, "device remote wakeup\n");
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* force port resume */
- portsc1 |= PORTS_FPR;
- writel(portsc1, &dev->op_regs->portsc1);
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* notify controller that VBUS is powered or not */
-static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
- struct langwell_udc *dev;
- unsigned long flags;
- u32 usbcmd;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
- dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n",
- is_active ? "on" : "off");
-
- dev->vbus_active = (is_active != 0);
- if (dev->driver && dev->softconnected && dev->vbus_active) {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- } else {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* constrain controller's VBUS power usage */
-static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
- struct langwell_udc *dev;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->transceiver) {
- dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return usb_phy_set_power(dev->transceiver, mA);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return -ENOTSUPP;
-}
-
-
-/* D+ pullup, software-controlled connect/disconnect to USB host */
-static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
-{
- struct langwell_udc *dev;
- u32 usbcmd;
- unsigned long flags;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
- dev->softconnected = (is_on != 0);
-
- if (dev->driver && dev->softconnected && dev->vbus_active) {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- } else {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-static int langwell_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-
-static int langwell_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-
-/* device controller usb_gadget_ops structure */
-static const struct usb_gadget_ops langwell_ops = {
-
- /* returns the current frame number */
- .get_frame = langwell_get_frame,
-
- /* tries to wake up the host connected to this gadget */
- .wakeup = langwell_wakeup,
-
- /* set the device selfpowered feature, always selfpowered */
- /* .set_selfpowered = langwell_set_selfpowered, */
-
- /* notify controller that VBUS is powered or not */
- .vbus_session = langwell_vbus_session,
-
- /* constrain controller's VBUS power usage */
- .vbus_draw = langwell_vbus_draw,
-
- /* D+ pullup, software-controlled connect/disconnect to USB host */
- .pullup = langwell_pullup,
-
- .udc_start = langwell_start,
- .udc_stop = langwell_stop,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller operations */
-
-/* reset device controller */
-static int langwell_udc_reset(struct langwell_udc *dev)
-{
- u32 usbcmd, usbmode, devlc, endpointlistaddr;
- u8 devlc_byte0, devlc_byte2;
- unsigned long timeout;
-
- if (!dev)
- return -EINVAL;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* set controller to stop state */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- /* reset device controller */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RST;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- /* wait for reset to complete */
- timeout = jiffies + RESET_TIMEOUT;
- while (readl(&dev->op_regs->usbcmd) & CMD_RST) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "device reset timeout\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
-
- /* set controller to device mode */
- usbmode = readl(&dev->op_regs->usbmode);
- usbmode |= MODE_DEVICE;
-
- /* turn setup lockout off, require setup tripwire in usbcmd */
- usbmode |= MODE_SLOM;
-
- writel(usbmode, &dev->op_regs->usbmode);
- usbmode = readl(&dev->op_regs->usbmode);
- dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode);
-
- /* Write-Clear setup status */
- writel(0, &dev->op_regs->usbsts);
-
- /* if support USB LPM, ACK all LPM token */
- if (dev->lpm) {
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
- /* FIXME: workaround for Langwell A1/A2/A3 sighting */
- devlc &= ~LPM_STL; /* don't STALL LPM token */
- devlc &= ~LPM_NYT_ACK; /* ACK LPM token */
- devlc_byte0 = devlc & 0xff;
- devlc_byte2 = (devlc >> 16) & 0xff;
- writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc);
- writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev,
- "ACK LPM token, devlc = 0x%08x\n", devlc);
- }
-
- /* fill endpointlistaddr register */
- endpointlistaddr = dev->ep_dqh_dma;
- endpointlistaddr &= ENDPOINTLISTADDR_MASK;
- writel(endpointlistaddr, &dev->op_regs->endpointlistaddr);
-
- dev_vdbg(&dev->pdev->dev,
- "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n",
- dev->ep_dqh, endpointlistaddr,
- readl(&dev->op_regs->endpointlistaddr));
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* reinitialize device controller endpoints */
-static int eps_reinit(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- char name[14];
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* initialize ep0 */
- ep = &dev->ep[0];
- ep->dev = dev;
- strncpy(ep->name, "ep0", sizeof(ep->name));
- ep->ep.name = ep->name;
- ep->ep.ops = &langwell_ep_ops;
- ep->stopped = 0;
- ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
- ep->ep_num = 0;
- ep->desc = &langwell_ep0_desc;
- INIT_LIST_HEAD(&ep->queue);
-
- ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
- /* initialize other endpoints */
- for (i = 2; i < dev->ep_max; i++) {
- ep = &dev->ep[i];
- if (i % 2)
- snprintf(name, sizeof(name), "ep%din", i / 2);
- else
- snprintf(name, sizeof(name), "ep%dout", i / 2);
- ep->dev = dev;
- strncpy(ep->name, name, sizeof(ep->name));
- ep->ep.name = ep->name;
-
- ep->ep.ops = &langwell_ep_ops;
- ep->stopped = 0;
- ep->ep.maxpacket = (unsigned short) ~0;
- ep->ep_num = i / 2;
-
- INIT_LIST_HEAD(&ep->queue);
- list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* enable interrupt and set controller to run state */
-static void langwell_udc_start(struct langwell_udc *dev)
-{
- u32 usbintr, usbcmd;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* enable interrupts */
- usbintr = INTR_ULPIE /* ULPI */
- | INTR_SLE /* suspend */
- /* | INTR_SRE SOF received */
- | INTR_URE /* USB reset */
- | INTR_AAE /* async advance */
- | INTR_SEE /* system error */
- | INTR_FRE /* frame list rollover */
- | INTR_PCE /* port change detect */
- | INTR_UEE /* USB error interrupt */
- | INTR_UE; /* USB interrupt */
- writel(usbintr, &dev->op_regs->usbintr);
-
- /* clear stopped bit */
- dev->stopped = 0;
-
- /* set controller to run */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* disable interrupt and set controller to stop state */
-static void langwell_udc_stop(struct langwell_udc *dev)
-{
- u32 usbcmd;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* disable all interrupts */
- writel(0, &dev->op_regs->usbintr);
-
- /* set stopped bit */
- dev->stopped = 1;
-
- /* set controller to stop state */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* stop all USB activities */
-static void stop_activity(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- nuke(&dev->ep[0], -ESHUTDOWN);
-
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- nuke(ep, -ESHUTDOWN);
- }
-
- /* report disconnect; the driver is already quiesced */
- if (dev->driver) {
- spin_unlock(&dev->lock);
- dev->driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device "function" sysfs attribute file */
-static ssize_t show_function(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
-
- if (!dev->driver || !dev->driver->function
- || strlen(dev->driver->function) > PAGE_SIZE)
- return 0;
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function);
-}
-static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
-
-
-static inline enum usb_device_speed lpm_device_speed(u32 reg)
-{
- switch (LPM_PSPD(reg)) {
- case LPM_SPEED_HIGH:
- return USB_SPEED_HIGH;
- case LPM_SPEED_FULL:
- return USB_SPEED_FULL;
- case LPM_SPEED_LOW:
- return USB_SPEED_LOW;
- default:
- return USB_SPEED_UNKNOWN;
- }
-}
-
-/* device "langwell_udc" sysfs attribute file */
-static ssize_t show_langwell_udc(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
- struct langwell_request *req;
- struct langwell_ep *ep = NULL;
- char *next;
- unsigned size;
- unsigned t;
- unsigned i;
- unsigned long flags;
- u32 tmp_reg;
-
- next = buf;
- size = PAGE_SIZE;
- spin_lock_irqsave(&dev->lock, flags);
-
- /* driver basic information */
- t = scnprintf(next, size,
- DRIVER_DESC "\n"
- "%s version: %s\n"
- "Gadget driver: %s\n\n",
- driver_name, DRIVER_VERSION,
- dev->driver ? dev->driver->driver.name : "(none)");
- size -= t;
- next += t;
-
- /* device registers */
- tmp_reg = readl(&dev->op_regs->usbcmd);
- t = scnprintf(next, size,
- "USBCMD reg:\n"
- "SetupTW: %d\n"
- "Run/Stop: %s\n\n",
- (tmp_reg & CMD_SUTW) ? 1 : 0,
- (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbsts);
- t = scnprintf(next, size,
- "USB Status Reg:\n"
- "Device Suspend: %d\n"
- "Reset Received: %d\n"
- "System Error: %s\n"
- "USB Error Interrupt: %s\n\n",
- (tmp_reg & STS_SLI) ? 1 : 0,
- (tmp_reg & STS_URI) ? 1 : 0,
- (tmp_reg & STS_SEI) ? "Error" : "No error",
- (tmp_reg & STS_UEI) ? "Error detected" : "No error");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbintr);
- t = scnprintf(next, size,
- "USB Intrrupt Enable Reg:\n"
- "Sleep Enable: %d\n"
- "SOF Received Enable: %d\n"
- "Reset Enable: %d\n"
- "System Error Enable: %d\n"
- "Port Change Dectected Enable: %d\n"
- "USB Error Intr Enable: %d\n"
- "USB Intr Enable: %d\n\n",
- (tmp_reg & INTR_SLE) ? 1 : 0,
- (tmp_reg & INTR_SRE) ? 1 : 0,
- (tmp_reg & INTR_URE) ? 1 : 0,
- (tmp_reg & INTR_SEE) ? 1 : 0,
- (tmp_reg & INTR_PCE) ? 1 : 0,
- (tmp_reg & INTR_UEE) ? 1 : 0,
- (tmp_reg & INTR_UE) ? 1 : 0);
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->frindex);
- t = scnprintf(next, size,
- "USB Frame Index Reg:\n"
- "Frame Number is 0x%08x\n\n",
- (tmp_reg & FRINDEX_MASK));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->deviceaddr);
- t = scnprintf(next, size,
- "USB Device Address Reg:\n"
- "Device Addr is 0x%x\n\n",
- USBADR(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->endpointlistaddr);
- t = scnprintf(next, size,
- "USB Endpoint List Address Reg:\n"
- "Endpoint List Pointer is 0x%x\n\n",
- EPBASE(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->portsc1);
- t = scnprintf(next, size,
- "USB Port Status & Control Reg:\n"
- "Port Reset: %s\n"
- "Port Suspend Mode: %s\n"
- "Over-current Change: %s\n"
- "Port Enable/Disable Change: %s\n"
- "Port Enabled/Disabled: %s\n"
- "Current Connect Status: %s\n"
- "LPM Suspend Status: %s\n\n",
- (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset",
- (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend",
- (tmp_reg & PORTS_OCC) ? "Detected" : "No",
- (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed",
- (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct",
- (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached",
- (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->devlc);
- t = scnprintf(next, size,
- "Device LPM Control Reg:\n"
- "Parallel Transceiver : %d\n"
- "Serial Transceiver : %d\n"
- "Port Speed: %s\n"
- "Port Force Full Speed Connenct: %s\n"
- "PHY Low Power Suspend Clock: %s\n"
- "BmAttributes: %d\n\n",
- LPM_PTS(tmp_reg),
- (tmp_reg & LPM_STS) ? 1 : 0,
- usb_speed_string(lpm_device_speed(tmp_reg)),
- (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
- (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
- LPM_BA(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbmode);
- t = scnprintf(next, size,
- "USB Mode Reg:\n"
- "Controller Mode is : %s\n\n", ({
- char *s;
- switch (MODE_CM(tmp_reg)) {
- case MODE_IDLE:
- s = "Idle"; break;
- case MODE_DEVICE:
- s = "Device Controller"; break;
- case MODE_HOST:
- s = "Host Controller"; break;
- default:
- s = "None"; break;
- }
- s;
- }));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->endptsetupstat);
- t = scnprintf(next, size,
- "Endpoint Setup Status Reg:\n"
- "SETUP on ep 0x%04x\n\n",
- tmp_reg & SETUPSTAT_MASK);
- size -= t;
- next += t;
-
- for (i = 0; i < dev->ep_max / 2; i++) {
- tmp_reg = readl(&dev->op_regs->endptctrl[i]);
- t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n",
- i, tmp_reg);
- size -= t;
- next += t;
- }
- tmp_reg = readl(&dev->op_regs->endptprime);
- t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg);
- size -= t;
- next += t;
-
- /* langwell_udc, langwell_ep, langwell_request structure information */
- ep = &dev->ep[0];
- t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n",
- ep->ep.name, ep->ep.maxpacket, ep->ep_num);
- size -= t;
- next += t;
-
- if (list_empty(&ep->queue)) {
- t = scnprintf(next, size, "its req queue is empty\n\n");
- size -= t;
- next += t;
- } 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->req, req->req.actual,
- req->req.length, req->req.buf);
- size -= t;
- next += t;
- }
- }
- /* other gadget->eplist ep */
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
- t = scnprintf(next, size,
- "\n%s MaxPacketSize: 0x%x, "
- "ep_num: %d\n",
- ep->ep.name, ep->ep.maxpacket,
- ep->ep_num);
- size -= t;
- next += t;
-
- if (list_empty(&ep->queue)) {
- t = scnprintf(next, size,
- "its req queue is empty\n\n");
- size -= t;
- next += t;
- } 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->req, req->req.actual,
- req->req.length, req->req.buf);
- size -= t;
- next += t;
- }
- }
- }
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
- return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
-
-
-/* device "remote_wakeup" sysfs attribute file */
-static ssize_t store_remote_wakeup(struct device *_dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
- unsigned long flags;
- ssize_t rc = count;
-
- if (count > 2)
- return -EINVAL;
-
- if (count > 0 && buf[count-1] == '\n')
- ((char *) buf)[count-1] = 0;
-
- if (buf[0] != '1')
- return -EINVAL;
-
- /* force remote wakeup enabled in case gadget driver doesn't support */
- spin_lock_irqsave(&dev->lock, flags);
- dev->remote_wakeup = 1;
- dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- langwell_wakeup(&dev->gadget);
-
- return rc;
-}
-static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * when a driver is successfully registered, it will receive
- * control requests including set_configuration(), which enables
- * non-control requests. then usb traffic follows until a
- * disconnect is reported. then a host may connect again, or
- * the driver might get unbound.
- */
-
-static int langwell_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct langwell_udc *dev = gadget_to_langwell(g);
- unsigned long flags;
- int retval;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* hook up the driver ... */
- driver->driver.bus = NULL;
- dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
- if (retval)
- goto err;
-
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- /* enable interrupt and set controller to run state */
- if (dev->got_irq)
- langwell_udc_start(dev);
-
- dev_vdbg(&dev->pdev->dev,
- "After langwell_udc_start(), print all registers:\n");
- print_all_registers(dev);
-
- dev_info(&dev->pdev->dev, "register driver: %s\n",
- driver->driver.name);
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-
-err:
- dev->gadget.dev.driver = NULL;
- dev->driver = NULL;
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return retval;
-}
-
-/* unregister gadget driver */
-static int langwell_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct langwell_udc *dev = gadget_to_langwell(g);
- unsigned long flags;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* unbind OTG transceiver */
- if (dev->transceiver)
- (void)otg_set_peripheral(dev->transceiver->otg, 0);
-
- /* disable interrupt and set controller to stop state */
- langwell_udc_stop(dev);
-
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* stop all usb activities */
- dev->gadget.speed = USB_SPEED_UNKNOWN;
- dev->gadget.dev.driver = NULL;
- dev->driver = NULL;
- stop_activity(dev);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- device_remove_file(&dev->pdev->dev, &dev_attr_function);
-
- dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
- driver->driver.name);
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * setup tripwire is used as a semaphore to ensure that the setup data
- * payload is extracted from a dQH without being corrupted
- */
-static void setup_tripwire(struct langwell_udc *dev)
-{
- u32 usbcmd,
- endptsetupstat;
- unsigned long timeout;
- struct langwell_dqh *dqh;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 OUT dQH */
- dqh = &dev->ep_dqh[EP_DIR_OUT];
-
- /* Write-Clear endptsetupstat */
- endptsetupstat = readl(&dev->op_regs->endptsetupstat);
- writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
- /* wait until endptsetupstat is cleared */
- timeout = jiffies + SETUPSTAT_TIMEOUT;
- while (readl(&dev->op_regs->endptsetupstat)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "setup_tripwire timeout\n");
- break;
- }
- cpu_relax();
- }
-
- /* while a hazard exists when setup packet arrives */
- do {
- /* set setup tripwire bit */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd);
-
- /* copy the setup packet to local buffer */
- memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8);
- } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW));
-
- /* Write-Clear setup tripwire bit */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* protocol ep0 stall, will automatically be cleared on new transaction */
-static void ep0_stall(struct langwell_udc *dev)
-{
- u32 endptctrl;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* set TX and RX to stall */
- endptctrl = readl(&dev->op_regs->endptctrl[0]);
- endptctrl |= EPCTRL_TXS | EPCTRL_RXS;
- writel(endptctrl, &dev->op_regs->endptctrl[0]);
-
- /* update ep0 state */
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* PRIME a status phase for ep0 */
-static int prime_status_phase(struct langwell_udc *dev, int dir)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- int status = 0;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dir == EP_DIR_IN)
- dev->ep0_dir = USB_DIR_IN;
- else
- dev->ep0_dir = USB_DIR_OUT;
-
- ep = &dev->ep[0];
- dev->ep0_state = WAIT_FOR_OUT_STATUS;
-
- req = dev->status_req;
-
- req->ep = ep;
- req->req.length = 0;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- if (!req_to_dtd(req))
- status = queue_dtd(ep, req);
- else
- return -ENOMEM;
-
- if (status)
- dev_err(&dev->pdev->dev, "can't queue ep0 status request\n");
-
- list_add_tail(&req->queue, &ep->queue);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return status;
-}
-
-
-/* SET_ADDRESS request routine */
-static void set_address(struct langwell_udc *dev, u16 value,
- u16 index, u16 length)
-{
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* save the new address to device struct */
- dev->dev_addr = (u8) value;
- dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr);
-
- /* update usb state */
- dev->usb_state = USB_STATE_ADDRESS;
-
- /* STATUS phase */
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* return endpoint by windex */
-static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev,
- u16 wIndex)
-{
- struct langwell_ep *ep;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
- return &dev->ep[0];
-
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- u8 bEndpointAddress;
- if (!ep->desc)
- continue;
-
- bEndpointAddress = ep->desc->bEndpointAddress;
- if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
- continue;
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK)
- == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
- return ep;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return NULL;
-}
-
-
-/* return whether endpoint is stalled, 0: not stalled; 1: stalled */
-static int ep_is_stall(struct langwell_ep *ep)
-{
- struct langwell_udc *dev = ep->dev;
- u32 endptctrl;
- int retval;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]);
- if (is_in(ep))
- retval = endptctrl & EPCTRL_TXS ? 1 : 0;
- else
- retval = endptctrl & EPCTRL_RXS ? 1 : 0;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* GET_STATUS request routine */
-static void get_status(struct langwell_udc *dev, u8 request_type, u16 value,
- u16 index, u16 length)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- u16 status_data = 0; /* 16 bits cpu view status data */
- int status = 0;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- ep = &dev->ep[0];
-
- if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- /* get device status */
- status_data = dev->dev_status;
- } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
- /* get interface status */
- status_data = 0;
- } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
- /* get endpoint status */
- struct langwell_ep *epn;
- epn = get_ep_by_windex(dev, index);
- /* stall if endpoint doesn't exist */
- if (!epn)
- goto stall;
-
- status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT;
- }
-
- dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data);
-
- dev->ep0_dir = USB_DIR_IN;
-
- /* borrow the per device status_req */
- req = dev->status_req;
-
- /* fill in the reqest structure */
- *((u16 *) req->req.buf) = cpu_to_le16(status_data);
- req->ep = ep;
- req->req.length = 2;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- /* prime the data phase */
- if (!req_to_dtd(req))
- status = queue_dtd(ep, req);
- else /* no mem */
- goto stall;
-
- if (status) {
- dev_err(&dev->pdev->dev,
- "response error on GET_STATUS request\n");
- goto stall;
- }
-
- list_add_tail(&req->queue, &ep->queue);
- dev->ep0_state = DATA_STATE_XMIT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return;
-stall:
- ep0_stall(dev);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* setup packet interrupt handler */
-static void handle_setup_packet(struct langwell_udc *dev,
- struct usb_ctrlrequest *setup)
-{
- u16 wValue = le16_to_cpu(setup->wValue);
- u16 wIndex = le16_to_cpu(setup->wIndex);
- u16 wLength = le16_to_cpu(setup->wLength);
- u32 portsc1;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 fifo flush */
- nuke(&dev->ep[0], -ESHUTDOWN);
-
- dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
- setup->bRequestType, setup->bRequest,
- wValue, wIndex, wLength);
-
- /* RNDIS gadget delegate */
- if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) {
- /* USB_CDC_SEND_ENCAPSULATED_COMMAND */
- goto delegate;
- }
-
- /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
- if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) {
- /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
- goto delegate;
- }
-
- /* We process some stardard setup requests here */
- switch (setup->bRequest) {
- case USB_REQ_GET_STATUS:
- dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n");
- /* get status, DATA and STATUS phase */
- if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
- != (USB_DIR_IN | USB_TYPE_STANDARD))
- break;
- get_status(dev, setup->bRequestType, wValue, wIndex, wLength);
- goto end;
-
- case USB_REQ_SET_ADDRESS:
- dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n");
- /* STATUS phase */
- if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
- | USB_RECIP_DEVICE))
- break;
- set_address(dev, wValue, wIndex, wLength);
- goto end;
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- /* STATUS phase */
- {
- int rc = -EOPNOTSUPP;
- if (setup->bRequest == USB_REQ_SET_FEATURE)
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_FEATURE\n");
- else if (setup->bRequest == USB_REQ_CLEAR_FEATURE)
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_CLEAR_FEATURE\n");
-
- if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
- == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
- struct langwell_ep *epn;
- epn = get_ep_by_windex(dev, wIndex);
- /* stall if endpoint doesn't exist */
- if (!epn) {
- ep0_stall(dev);
- goto end;
- }
-
- if (wValue != 0 || wLength != 0
- || epn->ep_num > dev->ep_max)
- break;
-
- spin_unlock(&dev->lock);
- rc = langwell_ep_set_halt(&epn->ep,
- (setup->bRequest == USB_REQ_SET_FEATURE)
- ? 1 : 0);
- spin_lock(&dev->lock);
-
- } else if ((setup->bRequestType & (USB_RECIP_MASK
- | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
- | USB_TYPE_STANDARD)) {
- rc = 0;
- switch (wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- if (setup->bRequest == USB_REQ_SET_FEATURE) {
- dev->remote_wakeup = 1;
- dev->dev_status |= (1 << wValue);
- } else {
- dev->remote_wakeup = 0;
- dev->dev_status &= ~(1 << wValue);
- }
- break;
- case USB_DEVICE_TEST_MODE:
- dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n");
- if ((wIndex & 0xff) ||
- (dev->gadget.speed != USB_SPEED_HIGH))
- ep0_stall(dev);
-
- switch (wIndex >> 8) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- portsc1 = readl(&dev->op_regs->portsc1);
- portsc1 |= (wIndex & 0xf00) << 8;
- writel(portsc1, &dev->op_regs->portsc1);
- goto end;
- default:
- rc = -EOPNOTSUPP;
- }
- break;
- default:
- rc = -EOPNOTSUPP;
- break;
- }
-
- if (!gadget_is_otg(&dev->gadget))
- break;
- else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
- dev->gadget.b_hnp_enable = 1;
- else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
- dev->gadget.a_hnp_support = 1;
- else if (setup->bRequest ==
- USB_DEVICE_A_ALT_HNP_SUPPORT)
- dev->gadget.a_alt_hnp_support = 1;
- else
- break;
- } else
- break;
-
- if (rc == 0) {
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- }
- goto end;
- }
-
- case USB_REQ_GET_DESCRIPTOR:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_DESCRIPTOR\n");
- goto delegate;
-
- case USB_REQ_SET_DESCRIPTOR:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n");
- goto delegate;
-
- case USB_REQ_GET_CONFIGURATION:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_CONFIGURATION\n");
- goto delegate;
-
- case USB_REQ_SET_CONFIGURATION:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_CONFIGURATION\n");
- goto delegate;
-
- case USB_REQ_GET_INTERFACE:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_INTERFACE\n");
- goto delegate;
-
- case USB_REQ_SET_INTERFACE:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_INTERFACE\n");
- goto delegate;
-
- case USB_REQ_SYNCH_FRAME:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SYNCH_FRAME unsupported\n");
- goto delegate;
-
- default:
- /* delegate USB standard requests to the gadget driver */
- goto delegate;
-delegate:
- /* USB requests handled by gadget */
- if (wLength) {
- /* DATA phase from gadget, STATUS phase from udc */
- dev->ep0_dir = (setup->bRequestType & USB_DIR_IN)
- ? USB_DIR_IN : USB_DIR_OUT;
- dev_vdbg(&dev->pdev->dev,
- "dev->ep0_dir = 0x%x, wLength = %d\n",
- dev->ep0_dir, wLength);
- spin_unlock(&dev->lock);
- if (dev->driver->setup(&dev->gadget,
- &dev->local_setup_buff) < 0)
- ep0_stall(dev);
- spin_lock(&dev->lock);
- dev->ep0_state = (setup->bRequestType & USB_DIR_IN)
- ? DATA_STATE_XMIT : DATA_STATE_RECV;
- } else {
- /* no DATA phase, IN STATUS phase from gadget */
- dev->ep0_dir = USB_DIR_IN;
- dev_vdbg(&dev->pdev->dev,
- "dev->ep0_dir = 0x%x, wLength = %d\n",
- dev->ep0_dir, wLength);
- spin_unlock(&dev->lock);
- if (dev->driver->setup(&dev->gadget,
- &dev->local_setup_buff) < 0)
- ep0_stall(dev);
- spin_lock(&dev->lock);
- dev->ep0_state = WAIT_FOR_OUT_STATUS;
- }
- break;
- }
-end:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* transfer completion, process endpoint request and free the completed dTDs
- * for this request
- */
-static int process_ep_req(struct langwell_udc *dev, int index,
- struct langwell_request *curr_req)
-{
- struct langwell_dtd *curr_dtd;
- struct langwell_dqh *curr_dqh;
- int td_complete, actual, remaining_length;
- int i, dir;
- u8 dtd_status = 0;
- int retval = 0;
-
- curr_dqh = &dev->ep_dqh[index];
- dir = index % 2;
-
- curr_dtd = curr_req->head;
- td_complete = 0;
- actual = curr_req->req.length;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- for (i = 0; i < curr_req->dtd_count; i++) {
-
- /* command execution states by dTD */
- dtd_status = curr_dtd->dtd_status;
-
- barrier();
- remaining_length = le16_to_cpu(curr_dtd->dtd_total);
- actual -= remaining_length;
-
- if (!dtd_status) {
- /* transfers completed successfully */
- if (!remaining_length) {
- td_complete++;
- dev_vdbg(&dev->pdev->dev,
- "dTD transmitted successfully\n");
- } else {
- if (dir) {
- dev_vdbg(&dev->pdev->dev,
- "TX dTD remains data\n");
- retval = -EPROTO;
- break;
-
- } else {
- td_complete++;
- break;
- }
- }
- } else {
- /* transfers completed with errors */
- if (dtd_status & DTD_STS_ACTIVE) {
- dev_dbg(&dev->pdev->dev,
- "dTD status ACTIVE dQH[%d]\n", index);
- retval = 1;
- return retval;
- } else if (dtd_status & DTD_STS_HALTED) {
- dev_err(&dev->pdev->dev,
- "dTD error %08x dQH[%d]\n",
- dtd_status, index);
- /* clear the errors and halt condition */
- curr_dqh->dtd_status = 0;
- retval = -EPIPE;
- break;
- } else if (dtd_status & DTD_STS_DBE) {
- dev_dbg(&dev->pdev->dev,
- "data buffer (overflow) error\n");
- retval = -EPROTO;
- break;
- } else if (dtd_status & DTD_STS_TRE) {
- dev_dbg(&dev->pdev->dev,
- "transaction(ISO) error\n");
- retval = -EILSEQ;
- break;
- } else
- dev_err(&dev->pdev->dev,
- "unknown error (0x%x)!\n",
- dtd_status);
- }
-
- if (i != curr_req->dtd_count - 1)
- curr_dtd = (struct langwell_dtd *)
- curr_dtd->next_dtd_virt;
- }
-
- if (retval)
- return retval;
-
- curr_req->req.actual = actual;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* complete DATA or STATUS phase of ep0 prime status phase if needed */
-static void ep0_req_complete(struct langwell_udc *dev,
- struct langwell_ep *ep0, struct langwell_request *req)
-{
- u32 new_addr;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->usb_state == USB_STATE_ADDRESS) {
- /* set the new address */
- new_addr = (u32)dev->dev_addr;
- writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr);
-
- new_addr = USBADR(readl(&dev->op_regs->deviceaddr));
- dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr);
- }
-
- done(ep0, req, 0);
-
- switch (dev->ep0_state) {
- case DATA_STATE_XMIT:
- /* receive status phase */
- if (prime_status_phase(dev, EP_DIR_OUT))
- ep0_stall(dev);
- break;
- case DATA_STATE_RECV:
- /* send status phase */
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- break;
- case WAIT_FOR_OUT_STATUS:
- dev->ep0_state = WAIT_FOR_SETUP;
- break;
- case WAIT_FOR_SETUP:
- dev_err(&dev->pdev->dev, "unexpect ep0 packets\n");
- break;
- default:
- ep0_stall(dev);
- break;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB transfer completion interrupt */
-static void handle_trans_complete(struct langwell_udc *dev)
-{
- u32 complete_bits;
- int i, ep_num, dir, bit_mask, status;
- struct langwell_ep *epn;
- struct langwell_request *curr_req, *temp_req;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- complete_bits = readl(&dev->op_regs->endptcomplete);
- dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n",
- complete_bits);
-
- /* Write-Clear the bits in endptcomplete register */
- writel(complete_bits, &dev->op_regs->endptcomplete);
-
- if (!complete_bits) {
- dev_dbg(&dev->pdev->dev, "complete_bits = 0\n");
- goto done;
- }
-
- for (i = 0; i < dev->ep_max; i++) {
- ep_num = i / 2;
- dir = i % 2;
-
- bit_mask = 1 << (ep_num + 16 * dir);
-
- if (!(complete_bits & bit_mask))
- continue;
-
- /* ep0 */
- if (i == 1)
- epn = &dev->ep[0];
- else
- epn = &dev->ep[i];
-
- if (epn->name == NULL) {
- dev_warn(&dev->pdev->dev, "invalid endpoint\n");
- continue;
- }
-
- if (i < 2)
- /* ep0 in and out */
- dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n",
- epn->name,
- is_in(epn) ? "in" : "out");
- else
- dev_dbg(&dev->pdev->dev, "%s transfer completed\n",
- epn->name);
-
- /* process the req queue until an uncomplete request */
- list_for_each_entry_safe(curr_req, temp_req,
- &epn->queue, queue) {
- status = process_ep_req(dev, i, curr_req);
- dev_vdbg(&dev->pdev->dev, "%s req status: %d\n",
- epn->name, status);
-
- if (status)
- break;
-
- /* write back status to req */
- curr_req->req.status = status;
-
- /* ep0 request completion */
- if (ep_num == 0) {
- ep0_req_complete(dev, epn, curr_req);
- break;
- } else {
- done(epn, curr_req, status);
- }
- }
- }
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/* port change detect interrupt handler */
-static void handle_port_change(struct langwell_udc *dev)
-{
- u32 portsc1, devlc;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->bus_reset)
- dev->bus_reset = 0;
-
- portsc1 = readl(&dev->op_regs->portsc1);
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n",
- portsc1, devlc);
-
- /* bus reset is finished */
- if (!(portsc1 & PORTS_PR)) {
- /* get the speed */
- dev->gadget.speed = lpm_device_speed(devlc);
- dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n",
- dev->gadget.speed);
- }
-
- /* LPM L0 to L1 */
- if (dev->lpm && dev->lpm_state == LPM_L0)
- if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) {
- dev_info(&dev->pdev->dev, "LPM L0 to L1\n");
- dev->lpm_state = LPM_L1;
- }
-
- /* LPM L1 to L0, force resume or remote wakeup finished */
- if (dev->lpm && dev->lpm_state == LPM_L1)
- if (!(portsc1 & PORTS_SUSP)) {
- dev_info(&dev->pdev->dev, "LPM L1 to L0\n");
- dev->lpm_state = LPM_L0;
- }
-
- /* update USB state */
- if (!dev->resume_state)
- dev->usb_state = USB_STATE_DEFAULT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB reset interrupt handler */
-static void handle_usb_reset(struct langwell_udc *dev)
-{
- u32 deviceaddr,
- endptsetupstat,
- endptcomplete;
- unsigned long timeout;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* Write-Clear the device address */
- deviceaddr = readl(&dev->op_regs->deviceaddr);
- writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr);
-
- dev->dev_addr = 0;
-
- /* clear usb state */
- dev->resume_state = 0;
-
- /* LPM L1 to L0, reset */
- if (dev->lpm)
- dev->lpm_state = LPM_L0;
-
- dev->ep0_dir = USB_DIR_OUT;
- dev->ep0_state = WAIT_FOR_SETUP;
-
- /* remote wakeup reset to 0 when the device is reset */
- dev->remote_wakeup = 0;
- dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
- dev->gadget.b_hnp_enable = 0;
- dev->gadget.a_hnp_support = 0;
- dev->gadget.a_alt_hnp_support = 0;
-
- /* Write-Clear all the setup token semaphores */
- endptsetupstat = readl(&dev->op_regs->endptsetupstat);
- writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
- /* Write-Clear all the endpoint complete status bits */
- endptcomplete = readl(&dev->op_regs->endptcomplete);
- writel(endptcomplete, &dev->op_regs->endptcomplete);
-
- /* wait until all endptprime bits cleared */
- timeout = jiffies + PRIME_TIMEOUT;
- while (readl(&dev->op_regs->endptprime)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "USB reset timeout\n");
- break;
- }
- cpu_relax();
- }
-
- /* write 1s to endptflush register to clear any primed buffers */
- writel((u32) ~0, &dev->op_regs->endptflush);
-
- if (readl(&dev->op_regs->portsc1) & PORTS_PR) {
- dev_vdbg(&dev->pdev->dev, "USB bus reset\n");
- /* bus is reseting */
- dev->bus_reset = 1;
-
- /* reset all the queues, stop all USB activities */
- stop_activity(dev);
- dev->usb_state = USB_STATE_DEFAULT;
- } else {
- dev_vdbg(&dev->pdev->dev, "device controller reset\n");
- /* controller reset */
- langwell_udc_reset(dev);
-
- /* reset all the queues, stop all USB activities */
- stop_activity(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* enable interrupt and set controller to run state */
- langwell_udc_start(dev);
-
- dev->usb_state = USB_STATE_ATTACHED;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB bus suspend/resume interrupt */
-static void handle_bus_suspend(struct langwell_udc *dev)
-{
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->resume_state = dev->usb_state;
- dev->usb_state = USB_STATE_SUSPENDED;
-
- /* report suspend to the driver */
- if (dev->driver) {
- if (dev->driver->suspend) {
- spin_unlock(&dev->lock);
- dev->driver->suspend(&dev->gadget);
- spin_lock(&dev->lock);
- dev_dbg(&dev->pdev->dev, "suspend %s\n",
- dev->driver->driver.name);
- }
- }
-
- /* enter PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void handle_bus_resume(struct langwell_udc *dev)
-{
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->usb_state = dev->resume_state;
- dev->resume_state = 0;
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* report resume to the driver */
- if (dev->driver) {
- if (dev->driver->resume) {
- spin_unlock(&dev->lock);
- dev->driver->resume(&dev->gadget);
- spin_lock(&dev->lock);
- dev_dbg(&dev->pdev->dev, "resume %s\n",
- dev->driver->driver.name);
- }
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB device controller interrupt handler */
-static irqreturn_t langwell_irq(int irq, void *_dev)
-{
- struct langwell_udc *dev = _dev;
- u32 usbsts,
- usbintr,
- irq_sts,
- portsc1;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->stopped) {
- dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return IRQ_NONE;
- }
-
- spin_lock(&dev->lock);
-
- /* USB status */
- usbsts = readl(&dev->op_regs->usbsts);
-
- /* USB interrupt enable */
- usbintr = readl(&dev->op_regs->usbintr);
-
- irq_sts = usbsts & usbintr;
- dev_vdbg(&dev->pdev->dev,
- "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n",
- usbsts, usbintr, irq_sts);
-
- if (!irq_sts) {
- dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- spin_unlock(&dev->lock);
- return IRQ_NONE;
- }
-
- /* Write-Clear interrupt status bits */
- writel(irq_sts, &dev->op_regs->usbsts);
-
- /* resume from suspend */
- portsc1 = readl(&dev->op_regs->portsc1);
- if (dev->usb_state == USB_STATE_SUSPENDED)
- if (!(portsc1 & PORTS_SUSP))
- handle_bus_resume(dev);
-
- /* USB interrupt */
- if (irq_sts & STS_UI) {
- dev_vdbg(&dev->pdev->dev, "USB interrupt\n");
-
- /* setup packet received from ep0 */
- if (readl(&dev->op_regs->endptsetupstat)
- & EP0SETUPSTAT_MASK) {
- dev_vdbg(&dev->pdev->dev,
- "USB SETUP packet received interrupt\n");
- /* setup tripwire semaphone */
- setup_tripwire(dev);
- handle_setup_packet(dev, &dev->local_setup_buff);
- }
-
- /* USB transfer completion */
- if (readl(&dev->op_regs->endptcomplete)) {
- dev_vdbg(&dev->pdev->dev,
- "USB transfer completion interrupt\n");
- handle_trans_complete(dev);
- }
- }
-
- /* SOF received interrupt (for ISO transfer) */
- if (irq_sts & STS_SRI) {
- /* FIXME */
- /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */
- }
-
- /* port change detect interrupt */
- if (irq_sts & STS_PCI) {
- dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n");
- handle_port_change(dev);
- }
-
- /* suspend interrupt */
- if (irq_sts & STS_SLI) {
- dev_vdbg(&dev->pdev->dev, "suspend interrupt\n");
- handle_bus_suspend(dev);
- }
-
- /* USB reset interrupt */
- if (irq_sts & STS_URI) {
- dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n");
- handle_usb_reset(dev);
- }
-
- /* USB error or system error interrupt */
- if (irq_sts & (STS_UEI | STS_SEI)) {
- /* FIXME */
- dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts);
- }
-
- spin_unlock(&dev->lock);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return IRQ_HANDLED;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* release device structure */
-static void gadget_release(struct device *_dev)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- complete(dev->done);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- kfree(dev);
-}
-
-
-/* enable SRAM caching if SRAM detected */
-static void sram_init(struct langwell_udc *dev)
-{
- struct pci_dev *pdev = dev->pdev;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->sram_addr = pci_resource_start(pdev, 1);
- dev->sram_size = pci_resource_len(pdev, 1);
- dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n",
- dev->sram_addr, dev->sram_size);
- dev->got_sram = 1;
-
- if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) {
- dev_warn(&dev->pdev->dev, "SRAM request failed\n");
- dev->got_sram = 0;
- } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr,
- dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) {
- dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n");
- pci_release_region(pdev, 1);
- dev->got_sram = 0;
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* release SRAM caching */
-static void sram_deinit(struct langwell_udc *dev)
-{
- struct pci_dev *pdev = dev->pdev;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dma_release_declared_memory(&pdev->dev);
- pci_release_region(pdev, 1);
-
- dev->got_sram = 0;
-
- dev_info(&dev->pdev->dev, "release SRAM caching\n");
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* tear down the binding between this driver and the pci device */
-static void langwell_udc_remove(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
-
- DECLARE_COMPLETION(done);
-
- BUG_ON(dev->driver);
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->done = &done;
-
- /* free dTD dma_pool and dQH */
- if (dev->dtd_pool)
- dma_pool_destroy(dev->dtd_pool);
-
- if (dev->ep_dqh)
- dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
- dev->ep_dqh, dev->ep_dqh_dma);
-
- /* release SRAM caching */
- if (dev->has_sram && dev->got_sram)
- sram_deinit(dev);
-
- if (dev->status_req) {
- kfree(dev->status_req->req.buf);
- kfree(dev->status_req);
- }
-
- kfree(dev->ep);
-
- /* disable IRQ handler */
- if (dev->got_irq)
- free_irq(pdev->irq, dev);
-
- if (dev->cap_regs)
- iounmap(dev->cap_regs);
-
- if (dev->region)
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
-
- if (dev->enabled)
- pci_disable_device(pdev);
-
- dev->cap_regs = NULL;
-
- dev_info(&dev->pdev->dev, "unbind\n");
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- device_unregister(&dev->gadget.dev);
- device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
- device_remove_file(&pdev->dev, &dev_attr_remote_wakeup);
-
- pci_set_drvdata(pdev, NULL);
-
- /* free dev, wait for the release() finished */
- wait_for_completion(&done);
-}
-
-
-/*
- * wrap this driver around the specified device, but
- * don't respond over USB until a gadget driver binds to us.
- */
-static int langwell_udc_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct langwell_udc *dev;
- unsigned long resource, len;
- void __iomem *base = NULL;
- size_t size;
- int retval;
-
- /* alloc, and start init */
- dev = kzalloc(sizeof *dev, GFP_KERNEL);
- if (dev == NULL) {
- retval = -ENOMEM;
- goto error;
- }
-
- /* initialize device spinlock */
- spin_lock_init(&dev->lock);
-
- dev->pdev = pdev;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- pci_set_drvdata(pdev, dev);
-
- /* now all the pci goodies ... */
- if (pci_enable_device(pdev) < 0) {
- retval = -ENODEV;
- goto error;
- }
- dev->enabled = 1;
-
- /* control register: BAR 0 */
- resource = pci_resource_start(pdev, 0);
- len = pci_resource_len(pdev, 0);
- if (!request_mem_region(resource, len, driver_name)) {
- dev_err(&dev->pdev->dev, "controller already in use\n");
- retval = -EBUSY;
- goto error;
- }
- dev->region = 1;
-
- base = ioremap_nocache(resource, len);
- if (base == NULL) {
- dev_err(&dev->pdev->dev, "can't map memory\n");
- retval = -EFAULT;
- goto error;
- }
-
- dev->cap_regs = (struct langwell_cap_regs __iomem *) base;
- dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs);
- dev->op_regs = (struct langwell_op_regs __iomem *)
- (base + OP_REG_OFFSET);
- dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs);
-
- /* irq setup after old hardware is cleaned up */
- if (!pdev->irq) {
- dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n");
- retval = -ENODEV;
- goto error;
- }
-
- dev->has_sram = 1;
- dev->got_sram = 0;
- dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram);
-
- /* enable SRAM caching if detected */
- if (dev->has_sram && !dev->got_sram)
- sram_init(dev);
-
- dev_info(&dev->pdev->dev,
- "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n",
- pdev->irq, resource, len, base);
- /* enables bus-mastering for device dev */
- pci_set_master(pdev);
-
- if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
- driver_name, dev) != 0) {
- dev_err(&dev->pdev->dev,
- "request interrupt %d failed\n", pdev->irq);
- retval = -EBUSY;
- goto error;
- }
- dev->got_irq = 1;
-
- /* set stopped bit */
- dev->stopped = 1;
-
- /* capabilities and endpoint number */
- dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0;
- dev->dciversion = readw(&dev->cap_regs->dciversion);
- dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0;
- dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm);
- dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n",
- dev->dciversion);
- dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n",
- readl(&dev->cap_regs->dccparams));
- dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap);
- if (!dev->devcap) {
- dev_err(&dev->pdev->dev, "can't support device mode\n");
- retval = -ENODEV;
- goto error;
- }
-
- /* a pair of endpoints (out/in) for each address */
- dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2;
- dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max);
-
- /* allocate endpoints memory */
- dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max,
- GFP_KERNEL);
- if (!dev->ep) {
- dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
-
- /* allocate device dQH memory */
- size = dev->ep_max * sizeof(struct langwell_dqh);
- dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
- if (size < DQH_ALIGNMENT)
- size = DQH_ALIGNMENT;
- else if ((size % DQH_ALIGNMENT) != 0) {
- size += DQH_ALIGNMENT + 1;
- size &= ~(DQH_ALIGNMENT - 1);
- }
- dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
- &dev->ep_dqh_dma, GFP_KERNEL);
- if (!dev->ep_dqh) {
- dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
- dev->ep_dqh_size = size;
- dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
- /* initialize ep0 status request structure */
- dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
- if (!dev->status_req) {
- dev_err(&dev->pdev->dev,
- "allocate status_req memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
- INIT_LIST_HEAD(&dev->status_req->queue);
-
- /* allocate a small amount of memory to get valid address */
- dev->status_req->req.buf = kmalloc(8, GFP_KERNEL);
- dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf);
-
- dev->resume_state = USB_STATE_NOTATTACHED;
- dev->usb_state = USB_STATE_POWERED;
- dev->ep0_dir = USB_DIR_OUT;
-
- /* remote wakeup reset to 0 when the device is reset */
- dev->remote_wakeup = 0;
- dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
-
- /* reset device controller */
- langwell_udc_reset(dev);
-
- /* initialize gadget structure */
- dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */
- dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */
- INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */
- dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
- dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
-
- /* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
- dev->gadget.name = driver_name; /* gadget name */
-
- /* controller endpoints reinit */
- eps_reinit(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* create dTD dma_pool resource */
- dev->dtd_pool = dma_pool_create("langwell_dtd",
- &dev->pdev->dev,
- sizeof(struct langwell_dtd),
- DTD_ALIGNMENT,
- DMA_BOUNDARY);
-
- if (!dev->dtd_pool) {
- retval = -ENOMEM;
- goto error;
- }
-
- /* done */
- dev_info(&dev->pdev->dev, "%s\n", driver_desc);
- dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base);
- dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n");
- dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max);
- dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n",
- dev->dciversion);
- dev_info(&dev->pdev->dev, "Controller mode: %s\n",
- dev->devcap ? "Device" : "Host");
- dev_info(&dev->pdev->dev, "Support USB LPM: %s\n",
- dev->lpm ? "Yes" : "No");
-
- dev_vdbg(&dev->pdev->dev,
- "After langwell_udc_probe(), print all registers:\n");
- print_all_registers(dev);
-
- retval = device_register(&dev->gadget.dev);
- if (retval)
- goto error;
-
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
- if (retval)
- goto error;
-
- retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
- if (retval)
- goto error;
-
- retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup);
- if (retval)
- goto error_attr1;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-
-error_attr1:
- device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
-error:
- if (dev) {
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- langwell_udc_remove(pdev);
- }
-
- return retval;
-}
-
-
-/* device controller suspend */
-static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- usb_del_gadget_udc(&dev->gadget);
- /* disable interrupt and set controller to stop state */
- langwell_udc_stop(dev);
-
- /* disable IRQ handler */
- if (dev->got_irq)
- free_irq(pdev->irq, dev);
- dev->got_irq = 0;
-
- /* save PCI state */
- pci_save_state(pdev);
-
- spin_lock_irq(&dev->lock);
- /* stop all usb activities */
- stop_activity(dev);
- spin_unlock_irq(&dev->lock);
-
- /* free dTD dma_pool and dQH */
- if (dev->dtd_pool)
- dma_pool_destroy(dev->dtd_pool);
-
- if (dev->ep_dqh)
- dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
- dev->ep_dqh, dev->ep_dqh_dma);
-
- /* release SRAM caching */
- if (dev->has_sram && dev->got_sram)
- sram_deinit(dev);
-
- /* set device power state */
- pci_set_power_state(pdev, PCI_D3hot);
-
- /* enter PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 1);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* device controller resume */
-static int langwell_udc_resume(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
- size_t size;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* set device D0 power state */
- pci_set_power_state(pdev, PCI_D0);
-
- /* enable SRAM caching if detected */
- if (dev->has_sram && !dev->got_sram)
- sram_init(dev);
-
- /* allocate device dQH memory */
- size = dev->ep_max * sizeof(struct langwell_dqh);
- dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
- if (size < DQH_ALIGNMENT)
- size = DQH_ALIGNMENT;
- else if ((size % DQH_ALIGNMENT) != 0) {
- size += DQH_ALIGNMENT + 1;
- size &= ~(DQH_ALIGNMENT - 1);
- }
- dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
- &dev->ep_dqh_dma, GFP_KERNEL);
- if (!dev->ep_dqh) {
- dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
- return -ENOMEM;
- }
- dev->ep_dqh_size = size;
- dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
- /* create dTD dma_pool resource */
- dev->dtd_pool = dma_pool_create("langwell_dtd",
- &dev->pdev->dev,
- sizeof(struct langwell_dtd),
- DTD_ALIGNMENT,
- DMA_BOUNDARY);
-
- if (!dev->dtd_pool)
- return -ENOMEM;
-
- /* restore PCI state */
- pci_restore_state(pdev);
-
- /* enable IRQ handler */
- if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
- driver_name, dev) != 0) {
- dev_err(&dev->pdev->dev, "request interrupt %d failed\n",
- pdev->irq);
- return -EBUSY;
- }
- dev->got_irq = 1;
-
- /* reset and start controller to run state */
- if (dev->stopped) {
- /* reset device controller */
- langwell_udc_reset(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* start device if gadget is loaded */
- if (dev->driver)
- langwell_udc_start(dev);
- }
-
- /* reset USB status */
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* pci driver shutdown */
-static void langwell_udc_shutdown(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
- u32 usbmode;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* reset controller mode to IDLE */
- usbmode = readl(&dev->op_regs->usbmode);
- dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode);
- usbmode &= (~3 | MODE_IDLE);
- writel(usbmode, &dev->op_regs->usbmode);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id pci_ids[] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
- .vendor = 0x8086,
- .device = 0x0811,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
-}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-
-static struct pci_driver langwell_pci_driver = {
- .name = (char *) driver_name,
- .id_table = pci_ids,
-
- .probe = langwell_udc_probe,
- .remove = langwell_udc_remove,
-
- /* device controller suspend/resume */
- .suspend = langwell_udc_suspend,
- .resume = langwell_udc_resume,
-
- .shutdown = langwell_udc_shutdown,
-};
-
-
-static int __init init(void)
-{
- return pci_register_driver(&langwell_pci_driver);
-}
-module_init(init);
-
-
-static void __exit cleanup(void)
-{
- pci_unregister_driver(&langwell_pci_driver);
-}
-module_exit(cleanup);
-
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
deleted file mode 100644
index 8c8087a..0000000
--- a/drivers/usb/gadget/langwell_udc.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- */
-
-#include <linux/usb/langwell_udc.h>
-
-/*-------------------------------------------------------------------------*/
-
-/* driver data structures and utilities */
-
-/*
- * dTD: Device Endpoint Transfer Descriptor
- * describe to the device controller the location and quantity of
- * data to be send/received for given transfer
- */
-struct langwell_dtd {
- u32 dtd_next;
-/* bits 31:5, next transfer element pointer */
-#define DTD_NEXT(d) (((d)>>5)&0x7ffffff)
-#define DTD_NEXT_MASK (0x7ffffff << 5)
-/* terminate */
-#define DTD_TERM BIT(0)
- /* bits 7:0, execution back states */
- u32 dtd_status:8;
-#define DTD_STATUS(d) (((d)>>0)&0xff)
-#define DTD_STS_ACTIVE BIT(7) /* active */
-#define DTD_STS_HALTED BIT(6) /* halted */
-#define DTD_STS_DBE BIT(5) /* data buffer error */
-#define DTD_STS_TRE BIT(3) /* transaction error */
- /* bits 9:8 */
- u32 dtd_res0:2;
- /* bits 11:10, multipier override */
- u32 dtd_multo:2;
-#define DTD_MULTO (BIT(11) | BIT(10))
- /* bits 14:12 */
- u32 dtd_res1:3;
- /* bit 15, interrupt on complete */
- u32 dtd_ioc:1;
-#define DTD_IOC BIT(15)
- /* bits 30:16, total bytes */
- u32 dtd_total:15;
-#define DTD_TOTAL(d) (((d)>>16)&0x7fff)
-#define DTD_MAX_TRANSFER_LENGTH 0x4000
- /* bit 31 */
- u32 dtd_res2:1;
- /* dTD buffer pointer page 0 to 4 */
- u32 dtd_buf[5];
-#define DTD_OFFSET_MASK 0xfff
-/* bits 31:12, buffer pointer */
-#define DTD_BUFFER(d) (((d)>>12)&0x3ff)
-/* bits 11:0, current offset */
-#define DTD_C_OFFSET(d) (((d)>>0)&0xfff)
-/* bits 10:0, frame number */
-#define DTD_FRAME(d) (((d)>>0)&0x7ff)
-
- /* driver-private parts */
-
- /* dtd dma address */
- dma_addr_t dtd_dma;
- /* next dtd virtual address */
- struct langwell_dtd *next_dtd_virt;
-};
-
-
-/*
- * dQH: Device Endpoint Queue Head
- * describe where all transfers are managed
- * 48-byte data structure, aligned on 64-byte boundary
- *
- * These are associated with dTD structure
- */
-struct langwell_dqh {
- /* endpoint capabilities and characteristics */
- u32 dqh_res0:15; /* bits 14:0 */
- u32 dqh_ios:1; /* bit 15, interrupt on setup */
-#define DQH_IOS BIT(15)
- u32 dqh_mpl:11; /* bits 26:16, maximum packet length */
-#define DQH_MPL (0x7ff << 16)
- u32 dqh_res1:2; /* bits 28:27 */
- u32 dqh_zlt:1; /* bit 29, zero length termination */
-#define DQH_ZLT BIT(29)
- u32 dqh_mult:2; /* bits 31:30 */
-#define DQH_MULT (BIT(30) | BIT(31))
-
- /* current dTD pointer */
- u32 dqh_current; /* locate the transfer in progress */
-#define DQH_C_DTD(e) \
- (((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */
-
- /* transfer overlay, hardware parts of a struct langwell_dtd */
- u32 dtd_next;
- u32 dtd_status:8; /* bits 7:0, execution back states */
- u32 dtd_res0:2; /* bits 9:8 */
- u32 dtd_multo:2; /* bits 11:10, multipier override */
- u32 dtd_res1:3; /* bits 14:12 */
- u32 dtd_ioc:1; /* bit 15, interrupt on complete */
- u32 dtd_total:15; /* bits 30:16, total bytes */
- u32 dtd_res2:1; /* bit 31 */
- u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */
-
- u32 dqh_res2;
- struct usb_ctrlrequest dqh_setup; /* setup packet buffer */
-} __attribute__ ((aligned(64)));
-
-
-/* endpoint data structure */
-struct langwell_ep {
- struct usb_ep ep;
- dma_addr_t dma;
- struct langwell_udc *dev;
- unsigned long irqs;
- struct list_head queue;
- struct langwell_dqh *dqh;
- const struct usb_endpoint_descriptor *desc;
- char name[14];
- unsigned stopped:1,
- ep_type:2,
- ep_num:8;
-};
-
-
-/* request data structure */
-struct langwell_request {
- struct usb_request req;
- struct langwell_dtd *dtd, *head, *tail;
- struct langwell_ep *ep;
- dma_addr_t dtd_dma;
- struct list_head queue;
- unsigned dtd_count;
- unsigned mapped:1;
-};
-
-
-/* ep0 transfer state */
-enum ep0_state {
- WAIT_FOR_SETUP,
- DATA_STATE_XMIT,
- DATA_STATE_NEED_ZLP,
- WAIT_FOR_OUT_STATUS,
- DATA_STATE_RECV,
-};
-
-
-/* device suspend state */
-enum lpm_state {
- LPM_L0, /* on */
- LPM_L1, /* LPM L1 sleep */
- LPM_L2, /* suspend */
- LPM_L3, /* off */
-};
-
-
-/* device data structure */
-struct langwell_udc {
- /* each pci device provides one gadget, several endpoints */
- struct usb_gadget gadget;
- spinlock_t lock; /* device lock */
- struct langwell_ep *ep;
- struct usb_gadget_driver *driver;
- struct usb_phy *transceiver;
- u8 dev_addr;
- u32 usb_state;
- u32 resume_state;
- u32 bus_reset;
- enum lpm_state lpm_state;
- enum ep0_state ep0_state;
- u32 ep0_dir;
- u16 dciversion;
- unsigned ep_max;
- unsigned devcap:1,
- enabled:1,
- region:1,
- got_irq:1,
- powered:1,
- remote_wakeup:1,
- rate:1,
- is_reset:1,
- softconnected:1,
- vbus_active:1,
- suspended:1,
- stopped:1,
- lpm:1, /* LPM capability */
- has_sram:1, /* SRAM caching */
- got_sram:1;
-
- /* pci state used to access those endpoints */
- struct pci_dev *pdev;
-
- /* Langwell otg transceiver */
- struct langwell_otg *lotg;
-
- /* control registers */
- struct langwell_cap_regs __iomem *cap_regs;
- struct langwell_op_regs __iomem *op_regs;
-
- struct usb_ctrlrequest local_setup_buff;
- struct langwell_dqh *ep_dqh;
- size_t ep_dqh_size;
- dma_addr_t ep_dqh_dma;
-
- /* ep0 status request */
- struct langwell_request *status_req;
-
- /* dma pool */
- struct dma_pool *dtd_pool;
-
- /* make sure release() is done */
- struct completion *done;
-
- /* for private SRAM caching */
- unsigned int sram_addr;
- unsigned int sram_size;
-
- /* device status data for get_status request */
- u16 dev_status;
-};
-
-#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget)
-
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
new file mode 100644
index 0000000..262acfd
--- /dev/null
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -0,0 +1,3538 @@
+/*
+ * USB Gadget driver for LPC32xx
+ *
+ * Authors:
+ * Kevin Wells <kevin.wells@nxp.com>
+ * Mike James
+ * Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2006 Philips Semiconductors
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Note: This driver is based on original work done by Mike James for
+ * the LPC3180.
+ *
+ * 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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
+
+#include <asm/byteorder.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <mach/platform.h>
+#include <mach/irqs.h>
+#include <mach/board.h>
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#include <linux/seq_file.h>
+#endif
+
+/*
+ * USB device configuration structure
+ */
+typedef void (*usc_chg_event)(int);
+struct lpc32xx_usbd_cfg {
+ int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */
+ usc_chg_event conn_chgb; /* Connection change event (optional) */
+ usc_chg_event susp_chgb; /* Suspend/resume event (optional) */
+ usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */
+};
+
+/*
+ * controller driver data structures
+ */
+
+/* 16 endpoints (not to be confused with 32 hardware endpoints) */
+#define NUM_ENDPOINTS 16
+
+/*
+ * IRQ indices make reading the code a little easier
+ */
+#define IRQ_USB_LP 0
+#define IRQ_USB_HP 1
+#define IRQ_USB_DEVDMA 2
+#define IRQ_USB_ATX 3
+
+#define EP_OUT 0 /* RX (from host) */
+#define EP_IN 1 /* TX (to host) */
+
+/* Returns the interrupt mask for the selected hardware endpoint */
+#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir))
+
+#define EP_INT_TYPE 0
+#define EP_ISO_TYPE 1
+#define EP_BLK_TYPE 2
+#define EP_CTL_TYPE 3
+
+/* EP0 states */
+#define WAIT_FOR_SETUP 0 /* Wait for setup packet */
+#define DATA_IN 1 /* Expect dev->host transfer */
+#define DATA_OUT 2 /* Expect host->dev transfer */
+
+/* DD (DMA Descriptor) structure, requires word alignment, this is already
+ * defined in the LPC32XX USB device header file, but this version is slightly
+ * modified to tag some work data with each DMA descriptor. */
+struct lpc32xx_usbd_dd_gad {
+ u32 dd_next_phy;
+ u32 dd_setup;
+ u32 dd_buffer_addr;
+ u32 dd_status;
+ u32 dd_iso_ps_mem_addr;
+ u32 this_dma;
+ u32 iso_status[6]; /* 5 spare */
+ u32 dd_next_v;
+};
+
+/*
+ * Logical endpoint structure
+ */
+struct lpc32xx_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct lpc32xx_udc *udc;
+
+ u32 hwep_num_base; /* Physical hardware EP */
+ u32 hwep_num; /* Maps to hardware endpoint */
+ u32 maxpacket;
+ u32 lep;
+
+ bool is_in;
+ bool req_pending;
+ u32 eptype;
+
+ u32 totalints;
+
+ bool wedge;
+
+ const struct usb_endpoint_descriptor *desc;
+};
+
+/*
+ * Common UDC structure
+ */
+struct lpc32xx_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *pdev;
+ struct device *dev;
+ struct dentry *pde;
+ spinlock_t lock;
+ struct i2c_client *isp1301_i2c_client;
+
+ /* Board and device specific */
+ struct lpc32xx_usbd_cfg *board;
+ u32 io_p_start;
+ u32 io_p_size;
+ void __iomem *udp_baseaddr;
+ int udp_irq[4];
+ struct clk *usb_pll_clk;
+ struct clk *usb_slv_clk;
+
+ /* DMA support */
+ u32 *udca_v_base;
+ u32 udca_p_base;
+ struct dma_pool *dd_cache;
+
+ /* Common EP and control data */
+ u32 enabled_devints;
+ u32 enabled_hwepints;
+ u32 dev_status;
+ u32 realized_eps;
+
+ /* VBUS detection, pullup, and power flags */
+ u8 vbus;
+ u8 last_vbus;
+ int pullup;
+ int poweron;
+
+ /* Work queues related to I2C support */
+ struct work_struct pullup_job;
+ struct work_struct vbus_job;
+ struct work_struct power_job;
+
+ /* USB device peripheral - various */
+ struct lpc32xx_ep ep[NUM_ENDPOINTS];
+ bool enabled;
+ bool clocked;
+ bool suspended;
+ bool selfpowered;
+ int ep0state;
+ atomic_t enabled_ep_cnt;
+ wait_queue_head_t ep_disable_wait_queue;
+};
+
+/*
+ * Endpoint request
+ */
+struct lpc32xx_request {
+ struct usb_request req;
+ struct list_head queue;
+ struct lpc32xx_usbd_dd_gad *dd_desc_ptr;
+ bool mapped;
+ bool send_zlp;
+};
+
+static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
+{
+ return container_of(g, struct lpc32xx_udc, gadget);
+}
+
+#define ep_dbg(epp, fmt, arg...) \
+ dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_err(epp, fmt, arg...) \
+ dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_info(epp, fmt, arg...) \
+ dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_warn(epp, fmt, arg...) \
+ dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg)
+
+#define UDCA_BUFF_SIZE (128)
+
+/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
+ * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL()
+ * */
+#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
+#define USB_CLOCK_MASK (AHB_M_CLOCK_ON | OTG_CLOCK_ON | \
+ DEV_CLOCK_ON | I2C_CLOCK_ON)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_HOST_NEED_CLK_EN (1 << 21)
+#define USB_DEV_NEED_CLK_EN (1 << 22)
+
+#define USB_OTG_CLK_CTRL(udc) ((udc)->udp_baseaddr + 0xFF4)
+#define USB_OTG_CLK_STAT(udc) ((udc)->udp_baseaddr + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON (1 << 4)
+#define OTG_CLOCK_ON (1 << 3)
+#define I2C_CLOCK_ON (1 << 2)
+#define DEV_CLOCK_ON (1 << 1)
+#define HOST_CLOCK_ON (1 << 0)
+
+#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN (1 << 7)
+#define HOST_EN (1 << 0)
+
+/**********************************************************************
+ * USB device controller register offsets
+ **********************************************************************/
+
+#define USBD_DEVINTST(x) ((x) + 0x200)
+#define USBD_DEVINTEN(x) ((x) + 0x204)
+#define USBD_DEVINTCLR(x) ((x) + 0x208)
+#define USBD_DEVINTSET(x) ((x) + 0x20C)
+#define USBD_CMDCODE(x) ((x) + 0x210)
+#define USBD_CMDDATA(x) ((x) + 0x214)
+#define USBD_RXDATA(x) ((x) + 0x218)
+#define USBD_TXDATA(x) ((x) + 0x21C)
+#define USBD_RXPLEN(x) ((x) + 0x220)
+#define USBD_TXPLEN(x) ((x) + 0x224)
+#define USBD_CTRL(x) ((x) + 0x228)
+#define USBD_DEVINTPRI(x) ((x) + 0x22C)
+#define USBD_EPINTST(x) ((x) + 0x230)
+#define USBD_EPINTEN(x) ((x) + 0x234)
+#define USBD_EPINTCLR(x) ((x) + 0x238)
+#define USBD_EPINTSET(x) ((x) + 0x23C)
+#define USBD_EPINTPRI(x) ((x) + 0x240)
+#define USBD_REEP(x) ((x) + 0x244)
+#define USBD_EPIND(x) ((x) + 0x248)
+#define USBD_EPMAXPSIZE(x) ((x) + 0x24C)
+/* DMA support registers only below */
+/* Set, clear, or get enabled state of the DMA request status. If
+ * enabled, an IN or OUT token will start a DMA transfer for the EP */
+#define USBD_DMARST(x) ((x) + 0x250)
+#define USBD_DMARCLR(x) ((x) + 0x254)
+#define USBD_DMARSET(x) ((x) + 0x258)
+/* DMA UDCA head pointer */
+#define USBD_UDCAH(x) ((x) + 0x280)
+/* EP DMA status, enable, and disable. This is used to specifically
+ * enabled or disable DMA for a specific EP */
+#define USBD_EPDMAST(x) ((x) + 0x284)
+#define USBD_EPDMAEN(x) ((x) + 0x288)
+#define USBD_EPDMADIS(x) ((x) + 0x28C)
+/* DMA master interrupts enable and pending interrupts */
+#define USBD_DMAINTST(x) ((x) + 0x290)
+#define USBD_DMAINTEN(x) ((x) + 0x294)
+/* DMA end of transfer interrupt enable, disable, status */
+#define USBD_EOTINTST(x) ((x) + 0x2A0)
+#define USBD_EOTINTCLR(x) ((x) + 0x2A4)
+#define USBD_EOTINTSET(x) ((x) + 0x2A8)
+/* New DD request interrupt enable, disable, status */
+#define USBD_NDDRTINTST(x) ((x) + 0x2AC)
+#define USBD_NDDRTINTCLR(x) ((x) + 0x2B0)
+#define USBD_NDDRTINTSET(x) ((x) + 0x2B4)
+/* DMA error interrupt enable, disable, status */
+#define USBD_SYSERRTINTST(x) ((x) + 0x2B8)
+#define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC)
+#define USBD_SYSERRTINTSET(x) ((x) + 0x2C0)
+
+/**********************************************************************
+ * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/
+ * USBD_DEVINTPRI register definitions
+ **********************************************************************/
+#define USBD_ERR_INT (1 << 9)
+#define USBD_EP_RLZED (1 << 8)
+#define USBD_TXENDPKT (1 << 7)
+#define USBD_RXENDPKT (1 << 6)
+#define USBD_CDFULL (1 << 5)
+#define USBD_CCEMPTY (1 << 4)
+#define USBD_DEV_STAT (1 << 3)
+#define USBD_EP_SLOW (1 << 2)
+#define USBD_EP_FAST (1 << 1)
+#define USBD_FRAME (1 << 0)
+
+/**********************************************************************
+ * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/
+ * USBD_EPINTPRI register definitions
+ **********************************************************************/
+/* End point selection macro (RX) */
+#define USBD_RX_EP_SEL(e) (1 << ((e) << 1))
+
+/* End point selection macro (TX) */
+#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1))
+
+/**********************************************************************
+ * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/
+ * USBD_EPDMAEN/USBD_EPDMADIS/
+ * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/
+ * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/
+ * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET
+ * register definitions
+ **********************************************************************/
+/* Endpoint selection macro */
+#define USBD_EP_SEL(e) (1 << (e))
+
+/**********************************************************************
+ * SBD_DMAINTST/USBD_DMAINTEN
+ **********************************************************************/
+#define USBD_SYS_ERR_INT (1 << 2)
+#define USBD_NEW_DD_INT (1 << 1)
+#define USBD_EOT_INT (1 << 0)
+
+/**********************************************************************
+ * USBD_RXPLEN register definitions
+ **********************************************************************/
+#define USBD_PKT_RDY (1 << 11)
+#define USBD_DV (1 << 10)
+#define USBD_PK_LEN_MASK 0x3FF
+
+/**********************************************************************
+ * USBD_CTRL register definitions
+ **********************************************************************/
+#define USBD_LOG_ENDPOINT(e) ((e) << 2)
+#define USBD_WR_EN (1 << 1)
+#define USBD_RD_EN (1 << 0)
+
+/**********************************************************************
+ * USBD_CMDCODE register definitions
+ **********************************************************************/
+#define USBD_CMD_CODE(c) ((c) << 16)
+#define USBD_CMD_PHASE(p) ((p) << 8)
+
+/**********************************************************************
+ * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions
+ **********************************************************************/
+#define USBD_DMAEP(e) (1 << (e))
+
+/* DD (DMA Descriptor) structure, requires word alignment */
+struct lpc32xx_usbd_dd {
+ u32 *dd_next;
+ u32 dd_setup;
+ u32 dd_buffer_addr;
+ u32 dd_status;
+ u32 dd_iso_ps_mem_addr;
+};
+
+/* dd_setup bit defines */
+#define DD_SETUP_ATLE_DMA_MODE 0x01
+#define DD_SETUP_NEXT_DD_VALID 0x04
+#define DD_SETUP_ISO_EP 0x10
+#define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5)
+#define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16)
+
+/* dd_status bit defines */
+#define DD_STATUS_DD_RETIRED 0x01
+#define DD_STATUS_STS_MASK 0x1E
+#define DD_STATUS_STS_NS 0x00 /* Not serviced */
+#define DD_STATUS_STS_BS 0x02 /* Being serviced */
+#define DD_STATUS_STS_NC 0x04 /* Normal completion */
+#define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */
+#define DD_STATUS_STS_DOR 0x08 /* Data overrun */
+#define DD_STATUS_STS_SE 0x12 /* System error */
+#define DD_STATUS_PKT_VAL 0x20 /* Packet valid */
+#define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */
+#define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */
+#define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F)
+#define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF)
+
+/*
+ *
+ * Protocol engine bits below
+ *
+ */
+/* Device Interrupt Bit Definitions */
+#define FRAME_INT 0x00000001
+#define EP_FAST_INT 0x00000002
+#define EP_SLOW_INT 0x00000004
+#define DEV_STAT_INT 0x00000008
+#define CCEMTY_INT 0x00000010
+#define CDFULL_INT 0x00000020
+#define RxENDPKT_INT 0x00000040
+#define TxENDPKT_INT 0x00000080
+#define EP_RLZED_INT 0x00000100
+#define ERR_INT 0x00000200
+
+/* Rx & Tx Packet Length Definitions */
+#define PKT_LNGTH_MASK 0x000003FF
+#define PKT_DV 0x00000400
+#define PKT_RDY 0x00000800
+
+/* USB Control Definitions */
+#define CTRL_RD_EN 0x00000001
+#define CTRL_WR_EN 0x00000002
+
+/* Command Codes */
+#define CMD_SET_ADDR 0x00D00500
+#define CMD_CFG_DEV 0x00D80500
+#define CMD_SET_MODE 0x00F30500
+#define CMD_RD_FRAME 0x00F50500
+#define DAT_RD_FRAME 0x00F50200
+#define CMD_RD_TEST 0x00FD0500
+#define DAT_RD_TEST 0x00FD0200
+#define CMD_SET_DEV_STAT 0x00FE0500
+#define CMD_GET_DEV_STAT 0x00FE0500
+#define DAT_GET_DEV_STAT 0x00FE0200
+#define CMD_GET_ERR_CODE 0x00FF0500
+#define DAT_GET_ERR_CODE 0x00FF0200
+#define CMD_RD_ERR_STAT 0x00FB0500
+#define DAT_RD_ERR_STAT 0x00FB0200
+#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16))
+#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16))
+#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16))
+#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16))
+#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16))
+#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16))
+#define CMD_CLR_BUF 0x00F20500
+#define DAT_CLR_BUF 0x00F20200
+#define CMD_VALID_BUF 0x00FA0500
+
+/* Device Address Register Definitions */
+#define DEV_ADDR_MASK 0x7F
+#define DEV_EN 0x80
+
+/* Device Configure Register Definitions */
+#define CONF_DVICE 0x01
+
+/* Device Mode Register Definitions */
+#define AP_CLK 0x01
+#define INAK_CI 0x02
+#define INAK_CO 0x04
+#define INAK_II 0x08
+#define INAK_IO 0x10
+#define INAK_BI 0x20
+#define INAK_BO 0x40
+
+/* Device Status Register Definitions */
+#define DEV_CON 0x01
+#define DEV_CON_CH 0x02
+#define DEV_SUS 0x04
+#define DEV_SUS_CH 0x08
+#define DEV_RST 0x10
+
+/* Error Code Register Definitions */
+#define ERR_EC_MASK 0x0F
+#define ERR_EA 0x10
+
+/* Error Status Register Definitions */
+#define ERR_PID 0x01
+#define ERR_UEPKT 0x02
+#define ERR_DCRC 0x04
+#define ERR_TIMOUT 0x08
+#define ERR_EOP 0x10
+#define ERR_B_OVRN 0x20
+#define ERR_BTSTF 0x40
+#define ERR_TGL 0x80
+
+/* Endpoint Select Register Definitions */
+#define EP_SEL_F 0x01
+#define EP_SEL_ST 0x02
+#define EP_SEL_STP 0x04
+#define EP_SEL_PO 0x08
+#define EP_SEL_EPN 0x10
+#define EP_SEL_B_1_FULL 0x20
+#define EP_SEL_B_2_FULL 0x40
+
+/* Endpoint Status Register Definitions */
+#define EP_STAT_ST 0x01
+#define EP_STAT_DA 0x20
+#define EP_STAT_RF_MO 0x40
+#define EP_STAT_CND_ST 0x80
+
+/* Clear Buffer Register Definitions */
+#define CLR_BUF_PO 0x01
+
+/* DMA Interrupt Bit Definitions */
+#define EOT_INT 0x01
+#define NDD_REQ_INT 0x02
+#define SYS_ERR_INT 0x04
+
+#define DRIVER_VERSION "1.03"
+static const char driver_name[] = "lpc32xx_udc";
+
+/*
+ *
+ * proc interface support
+ *
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"};
+static const char debug_filename[] = "driver/udc";
+
+static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+
+ seq_printf(s, "\n");
+ seq_printf(s, "%12s, maxpacket %4d %3s",
+ ep->ep.name, ep->ep.maxpacket,
+ ep->is_in ? "in" : "out");
+ seq_printf(s, " type %4s", epnames[ep->eptype]);
+ seq_printf(s, " ints: %12d", ep->totalints);
+
+ if (list_empty(&ep->queue))
+ seq_printf(s, "\t(queue empty)\n");
+ else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ u32 length = req->req.actual;
+
+ seq_printf(s, "\treq %p len %d/%d buf %p\n",
+ &req->req, length,
+ req->req.length, req->req.buf);
+ }
+ }
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+ struct lpc32xx_udc *udc = s->private;
+ struct lpc32xx_ep *ep;
+ unsigned long flags;
+
+ seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+ udc->vbus ? "present" : "off",
+ udc->enabled ? (udc->vbus ? "active" : "enabled") :
+ "disabled",
+ udc->selfpowered ? "self" : "VBUS",
+ udc->suspended ? ", suspended" : "",
+ udc->driver ? udc->driver->driver.name : "(none)");
+
+ if (udc->enabled && udc->vbus) {
+ proc_ep_show(s, &udc->ep[0]);
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc)
+ proc_ep_show(s, ep);
+ }
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
+ .open = proc_udc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void create_debug_file(struct lpc32xx_udc *udc)
+{
+ udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops);
+}
+
+static void remove_debug_file(struct lpc32xx_udc *udc)
+{
+ if (udc->pde)
+ debugfs_remove(udc->pde);
+}
+
+#else
+static inline void create_debug_file(struct lpc32xx_udc *udc) {}
+static inline void remove_debug_file(struct lpc32xx_udc *udc) {}
+#endif
+
+/* Primary initialization sequence for the ISP1301 transceiver */
+static void isp1301_udc_configure(struct lpc32xx_udc *udc)
+{
+ /* LPC32XX only supports DAT_SE0 USB mode */
+ /* This sequence is important */
+
+ /* Disable transparent UART mode first */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ MC1_UART_EN);
+
+ /* Set full speed and SE0 mode */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0));
+
+ /*
+ * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide
+ */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL));
+
+ /* Driver VBUS_DRV high or low depending on board setup */
+ if (udc->board->vbus_drv_pol != 0)
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+ else
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_VBUS_DRV);
+
+ /* Bi-directional mode with suspend control
+ * Enable both pulldowns for now - the pullup will be enable when VBUS
+ * is detected */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1,
+ (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+ /* Discharge VBUS (just in case) */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+ msleep(1);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ OTG1_VBUS_DISCHRG);
+
+ /* Clear and enable VBUS high edge interrupt */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
+
+ /* Enable usb_need_clk clock after transceiver is initialized */
+ writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+
+ dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
+ dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02));
+ dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14));
+}
+
+/* Enables or disables the USB device pullup via the ISP1301 transceiver */
+static void isp1301_pullup_set(struct lpc32xx_udc *udc)
+{
+ if (udc->pullup)
+ /* Enable pullup for bus signalling */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP);
+ else
+ /* Enable pullup for bus signalling */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_DP_PULLUP);
+}
+
+static void pullup_work(struct work_struct *work)
+{
+ struct lpc32xx_udc *udc =
+ container_of(work, struct lpc32xx_udc, pullup_job);
+
+ isp1301_pullup_set(udc);
+}
+
+static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup,
+ int block)
+{
+ if (en_pullup == udc->pullup)
+ return;
+
+ udc->pullup = en_pullup;
+ if (block)
+ isp1301_pullup_set(udc);
+ else
+ /* defer slow i2c pull up setting */
+ schedule_work(&udc->pullup_job);
+}
+
+#ifdef CONFIG_PM
+/* Powers up or down the ISP1301 transceiver */
+static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable)
+{
+ if (enable != 0)
+ /* Power up ISP1301 - this ISP1301 will automatically wakeup
+ when VBUS is detected */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
+ MC2_GLOBAL_PWR_DN);
+ else
+ /* Power down ISP1301 */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+}
+
+static void power_work(struct work_struct *work)
+{
+ struct lpc32xx_udc *udc =
+ container_of(work, struct lpc32xx_udc, power_job);
+
+ isp1301_set_powerstate(udc, udc->poweron);
+}
+#endif
+
+/*
+ *
+ * USB protocol engine command/data read/write helper functions
+ *
+ */
+/* Issues a single command to the USB device state machine */
+static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd)
+{
+ u32 pass = 0;
+ int to;
+
+ /* EP may lock on CLRI if this read isn't done */
+ u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+ (void) tmp;
+
+ while (pass == 0) {
+ writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Write command code */
+ writel(cmd, USBD_CMDCODE(udc->udp_baseaddr));
+ to = 10000;
+ while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+ USBD_CCEMPTY) == 0) && (to > 0)) {
+ to--;
+ }
+
+ if (to > 0)
+ pass = 1;
+
+ cpu_relax();
+ }
+}
+
+/* Issues 2 commands (or command and data) to the USB device state machine */
+static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd,
+ u32 data)
+{
+ udc_protocol_cmd_w(udc, cmd);
+ udc_protocol_cmd_w(udc, data);
+}
+
+/* Issues a single command to the USB device state machine and reads
+ * response data */
+static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd)
+{
+ u32 tmp;
+ int to = 1000;
+
+ /* Write a command and read data from the protocol engine */
+ writel((USBD_CDFULL | USBD_CCEMPTY),
+ USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Write command code */
+ udc_protocol_cmd_w(udc, cmd);
+
+ tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+ while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL))
+ && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev,
+ "Protocol engine didn't receive response (CDFULL)\n");
+
+ return readl(USBD_CMDDATA(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * USB device interrupt mask support functions
+ *
+ */
+/* Enable one or more USB device interrupts */
+static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask)
+{
+ udc->enabled_devints |= devmask;
+ writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB device interrupts */
+static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+ udc->enabled_devints &= ~mask;
+ writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB device interrupts */
+static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+ writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint interrupt disable/enable functions
+ *
+ */
+/* Enable one or more USB endpoint interrupts */
+static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->enabled_hwepints |= (1 << hwep);
+ writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB endpoint interrupts */
+static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->enabled_hwepints &= ~(1 << hwep);
+ writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB endpoint interrupts */
+static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr));
+}
+
+/* Enable DMA for the HW channel */
+static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr));
+}
+
+/* Disable DMA for the HW channel */
+static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint realize/unrealize functions
+ *
+ */
+/* Before an endpoint can be used, it needs to be realized
+ * in the USB protocol engine - this realizes the endpoint.
+ * The interrupt (FIFO or DMA) is not enabled with this function */
+static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep,
+ u32 maxpacket)
+{
+ int to = 1000;
+
+ writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+ writel(hwep, USBD_EPIND(udc->udp_baseaddr));
+ udc->realized_eps |= (1 << hwep);
+ writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+ writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr));
+
+ /* Wait until endpoint is realized in hardware */
+ while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+ USBD_EP_RLZED)) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "EP not correctly realized in hardware\n");
+
+ writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/* Unrealize an EP */
+static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->realized_eps &= ~(1 << hwep);
+ writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint support functions
+ *
+ */
+/* Select and clear endpoint interrupt */
+static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep));
+ return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep));
+}
+
+/* Disables the endpoint in the USB protocol engine */
+static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(EP_STAT_DA));
+}
+
+/* Stalls the endpoint - endpoint will return STALL */
+static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(EP_STAT_ST));
+}
+
+/* Clear stall or reset endpoint */
+static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(0));
+}
+
+/* Select an endpoint for endpoint status, clear, validate */
+static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep));
+}
+
+/*
+ *
+ * Endpoint buffer management functions
+ *
+ */
+/* Clear the current endpoint's buffer */
+static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_select_hwep(udc, hwep);
+ udc_protocol_cmd_w(udc, CMD_CLR_BUF);
+}
+
+/* Validate the current endpoint's buffer */
+static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_select_hwep(udc, hwep);
+ udc_protocol_cmd_w(udc, CMD_VALID_BUF);
+}
+
+static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep)
+{
+ /* Clear EP interrupt */
+ uda_clear_hwepint(udc, hwep);
+ return udc_selep_clrint(udc, hwep);
+}
+
+/*
+ *
+ * USB EP DMA support
+ *
+ */
+/* Allocate a DMA Descriptor */
+static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc)
+{
+ dma_addr_t dma;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+ dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc(
+ udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma);
+ if (dd)
+ dd->this_dma = dma;
+
+ return dd;
+}
+
+/* Free a DMA Descriptor */
+static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd)
+{
+ dma_pool_free(udc->dd_cache, dd, dd->this_dma);
+}
+
+/*
+ *
+ * USB setup and shutdown functions
+ *
+ */
+/* Enables or disables most of the USB system clocks when low power mode is
+ * needed. Clocks are typically started on a connection event, and disabled
+ * when a cable is disconnected */
+#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON)
+static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
+{
+ int to = 1000;
+
+ if (enable != 0) {
+ if (udc->clocked)
+ return;
+
+ udc->clocked = 1;
+
+ /* 48MHz PLL up */
+ clk_enable(udc->usb_pll_clk);
+
+ /* Enable the USB device clock */
+ writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
+ USB_CTRL);
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n");
+ } else {
+ if (!udc->clocked)
+ return;
+
+ udc->clocked = 0;
+
+ /* Never disable the USB_HCLK during normal operation */
+
+ /* 48MHz PLL dpwn */
+ clk_disable(udc->usb_pll_clk);
+
+ /* Enable the USB device clock */
+ writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
+ USB_CTRL);
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ while (((readl(USB_OTG_CLK_STAT(udc)) &
+ OTGOFF_CLK_MASK) !=
+ OTGOFF_CLK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n");
+ }
+}
+
+/* Set/reset USB device address */
+static void udc_set_address(struct lpc32xx_udc *udc, u32 addr)
+{
+ /* Address will be latched at the end of the status phase, or
+ latched immediately if function is called twice */
+ udc_protocol_cmd_data_w(udc, CMD_SET_ADDR,
+ DAT_WR_BYTE(DEV_EN | addr));
+}
+
+/* Setup up a IN request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+ u32 hwep = ep->hwep_num;
+
+ ep->req_pending = 1;
+
+ /* There will always be a request waiting here */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+ /* Place the DD Descriptor into the UDCA */
+ udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+ /* Enable DMA and interrupt for the HW EP */
+ udc_ep_dma_enable(udc, hwep);
+
+ /* Clear ZLP if last packet is not of MAXP size */
+ if (req->req.length % ep->ep.maxpacket)
+ req->send_zlp = 0;
+
+ return 0;
+}
+
+/* Setup up a OUT request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+ u32 hwep = ep->hwep_num;
+
+ ep->req_pending = 1;
+
+ /* There will always be a request waiting here */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+ /* Place the DD Descriptor into the UDCA */
+ udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+ /* Enable DMA and interrupt for the HW EP */
+ udc_ep_dma_enable(udc, hwep);
+ return 0;
+}
+
+static void udc_disable(struct lpc32xx_udc *udc)
+{
+ u32 i;
+
+ /* Disable device */
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+ udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0));
+
+ /* Disable all device interrupts (including EP0) */
+ uda_disable_devint(udc, 0x3FF);
+
+ /* Disable and reset all endpoint interrupts */
+ for (i = 0; i < 32; i++) {
+ uda_disable_hwepint(udc, i);
+ uda_clear_hwepint(udc, i);
+ udc_disable_hwep(udc, i);
+ udc_unrealize_hwep(udc, i);
+ udc->udca_v_base[i] = 0;
+
+ /* Disable and clear all interrupts and DMA */
+ udc_ep_dma_disable(udc, i);
+ writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr));
+ }
+
+ /* Disable DMA interrupts */
+ writel(0, USBD_DMAINTEN(udc->udp_baseaddr));
+
+ writel(0, USBD_UDCAH(udc->udp_baseaddr));
+}
+
+static void udc_enable(struct lpc32xx_udc *udc)
+{
+ u32 i;
+ struct lpc32xx_ep *ep = &udc->ep[0];
+
+ /* Start with known state */
+ udc_disable(udc);
+
+ /* Enable device */
+ udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
+
+ /* EP interrupts on high priority, FRAME interrupt on low priority */
+ writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr));
+ writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr));
+
+ /* Clear any pending device interrupts */
+ writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Setup UDCA - not yet used (DMA) */
+ writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr));
+
+ /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */
+ for (i = 0; i <= 1; i++) {
+ udc_realize_hwep(udc, i, ep->ep.maxpacket);
+ uda_enable_hwepint(udc, i);
+ udc_select_hwep(udc, i);
+ udc_clrstall_hwep(udc, i);
+ udc_clr_buffer_hwep(udc, i);
+ }
+
+ /* Device interrupt setup */
+ uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+ USBD_EP_FAST));
+ uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+ USBD_EP_FAST));
+
+ /* Set device address to 0 - called twice to force a latch in the USB
+ engine without the need of a setup packet status closure */
+ udc_set_address(udc, 0);
+ udc_set_address(udc, 0);
+
+ /* Enable master DMA interrupts */
+ writel((USBD_SYS_ERR_INT | USBD_EOT_INT),
+ USBD_DMAINTEN(udc->udp_baseaddr));
+
+ udc->dev_status = 0;
+}
+
+/*
+ *
+ * USB device board specific events handled via callbacks
+ *
+ */
+/* Connection change event - notify board function of change */
+static void uda_power_event(struct lpc32xx_udc *udc, u32 conn)
+{
+ /* Just notify of a connection change event (optional) */
+ if (udc->board->conn_chgb != NULL)
+ udc->board->conn_chgb(conn);
+}
+
+/* Suspend/resume event - notify board function of change */
+static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn)
+{
+ /* Just notify of a Suspend/resume change event (optional) */
+ if (udc->board->susp_chgb != NULL)
+ udc->board->susp_chgb(conn);
+
+ if (conn)
+ udc->suspended = 0;
+ else
+ udc->suspended = 1;
+}
+
+/* Remote wakeup enable/disable - notify board function of change */
+static void uda_remwkp_cgh(struct lpc32xx_udc *udc)
+{
+ if (udc->board->rmwk_chgb != NULL)
+ udc->board->rmwk_chgb(udc->dev_status &
+ (1 << USB_DEVICE_REMOTE_WAKEUP));
+}
+
+/* Reads data from FIFO, adjusts for alignment and data size */
+static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+ int n, i, bl;
+ u16 *p16;
+ u32 *p32, tmp, cbytes;
+
+ /* Use optimal data transfer method based on source address and size */
+ switch (((u32) data) & 0x3) {
+ case 0: /* 32-bit aligned */
+ p32 = (u32 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4)
+ *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ for (n = 0; n < bl; n++)
+ data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+
+ }
+ break;
+
+ case 1: /* 8-bit aligned */
+ case 3:
+ /* Each byte has to be handled independently */
+ for (n = 0; n < bytes; n += 4) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+ bl = bytes - n;
+ if (bl > 3)
+ bl = 3;
+
+ for (i = 0; i < bl; i++)
+ data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
+ }
+ break;
+
+ case 2: /* 16-bit aligned */
+ p16 = (u16 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit sized objects first with 16-bit alignment */
+ for (n = 0; n < cbytes; n += 4) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ *p16++ = (u16)(tmp & 0xFFFF);
+ *p16++ = (u16)((tmp >> 16) & 0xFFFF);
+ }
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ for (n = 0; n < bl; n++)
+ data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+ }
+ break;
+ }
+}
+
+/* Read data from the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. This function should only be called if a packet
+ * is known to be ready to read for the endpoint. Note that the endpoint must
+ * be selected in the protocol engine prior to this call. */
+static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+ u32 bytes)
+{
+ u32 tmpv;
+ int to = 1000;
+ u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN;
+
+ /* Setup read of endpoint */
+ writel(hwrep, USBD_CTRL(udc->udp_baseaddr));
+
+ /* Wait until packet is ready */
+ while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) &
+ PKT_RDY) == 0) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "No packet ready on FIFO EP read\n");
+
+ /* Mask out count */
+ tmp = tmpv & PKT_LNGTH_MASK;
+ if (bytes < tmp)
+ tmp = bytes;
+
+ if ((tmp > 0) && (data != NULL))
+ udc_pop_fifo(udc, (u8 *) data, tmp);
+
+ writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+ /* Clear the buffer */
+ udc_clr_buffer_hwep(udc, hwep);
+
+ return tmp;
+}
+
+/* Stuffs data into the FIFO, adjusts for alignment and data size */
+static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+ int n, i, bl;
+ u16 *p16;
+ u32 *p32, tmp, cbytes;
+
+ /* Use optimal data transfer method based on source address and size */
+ switch (((u32) data) & 0x3) {
+ case 0: /* 32-bit aligned */
+ p32 = (u32 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4)
+ writel(*p32++, USBD_TXDATA(udc->udp_baseaddr));
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = 0;
+ for (n = 0; n < bl; n++)
+ tmp |= data[cbytes + n] << (n * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+
+ case 1: /* 8-bit aligned */
+ case 3:
+ /* Each byte has to be handled independently */
+ for (n = 0; n < bytes; n += 4) {
+ bl = bytes - n;
+ if (bl > 4)
+ bl = 4;
+
+ tmp = 0;
+ for (i = 0; i < bl; i++)
+ tmp |= data[n + i] << (i * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+
+ case 2: /* 16-bit aligned */
+ p16 = (u16 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4) {
+ tmp = *p16++ & 0xFFFF;
+ tmp |= (*p16++ & 0xFFFF) << 16;
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = 0;
+ for (n = 0; n < bl; n++)
+ tmp |= data[cbytes + n] << (n * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+ }
+}
+
+/* Write data to the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. Note that the endpoint must be selected in the
+ * protocol engine prior to this call. */
+static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+ u32 bytes)
+{
+ u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN;
+
+ if ((bytes > 0) && (data == NULL))
+ return;
+
+ /* Setup write of endpoint */
+ writel(hwwep, USBD_CTRL(udc->udp_baseaddr));
+
+ writel(bytes, USBD_TXPLEN(udc->udp_baseaddr));
+
+ /* Need at least 1 byte to trigger TX */
+ if (bytes == 0)
+ writel(0, USBD_TXDATA(udc->udp_baseaddr));
+ else
+ udc_stuff_fifo(udc, (u8 *) data, bytes);
+
+ writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+ udc_val_buffer_hwep(udc, hwep);
+}
+
+/* USB device reset - resets USB to a default state with just EP0
+ enabled */
+static void uda_usb_reset(struct lpc32xx_udc *udc)
+{
+ u32 i = 0;
+ /* Re-init device controller and EP0 */
+ udc_enable(udc);
+ udc->gadget.speed = USB_SPEED_FULL;
+
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+ ep->req_pending = 0;
+ }
+}
+
+/* Send a ZLP on EP0 */
+static void udc_ep0_send_zlp(struct lpc32xx_udc *udc)
+{
+ udc_write_hwep(udc, EP_IN, NULL, 0);
+}
+
+/* Get current frame number */
+static u16 udc_get_current_frame(struct lpc32xx_udc *udc)
+{
+ u16 flo, fhi;
+
+ udc_protocol_cmd_w(udc, CMD_RD_FRAME);
+ flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+ fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+
+ return (fhi << 8) | flo;
+}
+
+/* Set the device as configured - enables all endpoints */
+static inline void udc_set_device_configured(struct lpc32xx_udc *udc)
+{
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE));
+}
+
+/* Set the device as unconfigured - disables all endpoints */
+static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc)
+{
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct lpc32xx_udc *udc)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+
+ if (i != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->desc = NULL;
+ ep->ep.maxpacket = ep->maxpacket;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->req_pending = 0;
+ }
+
+ udc->ep0state = WAIT_FOR_SETUP;
+}
+
+/* Must be called with lock */
+static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
+{
+ struct lpc32xx_udc *udc = ep->udc;
+
+ list_del_init(&req->queue);
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (ep->lep) {
+ enum dma_data_direction direction;
+
+ if (ep->is_in)
+ direction = DMA_TO_DEVICE;
+ else
+ direction = DMA_FROM_DEVICE;
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ direction);
+ req->req.dma = 0;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ direction);
+
+ /* Free DDs */
+ udc_dd_free(udc, req->dd_desc_ptr);
+ }
+
+ if (status && status != -ESHUTDOWN)
+ ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status);
+
+ ep->req_pending = 0;
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+}
+
+/* Must be called with lock */
+static void nuke(struct lpc32xx_ep *ep, int status)
+{
+ struct lpc32xx_request *req;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ done(ep, req, status);
+ }
+
+ if (ep->desc && status == -ESHUTDOWN) {
+ uda_disable_hwepint(ep->udc, ep->hwep_num);
+ udc_disable_hwep(ep->udc, ep->hwep_num);
+ }
+}
+
+/* IN endpoint 0 transfer */
+static int udc_ep0_in_req(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 tsend, ts = 0;
+
+ if (list_empty(&ep0->queue))
+ /* Nothing to send */
+ return 0;
+ else
+ req = list_entry(ep0->queue.next, struct lpc32xx_request,
+ queue);
+
+ tsend = ts = req->req.length - req->req.actual;
+ if (ts == 0) {
+ /* Send a ZLP */
+ udc_ep0_send_zlp(udc);
+ done(ep0, req, 0);
+ return 1;
+ } else if (ts > ep0->ep.maxpacket)
+ ts = ep0->ep.maxpacket; /* Just send what we can */
+
+ /* Write data to the EP0 FIFO and start transfer */
+ udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts);
+
+ /* Increment data pointer */
+ req->req.actual += ts;
+
+ if (tsend >= ep0->ep.maxpacket)
+ return 0; /* Stay in data transfer state */
+
+ /* Transfer request is complete */
+ udc->ep0state = WAIT_FOR_SETUP;
+ done(ep0, req, 0);
+ return 1;
+}
+
+/* OUT endpoint 0 transfer */
+static int udc_ep0_out_req(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 tr, bufferspace;
+
+ if (list_empty(&ep0->queue))
+ return 0;
+ else
+ req = list_entry(ep0->queue.next, struct lpc32xx_request,
+ queue);
+
+ if (req) {
+ if (req->req.length == 0) {
+ /* Just dequeue request */
+ done(ep0, req, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return 1;
+ }
+
+ /* Get data from FIFO */
+ bufferspace = req->req.length - req->req.actual;
+ if (bufferspace > ep0->ep.maxpacket)
+ bufferspace = ep0->ep.maxpacket;
+
+ /* Copy data to buffer */
+ prefetchw(req->req.buf + req->req.actual);
+ tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual,
+ bufferspace);
+ req->req.actual += bufferspace;
+
+ if (tr < ep0->ep.maxpacket) {
+ /* This is the last packet */
+ done(ep0, req, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Must be called with lock */
+static void stop_activity(struct lpc32xx_udc *udc)
+{
+ struct usb_gadget_driver *driver = udc->driver;
+ int i;
+
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+ nuke(ep, -ESHUTDOWN);
+ }
+ if (driver) {
+ spin_unlock(&udc->lock);
+ driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+
+ isp1301_pullup_enable(udc, 0, 0);
+ udc_disable(udc);
+ udc_reinit(udc);
+}
+
+/*
+ * Activate or kill host pullup
+ * Can be called with or without lock
+ */
+static void pullup(struct lpc32xx_udc *udc, int is_on)
+{
+ if (!udc->clocked)
+ return;
+
+ if (!udc->enabled || !udc->vbus)
+ is_on = 0;
+
+ if (is_on != udc->pullup)
+ isp1301_pullup_enable(udc, is_on, 0);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_disable(struct usb_ep *_ep)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ unsigned long flags;
+
+ if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0))
+ return -EINVAL;
+ spin_lock_irqsave(&udc->lock, flags);
+
+ nuke(ep, -ESHUTDOWN);
+
+ /* restore the endpoint's pristine config */
+ ep->desc = NULL;
+
+ /* Clear all DMA statuses for this EP */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+ /* Remove the DD pointer in the UDCA */
+ udc->udca_v_base[ep->hwep_num] = 0;
+
+ /* Disable and reset endpoint and interrupt */
+ uda_clear_hwepint(udc, ep->hwep_num);
+ udc_unrealize_hwep(udc, ep->hwep_num);
+
+ ep->hwep_num = 0;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ atomic_dec(&udc->enabled_ep_cnt);
+ wake_up(&udc->ep_disable_wait_queue);
+
+ return 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ u16 maxpacket;
+ u32 tmp;
+ unsigned long flags;
+
+ /* Verify EP data */
+ if ((!_ep) || (!ep) || (!desc) || (ep->desc) ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT)) {
+ dev_dbg(udc->dev, "bad ep or descriptor\n");
+ return -EINVAL;
+ }
+ maxpacket = usb_endpoint_maxp(desc);
+ if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) {
+ dev_dbg(udc->dev, "bad ep descriptor's packet size\n");
+ return -EINVAL;
+ }
+
+ /* Don't touch EP0 */
+ if (ep->hwep_num_base == 0) {
+ dev_dbg(udc->dev, "Can't re-enable EP0!!!\n");
+ return -EINVAL;
+ }
+
+ /* Is driver ready? */
+ if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+ dev_dbg(udc->dev, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ switch (tmp) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ return -EINVAL;
+
+ case USB_ENDPOINT_XFER_INT:
+ if (maxpacket > ep->maxpacket) {
+ dev_dbg(udc->dev,
+ "Bad INT endpoint maxpacket %d\n", maxpacket);
+ return -EINVAL;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ switch (maxpacket) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+
+ default:
+ dev_dbg(udc->dev,
+ "Bad BULK endpoint maxpacket %d\n", maxpacket);
+ return -EINVAL;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ break;
+ }
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Initialize endpoint to match the selected descriptor */
+ ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ /* Map hardware endpoint from base and direction */
+ if (ep->is_in)
+ /* IN endpoints are offset 1 from the OUT endpoint */
+ ep->hwep_num = ep->hwep_num_base + EP_IN;
+ else
+ ep->hwep_num = ep->hwep_num_base;
+
+ ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name,
+ ep->hwep_num, maxpacket, (ep->is_in == 1));
+
+ /* Realize the endpoint, interrupt is enabled later when
+ * buffers are queued, IN EPs will NAK until buffers are ready */
+ udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket);
+ udc_clr_buffer_hwep(udc, ep->hwep_num);
+ uda_disable_hwepint(udc, ep->hwep_num);
+ udc_clrstall_hwep(udc, ep->hwep_num);
+
+ /* Clear all DMA statuses for this EP */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ atomic_inc(&udc->enabled_ep_cnt);
+ return 0;
+}
+
+/*
+ * Allocate a USB request list
+ * Can be called with or without lock
+ */
+static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct lpc32xx_request *req;
+
+ req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ return &req->req;
+}
+
+/*
+ * De-allocate a USB request list
+ * Can be called with or without lock
+ */
+static void lpc32xx_ep_free_request(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct lpc32xx_request *req;
+
+ req = container_of(_req, struct lpc32xx_request, req);
+ BUG_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_queue(struct usb_ep *_ep,
+ struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep;
+ struct lpc32xx_udc *udc;
+ unsigned long flags;
+ int status = 0;
+
+ req = container_of(_req, struct lpc32xx_request, req);
+ ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+ if (!_req || !_req->complete || !_req->buf ||
+ !list_empty(&req->queue))
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) {
+ dev_dbg(udc->dev, "invalid ep\n");
+ return -EINVAL;
+ }
+
+
+ if ((!udc) || (!udc->driver) ||
+ (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+ dev_dbg(udc->dev, "invalid device\n");
+ return -EINVAL;
+ }
+
+ if (ep->lep) {
+ enum dma_data_direction direction;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+ /* Map DMA pointer */
+ if (ep->is_in)
+ direction = DMA_TO_DEVICE;
+ else
+ direction = DMA_FROM_DEVICE;
+
+ if (req->req.dma == 0) {
+ req->req.dma = dma_map_single(
+ ep->udc->gadget.dev.parent,
+ req->req.buf, req->req.length, direction);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(
+ ep->udc->gadget.dev.parent, req->req.dma,
+ req->req.length, direction);
+ req->mapped = 0;
+ }
+
+ /* For the request, build a list of DDs */
+ dd = udc_dd_alloc(udc);
+ if (!dd) {
+ /* Error allocating DD */
+ return -ENOMEM;
+ }
+ req->dd_desc_ptr = dd;
+
+ /* Setup the DMA descriptor */
+ dd->dd_next_phy = dd->dd_next_v = 0;
+ dd->dd_buffer_addr = req->req.dma;
+ dd->dd_status = 0;
+
+ /* Special handling for ISO EPs */
+ if (ep->eptype == EP_ISO_TYPE) {
+ dd->dd_setup = DD_SETUP_ISO_EP |
+ DD_SETUP_PACKETLEN(0) |
+ DD_SETUP_DMALENBYTES(1);
+ dd->dd_iso_ps_mem_addr = dd->this_dma + 24;
+ if (ep->is_in)
+ dd->iso_status[0] = req->req.length;
+ else
+ dd->iso_status[0] = 0;
+ } else
+ dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) |
+ DD_SETUP_DMALENBYTES(req->req.length);
+ }
+
+ ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name,
+ _req, _req->length, _req->buf, ep->is_in, _req->zero);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+ req->send_zlp = _req->zero;
+
+ /* Kickstart empty queues */
+ if (list_empty(&ep->queue)) {
+ list_add_tail(&req->queue, &ep->queue);
+
+ if (ep->hwep_num_base == 0) {
+ /* Handle expected data direction */
+ if (ep->is_in) {
+ /* IN packet to host */
+ udc->ep0state = DATA_IN;
+ status = udc_ep0_in_req(udc);
+ } else {
+ /* OUT packet from host */
+ udc->ep0state = DATA_OUT;
+ status = udc_ep0_out_req(udc);
+ }
+ } else if (ep->is_in) {
+ /* IN packet to host and kick off transfer */
+ if (!ep->req_pending)
+ udc_ep_in_req_dma(udc, ep);
+ } else
+ /* OUT packet from host and kick off list */
+ if (!ep->req_pending)
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ list_add_tail(&req->queue, &ep->queue);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return (status < 0) ? status : 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct lpc32xx_ep *ep;
+ struct lpc32xx_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct lpc32xx_ep, ep);
+ if (!_ep || ep->hwep_num_base == 0)
+ 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;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ unsigned long flags;
+
+ if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1))
+ return -EINVAL;
+
+ /* Don't halt an IN EP */
+ if (ep->is_in)
+ return -EAGAIN;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (value == 1) {
+ /* stall */
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+ DAT_WR_BYTE(EP_STAT_ST));
+ } else {
+ /* End stall */
+ ep->wedge = 0;
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+ DAT_WR_BYTE(0));
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* set the halt feature and ignores clear requests */
+static int lpc32xx_ep_set_wedge(struct usb_ep *_ep)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+ if (!_ep || !ep->udc)
+ return -EINVAL;
+
+ ep->wedge = 1;
+
+ return usb_ep_set_halt(_ep);
+}
+
+static const struct usb_ep_ops lpc32xx_ep_ops = {
+ .enable = lpc32xx_ep_enable,
+ .disable = lpc32xx_ep_disable,
+ .alloc_request = lpc32xx_ep_alloc_request,
+ .free_request = lpc32xx_ep_free_request,
+ .queue = lpc32xx_ep_queue,
+ .dequeue = lpc32xx_ep_dequeue,
+ .set_halt = lpc32xx_ep_set_halt,
+ .set_wedge = lpc32xx_ep_set_wedge,
+};
+
+/* Send a ZLP on a non-0 IN EP */
+void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ /* Clear EP status */
+ udc_clearep_getsts(udc, ep->hwep_num);
+
+ /* Send ZLP via FIFO mechanism */
+ udc_write_hwep(udc, ep->hwep_num, NULL, 0);
+}
+
+/*
+ * Handle EP completion for ZLP
+ * This function will only be called when a delayed ZLP needs to be sent out
+ * after a DMA transfer has filled both buffers.
+ */
+void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ u32 epstatus;
+ struct lpc32xx_request *req;
+
+ if (ep->hwep_num <= 0)
+ return;
+
+ uda_clear_hwepint(udc, ep->hwep_num);
+
+ /* If this interrupt isn't enabled, return now */
+ if (!(udc->enabled_hwepints & (1 << ep->hwep_num)))
+ return;
+
+ /* Get endpoint status */
+ epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+ /*
+ * This should never happen, but protect against writing to the
+ * buffer when full.
+ */
+ if (epstatus & EP_SEL_F)
+ return;
+
+ if (ep->is_in) {
+ udc_send_in_zlp(udc, ep);
+ uda_disable_hwepint(udc, ep->hwep_num);
+ } else
+ return;
+
+ /* If there isn't a request waiting, something went wrong */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ if (req) {
+ done(ep, req, 0);
+
+ /* Start another request if ready */
+ if (!list_empty(&ep->queue)) {
+ if (ep->is_in)
+ udc_ep_in_req_dma(udc, ep);
+ else
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ ep->req_pending = 0;
+ }
+}
+
+
+/* DMA end of transfer completion */
+static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ u32 status, epstatus;
+ struct lpc32xx_request *req;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep->totalints++;
+#endif
+
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ if (!req) {
+ ep_err(ep, "DMA interrupt on no req!\n");
+ return;
+ }
+ dd = req->dd_desc_ptr;
+
+ /* DMA descriptor should always be retired for this call */
+ if (!(dd->dd_status & DD_STATUS_DD_RETIRED))
+ ep_warn(ep, "DMA descriptor did not retire\n");
+
+ /* Disable DMA */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+
+ /* System error? */
+ if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) &
+ (1 << ep->hwep_num)) {
+ writel((1 << ep->hwep_num),
+ USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ ep_err(ep, "AHB critical error!\n");
+ ep->req_pending = 0;
+
+ /* The error could have occurred on a packet of a multipacket
+ * transfer, so recovering the transfer is not possible. Close
+ * the request with an error */
+ done(ep, req, -ECONNABORTED);
+ return;
+ }
+
+ /* Handle the current DD's status */
+ status = dd->dd_status;
+ switch (status & DD_STATUS_STS_MASK) {
+ case DD_STATUS_STS_NS:
+ /* DD not serviced? This shouldn't happen! */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n",
+ status);
+
+ done(ep, req, -ECONNABORTED);
+ return;
+
+ case DD_STATUS_STS_BS:
+ /* Interrupt only fires on EOT - This shouldn't happen! */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n",
+ status);
+ done(ep, req, -ECONNABORTED);
+ return;
+
+ case DD_STATUS_STS_NC:
+ case DD_STATUS_STS_DUR:
+ /* Really just a short packet, not an underrun */
+ /* This is a good status and what we expect */
+ break;
+
+ default:
+ /* Data overrun, system error, or unknown */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: System error (0x%x)!\n",
+ status);
+ done(ep, req, -ECONNABORTED);
+ return;
+ }
+
+ /* ISO endpoints are handled differently */
+ if (ep->eptype == EP_ISO_TYPE) {
+ if (ep->is_in)
+ req->req.actual = req->req.length;
+ else
+ req->req.actual = dd->iso_status[0] & 0xFFFF;
+ } else
+ req->req.actual += DD_STATUS_CURDMACNT(status);
+
+ /* Send a ZLP if necessary. This will be done for non-int
+ * packets which have a size that is a divisor of MAXP */
+ if (req->send_zlp) {
+ /*
+ * If at least 1 buffer is available, send the ZLP now.
+ * Otherwise, the ZLP send needs to be deferred until a
+ * buffer is available.
+ */
+ if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) {
+ udc_clearep_getsts(udc, ep->hwep_num);
+ uda_enable_hwepint(udc, ep->hwep_num);
+ epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+ /* Let the EP interrupt handle the ZLP */
+ return;
+ } else
+ udc_send_in_zlp(udc, ep);
+ }
+
+ /* Transfer request is complete */
+ done(ep, req, 0);
+
+ /* Start another request if ready */
+ udc_clearep_getsts(udc, ep->hwep_num);
+ if (!list_empty((&ep->queue))) {
+ if (ep->is_in)
+ udc_ep_in_req_dma(udc, ep);
+ else
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ ep->req_pending = 0;
+
+}
+
+/*
+ *
+ * Endpoint 0 functions
+ *
+ */
+static void udc_handle_dev(struct lpc32xx_udc *udc)
+{
+ u32 tmp;
+
+ udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT);
+ tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT);
+
+ if (tmp & DEV_RST)
+ uda_usb_reset(udc);
+ else if (tmp & DEV_CON_CH)
+ uda_power_event(udc, (tmp & DEV_CON));
+ else if (tmp & DEV_SUS_CH) {
+ if (tmp & DEV_SUS) {
+ if (udc->vbus == 0)
+ stop_activity(udc);
+ else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+ udc->driver) {
+ /* Power down transceiver */
+ udc->poweron = 0;
+ schedule_work(&udc->pullup_job);
+ uda_resm_susp_event(udc, 1);
+ }
+ } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+ udc->driver && udc->vbus) {
+ uda_resm_susp_event(udc, 0);
+ /* Power up transceiver */
+ udc->poweron = 1;
+ schedule_work(&udc->pullup_job);
+ }
+ }
+}
+
+static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
+{
+ struct lpc32xx_ep *ep;
+ u32 ep0buff = 0, tmp;
+
+ switch (reqtype & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ break; /* Not supported */
+
+ case USB_RECIP_DEVICE:
+ ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+ if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
+ ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ ep = &udc->ep[tmp];
+ if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc))
+ return -EOPNOTSUPP;
+
+ if (wIndex & USB_DIR_IN) {
+ if (!ep->is_in)
+ return -EOPNOTSUPP; /* Something's wrong */
+ } else if (ep->is_in)
+ return -EOPNOTSUPP; /* Not an IN endpoint */
+
+ /* Get status of the endpoint */
+ udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num));
+ tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num));
+
+ if (tmp & EP_SEL_ST)
+ ep0buff = (1 << USB_ENDPOINT_HALT);
+ else
+ ep0buff = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Return data */
+ udc_write_hwep(udc, EP_IN, &ep0buff, 2);
+
+ return 0;
+}
+
+static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep, *ep0 = &udc->ep[0];
+ struct usb_ctrlrequest ctrlpkt;
+ int i, bytes;
+ u16 wIndex, wValue, wLength, reqtype, req, tmp;
+
+ /* Nuke previous transfers */
+ nuke(ep0, -EPROTO);
+
+ /* Get setup packet */
+ bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8);
+ if (bytes != 8) {
+ ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n",
+ bytes);
+ return;
+ }
+
+ /* Native endianness */
+ wIndex = le16_to_cpu(ctrlpkt.wIndex);
+ wValue = le16_to_cpu(ctrlpkt.wValue);
+ wLength = le16_to_cpu(ctrlpkt.wLength);
+ reqtype = le16_to_cpu(ctrlpkt.bRequestType);
+
+ /* Set direction of EP0 */
+ if (likely(reqtype & USB_DIR_IN))
+ ep0->is_in = 1;
+ else
+ ep0->is_in = 0;
+
+ /* Handle SETUP packet */
+ req = le16_to_cpu(ctrlpkt.bRequest);
+ switch (req) {
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ switch (reqtype) {
+ case (USB_TYPE_STANDARD | USB_RECIP_DEVICE):
+ if (wValue != USB_DEVICE_REMOTE_WAKEUP)
+ goto stall; /* Nothing else handled */
+
+ /* Tell board about event */
+ if (req == USB_REQ_CLEAR_FEATURE)
+ udc->dev_status &=
+ ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+ else
+ udc->dev_status |=
+ (1 << USB_DEVICE_REMOTE_WAKEUP);
+ uda_remwkp_cgh(udc);
+ goto zlp_send;
+
+ case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
+ tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ if ((wValue != USB_ENDPOINT_HALT) ||
+ (tmp >= NUM_ENDPOINTS))
+ break;
+
+ /* Find hardware endpoint from logical endpoint */
+ ep = &udc->ep[tmp];
+ tmp = ep->hwep_num;
+ if (tmp == 0)
+ break;
+
+ if (req == USB_REQ_SET_FEATURE)
+ udc_stall_hwep(udc, tmp);
+ else if (!ep->wedge)
+ udc_clrstall_hwep(udc, tmp);
+
+ goto zlp_send;
+
+ default:
+ break;
+ }
+
+
+ case USB_REQ_SET_ADDRESS:
+ if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
+ udc_set_address(udc, wValue);
+ goto zlp_send;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ udc_get_status(udc, reqtype, wIndex);
+ return;
+
+ default:
+ break; /* Let GadgetFS handle the descriptor instead */
+ }
+
+ if (likely(udc->driver)) {
+ /* device-2-host (IN) or no data setup command, process
+ * immediately */
+ spin_unlock(&udc->lock);
+ i = udc->driver->setup(&udc->gadget, &ctrlpkt);
+
+ spin_lock(&udc->lock);
+ if (req == USB_REQ_SET_CONFIGURATION) {
+ /* Configuration is set after endpoints are realized */
+ if (wValue) {
+ /* Set configuration */
+ udc_set_device_configured(udc);
+
+ udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+ DAT_WR_BYTE(AP_CLK |
+ INAK_BI | INAK_II));
+ } else {
+ /* Clear configuration */
+ udc_set_device_unconfigured(udc);
+
+ /* Disable NAK interrupts */
+ udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+ DAT_WR_BYTE(AP_CLK));
+ }
+ }
+
+ if (i < 0) {
+ /* setup processing failed, force stall */
+ dev_err(udc->dev,
+ "req %02x.%02x protocol STALL; stat %d\n",
+ reqtype, req, i);
+ udc->ep0state = WAIT_FOR_SETUP;
+ goto stall;
+ }
+ }
+
+ if (!ep0->is_in)
+ udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */
+
+ return;
+
+stall:
+ udc_stall_hwep(udc, EP_IN);
+ return;
+
+zlp_send:
+ udc_ep0_send_zlp(udc);
+ return;
+}
+
+/* IN endpoint 0 transfer */
+static void udc_handle_ep0_in(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 epstatus;
+
+ /* Clear EP interrupt */
+ epstatus = udc_clearep_getsts(udc, EP_IN);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep0->totalints++;
+#endif
+
+ /* Stalled? Clear stall and reset buffers */
+ if (epstatus & EP_SEL_ST) {
+ udc_clrstall_hwep(udc, EP_IN);
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return;
+ }
+
+ /* Is a buffer available? */
+ if (!(epstatus & EP_SEL_F)) {
+ /* Handle based on current state */
+ if (udc->ep0state == DATA_IN)
+ udc_ep0_in_req(udc);
+ else {
+ /* Unknown state for EP0 oe end of DATA IN phase */
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+ }
+}
+
+/* OUT endpoint 0 transfer */
+static void udc_handle_ep0_out(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 epstatus;
+
+ /* Clear EP interrupt */
+ epstatus = udc_clearep_getsts(udc, EP_OUT);
+
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep0->totalints++;
+#endif
+
+ /* Stalled? */
+ if (epstatus & EP_SEL_ST) {
+ udc_clrstall_hwep(udc, EP_OUT);
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return;
+ }
+
+ /* A NAK may occur if a packet couldn't be received yet */
+ if (epstatus & EP_SEL_EPN)
+ return;
+ /* Setup packet incoming? */
+ if (epstatus & EP_SEL_STP) {
+ nuke(ep0, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+
+ /* Data available? */
+ if (epstatus & EP_SEL_F)
+ /* Handle based on current state */
+ switch (udc->ep0state) {
+ case WAIT_FOR_SETUP:
+ udc_handle_ep0_setup(udc);
+ break;
+
+ case DATA_OUT:
+ udc_ep0_out_req(udc);
+ break;
+
+ default:
+ /* Unknown state for EP0 */
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+}
+
+/* Must be called without lock */
+static int lpc32xx_get_frame(struct usb_gadget *gadget)
+{
+ int frame;
+ unsigned long flags;
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ if (!udc->clocked)
+ return -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ frame = (int) udc_get_current_frame(udc);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return frame;
+}
+
+static int lpc32xx_wakeup(struct usb_gadget *gadget)
+{
+ return -ENOTSUPP;
+}
+
+static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ /* Always self-powered */
+ udc->selfpowered = (is_on != 0);
+
+ return 0;
+}
+
+/*
+ * vbus is here! turn everything on that's ready
+ * Must be called without lock
+ */
+static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ unsigned long flags;
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Doesn't need lock */
+ if (udc->driver) {
+ udc_clk_set(udc, 1);
+ udc_enable(udc);
+ pullup(udc, is_active);
+ } else {
+ stop_activity(udc);
+ pullup(udc, 0);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ /*
+ * Wait for all the endpoints to disable,
+ * before disabling clocks. Don't wait if
+ * endpoints are not enabled.
+ */
+ if (atomic_read(&udc->enabled_ep_cnt))
+ wait_event_interruptible(udc->ep_disable_wait_queue,
+ (atomic_read(&udc->enabled_ep_cnt) == 0));
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ udc_clk_set(udc, 0);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* Can be called with or without lock */
+static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ /* Doesn't need lock */
+ pullup(udc, is_on);
+
+ return 0;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int lpc32xx_stop(struct usb_gadget_driver *driver);
+
+static const struct usb_gadget_ops lpc32xx_udc_ops = {
+ .get_frame = lpc32xx_get_frame,
+ .wakeup = lpc32xx_wakeup,
+ .set_selfpowered = lpc32xx_set_selfpowered,
+ .vbus_session = lpc32xx_vbus_session,
+ .pullup = lpc32xx_pullup,
+ .start = lpc32xx_start,
+ .stop = lpc32xx_stop,
+};
+
+static void nop_release(struct device *dev)
+{
+ /* nothing to free */
+}
+
+static struct lpc32xx_udc controller = {
+ .gadget = {
+ .ops = &lpc32xx_udc_ops,
+ .ep0 = &controller.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .init_name = "gadget",
+ .release = nop_release,
+ }
+ },
+ .ep[0] = {
+ .ep = {
+ .name = "ep0",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 0,
+ .hwep_num = 0, /* Can be 0 or 1, has special handling */
+ .lep = 0,
+ .eptype = EP_CTL_TYPE,
+ },
+ .ep[1] = {
+ .ep = {
+ .name = "ep1-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 2,
+ .hwep_num = 0, /* 2 or 3, will be set later */
+ .lep = 1,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[2] = {
+ .ep = {
+ .name = "ep2-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 4,
+ .hwep_num = 0, /* 4 or 5, will be set later */
+ .lep = 2,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[3] = {
+ .ep = {
+ .name = "ep3-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 6,
+ .hwep_num = 0, /* 6 or 7, will be set later */
+ .lep = 3,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[4] = {
+ .ep = {
+ .name = "ep4-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 8,
+ .hwep_num = 0, /* 8 or 9, will be set later */
+ .lep = 4,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[5] = {
+ .ep = {
+ .name = "ep5-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 10,
+ .hwep_num = 0, /* 10 or 11, will be set later */
+ .lep = 5,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[6] = {
+ .ep = {
+ .name = "ep6-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 12,
+ .hwep_num = 0, /* 12 or 13, will be set later */
+ .lep = 6,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[7] = {
+ .ep = {
+ .name = "ep7-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 14,
+ .hwep_num = 0,
+ .lep = 7,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[8] = {
+ .ep = {
+ .name = "ep8-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 16,
+ .hwep_num = 0,
+ .lep = 8,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[9] = {
+ .ep = {
+ .name = "ep9-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 18,
+ .hwep_num = 0,
+ .lep = 9,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[10] = {
+ .ep = {
+ .name = "ep10-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 20,
+ .hwep_num = 0,
+ .lep = 10,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[11] = {
+ .ep = {
+ .name = "ep11-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 22,
+ .hwep_num = 0,
+ .lep = 11,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[12] = {
+ .ep = {
+ .name = "ep12-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 24,
+ .hwep_num = 0,
+ .lep = 12,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[13] = {
+ .ep = {
+ .name = "ep13-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 26,
+ .hwep_num = 0,
+ .lep = 13,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[14] = {
+ .ep = {
+ .name = "ep14-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 28,
+ .hwep_num = 0,
+ .lep = 14,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[15] = {
+ .ep = {
+ .name = "ep15-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 30,
+ .hwep_num = 0,
+ .lep = 15,
+ .eptype = EP_BLK_TYPE,
+ },
+};
+
+/* ISO and status interrupts */
+static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc)
+{
+ u32 tmp, devstat;
+ struct lpc32xx_udc *udc = _udc;
+
+ spin_lock(&udc->lock);
+
+ /* Read the device status register */
+ devstat = readl(USBD_DEVINTST(udc->udp_baseaddr));
+
+ devstat &= ~USBD_EP_FAST;
+ writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr));
+ devstat = devstat & udc->enabled_devints;
+
+ /* Device specific handling needed? */
+ if (devstat & USBD_DEV_STAT)
+ udc_handle_dev(udc);
+
+ /* Start of frame? (devstat & FRAME_INT):
+ * The frame interrupt isn't really needed for ISO support,
+ * as the driver will queue the necessary packets */
+
+ /* Error? */
+ if (devstat & ERR_INT) {
+ /* All types of errors, from cable removal during transfer to
+ * misc protocol and bit errors. These are mostly for just info,
+ * as the USB hardware will work around these. If these errors
+ * happen alot, something is wrong. */
+ udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT);
+ tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT);
+ dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp);
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* EP interrupts */
+static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc)
+{
+ u32 tmp;
+ struct lpc32xx_udc *udc = _udc;
+
+ spin_lock(&udc->lock);
+
+ /* Read the device status register */
+ writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Endpoints */
+ tmp = readl(USBD_EPINTST(udc->udp_baseaddr));
+
+ /* Special handling for EP0 */
+ if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+ /* Handle EP0 IN */
+ if (tmp & (EP_MASK_SEL(0, EP_IN)))
+ udc_handle_ep0_in(udc);
+
+ /* Handle EP0 OUT */
+ if (tmp & (EP_MASK_SEL(0, EP_OUT)))
+ udc_handle_ep0_out(udc);
+ }
+
+ /* All other EPs */
+ if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+ int i;
+
+ /* Handle other EP interrupts */
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ if (tmp & (1 << udc->ep[i].hwep_num))
+ udc_handle_eps(udc, &udc->ep[i]);
+ }
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc)
+{
+ struct lpc32xx_udc *udc = _udc;
+
+ int i;
+ u32 tmp;
+
+ spin_lock(&udc->lock);
+
+ /* Handle EP DMA EOT interrupts */
+ tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) |
+ (readl(USBD_EPDMAST(udc->udp_baseaddr)) &
+ readl(USBD_NDDRTINTST(udc->udp_baseaddr))) |
+ readl(USBD_SYSERRTINTST(udc->udp_baseaddr));
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ if (tmp & (1 << udc->ep[i].hwep_num))
+ udc_handle_dma_ep(udc, &udc->ep[i]);
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ *
+ * VBUS detection, pullup handler, and Gadget cable state notification
+ *
+ */
+static void vbus_work(struct work_struct *work)
+{
+ u8 value;
+ struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc,
+ vbus_job);
+
+ if (udc->enabled != 0) {
+ /* Discharge VBUS real quick */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+
+ /* Give VBUS some time (100mS) to discharge */
+ msleep(100);
+
+ /* Disable VBUS discharge resistor */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_VBUS_DISCHRG);
+
+ /* Clear interrupt */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH |
+ ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+
+ /* Get the VBUS status from the transceiver */
+ value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_2);
+
+ /* VBUS on or off? */
+ if (value & OTG_B_SESS_VLD)
+ udc->vbus = 1;
+ else
+ udc->vbus = 0;
+
+ /* VBUS changed? */
+ if (udc->last_vbus != udc->vbus) {
+ udc->last_vbus = udc->vbus;
+ lpc32xx_vbus_session(&udc->gadget, udc->vbus);
+ }
+ }
+
+ /* Re-enable after completion */
+ enable_irq(udc->udp_irq[IRQ_USB_ATX]);
+}
+
+static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc)
+{
+ struct lpc32xx_udc *udc = _udc;
+
+ /* Defer handling of VBUS IRQ to work queue */
+ disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]);
+ schedule_work(&udc->vbus_job);
+
+ return IRQ_HANDLED;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct lpc32xx_udc *udc = &controller;
+ int retval, i;
+
+ if (!driver || driver->max_speed < USB_SPEED_FULL ||
+ !bind || !driver->setup) {
+ dev_err(udc->dev, "bad parameter.\n");
+ return -EINVAL;
+ }
+
+ if (udc->driver) {
+ dev_err(udc->dev, "UDC already has a gadget driver\n");
+ return -EBUSY;
+ }
+
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ udc->enabled = 1;
+ udc->selfpowered = 1;
+ udc->vbus = 0;
+
+ retval = bind(&udc->gadget);
+ if (retval) {
+ dev_err(udc->dev, "bind() returned %d\n", retval);
+ udc->enabled = 0;
+ udc->selfpowered = 0;
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ dev_dbg(udc->dev, "bound to %s\n", driver->driver.name);
+
+ /* Force VBUS process once to check for cable insertion */
+ udc->last_vbus = udc->vbus = 0;
+ schedule_work(&udc->vbus_job);
+
+ /* Do not re-enable ATX IRQ (3) */
+ for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++)
+ enable_irq(udc->udp_irq[i]);
+
+ return 0;
+}
+
+static int lpc32xx_stop(struct usb_gadget_driver *driver)
+{
+ int i;
+ struct lpc32xx_udc *udc = &controller;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ /* Disable USB pullup */
+ isp1301_pullup_enable(udc, 0, 1);
+
+ for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+ disable_irq(udc->udp_irq[i]);
+
+ if (udc->clocked) {
+
+ spin_lock(&udc->lock);
+ stop_activity(udc);
+ spin_unlock(&udc->lock);
+
+ /*
+ * Wait for all the endpoints to disable,
+ * before disabling clocks. Don't wait if
+ * endpoints are not enabled.
+ */
+ if (atomic_read(&udc->enabled_ep_cnt))
+ wait_event_interruptible(udc->ep_disable_wait_queue,
+ (atomic_read(&udc->enabled_ep_cnt) == 0));
+
+ spin_lock(&udc->lock);
+ udc_clk_set(udc, 0);
+ spin_unlock(&udc->lock);
+ }
+
+ udc->enabled = 0;
+ pullup(udc, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name);
+ return 0;
+}
+
+static void lpc32xx_udc_shutdown(struct platform_device *dev)
+{
+ /* Force disconnect on reboot */
+ struct lpc32xx_udc *udc = &controller;
+
+ pullup(udc, 0);
+}
+
+/*
+ * Callbacks to be overridden by options passed via OF (TODO)
+ */
+
+static void lpc32xx_usbd_conn_chg(int conn)
+{
+ /* Do nothing, it might be nice to enable an LED
+ * based on conn state being !0 */
+}
+
+static void lpc32xx_usbd_susp_chg(int susp)
+{
+ /* Device suspend if susp != 0 */
+}
+
+static void lpc32xx_rmwkup_chg(int remote_wakup_enable)
+{
+ /* Enable or disable USB remote wakeup */
+}
+
+struct lpc32xx_usbd_cfg lpc32xx_usbddata = {
+ .vbus_drv_pol = 0,
+ .conn_chgb = &lpc32xx_usbd_conn_chg,
+ .susp_chgb = &lpc32xx_usbd_susp_chg,
+ .rmwk_chgb = &lpc32xx_rmwkup_chg,
+};
+
+
+static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F;
+
+static int __init lpc32xx_udc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lpc32xx_udc *udc = &controller;
+ int retval, i;
+ struct resource *res;
+ dma_addr_t dma_handle;
+ struct device_node *isp1301_node;
+
+ /* init software state */
+ udc->gadget.dev.parent = dev;
+ udc->pdev = pdev;
+ udc->dev = &pdev->dev;
+ udc->enabled = 0;
+
+ if (pdev->dev.of_node) {
+ isp1301_node = of_parse_phandle(pdev->dev.of_node,
+ "transceiver", 0);
+ } else {
+ isp1301_node = NULL;
+ }
+
+ udc->isp1301_i2c_client = isp1301_get_client(isp1301_node);
+ if (!udc->isp1301_i2c_client)
+ return -EPROBE_DEFER;
+
+ dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n",
+ udc->isp1301_i2c_client->addr);
+
+ pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ udc->board = &lpc32xx_usbddata;
+
+ /*
+ * Resources are mapped as follows:
+ * IORESOURCE_MEM, base address and size of USB space
+ * IORESOURCE_IRQ, USB device low priority interrupt number
+ * IORESOURCE_IRQ, USB device high priority interrupt number
+ * IORESOURCE_IRQ, USB device interrupt number
+ * IORESOURCE_IRQ, USB transceiver interrupt number
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ spin_lock_init(&udc->lock);
+
+ /* Get IRQs */
+ for (i = 0; i < 4; i++) {
+ udc->udp_irq[i] = platform_get_irq(pdev, i);
+ if (udc->udp_irq[i] < 0) {
+ dev_err(udc->dev,
+ "irq resource %d not available!\n", i);
+ return udc->udp_irq[i];
+ }
+ }
+
+ udc->io_p_start = res->start;
+ udc->io_p_size = resource_size(res);
+ if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) {
+ dev_err(udc->dev, "someone's using UDC memory\n");
+ return -EBUSY;
+ }
+
+ udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size);
+ if (!udc->udp_baseaddr) {
+ retval = -ENOMEM;
+ dev_err(udc->dev, "IO map failure\n");
+ goto io_map_fail;
+ }
+
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+ /* Get required clocks */
+ udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(udc->usb_pll_clk)) {
+ dev_err(udc->dev, "failed to acquire USB PLL\n");
+ retval = PTR_ERR(udc->usb_pll_clk);
+ goto pll_get_fail;
+ }
+ udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd");
+ if (IS_ERR(udc->usb_slv_clk)) {
+ dev_err(udc->dev, "failed to acquire USB device clock\n");
+ retval = PTR_ERR(udc->usb_slv_clk);
+ goto usb_clk_get_fail;
+ }
+
+ /* Setup PLL clock to 48MHz */
+ retval = clk_enable(udc->usb_pll_clk);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to start USB PLL\n");
+ goto pll_enable_fail;
+ }
+
+ retval = clk_set_rate(udc->usb_pll_clk, 48000);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to set USB clock rate\n");
+ goto pll_set_fail;
+ }
+
+ writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL);
+
+ /* Enable USB device clock */
+ retval = clk_enable(udc->usb_slv_clk);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to start USB device clock\n");
+ goto usb_clk_enable_fail;
+ }
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ i = 1000;
+ while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) && (i > 0))
+ i--;
+ if (!i)
+ dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n");
+
+ /* Setup deferred workqueue data */
+ udc->poweron = udc->pullup = 0;
+ INIT_WORK(&udc->pullup_job, pullup_work);
+ INIT_WORK(&udc->vbus_job, vbus_work);
+#ifdef CONFIG_PM
+ INIT_WORK(&udc->power_job, power_work);
+#endif
+
+ /* All clocks are now on */
+ udc->clocked = 1;
+
+ isp1301_udc_configure(udc);
+ /* Allocate memory for the UDCA */
+ udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ &dma_handle,
+ (GFP_KERNEL | GFP_DMA));
+ if (!udc->udca_v_base) {
+ dev_err(udc->dev, "error getting UDCA region\n");
+ retval = -ENOMEM;
+ goto i2c_fail;
+ }
+ udc->udca_p_base = dma_handle;
+ dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n",
+ UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base);
+
+ /* Setup the DD DMA memory pool */
+ udc->dd_cache = dma_pool_create("udc_dd", udc->dev,
+ sizeof(struct lpc32xx_usbd_dd_gad),
+ sizeof(u32), 0);
+ if (!udc->dd_cache) {
+ dev_err(udc->dev, "error getting DD DMA region\n");
+ retval = -ENOMEM;
+ goto dma_alloc_fail;
+ }
+
+ /* Clear USB peripheral and initialize gadget endpoints */
+ udc_disable(udc);
+ udc_reinit(udc);
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval < 0) {
+ dev_err(udc->dev, "Device registration failure\n");
+ goto dev_register_fail;
+ }
+
+ /* Request IRQs - low and high priority USB device IRQs are routed to
+ * the same handler, while the DMA interrupt is routed elsewhere */
+ retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
+ 0, "udc_lp", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "LP request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_LP]);
+ goto irq_lp_fail;
+ }
+ retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq,
+ 0, "udc_hp", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "HP request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_HP]);
+ goto irq_hp_fail;
+ }
+
+ retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA],
+ lpc32xx_usb_devdma_irq, 0, "udc_dma", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "DEV request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_DEVDMA]);
+ goto irq_dev_fail;
+ }
+
+ /* The transceiver interrupt is used for VBUS detection and will
+ kick off the VBUS handler function */
+ retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq,
+ 0, "udc_otg", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "VBUS request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_ATX]);
+ goto irq_xcvr_fail;
+ }
+
+ /* Initialize wait queue */
+ init_waitqueue_head(&udc->ep_disable_wait_queue);
+ atomic_set(&udc->enabled_ep_cnt, 0);
+
+ /* Keep all IRQs disabled until GadgetFS starts up */
+ for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+ disable_irq(udc->udp_irq[i]);
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval < 0)
+ goto add_gadget_fail;
+
+ dev_set_drvdata(dev, udc);
+ device_init_wakeup(dev, 1);
+ create_debug_file(udc);
+
+ /* Disable clocks for now */
+ udc_clk_set(udc, 0);
+
+ dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION);
+ return 0;
+
+add_gadget_fail:
+ free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+irq_xcvr_fail:
+ free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+irq_dev_fail:
+ free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+irq_hp_fail:
+ free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+irq_lp_fail:
+ device_unregister(&udc->gadget.dev);
+dev_register_fail:
+ dma_pool_destroy(udc->dd_cache);
+dma_alloc_fail:
+ dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ udc->udca_v_base, udc->udca_p_base);
+i2c_fail:
+ clk_disable(udc->usb_slv_clk);
+usb_clk_enable_fail:
+pll_set_fail:
+ clk_disable(udc->usb_pll_clk);
+pll_enable_fail:
+ clk_put(udc->usb_slv_clk);
+usb_clk_get_fail:
+ clk_put(udc->usb_pll_clk);
+pll_get_fail:
+ iounmap(udc->udp_baseaddr);
+io_map_fail:
+ release_mem_region(udc->io_p_start, udc->io_p_size);
+ dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
+
+ return retval;
+}
+
+static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ usb_del_gadget_udc(&udc->gadget);
+ if (udc->driver)
+ return -EBUSY;
+
+ udc_clk_set(udc, 1);
+ udc_disable(udc);
+ pullup(udc, 0);
+
+ free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+
+ device_init_wakeup(&pdev->dev, 0);
+ remove_debug_file(udc);
+
+ dma_pool_destroy(udc->dd_cache);
+ dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ udc->udca_v_base, udc->udca_p_base);
+ free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+ free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+ free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+
+ device_unregister(&udc->gadget.dev);
+
+ clk_disable(udc->usb_slv_clk);
+ clk_put(udc->usb_slv_clk);
+ clk_disable(udc->usb_pll_clk);
+ clk_put(udc->usb_pll_clk);
+ iounmap(udc->udp_baseaddr);
+ release_mem_region(udc->io_p_start, udc->io_p_size);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int to = 1000;
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ if (udc->clocked) {
+ /* Power down ISP */
+ udc->poweron = 0;
+ isp1301_set_powerstate(udc, 0);
+
+ /* Disable clocking */
+ udc_clk_set(udc, 0);
+
+ /* Keep clock flag on, so we know to re-enable clocks
+ on resume */
+ udc->clocked = 1;
+
+ /* Kill OTG and I2C clocks */
+ writel(0, USB_OTG_CLK_CTRL(udc));
+ while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) !=
+ OTGOFF_CLK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev,
+ "USB OTG clocks not correctly enabled\n");
+
+ /* Kill global USB clock */
+ clk_disable(udc->usb_slv_clk);
+ }
+
+ return 0;
+}
+
+static int lpc32xx_udc_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ if (udc->clocked) {
+ /* Enable global USB clock */
+ clk_enable(udc->usb_slv_clk);
+
+ /* Enable clocking */
+ udc_clk_set(udc, 1);
+
+ /* ISP back to normal power mode */
+ udc->poweron = 1;
+ isp1301_set_powerstate(udc, 1);
+ }
+
+ return 0;
+}
+#else
+#define lpc32xx_udc_suspend NULL
+#define lpc32xx_udc_resume NULL
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_udc_of_match[] = {
+ { .compatible = "nxp,lpc3220-udc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
+#endif
+
+static struct platform_driver lpc32xx_udc_driver = {
+ .remove = __devexit_p(lpc32xx_udc_remove),
+ .shutdown = lpc32xx_udc_shutdown,
+ .suspend = lpc32xx_udc_suspend,
+ .resume = lpc32xx_udc_resume,
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_udc_of_match),
+ },
+};
+
+static int __init udc_init_module(void)
+{
+ return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe);
+}
+module_init(udc_init_module);
+
+static void __exit udc_exit_module(void)
+{
+ platform_driver_unregister(&lpc32xx_udc_driver);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("LPC32XX udc driver");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_udc");
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 3608b3b..8981fbb 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -390,7 +390,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
int *counter;
int ret;
- ep->desc = desc;
+ ep->ep.desc = desc;
BUG_ON(ep->pipenum);
@@ -558,7 +558,7 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
{
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
start_packet_write(ep, req);
else
start_packet_read(ep, req);
@@ -734,7 +734,7 @@ __acquires(m66592->lock)
if (restart) {
req = list_entry(ep->queue.next, struct m66592_request, queue);
- if (ep->desc)
+ if (ep->ep.desc)
start_packet(ep, req);
}
}
@@ -917,7 +917,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
ep = m66592->pipenum2ep[pipenum];
req = list_entry(ep->queue.next,
struct m66592_request, queue);
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
irq_packet_write(ep, req);
else
irq_packet_read(ep, req);
@@ -1377,7 +1377,7 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* control */
+ if (ep->ep.desc == NULL) /* control */
start_ep0(ep, req);
else {
if (request && !ep->busy)
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 9d9f7e3..88c85b4 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -456,7 +456,7 @@ struct m66592_ep {
unsigned use_dma:1;
u16 pipenum;
u16 type;
- const struct usb_endpoint_descriptor *desc;
+
/* register address */
unsigned long fifoaddr;
unsigned long fifosel;
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index e2be951..9073436 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -232,7 +232,6 @@ struct mv_ep {
struct mv_udc *udc;
struct list_head queue;
struct mv_dqh *dqh;
- const struct usb_endpoint_descriptor *desc;
u32 direction;
char name[14];
unsigned stopped:1,
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index a73cf40..dbcd132 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -464,7 +464,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
@@ -528,7 +528,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
dqh->size_ioc_int_sts = 0;
ep->ep.maxpacket = max;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
/* Enable the endpoint for Rx or Tx and set the endpoint type */
@@ -580,7 +580,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
- if ((_ep == NULL) || !ep->desc)
+ if ((_ep == NULL) || !ep->ep.desc)
return -EINVAL;
udc = ep->udc;
@@ -606,7 +606,6 @@ static int mv_ep_disable(struct usb_ep *_ep)
/* nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
@@ -651,7 +650,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep)
return;
ep = container_of(_ep, struct mv_ep, ep);
- if (!ep->desc)
+ if (!ep->ep.desc)
return;
udc = ep->udc;
@@ -715,11 +714,11 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
dev_err(&udc->dev->dev, "%s, bad params", __func__);
return -EINVAL;
}
- if (unlikely(!_ep || !ep->desc)) {
+ if (unlikely(!_ep || !ep->ep.desc)) {
dev_err(&udc->dev->dev, "%s, bad ep", __func__);
return -EINVAL;
}
- if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
}
@@ -925,12 +924,12 @@ static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
- if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
status = -EOPNOTSUPP;
goto out;
}
@@ -1279,7 +1278,7 @@ static int eps_init(struct mv_udc *udc)
ep->stopped = 0;
ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
ep->ep_num = 0;
- ep->desc = &mv_ep0_desc;
+ ep->ep.desc = &mv_ep0_desc;
INIT_LIST_HEAD(&ep->queue);
ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 3b4b6dd..7ba3246 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -153,7 +153,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
u16 maxp;
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->maxpacket < usb_endpoint_maxp(desc)) {
@@ -200,7 +200,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
spin_lock_irqsave(&udc->lock, flags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->irqs = 0;
ep->stopped = 0;
ep->ep.maxpacket = maxp;
@@ -242,14 +242,13 @@ static int omap_ep_disable(struct usb_ep *_ep)
struct omap_ep *ep = container_of(_ep, struct omap_ep, ep);
unsigned long flags;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
DBG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
spin_lock_irqsave(&ep->udc->lock, flags);
- ep->desc = NULL;
ep->ep.desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
@@ -917,7 +916,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
DBG("%s, bad params\n", __func__);
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
+ if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) {
DBG("%s, bad ep\n", __func__);
return -EINVAL;
}
@@ -1121,7 +1120,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
status = 0;
/* otherwise, all active non-ISO endpoints can halt */
- } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) {
+ } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) {
/* IN endpoints must already be idle */
if ((ep->bEndpointAddress & USB_DIR_IN)
@@ -1625,7 +1624,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- || !ep->desc)
+ || !ep->ep.desc)
goto do_stall;
use_ep(ep, 0);
omap_writew(udc->clr_halt, UDC_CTRL);
@@ -1653,7 +1652,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- || ep == ep0 || !ep->desc)
+ || ep == ep0 || !ep->ep.desc)
goto do_stall;
if (use_dma && ep->has_dma) {
/* this has rude side-effects (aborts) and
@@ -1688,7 +1687,7 @@ ep0out_status_stage:
ep = &udc->ep[w_index & 0xf];
if (w_index & USB_DIR_IN)
ep += 16;
- if (!ep->desc)
+ if (!ep->ep.desc)
goto do_stall;
/* iso never stalls */
@@ -2509,7 +2508,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
if (tmp & UDC_ADD) {
list_for_each_entry (ep, &udc->gadget.ep_list,
ep.ep_list) {
- if (ep->desc)
+ if (ep->ep.desc)
proc_ep_show(s, ep);
}
}
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 59d3b22..cfadeb5 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -140,7 +140,6 @@ struct omap_ep {
struct list_head queue;
unsigned long irqs;
struct list_head iso;
- const struct usb_endpoint_descriptor *desc;
char name[14];
u16 maxpacket;
u8 bEndpointAddress;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 6530706..1cfcc9e 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -295,7 +295,6 @@ struct pch_udc_ep {
struct pch_udc_data_dma_desc *td_data;
struct pch_udc_dev *dev;
unsigned long offset_addr;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned num:5,
in:1,
@@ -1705,7 +1704,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
spin_lock_irqsave(&dev->lock, iflags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
ep->ep.maxpacket = usb_endpoint_maxp(desc);
@@ -1734,7 +1733,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if ((usbep->name == ep0_string) || !ep->desc)
+ if ((usbep->name == ep0_string) || !ep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&ep->dev->lock, iflags);
@@ -1742,7 +1741,6 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
ep->halted = 1;
pch_udc_ep_disable(ep);
pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
- ep->desc = NULL;
ep->ep.desc = NULL;
INIT_LIST_HEAD(&ep->queue);
spin_unlock_irqrestore(&ep->dev->lock, iflags);
@@ -1849,7 +1847,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && ep->num)
+ if (!ep->ep.desc && ep->num)
return -EINVAL;
req = container_of(usbreq, struct pch_udc_request, req);
if (!list_empty(&req->queue))
@@ -1949,7 +1947,7 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!usbep || !usbreq || (!ep->desc && ep->num))
+ if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
return ret;
req = container_of(usbreq, struct pch_udc_request, req);
spin_lock_irqsave(&ep->dev->lock, flags);
@@ -1988,7 +1986,7 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && !ep->num)
+ if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
@@ -2033,7 +2031,7 @@ static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && !ep->num)
+ if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
@@ -2065,7 +2063,7 @@ static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep)
return;
ep = container_of(usbep, struct pch_udc_ep, ep);
- if (ep->desc || !ep->num)
+ if (ep->ep.desc || !ep->num)
pch_udc_ep_fifo_flush(ep, ep->in);
}
@@ -3282,7 +3280,6 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
-
static struct pci_driver pch_udc_driver = {
.name = KBUILD_MODNAME,
.id_table = pch_udc_pcidev_id,
@@ -3293,17 +3290,7 @@ static struct pci_driver pch_udc_driver = {
.shutdown = pch_udc_shutdown,
};
-static int __init pch_udc_pci_init(void)
-{
- return pci_register_driver(&pch_udc_driver);
-}
-module_init(pch_udc_pci_init);
-
-static void __exit pch_udc_pci_exit(void)
-{
- pci_unregister_driver(&pch_udc_driver);
-}
-module_exit(pch_udc_pci_exit);
+module_pci_driver(pch_udc_driver);
MODULE_DESCRIPTION("Intel EG20T USB Device Controller");
MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>");
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 4e4dc1f..f1f9290 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -51,6 +51,7 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
+#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
@@ -75,8 +76,6 @@ struct printer_dev {
/* lock buffer lists during read/write calls */
struct mutex lock_printer_io;
struct usb_gadget *gadget;
- struct usb_request *req; /* for control responses */
- u8 config;
s8 interface;
struct usb_ep *in_ep, *out_ep;
@@ -100,6 +99,7 @@ struct printer_dev {
struct device *pdev;
u8 printer_cdev_open;
wait_queue_head_t wait;
+ struct usb_function function;
};
static struct printer_dev usb_printer_gadget;
@@ -120,26 +120,6 @@ static struct printer_dev usb_printer_gadget;
* parameters are in UTF-8 (superset of ASCII's 7 bit characters).
*/
-static ushort idVendor;
-module_param(idVendor, ushort, S_IRUGO);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, S_IRUGO);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, S_IRUGO);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, S_IRUGO);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
static char *iSerialNum;
module_param(iSerialNum, charp, S_IRUGO);
MODULE_PARM_DESC(iSerialNum, "1");
@@ -154,47 +134,8 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
#define QLEN qlen
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define DEVSPEED USB_SPEED_HIGH
-#else /* full speed (low speed doesn't do bulk) */
-#define DEVSPEED USB_SPEED_FULL
-#endif
-
/*-------------------------------------------------------------------------*/
-#define xprintk(d, level, fmt, args...) \
- printk(level "%s: " fmt, DRIVER_DESC, ## args)
-
-#ifdef DEBUG
-#define DBG(dev, fmt, args...) \
- xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define DBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG(dev, fmt, args...) \
- xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define VDBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev, fmt, args...) \
- xprintk(dev, KERN_ERR, fmt, ## args)
-#define WARNING(dev, fmt, args...) \
- xprintk(dev, KERN_WARNING, fmt, ## args)
-#define INFO(dev, fmt, args...) \
- xprintk(dev, KERN_INFO, fmt, ## args)
-
-/*-------------------------------------------------------------------------*/
-
-/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
- * ep0 implementation: descriptors, config management, setup().
- * also optional class-specific notification interrupt transfer.
- */
-
/*
* DESCRIPTORS ... most are static, but strings and (full) configuration
* descriptors are built on demand.
@@ -227,24 +168,6 @@ static struct usb_device_descriptor device_desc = {
.bNumConfigurations = 1
};
-static struct usb_otg_descriptor otg_desc = {
- .bLength = sizeof otg_desc,
- .bDescriptorType = USB_DT_OTG,
- .bmAttributes = USB_OTG_SRP
-};
-
-static struct usb_config_descriptor config_desc = {
- .bLength = sizeof config_desc,
- .bDescriptorType = USB_DT_CONFIG,
-
- /* compute wTotalLength on the fly */
- .bNumInterfaces = 1,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = 0,
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
-};
-
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
@@ -270,16 +193,13 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK
};
-static const struct usb_descriptor_header *fs_printer_function [11] = {
- (struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *fs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_ep_in_desc,
(struct usb_descriptor_header *) &fs_ep_out_desc,
NULL
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -307,23 +227,26 @@ static struct usb_qualifier_descriptor dev_qualifier = {
.bNumConfigurations = 1
};
-static const struct usb_descriptor_header *hs_printer_function [11] = {
- (struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *hs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_ep_in_desc,
(struct usb_descriptor_header *) &hs_ep_out_desc,
NULL
};
-/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+ .bmAttributes = USB_OTG_SRP,
+};
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g, hs, fs) (((void)(g)), (fs))
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
/*-------------------------------------------------------------------------*/
@@ -343,11 +266,16 @@ static struct usb_string strings [] = {
{ } /* end of list */
};
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings,
};
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
/*-------------------------------------------------------------------------*/
static struct usb_request *
@@ -937,82 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev)
dev->interface = -1;
}
-/* change our operational config. must agree with the code
- * that returns config descriptors, and altsetting code.
- */
-static int
-printer_set_config(struct printer_dev *dev, unsigned number)
-{
- int result = 0;
- struct usb_gadget *gadget = dev->gadget;
-
- switch (number) {
- case DEV_CONFIG_VALUE:
- result = 0;
- break;
- default:
- result = -EINVAL;
- /* FALL THROUGH */
- case 0:
- break;
- }
-
- if (result) {
- usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
- } else {
- unsigned power;
-
- power = 2 * config_desc.bMaxPower;
- usb_gadget_vbus_draw(dev->gadget, power);
-
- dev->config = number;
- INFO(dev, "%s config #%d: %d mA, %s\n",
- usb_speed_string(gadget->speed),
- number, power, driver_desc);
- }
- return result;
-}
-
-static int
-config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
- int is_otg)
-{
- int len;
- const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (speed == USB_SPEED_HIGH);
-
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
-
- if (hs) {
- function = hs_printer_function;
- } else {
- function = fs_printer_function;
- }
-#else
- function = fs_printer_function;
-#endif
-
- if (index >= device_desc.bNumConfigurations)
- return -EINVAL;
-
- /* for now, don't advertise srp-only devices */
- if (!is_otg)
- function++;
-
- len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
- function);
- if (len < 0)
- return len;
- ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
- return len;
-}
-
/* Change our operational Interface. */
-static int
-set_interface(struct printer_dev *dev, unsigned number)
+static int set_interface(struct printer_dev *dev, unsigned number)
{
int result = 0;
@@ -1043,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number)
return result;
}
-static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
- if (req->status || req->actual != req->length)
- DBG((struct printer_dev *) ep->driver_data,
- "setup complete --> %d, %d/%d\n",
- req->status, req->actual, req->length);
-}
-
static void printer_soft_reset(struct printer_dev *dev)
{
struct usb_request *req;
@@ -1107,11 +953,12 @@ static void printer_soft_reset(struct printer_dev *dev)
* The setup() callback implements all the ep0 functionality that's not
* handled lower down.
*/
-static int
-printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+static int printer_func_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
{
- struct printer_dev *dev = get_gadget_data(gadget);
- struct usb_request *req = dev->req;
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
@@ -1120,102 +967,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
- req->complete = printer_setup_complete;
-
switch (ctrl->bRequestType&USB_TYPE_MASK) {
-
- case USB_TYPE_STANDARD:
- switch (ctrl->bRequest) {
-
- case USB_REQ_GET_DESCRIPTOR:
- if (ctrl->bRequestType != USB_DIR_IN)
- break;
- switch (wValue >> 8) {
-
- case USB_DT_DEVICE:
- device_desc.bMaxPacketSize0 =
- gadget->ep0->maxpacket;
- value = min(wLength, (u16) sizeof device_desc);
- memcpy(req->buf, &device_desc, value);
- break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
- break;
- /*
- * assumes ep0 uses the same value for both
- * speeds
- */
- dev_qualifier.bMaxPacketSize0 =
- gadget->ep0->maxpacket;
- value = min(wLength,
- (u16) sizeof dev_qualifier);
- memcpy(req->buf, &dev_qualifier, value);
- break;
-
- case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
- break;
- /* FALLTHROUGH */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- case USB_DT_CONFIG:
- value = config_buf(gadget->speed, req->buf,
- wValue >> 8,
- wValue & 0xff,
- gadget->is_otg);
- if (value >= 0)
- value = min(wLength, (u16) value);
- break;
-
- case USB_DT_STRING:
- value = usb_gadget_get_string(&stringtab,
- wValue & 0xff, req->buf);
- if (value >= 0)
- value = min(wLength, (u16) value);
- break;
- }
- break;
-
- case USB_REQ_SET_CONFIGURATION:
- if (ctrl->bRequestType != 0)
- break;
- if (gadget->a_hnp_support)
- DBG(dev, "HNP available\n");
- else if (gadget->a_alt_hnp_support)
- DBG(dev, "HNP needs a different root port\n");
- value = printer_set_config(dev, wValue);
- if (!value)
- value = set_interface(dev, PRINTER_INTERFACE);
- break;
- case USB_REQ_GET_CONFIGURATION:
- if (ctrl->bRequestType != USB_DIR_IN)
- break;
- *(u8 *)req->buf = dev->config;
- value = min(wLength, (u16) 1);
- break;
-
- case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
- !dev->config)
- break;
-
- value = set_interface(dev, PRINTER_INTERFACE);
- break;
- case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType !=
- (USB_DIR_IN|USB_RECIP_INTERFACE)
- || !dev->config)
- break;
-
- *(u8 *)req->buf = dev->interface;
- value = min(wLength, (u16) 1);
- break;
-
- default:
- goto unknown;
- }
- break;
-
case USB_TYPE_CLASS:
switch (ctrl->bRequest) {
case 0: /* Get the IEEE-1284 PNP String */
@@ -1261,44 +1013,50 @@ unknown:
wValue, wIndex, wLength);
break;
}
-
- /* respond with data transfer before status phase? */
- if (value >= 0) {
- req->length = value;
- req->zero = value < wLength;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(dev, "ep_queue --> %d\n", value);
- req->status = 0;
- printer_setup_complete(gadget->ep0, req);
- }
- }
-
/* host either stalls (value < 0) or reports success */
return value;
}
-static void
-printer_disconnect(struct usb_gadget *gadget)
+static int __init printer_func_bind(struct usb_configuration *c,
+ struct usb_function *f)
{
- struct printer_dev *dev = get_gadget_data(gadget);
+ return 0;
+}
+
+static void printer_func_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+}
+
+static int printer_func_set_alt(struct usb_function *f,
+ unsigned intf, unsigned alt)
+{
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
+ int ret = -ENOTSUPP;
+
+ if (!alt)
+ ret = set_interface(dev, PRINTER_INTERFACE);
+ return ret;
+}
+
+static void printer_func_disable(struct usb_function *f)
+{
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
unsigned long flags;
DBG(dev, "%s\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
-
printer_reset_interface(dev);
-
spin_unlock_irqrestore(&dev->lock, flags);
}
-static void
-printer_unbind(struct usb_gadget *gadget)
+static void printer_cfg_unbind(struct usb_configuration *c)
{
- struct printer_dev *dev = get_gadget_data(gadget);
+ struct printer_dev *dev;
struct usb_request *req;
+ dev = &usb_printer_gadget;
DBG(dev, "%s\n", __func__);
@@ -1336,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget)
list_del(&req->list);
printer_req_free(dev->out_ep, req);
}
-
- if (dev->req) {
- printer_req_free(gadget->ep0, dev->req);
- dev->req = NULL;
- }
-
- set_gadget_data(gadget, NULL);
}
-static int __init
-printer_bind(struct usb_gadget *gadget)
+static struct usb_configuration printer_cfg_driver = {
+ .label = "printer",
+ .unbind = printer_cfg_unbind,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+};
+
+static int __init printer_bind_config(struct usb_configuration *c)
{
+ struct usb_gadget *gadget = c->cdev->gadget;
struct printer_dev *dev;
struct usb_ep *in_ep, *out_ep;
int status = -ENOMEM;
@@ -1358,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget)
dev = &usb_printer_gadget;
+ dev->function.name = shortname;
+ dev->function.descriptors = fs_printer_function;
+ dev->function.hs_descriptors = hs_printer_function;
+ dev->function.bind = printer_func_bind;
+ dev->function.setup = printer_func_setup;
+ dev->function.unbind = printer_func_unbind;
+ dev->function.set_alt = printer_func_set_alt;
+ dev->function.disable = printer_func_disable;
/* Setup the sysfs files for the printer gadget. */
dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
@@ -1393,29 +1159,6 @@ printer_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- device_desc.idVendor =
- cpu_to_le16(PRINTER_VENDOR_NUM);
- device_desc.idProduct =
- cpu_to_le16(PRINTER_PRODUCT_NUM);
-
- /* support optional vendor/distro customization */
- if (idVendor) {
- if (!idProduct) {
- dev_err(&gadget->dev, "idVendor needs idProduct!\n");
- return -ENODEV;
- }
- device_desc.idVendor = cpu_to_le16(idVendor);
- device_desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- device_desc.bcdDevice = cpu_to_le16(bcdDevice);
- }
-
- if (iManufacturer)
- strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
-
- if (iProduct)
- strlcpy(product_desc, iProduct, sizeof product_desc);
-
if (iSerialNum)
strlcpy(serial_num, iSerialNum, sizeof serial_num);
@@ -1442,17 +1185,16 @@ autoconf_fail:
goto autoconf_fail;
out_ep->driver_data = out_ep; /* claim */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assumes that all endpoints are dual-speed */
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-#endif /* DUALSPEED */
usb_gadget_set_selfpowered(gadget);
if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
- config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ otg_descriptor.bmAttributes |= USB_OTG_HNP;
+ printer_cfg_driver.descriptors = otg_desc;
+ printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
spin_lock_init(&dev->lock);
@@ -1466,7 +1208,6 @@ autoconf_fail:
init_waitqueue_head(&dev->tx_wait);
init_waitqueue_head(&dev->tx_flush_wait);
- dev->config = 0;
dev->interface = -1;
dev->printer_cdev_open = 0;
dev->printer_status = PRINTER_NOT_ERROR;
@@ -1477,14 +1218,6 @@ autoconf_fail:
dev->in_ep = in_ep;
dev->out_ep = out_ep;
- /* preallocate control message data and buffer */
- dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
- GFP_KERNEL);
- if (!dev->req) {
- status = -ENOMEM;
- goto fail;
- }
-
for (i = 0; i < QLEN; i++) {
req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
if (!req) {
@@ -1513,45 +1246,37 @@ autoconf_fail:
list_add(&req->list, &dev->rx_reqs);
}
- dev->req->complete = printer_setup_complete;
-
/* finish hookup to lower layer ... */
dev->gadget = gadget;
- set_gadget_data(gadget, dev);
- gadget->ep0->driver_data = dev;
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
in_ep->name);
-
return 0;
fail:
- printer_unbind(gadget);
+ printer_cfg_unbind(c);
return status;
}
-/*-------------------------------------------------------------------------*/
+static int printer_unbind(struct usb_composite_dev *cdev)
+{
+ return 0;
+}
-static struct usb_gadget_driver printer_driver = {
- .max_speed = DEVSPEED,
+static int __init printer_bind(struct usb_composite_dev *cdev)
+{
+ return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+}
- .function = (char *) driver_desc,
+static struct usb_composite_driver printer_driver = {
+ .name = shortname,
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = printer_unbind,
-
- .setup = printer_setup,
- .disconnect = printer_disconnect,
-
- .driver = {
- .name = (char *) shortname,
- .owner = THIS_MODULE,
- },
};
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Craig Nadler");
-MODULE_LICENSE("GPL");
-
static int __init
init(void)
{
@@ -1560,23 +1285,23 @@ init(void)
usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
if (IS_ERR(usb_gadget_class)) {
status = PTR_ERR(usb_gadget_class);
- ERROR(dev, "unable to create usb_gadget class %d\n", status);
+ pr_err("unable to create usb_gadget class %d\n", status);
return status;
}
status = alloc_chrdev_region(&g_printer_devno, 0, 1,
"USB printer gadget");
if (status) {
- ERROR(dev, "alloc_chrdev_region %d\n", status);
+ pr_err("alloc_chrdev_region %d\n", status);
class_destroy(usb_gadget_class);
return status;
}
- status = usb_gadget_probe_driver(&printer_driver, printer_bind);
+ status = usb_composite_probe(&printer_driver, printer_bind);
if (status) {
class_destroy(usb_gadget_class);
unregister_chrdev_region(g_printer_devno, 1);
- DBG(dev, "usb_gadget_probe_driver %x\n", status);
+ pr_err("usb_gadget_probe_driver %x\n", status);
}
return status;
@@ -1586,15 +1311,14 @@ module_init(init);
static void __exit
cleanup(void)
{
- int status;
-
mutex_lock(&usb_printer_gadget.lock_printer_io);
- status = usb_gadget_unregister_driver(&printer_driver);
- if (status)
- ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
-
+ usb_composite_unregister(&printer_driver);
unregister_chrdev_region(g_printer_devno, 1);
class_destroy(usb_gadget_class);
mutex_unlock(&usb_printer_gadget.lock_printer_io);
}
module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 41ed69c..d7c8cb3 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -218,7 +218,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
struct pxa25x_udc *dev;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->fifo_size < usb_endpoint_maxp (desc)) {
@@ -249,7 +249,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
return -ESHUTDOWN;
}
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
ep->pio_irqs = 0;
ep->ep.maxpacket = usb_endpoint_maxp (desc);
@@ -269,7 +269,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
unsigned long flags;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
DMSG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
@@ -281,7 +281,6 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
/* flush fifo (mostly for IN buffers) */
pxa25x_ep_fifo_flush (_ep);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
@@ -390,7 +389,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
{
unsigned max;
- max = usb_endpoint_maxp(ep->desc);
+ max = usb_endpoint_maxp(ep->ep.desc);
do {
unsigned count;
int is_last, is_short;
@@ -644,7 +643,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
ep = container_of(_ep, struct pxa25x_ep, ep);
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
}
@@ -660,7 +659,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- && req->req.length > usb_endpoint_maxp (ep->desc)))
+ && req->req.length > usb_endpoint_maxp(ep->ep.desc)))
return -EMSGSIZE;
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -673,7 +672,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
- if (ep->desc == NULL/* ep0 */) {
+ if (ep->ep.desc == NULL/* ep0 */) {
unsigned length = _req->length;
switch (dev->ep0state) {
@@ -722,7 +721,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
- if (likely (req && ep->desc))
+ if (likely(req && ep->ep.desc))
pio_irq_enable(ep->bEndpointAddress);
}
@@ -749,7 +748,7 @@ static void nuke(struct pxa25x_ep *ep, int status)
queue);
done(ep, req, status);
}
- if (ep->desc)
+ if (ep->ep.desc)
pio_irq_disable (ep->bEndpointAddress);
}
@@ -792,7 +791,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct pxa25x_ep, ep);
if (unlikely (!_ep
- || (!ep->desc && ep->ep.name != ep0name))
+ || (!ep->ep.desc && ep->ep.name != ep0name))
|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
@@ -820,7 +819,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
*ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
/* ep0 needs special care */
- if (!ep->desc) {
+ if (!ep->ep.desc) {
start_watchdog(ep->dev);
ep->dev->req_pending = 0;
ep->dev->ep0state = EP0_STALL;
@@ -1087,7 +1086,7 @@ udc_seq_show(struct seq_file *m, void *_d)
if (i != 0) {
const struct usb_endpoint_descriptor *desc;
- desc = ep->desc;
+ desc = ep->ep.desc;
if (!desc)
continue;
tmp = *dev->ep [i].reg_udccs;
@@ -1191,7 +1190,6 @@ static void udc_reinit(struct pxa25x_udc *dev)
if (i != 0)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 893e917..861f4df 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -41,7 +41,6 @@ struct pxa25x_ep {
struct usb_ep ep;
struct pxa25x_udc *dev;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index c4401e7..f3ac2a2 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -459,7 +459,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
unsigned char *counter;
int ret;
- ep->desc = desc;
+ ep->ep.desc = desc;
if (ep->pipenum) /* already allocated pipe */
return 0;
@@ -648,7 +648,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
/* set SUDMAC parameters */
dma = &r8a66597->dma;
dma->used = 1;
- if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) {
dma->dir = 1;
} else {
dma->dir = 0;
@@ -770,7 +770,7 @@ static void start_packet_read(struct r8a66597_ep *ep,
static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req)
{
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
start_packet_write(ep, req);
else
start_packet_read(ep, req);
@@ -930,7 +930,7 @@ __acquires(r8a66597->lock)
if (restart) {
req = get_request_from_ep(ep);
- if (ep->desc)
+ if (ep->ep.desc)
start_packet(ep, req);
}
}
@@ -1116,7 +1116,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb)
r8a66597_write(r8a66597, ~check, BRDYSTS);
ep = r8a66597->pipenum2ep[pipenum];
req = get_request_from_ep(ep);
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
irq_packet_write(ep, req);
else
irq_packet_read(ep, req);
@@ -1170,7 +1170,7 @@ __acquires(r8a66597->lock)
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
- status = 1 << USB_DEVICE_SELF_POWERED;
+ status = r8a66597->device_status;
break;
case USB_RECIP_INTERFACE:
status = 0;
@@ -1627,7 +1627,7 @@ static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* control */
+ if (ep->ep.desc == NULL) /* control */
start_ep0(ep, req);
else {
if (request && !ep->busy)
@@ -1692,7 +1692,7 @@ static int r8a66597_set_wedge(struct usb_ep *_ep)
ep = container_of(_ep, struct r8a66597_ep, ep);
- if (!ep || !ep->desc)
+ if (!ep || !ep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&ep->r8a66597->lock, flags);
@@ -1800,11 +1800,24 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
+static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
+
+ if (is_self)
+ r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ r8a66597->device_status &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ return 0;
+}
+
static struct usb_gadget_ops r8a66597_gadget_ops = {
.get_frame = r8a66597_get_frame,
.udc_start = r8a66597_start,
.udc_stop = r8a66597_stop,
.pullup = r8a66597_pullup,
+ .set_selfpowered = r8a66597_set_selfpowered,
};
static int __exit r8a66597_remove(struct platform_device *pdev)
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 8e3de61..99908c7 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -72,7 +72,7 @@ struct r8a66597_ep {
unsigned use_dma:1;
u16 pipenum;
u16 type;
- const struct usb_endpoint_descriptor *desc;
+
/* register address */
unsigned char fifoaddr;
unsigned char fifosel;
@@ -111,6 +111,7 @@ struct r8a66597 {
u16 old_vbus;
u16 scount;
u16 old_dvsq;
+ u16 device_status; /* for GET_STATUS */
/* pipe config */
unsigned char bulk;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 105b206..f4abb0e 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -1,4 +1,5 @@
-/* linux/drivers/usb/gadget/s3c-hsotg.c
+/**
+ * linux/drivers/usb/gadget/s3c-hsotg.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -13,7 +14,7 @@
* 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>
@@ -27,21 +28,25 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <mach/map.h>
-#include <plat/regs-usb-hsotg-phy.h>
-#include <plat/regs-usb-hsotg.h>
-#include <mach/regs-sys.h>
-#include <plat/udc-hs.h>
-#include <plat/cpu.h>
+#include "s3c-hsotg.h"
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
-/* EP0_MPS_LIMIT
+static const char * const s3c_hsotg_supply_names[] = {
+ "vusb_d", /* digital USB supply, 1.2V */
+ "vusb_a", /* analog USB supply, 1.1V */
+};
+
+/*
+ * EP0_MPS_LIMIT
*
* Unfortunately there seems to be a limit of the amount of data that can
* be transferred by IN transactions on EP0. This is either 127 bytes or 3
@@ -125,8 +130,6 @@ struct s3c_hsotg_ep {
char name[10];
};
-#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */
-
/**
* struct s3c_hsotg - driver state.
* @dev: The parent device supplied to the probe function
@@ -135,7 +138,9 @@ struct s3c_hsotg_ep {
* @regs: The memory area mapped for accessing registers.
* @regs_res: The resource that was allocated when claiming register space.
* @irq: The IRQ number we are using
+ * @supplies: Definition of USB power supplies
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
+ * @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: root directrory for debugfs.
* @debug_file: main status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
@@ -143,6 +148,8 @@ struct s3c_hsotg_ep {
* @ep0_buff: Buffer for EP0 reply data, if needed.
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
+ * @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
*/
struct s3c_hsotg {
@@ -155,7 +162,10 @@ struct s3c_hsotg {
int irq;
struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
+
unsigned int dedicated_fifos:1;
+ unsigned char num_of_eps;
struct dentry *debug_root;
struct dentry *debug_file;
@@ -167,7 +177,9 @@ struct s3c_hsotg {
u8 ctrl_buff[8];
struct usb_gadget gadget;
- struct s3c_hsotg_ep eps[];
+ unsigned int setup;
+ unsigned long last_rst;
+ struct s3c_hsotg_ep *eps;
};
/**
@@ -244,14 +256,14 @@ static inline bool using_dma(struct s3c_hsotg *hsotg)
*/
static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
{
- u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
new_gsintmsk = gsintmsk | ints;
if (new_gsintmsk != gsintmsk) {
dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
- writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+ writel(new_gsintmsk, hsotg->regs + GINTMSK);
}
}
@@ -262,13 +274,13 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
*/
static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
{
- u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
new_gsintmsk = gsintmsk & ~ints;
if (new_gsintmsk != gsintmsk)
- writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+ writel(new_gsintmsk, hsotg->regs + GINTMSK);
}
/**
@@ -293,12 +305,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
bit <<= 16;
local_irq_save(flags);
- daint = readl(hsotg->regs + S3C_DAINTMSK);
+ daint = readl(hsotg->regs + DAINTMSK);
if (en)
daint |= bit;
else
daint &= ~bit;
- writel(daint, hsotg->regs + S3C_DAINTMSK);
+ writel(daint, hsotg->regs + DAINTMSK);
local_irq_restore(flags);
}
@@ -314,52 +326,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
int timeout;
u32 val;
- /* the ryu 2.6.24 release ahs
- writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
- writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
- S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
- hsotg->regs + S3C_GNPTXFSIZ);
- */
-
/* set FIFO sizes to 2048/1024 */
- writel(2048, hsotg->regs + S3C_GRXFSIZ);
- writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
- S3C_GNPTXFSIZ_NPTxFDep(1024),
- hsotg->regs + S3C_GNPTXFSIZ);
+ writel(2048, hsotg->regs + GRXFSIZ);
+ writel(GNPTXFSIZ_NPTxFStAddr(2048) |
+ GNPTXFSIZ_NPTxFDep(1024),
+ hsotg->regs + GNPTXFSIZ);
- /* arange all the rest of the TX FIFOs, as some versions of this
+ /*
+ * arange all the rest of the TX FIFOs, as some versions of this
* block have overlapping default addresses. This also ensures
* that if the settings have been changed, then they are set to
- * known values. */
+ * known values.
+ */
/* start at the end of the GNPTXFSIZ, rounded up */
addr = 2048 + 1024;
size = 768;
- /* currently we allocate TX FIFOs for all possible endpoints,
- * and assume that they are all the same size. */
+ /*
+ * currently we allocate TX FIFOs for all possible endpoints,
+ * and assume that they are all the same size.
+ */
for (ep = 1; ep <= 15; ep++) {
val = addr;
- val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
+ val |= size << DPTXFSIZn_DPTxFSize_SHIFT;
addr += size;
- writel(val, hsotg->regs + S3C_DPTXFSIZn(ep));
+ writel(val, hsotg->regs + DPTXFSIZn(ep));
}
- /* according to p428 of the design guide, we need to ensure that
- * all fifos are flushed before continuing */
+ /*
+ * according to p428 of the design guide, we need to ensure that
+ * all fifos are flushed before continuing
+ */
- writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh |
- S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL);
+ writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh |
+ GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL);
/* wait until the fifos are both flushed */
timeout = 100;
while (1) {
- val = readl(hsotg->regs + S3C_GRSTCTL);
+ val = readl(hsotg->regs + GRSTCTL);
- if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0)
+ if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0)
break;
if (--timeout == 0) {
@@ -415,7 +426,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep)
*
* This is the reverse of s3c_hsotg_map_dma(), called for the completion
* of a request to ensure the buffer is ready for access by the caller.
-*/
+ */
static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
@@ -456,13 +467,13 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
* otherwise -ENOSPC is returned if the FIFO space was used up.
*
* This routine is only needed for PIO
-*/
+ */
static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
{
bool periodic = is_ep_periodic(hs_ep);
- u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS);
+ u32 gnptxsts = readl(hsotg->regs + GNPTXSTS);
int buf_pos = hs_req->req.actual;
int to_write = hs_ep->size_loaded;
void *data;
@@ -476,20 +487,23 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
return 0;
if (periodic && !hsotg->dedicated_fifos) {
- u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+ u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
int size_left;
int size_done;
- /* work out how much data was loaded so we can calculate
- * how much data is left in the fifo. */
+ /*
+ * work out how much data was loaded so we can calculate
+ * how much data is left in the fifo.
+ */
- size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ size_left = DxEPTSIZ_XferSize_GET(epsize);
- /* if shared fifo, we cannot write anything until the
+ /*
+ * if shared fifo, we cannot write anything until the
* previous data has been completely sent.
*/
if (hs_ep->fifo_load != 0) {
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
return -ENOSPC;
}
@@ -510,47 +524,50 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
__func__, can_write);
if (can_write <= 0) {
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
return -ENOSPC;
}
} else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
- can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index));
+ can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index));
can_write &= 0xffff;
can_write *= 4;
} else {
- if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
+ if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
dev_dbg(hsotg->dev,
"%s: no queue slots available (0x%08x)\n",
__func__, gnptxsts);
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp);
return -ENOSPC;
}
- can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
+ can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
can_write *= 4; /* fifo size is in 32bit quantities. */
}
dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
__func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket);
- /* limit to 512 bytes of data, it seems at least on the non-periodic
+ /*
+ * limit to 512 bytes of data, it seems at least on the non-periodic
* FIFO, requests of >512 cause the endpoint to get stuck with a
* fragment of the end of the transfer in it.
*/
if (can_write > 512)
can_write = 512;
- /* limit the write to one max-packet size worth of data, but allow
+ /*
+ * limit the write to one max-packet size worth of data, but allow
* the transfer to return that it did not run out of fifo space
- * doing it. */
+ * doing it.
+ */
if (to_write > hs_ep->ep.maxpacket) {
to_write = hs_ep->ep.maxpacket;
s3c_hsotg_en_gsint(hsotg,
- periodic ? S3C_GINTSTS_PTxFEmp :
- S3C_GINTSTS_NPTxFEmp);
+ periodic ? GINTSTS_PTxFEmp :
+ GINTSTS_NPTxFEmp);
}
/* see if we can write data */
@@ -559,8 +576,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
to_write = can_write;
pkt_round = to_write % hs_ep->ep.maxpacket;
- /* Not sure, but we probably shouldn't be writing partial
- * packets into the FIFO, so round the write down to an
+ /*
+ * Round the write down to an
* exact number of packets.
*
* Note, we do not currently check to see if we can ever
@@ -570,12 +587,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
if (pkt_round)
to_write -= pkt_round;
- /* enable correct FIFO interrupt to alert us when there
- * is more room left. */
+ /*
+ * enable correct FIFO interrupt to alert us when there
+ * is more room left.
+ */
s3c_hsotg_en_gsint(hsotg,
- periodic ? S3C_GINTSTS_PTxFEmp :
- S3C_GINTSTS_NPTxFEmp);
+ periodic ? GINTSTS_PTxFEmp :
+ GINTSTS_NPTxFEmp);
}
dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
@@ -593,7 +612,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
to_write = DIV_ROUND_UP(to_write, 4);
data = hs_req->req.buf + buf_pos;
- writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write);
+ writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
return (to_write >= can_write) ? -ENOSPC : 0;
}
@@ -612,12 +631,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
unsigned maxpkt;
if (index != 0) {
- maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
- maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
+ maxsize = DxEPTSIZ_XferSize_LIMIT + 1;
+ maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1;
} else {
maxsize = 64+64;
if (hs_ep->dir_in)
- maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
+ maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1;
else
maxpkt = 2;
}
@@ -626,8 +645,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
maxpkt--;
maxsize--;
- /* constrain by packet count if maxpkts*pktsize is greater
- * than the length register size. */
+ /*
+ * constrain by packet count if maxpkts*pktsize is greater
+ * than the length register size.
+ */
if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
maxsize = maxpkt * hs_ep->ep.maxpacket;
@@ -674,8 +695,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
}
}
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
- epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
+ epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
__func__, readl(hsotg->regs + epctrl_reg), index,
@@ -684,13 +705,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
/* If endpoint is stalled, we will restart request later */
ctrl = readl(hsotg->regs + epctrl_reg);
- if (ctrl & S3C_DxEPCTL_Stall) {
+ if (ctrl & DxEPCTL_Stall) {
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
return;
}
length = ureq->length - ureq->actual;
-
+ dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
+ ureq->length, ureq->actual);
if (0)
dev_dbg(hsotg->dev,
"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
@@ -717,20 +739,22 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
packets = 1; /* send one packet if length is zero. */
if (dir_in && index != 0)
- epsize = S3C_DxEPTSIZ_MC(1);
+ epsize = DxEPTSIZ_MC(1);
else
epsize = 0;
if (index != 0 && ureq->zero) {
- /* test for the packets being exactly right for the
- * transfer */
+ /*
+ * test for the packets being exactly right for the
+ * transfer
+ */
if (length == (packets * hs_ep->ep.maxpacket))
packets++;
}
- epsize |= S3C_DxEPTSIZ_PktCnt(packets);
- epsize |= S3C_DxEPTSIZ_XferSize(length);
+ epsize |= DxEPTSIZ_PktCnt(packets);
+ epsize |= DxEPTSIZ_XferSize(length);
dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",
__func__, packets, length, ureq->length, epsize, epsize_reg);
@@ -744,26 +768,38 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
if (using_dma(hsotg) && !continuing) {
unsigned int dma_reg;
- /* write DMA address to control register, buffer already
- * synced by s3c_hsotg_ep_queue(). */
+ /*
+ * write DMA address to control register, buffer already
+ * synced by s3c_hsotg_ep_queue().
+ */
- dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index);
+ dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
writel(ureq->dma, hsotg->regs + dma_reg);
dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
__func__, ureq->dma, dma_reg);
}
- ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
- ctrl |= S3C_DxEPCTL_USBActEp;
- ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */
+ ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
+ ctrl |= DxEPCTL_USBActEp;
+
+ dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup);
+
+ /* For Setup request do not clear NAK */
+ if (hsotg->setup && index == 0)
+ hsotg->setup = 0;
+ else
+ ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */
+
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
writel(ctrl, hsotg->regs + epctrl_reg);
- /* set these, it seems that DMA support increments past the end
+ /*
+ * set these, it seems that DMA support increments past the end
* of the packet buffer so we need to calculate the length from
- * this information. */
+ * this information.
+ */
hs_ep->size_loaded = length;
hs_ep->last_load = ureq->actual;
@@ -774,17 +810,21 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req);
}
- /* clear the INTknTXFEmpMsk when we start request, more as a aide
- * to debugging to see what is going on. */
+ /*
+ * clear the INTknTXFEmpMsk when we start request, more as a aide
+ * to debugging to see what is going on.
+ */
if (dir_in)
- writel(S3C_DIEPMSK_INTknTXFEmpMsk,
- hsotg->regs + S3C_DIEPINT(index));
+ writel(DIEPMSK_INTknTXFEmpMsk,
+ hsotg->regs + DIEPINT(index));
- /* Note, trying to clear the NAK here causes problems with transmit
- * on the S3C6400 ending up with the TXFIFO becoming full. */
+ /*
+ * Note, trying to clear the NAK here causes problems with transmit
+ * on the S3C6400 ending up with the TXFIFO becoming full.
+ */
/* check ep is enabled */
- if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna))
+ if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna))
dev_warn(hsotg->dev,
"ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n",
index, readl(hsotg->regs + epctrl_reg));
@@ -804,7 +844,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
* then ensure the buffer has been synced to memory. If our buffer has no
* DMA memory, then we map the memory and mark our request to allow us to
* cleanup on completion.
-*/
+ */
static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct usb_request *req)
@@ -922,7 +962,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
*
* Convert the given wIndex into a pointer to an driver endpoint
* structure, or return NULL if it is not a valid endpoint.
-*/
+ */
static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
u32 windex)
{
@@ -933,7 +973,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
if (windex >= 0x100)
return NULL;
- if (idx > S3C_HSOTG_EPS)
+ if (idx > hsotg->num_of_eps)
return NULL;
if (idx && ep->dir_in != dir)
@@ -1151,24 +1191,28 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
ctrl->bRequest, ctrl->bRequestType,
ctrl->wValue, ctrl->wLength);
- /* record the direction of the request, for later use when enquing
- * packets onto EP0. */
+ /*
+ * record the direction of the request, for later use when enquing
+ * packets onto EP0.
+ */
ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
- /* if we've no data with this request, then the last part of the
- * transaction is going to implicitly be IN. */
+ /*
+ * if we've no data with this request, then the last part of the
+ * transaction is going to implicitly be IN.
+ */
if (ctrl->wLength == 0)
ep0->dir_in = 1;
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) {
case USB_REQ_SET_ADDRESS:
- dcfg = readl(hsotg->regs + S3C_DCFG);
- dcfg &= ~S3C_DCFG_DevAddr_MASK;
- dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT;
- writel(dcfg, hsotg->regs + S3C_DCFG);
+ dcfg = readl(hsotg->regs + DCFG);
+ dcfg &= ~DCFG_DevAddr_MASK;
+ dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;
+ writel(dcfg, hsotg->regs + DCFG);
dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
@@ -1194,7 +1238,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
}
- /* the request is either unhandlable, or is not formatted correctly
+ /*
+ * the request is either unhandlable, or is not formatted correctly
* so respond with a STALL for the status stage to indicate failure.
*/
@@ -1203,22 +1248,26 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
u32 ctrl;
dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
- reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0;
+ reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
- /* S3C_DxEPCTL_Stall will be cleared by EP once it has
- * taken effect, so no need to clear later. */
+ /*
+ * DxEPCTL_Stall will be cleared by EP once it has
+ * taken effect, so no need to clear later.
+ */
ctrl = readl(hsotg->regs + reg);
- ctrl |= S3C_DxEPCTL_Stall;
- ctrl |= S3C_DxEPCTL_CNAK;
+ ctrl |= DxEPCTL_Stall;
+ ctrl |= DxEPCTL_CNAK;
writel(ctrl, hsotg->regs + reg);
dev_dbg(hsotg->dev,
"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
ctrl, reg, readl(hsotg->regs + reg));
- /* don't believe we need to anything more to get the EP
- * to reply with a STALL packet */
+ /*
+ * don't believe we need to anything more to get the EP
+ * to reply with a STALL packet
+ */
}
}
@@ -1279,8 +1328,10 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
if (ret < 0) {
dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
- /* Don't think there's much we can do other than watch the
- * driver fail. */
+ /*
+ * Don't think there's much we can do other than watch the
+ * driver fail.
+ */
}
}
@@ -1296,7 +1347,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
* on the endpoint.
*
* Note, expects the ep to already be locked as appropriate.
-*/
+ */
static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
@@ -1312,8 +1363,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",
hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);
- /* only replace the status if we've not already set an error
- * from a previous transaction */
+ /*
+ * only replace the status if we've not already set an error
+ * from a previous transaction
+ */
if (hs_req->req.status == -EINPROGRESS)
hs_req->req.status = result;
@@ -1324,8 +1377,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
if (using_dma(hsotg))
s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req);
- /* call the complete request with the locks off, just in case the
- * request tries to queue more work for this endpoint. */
+ /*
+ * call the complete request with the locks off, just in case the
+ * request tries to queue more work for this endpoint.
+ */
if (hs_req->req.complete) {
spin_unlock(&hs_ep->lock);
@@ -1333,9 +1388,11 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
spin_lock(&hs_ep->lock);
}
- /* Look to see if there is anything else to do. Note, the completion
+ /*
+ * Look to see if there is anything else to do. Note, the completion
* of the previous request may have caused a new request to be started
- * so be careful when doing this. */
+ * so be careful when doing this.
+ */
if (!hs_ep->req && result >= 0) {
restart = !list_empty(&hs_ep->queue);
@@ -1355,7 +1412,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
*
* See s3c_hsotg_complete_request(), but called with the endpoint's
* lock held.
-*/
+ */
static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
@@ -1382,13 +1439,13 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
struct s3c_hsotg_req *hs_req = hs_ep->req;
- void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx);
+ void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
int to_read;
int max_req;
int read_ptr;
if (!hs_req) {
- u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx));
+ u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
int ptr;
dev_warn(hsotg->dev,
@@ -1412,7 +1469,8 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
__func__, to_read, max_req, read_ptr, hs_req->req.length);
if (to_read > max_req) {
- /* more data appeared than we where willing
+ /*
+ * more data appeared than we where willing
* to deal with in this request.
*/
@@ -1424,8 +1482,10 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
hs_req->req.actual += to_read;
to_read = DIV_ROUND_UP(to_read, 4);
- /* note, we might over-write the buffer end by 3 bytes depending on
- * alignment of the data. */
+ /*
+ * note, we might over-write the buffer end by 3 bytes depending on
+ * alignment of the data.
+ */
readsl(fifo, hs_req->req.buf + read_ptr, to_read);
spin_unlock(&hs_ep->lock);
@@ -1465,14 +1525,14 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "sending zero-length packet\n");
/* issue a zero-sized packet to terminate this */
- writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
- S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0));
+ writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+ DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0));
- ctrl = readl(hsotg->regs + S3C_DIEPCTL0);
- ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */
- ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
- ctrl |= S3C_DxEPCTL_USBActEp;
- writel(ctrl, hsotg->regs + S3C_DIEPCTL0);
+ ctrl = readl(hsotg->regs + DIEPCTL0);
+ ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */
+ ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
+ ctrl |= DxEPCTL_USBActEp;
+ writel(ctrl, hsotg->regs + DIEPCTL0);
}
/**
@@ -1484,15 +1544,15 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
* The RXFIFO has delivered an OutDone event, which means that the data
* transfer for an OUT endpoint has been completed, either by a short
* packet or by the finish of a transfer.
-*/
+ */
static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
int epnum, bool was_setup)
{
- u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
+ u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
struct s3c_hsotg_req *hs_req = hs_ep->req;
struct usb_request *req = &hs_req->req;
- unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ unsigned size_left = DxEPTSIZ_XferSize_GET(epsize);
int result = 0;
if (!hs_req) {
@@ -1503,7 +1563,8 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
if (using_dma(hsotg)) {
unsigned size_done;
- /* Calculate the size of the transfer by checking how much
+ /*
+ * Calculate the size of the transfer by checking how much
* is left in the endpoint size register and then working it
* out from the amount we loaded for the transfer.
*
@@ -1521,17 +1582,29 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
if (req->actual < req->length && size_left == 0) {
s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
return;
+ } else if (epnum == 0) {
+ /*
+ * After was_setup = 1 =>
+ * set CNAK for non Setup requests
+ */
+ hsotg->setup = was_setup ? 0 : 1;
}
if (req->actual < req->length && req->short_not_ok) {
dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
__func__, req->actual, req->length);
- /* todo - what should we return here? there's no one else
- * even bothering to check the status. */
+ /*
+ * todo - what should we return here? there's no one else
+ * even bothering to check the status.
+ */
}
if (epnum == 0) {
+ /*
+ * Condition req->complete != s3c_hsotg_complete_setup says:
+ * send ZLP when we have an asynchronous request from gadget
+ */
if (!was_setup && req->complete != s3c_hsotg_complete_setup)
s3c_hsotg_send_zlp(hsotg, hs_req);
}
@@ -1544,14 +1617,14 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
* @hsotg: The device instance
*
* Return the current frame number
-*/
+ */
static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
{
u32 dsts;
- dsts = readl(hsotg->regs + S3C_DSTS);
- dsts &= S3C_DSTS_SOFFN_MASK;
- dsts >>= S3C_DSTS_SOFFN_SHIFT;
+ dsts = readl(hsotg->regs + DSTS);
+ dsts &= DSTS_SOFFN_MASK;
+ dsts >>= DSTS_SOFFN_SHIFT;
return dsts;
}
@@ -1574,29 +1647,29 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
*/
static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
{
- u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
+ u32 grxstsr = readl(hsotg->regs + GRXSTSP);
u32 epnum, status, size;
WARN_ON(using_dma(hsotg));
- epnum = grxstsr & S3C_GRXSTS_EPNum_MASK;
- status = grxstsr & S3C_GRXSTS_PktSts_MASK;
+ epnum = grxstsr & GRXSTS_EPNum_MASK;
+ status = grxstsr & GRXSTS_PktSts_MASK;
- size = grxstsr & S3C_GRXSTS_ByteCnt_MASK;
- size >>= S3C_GRXSTS_ByteCnt_SHIFT;
+ size = grxstsr & GRXSTS_ByteCnt_MASK;
+ size >>= GRXSTS_ByteCnt_SHIFT;
if (1)
dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
__func__, grxstsr, size, epnum);
-#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT)
+#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT)
- switch (status >> S3C_GRXSTS_PktSts_SHIFT) {
- case __status(S3C_GRXSTS_PktSts_GlobalOutNAK):
+ switch (status >> GRXSTS_PktSts_SHIFT) {
+ case __status(GRXSTS_PktSts_GlobalOutNAK):
dev_dbg(hsotg->dev, "GlobalOutNAK\n");
break;
- case __status(S3C_GRXSTS_PktSts_OutDone):
+ case __status(GRXSTS_PktSts_OutDone):
dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg));
@@ -1604,24 +1677,24 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
s3c_hsotg_handle_outdone(hsotg, epnum, false);
break;
- case __status(S3C_GRXSTS_PktSts_SetupDone):
+ case __status(GRXSTS_PktSts_SetupDone):
dev_dbg(hsotg->dev,
"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg),
- readl(hsotg->regs + S3C_DOEPCTL(0)));
+ readl(hsotg->regs + DOEPCTL(0)));
s3c_hsotg_handle_outdone(hsotg, epnum, true);
break;
- case __status(S3C_GRXSTS_PktSts_OutRX):
+ case __status(GRXSTS_PktSts_OutRX):
s3c_hsotg_rx_data(hsotg, epnum, size);
break;
- case __status(S3C_GRXSTS_PktSts_SetupRX):
+ case __status(GRXSTS_PktSts_SetupRX):
dev_dbg(hsotg->dev,
"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg),
- readl(hsotg->regs + S3C_DOEPCTL(0)));
+ readl(hsotg->regs + DOEPCTL(0)));
s3c_hsotg_rx_data(hsotg, epnum, size);
break;
@@ -1638,18 +1711,18 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
/**
* s3c_hsotg_ep0_mps - turn max packet size into register setting
* @mps: The maximum packet size in bytes.
-*/
+ */
static u32 s3c_hsotg_ep0_mps(unsigned int mps)
{
switch (mps) {
case 64:
- return S3C_D0EPCTL_MPS_64;
+ return D0EPCTL_MPS_64;
case 32:
- return S3C_D0EPCTL_MPS_32;
+ return D0EPCTL_MPS_32;
case 16:
- return S3C_D0EPCTL_MPS_16;
+ return D0EPCTL_MPS_16;
case 8:
- return S3C_D0EPCTL_MPS_8;
+ return D0EPCTL_MPS_8;
}
/* bad max packet size, warn and return invalid result */
@@ -1680,7 +1753,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
if (mpsval > 3)
goto bad_mps;
} else {
- if (mps >= S3C_DxEPCTL_MPS_LIMIT+1)
+ if (mps >= DxEPCTL_MPS_LIMIT+1)
goto bad_mps;
mpsval = mps;
@@ -1688,19 +1761,21 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
hs_ep->ep.maxpacket = mps;
- /* update both the in and out endpoint controldir_ registers, even
- * if one of the directions may not be in use. */
+ /*
+ * update both the in and out endpoint controldir_ registers, even
+ * if one of the directions may not be in use.
+ */
- reg = readl(regs + S3C_DIEPCTL(ep));
- reg &= ~S3C_DxEPCTL_MPS_MASK;
+ reg = readl(regs + DIEPCTL(ep));
+ reg &= ~DxEPCTL_MPS_MASK;
reg |= mpsval;
- writel(reg, regs + S3C_DIEPCTL(ep));
+ writel(reg, regs + DIEPCTL(ep));
if (ep) {
- reg = readl(regs + S3C_DOEPCTL(ep));
- reg &= ~S3C_DxEPCTL_MPS_MASK;
+ reg = readl(regs + DOEPCTL(ep));
+ reg &= ~DxEPCTL_MPS_MASK;
reg |= mpsval;
- writel(reg, regs + S3C_DOEPCTL(ep));
+ writel(reg, regs + DOEPCTL(ep));
}
return;
@@ -1719,16 +1794,16 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
int timeout;
int val;
- writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh,
- hsotg->regs + S3C_GRSTCTL);
+ writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh,
+ hsotg->regs + GRSTCTL);
/* wait until the fifo is flushed */
timeout = 100;
while (1) {
- val = readl(hsotg->regs + S3C_GRSTCTL);
+ val = readl(hsotg->regs + GRSTCTL);
- if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0)
+ if ((val & (GRSTCTL_TxFFlsh)) == 0)
break;
if (--timeout == 0) {
@@ -1778,7 +1853,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep)
{
struct s3c_hsotg_req *hs_req = hs_ep->req;
- u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+ u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
int size_left, size_done;
if (!hs_req) {
@@ -1786,7 +1861,15 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
return;
}
- /* Calculate the size of the transfer by checking how much is left
+ /* Finish ZLP handling for IN EP0 transactions */
+ if (hsotg->eps[0].sent_zlp) {
+ dev_dbg(hsotg->dev, "zlp packet received\n");
+ s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+ return;
+ }
+
+ /*
+ * Calculate the size of the transfer by checking how much is left
* in the endpoint size register and then working it out from
* the amount we loaded for the transfer.
*
@@ -1795,7 +1878,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
* aligned).
*/
- size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ size_left = DxEPTSIZ_XferSize_GET(epsize);
size_done = hs_ep->size_loaded - size_left;
size_done += hs_ep->last_load;
@@ -1805,9 +1888,28 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
__func__, hs_req->req.actual, size_done);
hs_req->req.actual = size_done;
+ dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
+ hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
+
+ /*
+ * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
+ * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
+ * ,256B ... ), after last MPS sized packet send IN ZLP packet to
+ * inform the host that no more data is available.
+ * The state of req.zero member is checked to be sure that the value to
+ * send is smaller than wValue expected from host.
+ * Check req.length to NOT send another ZLP when the current one is
+ * under completion (the one for which this completion has been called).
+ */
+ if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
+ hs_req->req.length == hs_req->req.actual &&
+ !(hs_req->req.length % hs_ep->ep.maxpacket)) {
- /* if we did all of the transfer, and there is more data left
- * around, then try restarting the rest of the request */
+ dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
+ s3c_hsotg_send_zlp(hsotg, hs_req);
+
+ return;
+ }
if (!size_left && hs_req->req.actual < hs_req->req.length) {
dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
@@ -1823,14 +1925,14 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
* @dir_in: Set if this is an IN endpoint
*
* Process and clear any interrupt pending for an individual endpoint
-*/
+ */
static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
int dir_in)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
- u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx);
- u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
- u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
+ u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
+ u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
+ u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
u32 ints;
ints = readl(hsotg->regs + epint_reg);
@@ -1841,28 +1943,32 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
__func__, idx, dir_in ? "in" : "out", ints);
- if (ints & S3C_DxEPINT_XferCompl) {
+ if (ints & DxEPINT_XferCompl) {
dev_dbg(hsotg->dev,
"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",
__func__, readl(hsotg->regs + epctl_reg),
readl(hsotg->regs + epsiz_reg));
- /* we get OutDone from the FIFO, so we only need to look
- * at completing IN requests here */
+ /*
+ * we get OutDone from the FIFO, so we only need to look
+ * at completing IN requests here
+ */
if (dir_in) {
s3c_hsotg_complete_in(hsotg, hs_ep);
if (idx == 0 && !hs_ep->req)
s3c_hsotg_enqueue_setup(hsotg);
} else if (using_dma(hsotg)) {
- /* We're using DMA, we need to fire an OutDone here
- * as we ignore the RXFIFO. */
+ /*
+ * We're using DMA, we need to fire an OutDone here
+ * as we ignore the RXFIFO.
+ */
s3c_hsotg_handle_outdone(hsotg, idx, false);
}
}
- if (ints & S3C_DxEPINT_EPDisbld) {
+ if (ints & DxEPINT_EPDisbld) {
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (dir_in) {
@@ -1870,27 +1976,29 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
s3c_hsotg_txfifo_flush(hsotg, idx);
- if ((epctl & S3C_DxEPCTL_Stall) &&
- (epctl & S3C_DxEPCTL_EPType_Bulk)) {
- int dctl = readl(hsotg->regs + S3C_DCTL);
+ if ((epctl & DxEPCTL_Stall) &&
+ (epctl & DxEPCTL_EPType_Bulk)) {
+ int dctl = readl(hsotg->regs + DCTL);
- dctl |= S3C_DCTL_CGNPInNAK;
- writel(dctl, hsotg->regs + S3C_DCTL);
+ dctl |= DCTL_CGNPInNAK;
+ writel(dctl, hsotg->regs + DCTL);
}
}
}
- if (ints & S3C_DxEPINT_AHBErr)
+ if (ints & DxEPINT_AHBErr)
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
- if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */
+ if (ints & DxEPINT_Setup) { /* Setup or Timeout */
dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__);
if (using_dma(hsotg) && idx == 0) {
- /* this is the notification we've received a
+ /*
+ * this is the notification we've received a
* setup packet. In non-DMA mode we'd get this
* from the RXFIFO, instead we need to process
- * the setup here. */
+ * the setup here.
+ */
if (dir_in)
WARN_ON_ONCE(1);
@@ -1899,26 +2007,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
}
}
- if (ints & S3C_DxEPINT_Back2BackSetup)
+ if (ints & DxEPINT_Back2BackSetup)
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
if (dir_in) {
- /* not sure if this is important, but we'll clear it anyway
- */
- if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
+ /* not sure if this is important, but we'll clear it anyway */
+ if (ints & DIEPMSK_INTknTXFEmpMsk) {
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
__func__, idx);
}
/* this probably means something bad is happening */
- if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
+ if (ints & DIEPMSK_INTknEPMisMsk) {
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
__func__, idx);
}
/* FIFO has space or is empty (see GAHBCFG) */
if (hsotg->dedicated_fifos &&
- ints & S3C_DIEPMSK_TxFIFOEmpty) {
+ ints & DIEPMSK_TxFIFOEmpty) {
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx);
if (!using_dma(hsotg))
@@ -1933,40 +2040,45 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
*
* Handle updating the device settings after the enumeration phase has
* been completed.
-*/
+ */
static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
{
- u32 dsts = readl(hsotg->regs + S3C_DSTS);
+ u32 dsts = readl(hsotg->regs + DSTS);
int ep0_mps = 0, ep_mps;
- /* This should signal the finish of the enumeration phase
+ /*
+ * This should signal the finish of the enumeration phase
* of the USB handshaking, so we should now know what rate
- * we connected at. */
+ * we connected at.
+ */
dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts);
- /* note, since we're limited by the size of transfer on EP0, and
+ /*
+ * note, since we're limited by the size of transfer on EP0, and
* it seems IN transfers must be a even number of packets we do
- * not advertise a 64byte MPS on EP0. */
+ * not advertise a 64byte MPS on EP0.
+ */
/* catch both EnumSpd_FS and EnumSpd_FS48 */
- switch (dsts & S3C_DSTS_EnumSpd_MASK) {
- case S3C_DSTS_EnumSpd_FS:
- case S3C_DSTS_EnumSpd_FS48:
+ switch (dsts & DSTS_EnumSpd_MASK) {
+ case DSTS_EnumSpd_FS:
+ case DSTS_EnumSpd_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 64;
break;
- case S3C_DSTS_EnumSpd_HS:
+ case DSTS_EnumSpd_HS:
hsotg->gadget.speed = USB_SPEED_HIGH;
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 512;
break;
- case S3C_DSTS_EnumSpd_LS:
+ case DSTS_EnumSpd_LS:
hsotg->gadget.speed = USB_SPEED_LOW;
- /* note, we don't actually support LS in this driver at the
+ /*
+ * note, we don't actually support LS in this driver at the
* moment, and the documentation seems to imply that it isn't
* supported by the PHYs on some of the devices.
*/
@@ -1975,13 +2087,15 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
dev_info(hsotg->dev, "new device is %s\n",
usb_speed_string(hsotg->gadget.speed));
- /* we should now know the maximum packet size for an
- * endpoint, so set the endpoints to a default value. */
+ /*
+ * we should now know the maximum packet size for an
+ * endpoint, so set the endpoints to a default value.
+ */
if (ep0_mps) {
int i;
s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
- for (i = 1; i < S3C_HSOTG_EPS; i++)
+ for (i = 1; i < hsotg->num_of_eps; i++)
s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
}
@@ -1990,8 +2104,8 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
s3c_hsotg_enqueue_setup(hsotg);
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
}
/**
@@ -2014,8 +2128,10 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
spin_lock_irqsave(&ep->lock, flags);
list_for_each_entry_safe(req, treq, &ep->queue, queue) {
- /* currently, we can't do much about an already
- * running request on an in endpoint */
+ /*
+ * currently, we can't do much about an already
+ * running request on an in endpoint
+ */
if (ep->req == req && ep->dir_in && !force)
continue;
@@ -2033,18 +2149,18 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
(_hs)->driver->_entry(&(_hs)->gadget);
/**
- * s3c_hsotg_disconnect_irq - disconnect irq service
+ * s3c_hsotg_disconnect - disconnect service
* @hsotg: The device state.
*
- * A disconnect IRQ has been received, meaning that the host has
- * lost contact with the bus. Remove all current transactions
- * and signal the gadget driver that this has happened.
-*/
-static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg)
+ * The device has been disconnected. Remove all current
+ * transactions and signal the gadget driver that this
+ * has happened.
+ */
+static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
{
unsigned ep;
- for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+ for (ep = 0; ep < hsotg->num_of_eps; ep++)
kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
call_gadget(hsotg, disconnect);
@@ -2062,7 +2178,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
/* look through for any more data to transmit */
- for (epno = 0; epno < S3C_HSOTG_EPS; epno++) {
+ for (epno = 0; epno < hsotg->num_of_eps; epno++) {
ep = &hsotg->eps[epno];
if (!ep->dir_in)
@@ -2078,12 +2194,187 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
}
}
-static struct s3c_hsotg *our_hsotg;
-
/* IRQ flags which will trigger a retry around the IRQ loop */
-#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \
- S3C_GINTSTS_PTxFEmp | \
- S3C_GINTSTS_RxFLvl)
+#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \
+ GINTSTS_PTxFEmp | \
+ GINTSTS_RxFLvl)
+
+/**
+ * s3c_hsotg_corereset - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+{
+ int timeout;
+ u32 grstctl;
+
+ dev_dbg(hsotg->dev, "resetting core\n");
+
+ /* issue soft reset */
+ writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL);
+
+ timeout = 1000;
+ do {
+ grstctl = readl(hsotg->regs + GRSTCTL);
+ } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0);
+
+ if (grstctl & GRSTCTL_CSftRst) {
+ dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
+ return -EINVAL;
+ }
+
+ timeout = 1000;
+
+ while (1) {
+ u32 grstctl = readl(hsotg->regs + GRSTCTL);
+
+ if (timeout-- < 0) {
+ dev_info(hsotg->dev,
+ "%s: reset failed, GRSTCTL=%08x\n",
+ __func__, grstctl);
+ return -ETIMEDOUT;
+ }
+
+ if (!(grstctl & GRSTCTL_AHBIdle))
+ continue;
+
+ break; /* reset done */
+ }
+
+ dev_dbg(hsotg->dev, "reset successful\n");
+ return 0;
+}
+
+/**
+ * s3c_hsotg_core_init - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
+{
+ s3c_hsotg_corereset(hsotg);
+
+ /*
+ * we must now enable ep0 ready for host detection and then
+ * set configuration.
+ */
+
+ /* set the PLL on, remove the HNP/SRP and set the PHY */
+ writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) |
+ (0x5 << 10), hsotg->regs + GUSBCFG);
+
+ s3c_hsotg_init_fifo(hsotg);
+
+ __orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
+
+ writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG);
+
+ /* Clear any pending OTG interrupts */
+ writel(0xffffffff, hsotg->regs + GOTGINT);
+
+ /* Clear any pending interrupts */
+ writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt |
+ GINTSTS_GOUTNakEff | GINTSTS_GINNakEff |
+ GINTSTS_ConIDStsChng | GINTSTS_USBRst |
+ GINTSTS_EnumDone | GINTSTS_OTGInt |
+ GINTSTS_USBSusp | GINTSTS_WkUpInt,
+ hsotg->regs + GINTMSK);
+
+ if (using_dma(hsotg))
+ writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn |
+ GAHBCFG_HBstLen_Incr4,
+ hsotg->regs + GAHBCFG);
+ else
+ writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG);
+
+ /*
+ * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
+ * up being flooded with interrupts if the host is polling the
+ * endpoint to try and read data.
+ */
+
+ writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) |
+ DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk |
+ DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+ DIEPMSK_INTknEPMisMsk,
+ hsotg->regs + DIEPMSK);
+
+ /*
+ * don't need XferCompl, we get that from RXFIFO in slave mode. In
+ * DMA mode we may need this.
+ */
+ writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk |
+ DIEPMSK_TimeOUTMsk) : 0) |
+ DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk |
+ DOEPMSK_SetupMsk,
+ hsotg->regs + DOEPMSK);
+
+ writel(0, hsotg->regs + DAINTMSK);
+
+ dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
+
+ /* enable in and out endpoint interrupts */
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt);
+
+ /*
+ * Enable the RXFIFO when in slave mode, as this is how we collect
+ * the data. In DMA mode, we get events from the FIFO but also
+ * things we cannot process, so do not use it.
+ */
+ if (!using_dma(hsotg))
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl);
+
+ /* Enable interrupts for EP0 in and out */
+ s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
+ s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
+
+ __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+ udelay(10); /* see openiboot */
+ __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+
+ dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
+
+ /*
+ * DxEPCTL_USBActEp says RO in manual, but seems to be set by
+ * writing to the EPCTL register..
+ */
+
+ /* set to read 1 8byte packet */
+ writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+ DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
+
+ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ DxEPCTL_CNAK | DxEPCTL_EPEna |
+ DxEPCTL_USBActEp,
+ hsotg->regs + DOEPCTL0);
+
+ /* enable, but don't activate EP0in */
+ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0);
+
+ s3c_hsotg_enqueue_setup(hsotg);
+
+ dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
+
+ /* clear global NAKs */
+ writel(DCTL_CGOUTNak | DCTL_CGNPInNAK,
+ hsotg->regs + DCTL);
+
+ /* must be at-least 3ms to allow bus to see disconnect */
+ mdelay(3);
+
+ /* remove the soft-disconnect and let's go */
+ __bic32(hsotg->regs + DCTL, DCTL_SftDiscon);
+}
/**
* s3c_hsotg_irq - handle device interrupt
@@ -2098,52 +2389,45 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
u32 gintmsk;
irq_retry:
- gintsts = readl(hsotg->regs + S3C_GINTSTS);
- gintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ gintsts = readl(hsotg->regs + GINTSTS);
+ gintmsk = readl(hsotg->regs + GINTMSK);
dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
__func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
gintsts &= gintmsk;
- if (gintsts & S3C_GINTSTS_OTGInt) {
- u32 otgint = readl(hsotg->regs + S3C_GOTGINT);
+ if (gintsts & GINTSTS_OTGInt) {
+ u32 otgint = readl(hsotg->regs + GOTGINT);
dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
- writel(otgint, hsotg->regs + S3C_GOTGINT);
- }
-
- if (gintsts & S3C_GINTSTS_DisconnInt) {
- dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__);
- writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS);
-
- s3c_hsotg_disconnect_irq(hsotg);
+ writel(otgint, hsotg->regs + GOTGINT);
}
- if (gintsts & S3C_GINTSTS_SessReqInt) {
+ if (gintsts & GINTSTS_SessReqInt) {
dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
- writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS);
}
- if (gintsts & S3C_GINTSTS_EnumDone) {
- writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_EnumDone) {
+ writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS);
s3c_hsotg_irq_enumdone(hsotg);
}
- if (gintsts & S3C_GINTSTS_ConIDStsChng) {
+ if (gintsts & GINTSTS_ConIDStsChng) {
dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",
- readl(hsotg->regs + S3C_DSTS),
- readl(hsotg->regs + S3C_GOTGCTL));
+ readl(hsotg->regs + DSTS),
+ readl(hsotg->regs + GOTGCTL));
- writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS);
}
- if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) {
- u32 daint = readl(hsotg->regs + S3C_DAINT);
- u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT;
- u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT);
+ if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) {
+ u32 daint = readl(hsotg->regs + DAINT);
+ u32 daint_out = daint >> DAINT_OutEP_SHIFT;
+ u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT);
int ep;
dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
@@ -2159,102 +2443,116 @@ irq_retry:
}
}
- if (gintsts & S3C_GINTSTS_USBRst) {
+ if (gintsts & GINTSTS_USBRst) {
+
+ u32 usb_status = readl(hsotg->regs + GOTGCTL);
+
dev_info(hsotg->dev, "%s: USBRst\n", __func__);
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
- readl(hsotg->regs + S3C_GNPTXSTS));
+ readl(hsotg->regs + GNPTXSTS));
- writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_USBRst, hsotg->regs + GINTSTS);
- kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+ if (usb_status & GOTGCTL_BSESVLD) {
+ if (time_after(jiffies, hsotg->last_rst +
+ msecs_to_jiffies(200))) {
- /* it seems after a reset we can end up with a situation
- * where the TXFIFO still has data in it... the docs
- * suggest resetting all the fifos, so use the init_fifo
- * code to relayout and flush the fifos.
- */
+ kill_all_requests(hsotg, &hsotg->eps[0],
+ -ECONNRESET, true);
- s3c_hsotg_init_fifo(hsotg);
-
- s3c_hsotg_enqueue_setup(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ hsotg->last_rst = jiffies;
+ }
+ }
}
/* check both FIFOs */
- if (gintsts & S3C_GINTSTS_NPTxFEmp) {
+ if (gintsts & GINTSTS_NPTxFEmp) {
dev_dbg(hsotg->dev, "NPTxFEmp\n");
- /* Disable the interrupt to stop it happening again
+ /*
+ * Disable the interrupt to stop it happening again
* unless one of these endpoint routines decides that
- * it needs re-enabling */
+ * it needs re-enabling
+ */
- s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+ s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, false);
}
- if (gintsts & S3C_GINTSTS_PTxFEmp) {
+ if (gintsts & GINTSTS_PTxFEmp) {
dev_dbg(hsotg->dev, "PTxFEmp\n");
- /* See note in S3C_GINTSTS_NPTxFEmp */
+ /* See note in GINTSTS_NPTxFEmp */
- s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, true);
}
- if (gintsts & S3C_GINTSTS_RxFLvl) {
- /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
+ if (gintsts & GINTSTS_RxFLvl) {
+ /*
+ * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
* we need to retry s3c_hsotg_handle_rx if this is still
- * set. */
+ * set.
+ */
s3c_hsotg_handle_rx(hsotg);
}
- if (gintsts & S3C_GINTSTS_ModeMis) {
+ if (gintsts & GINTSTS_ModeMis) {
dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");
- writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS);
}
- if (gintsts & S3C_GINTSTS_USBSusp) {
- dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n");
- writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_USBSusp) {
+ dev_info(hsotg->dev, "GINTSTS_USBSusp\n");
+ writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS);
call_gadget(hsotg, suspend);
+ s3c_hsotg_disconnect(hsotg);
}
- if (gintsts & S3C_GINTSTS_WkUpInt) {
- dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n");
- writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_WkUpInt) {
+ dev_info(hsotg->dev, "GINTSTS_WkUpIn\n");
+ writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS);
call_gadget(hsotg, resume);
}
- if (gintsts & S3C_GINTSTS_ErlySusp) {
- dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
- writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_ErlySusp) {
+ dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
+ writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS);
+
+ s3c_hsotg_disconnect(hsotg);
}
- /* these next two seem to crop-up occasionally causing the core
+ /*
+ * these next two seem to crop-up occasionally causing the core
* to shutdown the USB transfer, so try clearing them and logging
- * the occurrence. */
+ * the occurrence.
+ */
- if (gintsts & S3C_GINTSTS_GOUTNakEff) {
+ if (gintsts & GINTSTS_GOUTNakEff) {
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
- writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
+ writel(DCTL_CGOUTNak, hsotg->regs + DCTL);
s3c_hsotg_dump(hsotg);
}
- if (gintsts & S3C_GINTSTS_GINNakEff) {
+ if (gintsts & GINTSTS_GINNakEff) {
dev_info(hsotg->dev, "GINNakEff triggered\n");
- writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
+ writel(DCTL_CGNPInNAK, hsotg->regs + DCTL);
s3c_hsotg_dump(hsotg);
}
- /* if we've had fifo events, we should try and go around the
- * loop again to see if there's any point in returning yet. */
+ /*
+ * if we've had fifo events, we should try and go around the
+ * loop again to see if there's any point in returning yet.
+ */
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
goto irq_retry;
@@ -2268,7 +2566,7 @@ irq_retry:
* @desc: The USB endpoint descriptor to configure with.
*
* This is called from the USB gadget code's usb_ep_enable().
-*/
+ */
static int s3c_hsotg_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
@@ -2300,7 +2598,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
epctrl = readl(hsotg->regs + epctrl_reg);
dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
@@ -2308,20 +2606,23 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
spin_lock_irqsave(&hs_ep->lock, flags);
- epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK);
- epctrl |= S3C_DxEPCTL_MPS(mps);
+ epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
+ epctrl |= DxEPCTL_MPS(mps);
- /* mark the endpoint as active, otherwise the core may ignore
- * transactions entirely for this endpoint */
- epctrl |= S3C_DxEPCTL_USBActEp;
+ /*
+ * mark the endpoint as active, otherwise the core may ignore
+ * transactions entirely for this endpoint
+ */
+ epctrl |= DxEPCTL_USBActEp;
- /* set the NAK status on the endpoint, otherwise we might try and
+ /*
+ * set the NAK status on the endpoint, otherwise we might try and
* do something with data that we've yet got a request to process
* since the RXFIFO will take data for an endpoint even if the
* size register hasn't been set.
*/
- epctrl |= S3C_DxEPCTL_SNAK;
+ epctrl |= DxEPCTL_SNAK;
/* update the endpoint state */
hs_ep->ep.maxpacket = mps;
@@ -2336,37 +2637,40 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
goto out;
case USB_ENDPOINT_XFER_BULK:
- epctrl |= S3C_DxEPCTL_EPType_Bulk;
+ epctrl |= DxEPCTL_EPType_Bulk;
break;
case USB_ENDPOINT_XFER_INT:
if (dir_in) {
- /* Allocate our TxFNum by simply using the index
+ /*
+ * Allocate our TxFNum by simply using the index
* of the endpoint for the moment. We could do
* something better if the host indicates how
- * many FIFOs we are expecting to use. */
+ * many FIFOs we are expecting to use.
+ */
hs_ep->periodic = 1;
- epctrl |= S3C_DxEPCTL_TxFNum(index);
+ epctrl |= DxEPCTL_TxFNum(index);
}
- epctrl |= S3C_DxEPCTL_EPType_Intterupt;
+ epctrl |= DxEPCTL_EPType_Intterupt;
break;
case USB_ENDPOINT_XFER_CONTROL:
- epctrl |= S3C_DxEPCTL_EPType_Control;
+ epctrl |= DxEPCTL_EPType_Control;
break;
}
- /* if the hardware has dedicated fifos, we must give each IN EP
+ /*
+ * if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
if (dir_in && hsotg->dedicated_fifos)
- epctrl |= S3C_DxEPCTL_TxFNum(index);
+ epctrl |= DxEPCTL_TxFNum(index);
/* for non control endpoints, set PID to D0 */
if (index)
- epctrl |= S3C_DxEPCTL_SetD0PID;
+ epctrl |= DxEPCTL_SetD0PID;
dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
__func__, epctrl);
@@ -2383,6 +2687,10 @@ out:
return ret;
}
+/**
+ * s3c_hsotg_ep_disable - disable given endpoint
+ * @ep: The endpoint to disable.
+ */
static int s3c_hsotg_ep_disable(struct usb_ep *ep)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2400,7 +2708,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
return -EINVAL;
}
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
/* terminate all requests with shutdown */
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
@@ -2408,9 +2716,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
spin_lock_irqsave(&hs_ep->lock, flags);
ctrl = readl(hsotg->regs + epctrl_reg);
- ctrl &= ~S3C_DxEPCTL_EPEna;
- ctrl &= ~S3C_DxEPCTL_USBActEp;
- ctrl |= S3C_DxEPCTL_SNAK;
+ ctrl &= ~DxEPCTL_EPEna;
+ ctrl &= ~DxEPCTL_USBActEp;
+ ctrl |= DxEPCTL_SNAK;
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
writel(ctrl, hsotg->regs + epctrl_reg);
@@ -2426,7 +2734,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
* on_list - check request is on the given endpoint
* @ep: The endpoint to check.
* @test: The request to test if it is on the endpoint.
-*/
+ */
static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
{
struct s3c_hsotg_req *req, *treq;
@@ -2439,6 +2747,11 @@ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
return false;
}
+/**
+ * s3c_hsotg_ep_dequeue - dequeue given endpoint
+ * @ep: The endpoint to dequeue.
+ * @req: The request to be removed from a queue.
+ */
static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
struct s3c_hsotg_req *hs_req = our_req(req);
@@ -2461,6 +2774,11 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
return 0;
}
+/**
+ * s3c_hsotg_ep_sethalt - set halt on a given endpoint
+ * @ep: The endpoint to set halt.
+ * @value: Set or unset the halt.
+ */
static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2477,34 +2795,34 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
/* write both IN and OUT control registers */
- epreg = S3C_DIEPCTL(index);
+ epreg = DIEPCTL(index);
epctl = readl(hs->regs + epreg);
if (value) {
- epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK;
- if (epctl & S3C_DxEPCTL_EPEna)
- epctl |= S3C_DxEPCTL_EPDis;
+ epctl |= DxEPCTL_Stall + DxEPCTL_SNAK;
+ if (epctl & DxEPCTL_EPEna)
+ epctl |= DxEPCTL_EPDis;
} else {
- epctl &= ~S3C_DxEPCTL_Stall;
- xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
- if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
- xfertype == S3C_DxEPCTL_EPType_Intterupt)
- epctl |= S3C_DxEPCTL_SetD0PID;
+ epctl &= ~DxEPCTL_Stall;
+ xfertype = epctl & DxEPCTL_EPType_MASK;
+ if (xfertype == DxEPCTL_EPType_Bulk ||
+ xfertype == DxEPCTL_EPType_Intterupt)
+ epctl |= DxEPCTL_SetD0PID;
}
writel(epctl, hs->regs + epreg);
- epreg = S3C_DOEPCTL(index);
+ epreg = DOEPCTL(index);
epctl = readl(hs->regs + epreg);
if (value)
- epctl |= S3C_DxEPCTL_Stall;
+ epctl |= DxEPCTL_Stall;
else {
- epctl &= ~S3C_DxEPCTL_Stall;
- xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
- if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
- xfertype == S3C_DxEPCTL_EPType_Intterupt)
- epctl |= S3C_DxEPCTL_SetD0PID;
+ epctl &= ~DxEPCTL_Stall;
+ xfertype = epctl & DxEPCTL_EPType_MASK;
+ if (xfertype == DxEPCTL_EPType_Bulk ||
+ xfertype == DxEPCTL_EPType_Intterupt)
+ epctl |= DxEPCTL_SetD0PID;
}
writel(epctl, hs->regs + epreg);
@@ -2526,57 +2844,91 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = {
};
/**
- * s3c_hsotg_corereset - issue softreset to the core
- * @hsotg: The device state
+ * s3c_hsotg_phy_enable - enable platform phy dev
+ * @hsotg: The driver state
*
- * Issue a soft reset to the core, and await the core finishing it.
-*/
-static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
{
- int timeout;
- u32 grstctl;
+ struct platform_device *pdev = to_platform_device(hsotg->dev);
- dev_dbg(hsotg->dev, "resetting core\n");
+ dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
+ if (hsotg->plat->phy_init)
+ hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
+}
- /* issue soft reset */
- writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL);
+/**
+ * s3c_hsotg_phy_disable - disable platform phy dev
+ * @hsotg: The driver state
+ *
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
+{
+ struct platform_device *pdev = to_platform_device(hsotg->dev);
- timeout = 1000;
- do {
- grstctl = readl(hsotg->regs + S3C_GRSTCTL);
- } while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
+ if (hsotg->plat->phy_exit)
+ hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
+}
- if (grstctl & S3C_GRSTCTL_CSftRst) {
- dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
- return -EINVAL;
- }
+/**
+ * s3c_hsotg_init - initalize the usb core
+ * @hsotg: The driver state
+ */
+static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+{
+ /* unmask subset of endpoint interrupts */
- timeout = 1000;
+ writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+ DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk,
+ hsotg->regs + DIEPMSK);
- while (1) {
- u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL);
+ writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk |
+ DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk,
+ hsotg->regs + DOEPMSK);
- if (timeout-- < 0) {
- dev_info(hsotg->dev,
- "%s: reset failed, GRSTCTL=%08x\n",
- __func__, grstctl);
- return -ETIMEDOUT;
- }
+ writel(0, hsotg->regs + DAINTMSK);
- if (!(grstctl & S3C_GRSTCTL_AHBIdle))
- continue;
+ /* Be in disconnected state until gadget is registered */
+ __orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
- break; /* reset done */
+ if (0) {
+ /* post global nak until we're ready */
+ writel(DCTL_SGNPInNAK | DCTL_SGOUTNak,
+ hsotg->regs + DCTL);
}
- dev_dbg(hsotg->dev, "reset successful\n");
- return 0;
+ /* setup fifos */
+
+ dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+ readl(hsotg->regs + GRXFSIZ),
+ readl(hsotg->regs + GNPTXFSIZ));
+
+ s3c_hsotg_init_fifo(hsotg);
+
+ /* set the PLL on, remove the HNP/SRP and set the PHY */
+ writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10),
+ hsotg->regs + GUSBCFG);
+
+ writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0,
+ hsotg->regs + GAHBCFG);
}
-static int s3c_hsotg_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+/**
+ * s3c_hsotg_udc_start - prepare the udc for work
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Perform initialization to prepare udc device and driver
+ * to work.
+ */
+static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct s3c_hsotg *hsotg = our_hsotg;
+ struct s3c_hsotg *hsotg = to_hsotg(gadget);
int ret;
if (!hsotg) {
@@ -2592,7 +2944,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
if (driver->max_speed < USB_SPEED_FULL)
dev_err(hsotg->dev, "%s: bad speed\n", __func__);
- if (!bind || !driver->setup) {
+ if (!driver->setup) {
dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
return -EINVAL;
}
@@ -2605,135 +2957,17 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
- ret = device_add(&hsotg->gadget.dev);
+ ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
if (ret) {
- dev_err(hsotg->dev, "failed to register gadget device\n");
+ dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
goto err;
}
- ret = bind(&hsotg->gadget);
- if (ret) {
- dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name);
-
- hsotg->gadget.dev.driver = NULL;
- hsotg->driver = NULL;
- goto err;
- }
-
- /* we must now enable ep0 ready for host detection and then
- * set configuration. */
-
- s3c_hsotg_corereset(hsotg);
-
- /* set the PLL on, remove the HNP/SRP and set the PHY */
- writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) |
- (0x5 << 10), hsotg->regs + S3C_GUSBCFG);
-
- /* looks like soft-reset changes state of FIFOs */
- s3c_hsotg_init_fifo(hsotg);
-
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG);
-
- /* Clear any pending OTG interrupts */
- writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
-
- /* Clear any pending interrupts */
- writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
-
- writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
- S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
- S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
- S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt |
- S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff |
- S3C_GINTSTS_ErlySusp,
- hsotg->regs + S3C_GINTMSK);
-
- if (using_dma(hsotg))
- writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn |
- S3C_GAHBCFG_HBstLen_Incr4,
- hsotg->regs + S3C_GAHBCFG);
- else
- writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG);
-
- /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
- * up being flooded with interrupts if the host is polling the
- * endpoint to try and read data. */
-
- writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
- S3C_DIEPMSK_INTknEPMisMsk |
- S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk |
- ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0),
- hsotg->regs + S3C_DIEPMSK);
-
- /* don't need XferCompl, we get that from RXFIFO in slave mode. In
- * DMA mode we may need this. */
- writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
- S3C_DOEPMSK_EPDisbldMsk |
- (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
- S3C_DIEPMSK_TimeOUTMsk) : 0),
- hsotg->regs + S3C_DOEPMSK);
-
- writel(0, hsotg->regs + S3C_DAINTMSK);
-
- dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
-
- /* enable in and out endpoint interrupts */
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt);
-
- /* Enable the RXFIFO when in slave mode, as this is how we collect
- * the data. In DMA mode, we get events from the FIFO but also
- * things we cannot process, so do not use it. */
- if (!using_dma(hsotg))
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl);
-
- /* Enable interrupts for EP0 in and out */
- s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
- s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
-
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
- udelay(10); /* see openiboot */
- __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
-
- dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
-
- /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by
- writing to the EPCTL register.. */
-
- /* set to read 1 8byte packet */
- writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
- S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
-
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
- S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna |
- S3C_DxEPCTL_USBActEp,
- hsotg->regs + S3C_DOEPCTL0);
-
- /* enable, but don't activate EP0in */
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
- S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0);
-
- s3c_hsotg_enqueue_setup(hsotg);
-
- dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
-
- /* clear global NAKs */
- writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
- hsotg->regs + S3C_DCTL);
-
- /* must be at-least 3ms to allow bus to see disconnect */
- msleep(3);
-
- /* remove the soft-disconnect and let's go */
- __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- /* report to the user, and return */
+ s3c_hsotg_phy_enable(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ hsotg->last_rst = jiffies;
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
return 0;
@@ -2743,9 +2977,17 @@ err:
return ret;
}
-static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
+/**
+ * s3c_hsotg_udc_stop - stop the udc
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Stop udc hw block and stay tunned for future transmissions
+ */
+static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct s3c_hsotg *hsotg = our_hsotg;
+ struct s3c_hsotg *hsotg = to_hsotg(gadget);
int ep;
if (!hsotg)
@@ -2755,16 +2997,15 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
return -EINVAL;
/* all endpoints should be shutdown */
- for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+ for (ep = 0; ep < hsotg->num_of_eps; ep++)
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
- call_gadget(hsotg, disconnect);
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
- driver->unbind(&hsotg->gadget);
hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
-
- device_del(&hsotg->gadget.dev);
+ hsotg->gadget.dev.driver = NULL;
dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
driver->driver.name);
@@ -2772,6 +3013,12 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
return 0;
}
+/**
+ * s3c_hsotg_gadget_getframe - read the frame number
+ * @gadget: The usb gadget state
+ *
+ * Read the {micro} frame number
+ */
static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
{
return s3c_hsotg_read_frameno(to_hsotg(gadget));
@@ -2779,8 +3026,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
.get_frame = s3c_hsotg_gadget_getframe,
- .start = s3c_hsotg_start,
- .stop = s3c_hsotg_stop,
+ .udc_start = s3c_hsotg_udc_start,
+ .udc_stop = s3c_hsotg_udc_stop,
};
/**
@@ -2827,111 +3074,42 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT;
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
- /* Read the FIFO size for the Periodic TX FIFO, even if we're
+ /*
+ * Read the FIFO size for the Periodic TX FIFO, even if we're
* an OUT endpoint, we may as well do this if in future the
* code is changed to make each endpoint's direction changeable.
*/
- ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum));
- hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
+ ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum));
+ hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
- /* if we're using dma, we need to set the next-endpoint pointer
+ /*
+ * if we're using dma, we need to set the next-endpoint pointer
* to be something valid.
*/
if (using_dma(hsotg)) {
- u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15);
- writel(next, hsotg->regs + S3C_DIEPCTL(epnum));
- writel(next, hsotg->regs + S3C_DOEPCTL(epnum));
+ u32 next = DxEPCTL_NextEp((epnum + 1) % 15);
+ writel(next, hsotg->regs + DIEPCTL(epnum));
+ writel(next, hsotg->regs + DOEPCTL(epnum));
}
}
/**
- * s3c_hsotg_otgreset - reset the OtG phy block
- * @hsotg: The host state.
+ * s3c_hsotg_hw_cfg - read HW configuration registers
+ * @param: The device state
*
- * Power up the phy, set the basic configuration and start the PHY.
+ * Read the USB core HW configuration registers
*/
-static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
-{
- struct clk *xusbxti;
- u32 pwr, osc;
-
- pwr = readl(S3C_PHYPWR);
- pwr &= ~0x19;
- writel(pwr, S3C_PHYPWR);
- mdelay(1);
-
- osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0;
-
- xusbxti = clk_get(hsotg->dev, "xusbxti");
- if (xusbxti && !IS_ERR(xusbxti)) {
- switch (clk_get_rate(xusbxti)) {
- case 12*MHZ:
- osc |= S3C_PHYCLK_CLKSEL_12M;
- break;
- case 24*MHZ:
- osc |= S3C_PHYCLK_CLKSEL_24M;
- break;
- default:
- case 48*MHZ:
- /* default reference clock */
- break;
- }
- clk_put(xusbxti);
- }
-
- writel(osc | 0x10, S3C_PHYCLK);
-
- /* issue a full set of resets to the otg and core */
-
- writel(S3C_RSTCON_PHY, S3C_RSTCON);
- udelay(20); /* at-least 10uS */
- writel(0, S3C_RSTCON);
-}
-
-
-static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
{
- u32 cfg4;
-
- /* unmask subset of endpoint interrupts */
-
- writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
- S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
- hsotg->regs + S3C_DIEPMSK);
-
- writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
- S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk,
- hsotg->regs + S3C_DOEPMSK);
-
- writel(0, hsotg->regs + S3C_DAINTMSK);
-
- /* Be in disconnected state until gadget is registered */
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- if (0) {
- /* post global nak until we're ready */
- writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,
- hsotg->regs + S3C_DCTL);
- }
-
- /* setup fifos */
-
- dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
- readl(hsotg->regs + S3C_GRXFSIZ),
- readl(hsotg->regs + S3C_GNPTXFSIZ));
-
- s3c_hsotg_init_fifo(hsotg);
-
- /* set the PLL on, remove the HNP/SRP and set the PHY */
- writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10),
- hsotg->regs + S3C_GUSBCFG);
+ u32 cfg2, cfg4;
+ /* check hardware configuration */
- writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
- hsotg->regs + S3C_GAHBCFG);
+ cfg2 = readl(hsotg->regs + 0x48);
+ hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
- /* check hardware configuration */
+ dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps);
cfg4 = readl(hsotg->regs + 0x50);
hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
@@ -2940,6 +3118,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
hsotg->dedicated_fifos ? "dedicated" : "shared");
}
+/**
+ * s3c_hsotg_dump - dump state of the udc
+ * @param: The device state
+ */
static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
{
#ifdef DEBUG
@@ -2949,46 +3131,45 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
int idx;
dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
- readl(regs + S3C_DCFG), readl(regs + S3C_DCTL),
- readl(regs + S3C_DIEPMSK));
+ readl(regs + DCFG), readl(regs + DCTL),
+ readl(regs + DIEPMSK));
dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
- readl(regs + S3C_GAHBCFG), readl(regs + 0x44));
+ readl(regs + GAHBCFG), readl(regs + 0x44));
dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
- readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ));
+ readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
/* show periodic fifo settings */
for (idx = 1; idx <= 15; idx++) {
- val = readl(regs + S3C_DPTXFSIZn(idx));
+ val = readl(regs + DPTXFSIZn(idx));
dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
- val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
- val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+ val >> DPTXFSIZn_DPTxFSize_SHIFT,
+ val & DPTXFSIZn_DPTxFStAddr_MASK);
}
for (idx = 0; idx < 15; idx++) {
dev_info(dev,
"ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
- readl(regs + S3C_DIEPCTL(idx)),
- readl(regs + S3C_DIEPTSIZ(idx)),
- readl(regs + S3C_DIEPDMA(idx)));
+ readl(regs + DIEPCTL(idx)),
+ readl(regs + DIEPTSIZ(idx)),
+ readl(regs + DIEPDMA(idx)));
- val = readl(regs + S3C_DOEPCTL(idx));
+ val = readl(regs + DOEPCTL(idx));
dev_info(dev,
"ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
- idx, readl(regs + S3C_DOEPCTL(idx)),
- readl(regs + S3C_DOEPTSIZ(idx)),
- readl(regs + S3C_DOEPDMA(idx)));
+ idx, readl(regs + DOEPCTL(idx)),
+ readl(regs + DOEPTSIZ(idx)),
+ readl(regs + DOEPDMA(idx)));
}
dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
- readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE));
+ readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE));
#endif
}
-
/**
* state_show - debugfs: show overall driver and device state.
* @seq: The seq file to write to.
@@ -3005,38 +3186,38 @@ static int state_show(struct seq_file *seq, void *v)
int idx;
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
- readl(regs + S3C_DCFG),
- readl(regs + S3C_DCTL),
- readl(regs + S3C_DSTS));
+ readl(regs + DCFG),
+ readl(regs + DCTL),
+ readl(regs + DSTS));
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
- readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK));
+ readl(regs + DIEPMSK), readl(regs + DOEPMSK));
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
- readl(regs + S3C_GINTMSK),
- readl(regs + S3C_GINTSTS));
+ readl(regs + GINTMSK),
+ readl(regs + GINTSTS));
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
- readl(regs + S3C_DAINTMSK),
- readl(regs + S3C_DAINT));
+ readl(regs + DAINTMSK),
+ readl(regs + DAINT));
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
- readl(regs + S3C_GNPTXSTS),
- readl(regs + S3C_GRXSTSR));
+ readl(regs + GNPTXSTS),
+ readl(regs + GRXSTSR));
seq_printf(seq, "\nEndpoint status:\n");
for (idx = 0; idx < 15; idx++) {
u32 in, out;
- in = readl(regs + S3C_DIEPCTL(idx));
- out = readl(regs + S3C_DOEPCTL(idx));
+ in = readl(regs + DIEPCTL(idx));
+ out = readl(regs + DOEPCTL(idx));
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
idx, in, out);
- in = readl(regs + S3C_DIEPTSIZ(idx));
- out = readl(regs + S3C_DOEPTSIZ(idx));
+ in = readl(regs + DIEPTSIZ(idx));
+ out = readl(regs + DOEPTSIZ(idx));
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
in, out);
@@ -3067,7 +3248,7 @@ static const struct file_operations state_fops = {
*
* Show the FIFO information for the overall fifo and all the
* periodic transmission FIFOs.
-*/
+ */
static int fifo_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg *hsotg = seq->private;
@@ -3076,21 +3257,21 @@ static int fifo_show(struct seq_file *seq, void *v)
int idx;
seq_printf(seq, "Non-periodic FIFOs:\n");
- seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ));
+ seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
- val = readl(regs + S3C_GNPTXFSIZ);
+ val = readl(regs + GNPTXFSIZ);
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
- val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT,
- val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK);
+ val >> GNPTXFSIZ_NPTxFDep_SHIFT,
+ val & GNPTXFSIZ_NPTxFStAddr_MASK);
seq_printf(seq, "\nPeriodic TXFIFOs:\n");
for (idx = 1; idx <= 15; idx++) {
- val = readl(regs + S3C_DPTXFSIZn(idx));
+ val = readl(regs + DPTXFSIZn(idx));
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
- val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
- val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+ val >> DPTXFSIZn_DPTxFSize_SHIFT,
+ val & DPTXFSIZn_DPTxFStAddr_MASK);
}
return 0;
@@ -3122,7 +3303,7 @@ static const char *decode_direction(int is_in)
*
* This debugfs entry shows the state of the given endpoint (one is
* registered for each available).
-*/
+ */
static int ep_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg_ep *ep = seq->private;
@@ -3139,20 +3320,20 @@ static int ep_show(struct seq_file *seq, void *v)
/* first show the register state */
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
- readl(regs + S3C_DIEPCTL(index)),
- readl(regs + S3C_DOEPCTL(index)));
+ readl(regs + DIEPCTL(index)),
+ readl(regs + DOEPCTL(index)));
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
- readl(regs + S3C_DIEPDMA(index)),
- readl(regs + S3C_DOEPDMA(index)));
+ readl(regs + DIEPDMA(index)),
+ readl(regs + DOEPDMA(index)));
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
- readl(regs + S3C_DIEPINT(index)),
- readl(regs + S3C_DOEPINT(index)));
+ readl(regs + DIEPINT(index)),
+ readl(regs + DOEPINT(index)));
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
- readl(regs + S3C_DIEPTSIZ(index)),
- readl(regs + S3C_DOEPTSIZ(index)));
+ readl(regs + DIEPTSIZ(index)),
+ readl(regs + DOEPTSIZ(index)));
seq_printf(seq, "\n");
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
@@ -3202,7 +3383,7 @@ static const struct file_operations ep_fops = {
* about the state of the system. The directory name is created
* with the same name as the device itself, in case we end up
* with multiple blocks in future systems.
-*/
+ */
static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
{
struct dentry *root;
@@ -3231,7 +3412,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
/* create one file for each endpoint */
- for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+ for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
ep->debugfs = debugfs_create_file(ep->name, 0444,
@@ -3248,12 +3429,12 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
* @hsotg: The driver state
*
* Cleanup (remove) the debugfs files for use on module exit.
-*/
+ */
static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
{
unsigned epidx;
- for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+ for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
debugfs_remove(ep->debugfs);
}
@@ -3264,48 +3445,39 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
}
/**
- * s3c_hsotg_gate - set the hardware gate for the block
- * @pdev: The device we bound to
- * @on: On or off.
- *
- * Set the hardware gate setting into the block. If we end up on
- * something other than an S3C64XX, then we might need to change this
- * to using a platform data callback, or some other mechanism.
+ * s3c_hsotg_release - release callback for hsotg device
+ * @dev: Device to for which release is called
*/
-static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
+static void s3c_hsotg_release(struct device *dev)
{
- unsigned long flags;
- u32 others;
-
- local_irq_save(flags);
-
- others = __raw_readl(S3C64XX_OTHERS);
- if (on)
- others |= S3C64XX_OTHERS_USBMASK;
- else
- others &= ~S3C64XX_OTHERS_USBMASK;
- __raw_writel(others, S3C64XX_OTHERS);
+ struct s3c_hsotg *hsotg = dev_get_drvdata(dev);
- local_irq_restore(flags);
+ kfree(hsotg);
}
-static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+/**
+ * s3c_hsotg_probe - probe function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
{
struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
+ struct s3c_hsotg_ep *eps;
struct s3c_hsotg *hsotg;
struct resource *res;
int epnum;
int ret;
+ int i;
- if (!plat)
- plat = &s3c_hsotg_default_pdata;
+ plat = pdev->dev.platform_data;
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
- hsotg = kzalloc(sizeof(struct s3c_hsotg) +
- sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS,
- GFP_KERNEL);
+ hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL);
if (!hsotg) {
dev_err(dev, "cannot get memory\n");
return -ENOMEM;
@@ -3371,6 +3543,54 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
hsotg->gadget.dev.parent = dev;
hsotg->gadget.dev.dma_mask = dev->dma_mask;
+ hsotg->gadget.dev.release = s3c_hsotg_release;
+
+ /* reset the system */
+
+ clk_prepare_enable(hsotg->clk);
+
+ /* regulators */
+
+ for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
+ hsotg->supplies[i].supply = s3c_hsotg_supply_names[i];
+
+ ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ if (ret) {
+ dev_err(dev, "failed to request supplies: %d\n", ret);
+ goto err_irq;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+
+ if (ret) {
+ dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
+ goto err_supplies;
+ }
+
+ /* usb phy enable */
+ s3c_hsotg_phy_enable(hsotg);
+
+ s3c_hsotg_corereset(hsotg);
+ s3c_hsotg_init(hsotg);
+ s3c_hsotg_hw_cfg(hsotg);
+
+ /* hsotg->num_of_eps holds number of EPs other than ep0 */
+
+ if (hsotg->num_of_eps == 0) {
+ dev_err(dev, "wrong number of EPs (zero)\n");
+ goto err_supplies;
+ }
+
+ eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep),
+ GFP_KERNEL);
+ if (!eps) {
+ dev_err(dev, "cannot get memory\n");
+ goto err_supplies;
+ }
+
+ hsotg->eps = eps;
/* setup endpoint information */
@@ -3383,39 +3603,47 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!hsotg->ctrl_req) {
dev_err(dev, "failed to allocate ctrl req\n");
- goto err_regs;
+ goto err_ep_mem;
}
- /* reset the system */
+ /* initialise the endpoints now the core has been initialised */
+ for (epnum = 0; epnum < hsotg->num_of_eps; epnum++)
+ s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
- clk_enable(hsotg->clk);
+ /* disable power and clock */
- s3c_hsotg_gate(pdev, true);
+ ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ if (ret) {
+ dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret);
+ goto err_ep_mem;
+ }
- s3c_hsotg_otgreset(hsotg);
- s3c_hsotg_corereset(hsotg);
- s3c_hsotg_init(hsotg);
+ s3c_hsotg_phy_disable(hsotg);
- /* initialise the endpoints now the core has been initialised */
- for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
- s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+ ret = device_add(&hsotg->gadget.dev);
+ if (ret) {
+ put_device(&hsotg->gadget.dev);
+ goto err_ep_mem;
+ }
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
- goto err_add_udc;
+ goto err_ep_mem;
s3c_hsotg_create_debug(hsotg);
s3c_hsotg_dump(hsotg);
- our_hsotg = hsotg;
return 0;
-err_add_udc:
- s3c_hsotg_gate(pdev, false);
- clk_disable(hsotg->clk);
- clk_put(hsotg->clk);
-
+err_ep_mem:
+ kfree(eps);
+err_supplies:
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+err_irq:
+ free_irq(hsotg->irq, hsotg);
err_regs:
iounmap(hsotg->regs);
@@ -3423,12 +3651,17 @@ err_regs_res:
release_resource(hsotg->regs_res);
kfree(hsotg->regs_res);
err_clk:
+ clk_disable_unprepare(hsotg->clk);
clk_put(hsotg->clk);
err_mem:
kfree(hsotg);
return ret;
}
+/**
+ * s3c_hsotg_remove - remove function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
{
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
@@ -3437,7 +3670,10 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
s3c_hsotg_delete_debug(hsotg);
- usb_gadget_unregister_driver(hsotg->driver);
+ if (hsotg->driver) {
+ /* should have been done already by driver model core */
+ usb_gadget_unregister_driver(hsotg->driver);
+ }
free_irq(hsotg->irq, hsotg);
iounmap(hsotg->regs);
@@ -3445,12 +3681,13 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
release_resource(hsotg->regs_res);
kfree(hsotg->regs_res);
- s3c_hsotg_gate(pdev, false);
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
- clk_disable(hsotg->clk);
+ clk_disable_unprepare(hsotg->clk);
clk_put(hsotg->clk);
- kfree(hsotg);
+ device_unregister(&hsotg->gadget.dev);
return 0;
}
diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h
new file mode 100644
index 0000000..d650b12
--- /dev/null
+++ b/drivers/usb/gadget/s3c-hsotg.h
@@ -0,0 +1,377 @@
+/* drivers/usb/gadget/s3c-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers
+ *
+ * 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.
+*/
+
+#ifndef __REGS_USB_HSOTG_H
+#define __REGS_USB_HSOTG_H __FILE__
+
+#define HSOTG_REG(x) (x)
+
+#define GOTGCTL HSOTG_REG(0x000)
+#define GOTGCTL_BSESVLD (1 << 19)
+#define GOTGCTL_ASESVLD (1 << 18)
+#define GOTGCTL_DBNC_SHORT (1 << 17)
+#define GOTGCTL_CONID_B (1 << 16)
+#define GOTGCTL_DEVHNPEN (1 << 11)
+#define GOTGCTL_HSSETHNPEN (1 << 10)
+#define GOTGCTL_HNPREQ (1 << 9)
+#define GOTGCTL_HSTNEGSCS (1 << 8)
+#define GOTGCTL_SESREQ (1 << 1)
+#define GOTGCTL_SESREQSCS (1 << 0)
+
+#define GOTGINT HSOTG_REG(0x004)
+#define GOTGINT_DbnceDone (1 << 19)
+#define GOTGINT_ADevTOUTChg (1 << 18)
+#define GOTGINT_HstNegDet (1 << 17)
+#define GOTGINT_HstnegSucStsChng (1 << 9)
+#define GOTGINT_SesReqSucStsChng (1 << 8)
+#define GOTGINT_SesEndDet (1 << 2)
+
+#define GAHBCFG HSOTG_REG(0x008)
+#define GAHBCFG_PTxFEmpLvl (1 << 8)
+#define GAHBCFG_NPTxFEmpLvl (1 << 7)
+#define GAHBCFG_DMAEn (1 << 5)
+#define GAHBCFG_HBstLen_MASK (0xf << 1)
+#define GAHBCFG_HBstLen_SHIFT (1)
+#define GAHBCFG_HBstLen_Single (0x0 << 1)
+#define GAHBCFG_HBstLen_Incr (0x1 << 1)
+#define GAHBCFG_HBstLen_Incr4 (0x3 << 1)
+#define GAHBCFG_HBstLen_Incr8 (0x5 << 1)
+#define GAHBCFG_HBstLen_Incr16 (0x7 << 1)
+#define GAHBCFG_GlblIntrEn (1 << 0)
+
+#define GUSBCFG HSOTG_REG(0x00C)
+#define GUSBCFG_PHYLPClkSel (1 << 15)
+#define GUSBCFG_HNPCap (1 << 9)
+#define GUSBCFG_SRPCap (1 << 8)
+#define GUSBCFG_PHYIf16 (1 << 3)
+#define GUSBCFG_TOutCal_MASK (0x7 << 0)
+#define GUSBCFG_TOutCal_SHIFT (0)
+#define GUSBCFG_TOutCal_LIMIT (0x7)
+#define GUSBCFG_TOutCal(_x) ((_x) << 0)
+
+#define GRSTCTL HSOTG_REG(0x010)
+
+#define GRSTCTL_AHBIdle (1 << 31)
+#define GRSTCTL_DMAReq (1 << 30)
+#define GRSTCTL_TxFNum_MASK (0x1f << 6)
+#define GRSTCTL_TxFNum_SHIFT (6)
+#define GRSTCTL_TxFNum_LIMIT (0x1f)
+#define GRSTCTL_TxFNum(_x) ((_x) << 6)
+#define GRSTCTL_TxFFlsh (1 << 5)
+#define GRSTCTL_RxFFlsh (1 << 4)
+#define GRSTCTL_INTknQFlsh (1 << 3)
+#define GRSTCTL_FrmCntrRst (1 << 2)
+#define GRSTCTL_HSftRst (1 << 1)
+#define GRSTCTL_CSftRst (1 << 0)
+
+#define GINTSTS HSOTG_REG(0x014)
+#define GINTMSK HSOTG_REG(0x018)
+
+#define GINTSTS_WkUpInt (1 << 31)
+#define GINTSTS_SessReqInt (1 << 30)
+#define GINTSTS_DisconnInt (1 << 29)
+#define GINTSTS_ConIDStsChng (1 << 28)
+#define GINTSTS_PTxFEmp (1 << 26)
+#define GINTSTS_HChInt (1 << 25)
+#define GINTSTS_PrtInt (1 << 24)
+#define GINTSTS_FetSusp (1 << 22)
+#define GINTSTS_incompIP (1 << 21)
+#define GINTSTS_IncomplSOIN (1 << 20)
+#define GINTSTS_OEPInt (1 << 19)
+#define GINTSTS_IEPInt (1 << 18)
+#define GINTSTS_EPMis (1 << 17)
+#define GINTSTS_EOPF (1 << 15)
+#define GINTSTS_ISOutDrop (1 << 14)
+#define GINTSTS_EnumDone (1 << 13)
+#define GINTSTS_USBRst (1 << 12)
+#define GINTSTS_USBSusp (1 << 11)
+#define GINTSTS_ErlySusp (1 << 10)
+#define GINTSTS_GOUTNakEff (1 << 7)
+#define GINTSTS_GINNakEff (1 << 6)
+#define GINTSTS_NPTxFEmp (1 << 5)
+#define GINTSTS_RxFLvl (1 << 4)
+#define GINTSTS_SOF (1 << 3)
+#define GINTSTS_OTGInt (1 << 2)
+#define GINTSTS_ModeMis (1 << 1)
+#define GINTSTS_CurMod_Host (1 << 0)
+
+#define GRXSTSR HSOTG_REG(0x01C)
+#define GRXSTSP HSOTG_REG(0x020)
+
+#define GRXSTS_FN_MASK (0x7f << 25)
+#define GRXSTS_FN_SHIFT (25)
+
+#define GRXSTS_PktSts_MASK (0xf << 17)
+#define GRXSTS_PktSts_SHIFT (17)
+#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17)
+#define GRXSTS_PktSts_OutRX (0x2 << 17)
+#define GRXSTS_PktSts_OutDone (0x3 << 17)
+#define GRXSTS_PktSts_SetupDone (0x4 << 17)
+#define GRXSTS_PktSts_SetupRX (0x6 << 17)
+
+#define GRXSTS_DPID_MASK (0x3 << 15)
+#define GRXSTS_DPID_SHIFT (15)
+#define GRXSTS_ByteCnt_MASK (0x7ff << 4)
+#define GRXSTS_ByteCnt_SHIFT (4)
+#define GRXSTS_EPNum_MASK (0xf << 0)
+#define GRXSTS_EPNum_SHIFT (0)
+
+#define GRXFSIZ HSOTG_REG(0x024)
+
+#define GNPTXFSIZ HSOTG_REG(0x028)
+
+#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16)
+#define GNPTXFSIZ_NPTxFDep_SHIFT (16)
+#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff)
+#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16)
+#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0)
+#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0)
+#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff)
+#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0)
+
+#define GNPTXSTS HSOTG_REG(0x02C)
+
+#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24)
+#define GNPTXSTS_NPtxQTop_SHIFT (24)
+
+#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16)
+#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16)
+#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff)
+
+#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0)
+#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0)
+#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff)
+
+
+#define HPTXFSIZ HSOTG_REG(0x100)
+
+#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
+
+#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16)
+#define DPTXFSIZn_DPTxFSize_SHIFT (16)
+#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff)
+#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff)
+#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16)
+
+#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0)
+#define DPTXFSIZn_DPTxFStAddr_SHIFT (0)
+
+/* Device mode registers */
+#define DCFG HSOTG_REG(0x800)
+
+#define DCFG_EPMisCnt_MASK (0x1f << 18)
+#define DCFG_EPMisCnt_SHIFT (18)
+#define DCFG_EPMisCnt_LIMIT (0x1f)
+#define DCFG_EPMisCnt(_x) ((_x) << 18)
+
+#define DCFG_PerFrInt_MASK (0x3 << 11)
+#define DCFG_PerFrInt_SHIFT (11)
+#define DCFG_PerFrInt_LIMIT (0x3)
+#define DCFG_PerFrInt(_x) ((_x) << 11)
+
+#define DCFG_DevAddr_MASK (0x7f << 4)
+#define DCFG_DevAddr_SHIFT (4)
+#define DCFG_DevAddr_LIMIT (0x7f)
+#define DCFG_DevAddr(_x) ((_x) << 4)
+
+#define DCFG_NZStsOUTHShk (1 << 2)
+
+#define DCFG_DevSpd_MASK (0x3 << 0)
+#define DCFG_DevSpd_SHIFT (0)
+#define DCFG_DevSpd_HS (0x0 << 0)
+#define DCFG_DevSpd_FS (0x1 << 0)
+#define DCFG_DevSpd_LS (0x2 << 0)
+#define DCFG_DevSpd_FS48 (0x3 << 0)
+
+#define DCTL HSOTG_REG(0x804)
+
+#define DCTL_PWROnPrgDone (1 << 11)
+#define DCTL_CGOUTNak (1 << 10)
+#define DCTL_SGOUTNak (1 << 9)
+#define DCTL_CGNPInNAK (1 << 8)
+#define DCTL_SGNPInNAK (1 << 7)
+#define DCTL_TstCtl_MASK (0x7 << 4)
+#define DCTL_TstCtl_SHIFT (4)
+#define DCTL_GOUTNakSts (1 << 3)
+#define DCTL_GNPINNakSts (1 << 2)
+#define DCTL_SftDiscon (1 << 1)
+#define DCTL_RmtWkUpSig (1 << 0)
+
+#define DSTS HSOTG_REG(0x808)
+
+#define DSTS_SOFFN_MASK (0x3fff << 8)
+#define DSTS_SOFFN_SHIFT (8)
+#define DSTS_SOFFN_LIMIT (0x3fff)
+#define DSTS_SOFFN(_x) ((_x) << 8)
+#define DSTS_ErraticErr (1 << 3)
+#define DSTS_EnumSpd_MASK (0x3 << 1)
+#define DSTS_EnumSpd_SHIFT (1)
+#define DSTS_EnumSpd_HS (0x0 << 1)
+#define DSTS_EnumSpd_FS (0x1 << 1)
+#define DSTS_EnumSpd_LS (0x2 << 1)
+#define DSTS_EnumSpd_FS48 (0x3 << 1)
+
+#define DSTS_SuspSts (1 << 0)
+
+#define DIEPMSK HSOTG_REG(0x810)
+
+#define DIEPMSK_TxFIFOEmpty (1 << 7)
+#define DIEPMSK_INEPNakEffMsk (1 << 6)
+#define DIEPMSK_INTknEPMisMsk (1 << 5)
+#define DIEPMSK_INTknTXFEmpMsk (1 << 4)
+#define DIEPMSK_TimeOUTMsk (1 << 3)
+#define DIEPMSK_AHBErrMsk (1 << 2)
+#define DIEPMSK_EPDisbldMsk (1 << 1)
+#define DIEPMSK_XferComplMsk (1 << 0)
+
+#define DOEPMSK HSOTG_REG(0x814)
+
+#define DOEPMSK_Back2BackSetup (1 << 6)
+#define DOEPMSK_OUTTknEPdisMsk (1 << 4)
+#define DOEPMSK_SetupMsk (1 << 3)
+#define DOEPMSK_AHBErrMsk (1 << 2)
+#define DOEPMSK_EPDisbldMsk (1 << 1)
+#define DOEPMSK_XferComplMsk (1 << 0)
+
+#define DAINT HSOTG_REG(0x818)
+#define DAINTMSK HSOTG_REG(0x81C)
+
+#define DAINT_OutEP_SHIFT (16)
+#define DAINT_OutEP(x) (1 << ((x) + 16))
+#define DAINT_InEP(x) (1 << (x))
+
+#define DTKNQR1 HSOTG_REG(0x820)
+#define DTKNQR2 HSOTG_REG(0x824)
+#define DTKNQR3 HSOTG_REG(0x830)
+#define DTKNQR4 HSOTG_REG(0x834)
+
+#define DVBUSDIS HSOTG_REG(0x828)
+#define DVBUSPULSE HSOTG_REG(0x82C)
+
+#define DIEPCTL0 HSOTG_REG(0x900)
+#define DOEPCTL0 HSOTG_REG(0xB00)
+#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20))
+#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting differenct for EP0
+ */
+#define D0EPCTL_MPS_MASK (0x3 << 0)
+#define D0EPCTL_MPS_SHIFT (0)
+#define D0EPCTL_MPS_64 (0x0 << 0)
+#define D0EPCTL_MPS_32 (0x1 << 0)
+#define D0EPCTL_MPS_16 (0x2 << 0)
+#define D0EPCTL_MPS_8 (0x3 << 0)
+
+#define DxEPCTL_EPEna (1 << 31)
+#define DxEPCTL_EPDis (1 << 30)
+#define DxEPCTL_SetD1PID (1 << 29)
+#define DxEPCTL_SetOddFr (1 << 29)
+#define DxEPCTL_SetD0PID (1 << 28)
+#define DxEPCTL_SetEvenFr (1 << 28)
+#define DxEPCTL_SNAK (1 << 27)
+#define DxEPCTL_CNAK (1 << 26)
+#define DxEPCTL_TxFNum_MASK (0xf << 22)
+#define DxEPCTL_TxFNum_SHIFT (22)
+#define DxEPCTL_TxFNum_LIMIT (0xf)
+#define DxEPCTL_TxFNum(_x) ((_x) << 22)
+
+#define DxEPCTL_Stall (1 << 21)
+#define DxEPCTL_Snp (1 << 20)
+#define DxEPCTL_EPType_MASK (0x3 << 18)
+#define DxEPCTL_EPType_SHIFT (18)
+#define DxEPCTL_EPType_Control (0x0 << 18)
+#define DxEPCTL_EPType_Iso (0x1 << 18)
+#define DxEPCTL_EPType_Bulk (0x2 << 18)
+#define DxEPCTL_EPType_Intterupt (0x3 << 18)
+
+#define DxEPCTL_NAKsts (1 << 17)
+#define DxEPCTL_DPID (1 << 16)
+#define DxEPCTL_EOFrNum (1 << 16)
+#define DxEPCTL_USBActEp (1 << 15)
+#define DxEPCTL_NextEp_MASK (0xf << 11)
+#define DxEPCTL_NextEp_SHIFT (11)
+#define DxEPCTL_NextEp_LIMIT (0xf)
+#define DxEPCTL_NextEp(_x) ((_x) << 11)
+
+#define DxEPCTL_MPS_MASK (0x7ff << 0)
+#define DxEPCTL_MPS_SHIFT (0)
+#define DxEPCTL_MPS_LIMIT (0x7ff)
+#define DxEPCTL_MPS(_x) ((_x) << 0)
+
+#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
+
+#define DxEPINT_INEPNakEff (1 << 6)
+#define DxEPINT_Back2BackSetup (1 << 6)
+#define DxEPINT_INTknEPMis (1 << 5)
+#define DxEPINT_INTknTXFEmp (1 << 4)
+#define DxEPINT_OUTTknEPdis (1 << 4)
+#define DxEPINT_Timeout (1 << 3)
+#define DxEPINT_Setup (1 << 3)
+#define DxEPINT_AHBErr (1 << 2)
+#define DxEPINT_EPDisbld (1 << 1)
+#define DxEPINT_XferCompl (1 << 0)
+
+#define DIEPTSIZ0 HSOTG_REG(0x910)
+
+#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19)
+#define DIEPTSIZ0_PktCnt_SHIFT (19)
+#define DIEPTSIZ0_PktCnt_LIMIT (0x3)
+#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19)
+
+#define DIEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define DIEPTSIZ0_XferSize_SHIFT (0)
+#define DIEPTSIZ0_XferSize_LIMIT (0x7f)
+#define DIEPTSIZ0_XferSize(_x) ((_x) << 0)
+
+#define DOEPTSIZ0 HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29)
+#define DOEPTSIZ0_SUPCnt_SHIFT (29)
+#define DOEPTSIZ0_SUPCnt_LIMIT (0x3)
+#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29)
+
+#define DOEPTSIZ0_PktCnt (1 << 19)
+#define DOEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define DOEPTSIZ0_XferSize_SHIFT (0)
+
+#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
+
+#define DxEPTSIZ_MC_MASK (0x3 << 29)
+#define DxEPTSIZ_MC_SHIFT (29)
+#define DxEPTSIZ_MC_LIMIT (0x3)
+#define DxEPTSIZ_MC(_x) ((_x) << 29)
+
+#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19)
+#define DxEPTSIZ_PktCnt_SHIFT (19)
+#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff)
+#define DxEPTSIZ_PktCnt_LIMIT (0x3ff)
+#define DxEPTSIZ_PktCnt(_x) ((_x) << 19)
+
+#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0)
+#define DxEPTSIZ_XferSize_SHIFT (0)
+#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff)
+#define DxEPTSIZ_XferSize_LIMIT (0x7ffff)
+#define DxEPTSIZ_XferSize(_x) ((_x) << 0)
+
+#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20))
+#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+#endif /* __REGS_USB_HSOTG_H */
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index cef9b82..36c6836 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -110,7 +110,6 @@ struct s3c_hsudc_ep {
struct usb_ep ep;
char name[20];
struct s3c_hsudc *dev;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
u8 stopped;
u8 wedge;
@@ -761,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
u32 ecr = 0;
hsep = our_ep(_ep);
- if (!_ep || !desc || hsep->desc || _ep->name == ep0name
+ if (!_ep || !desc || hsep->ep.desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| hsep->bEndpointAddress != desc->bEndpointAddress
|| ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
@@ -783,7 +782,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
writel(ecr, hsudc->regs + S3C_ECR);
hsep->stopped = hsep->wedge = 0;
- hsep->desc = desc;
+ hsep->ep.desc = desc;
hsep->ep.maxpacket = usb_endpoint_maxp(desc);
s3c_hsudc_set_halt(_ep, 0);
@@ -806,7 +805,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
struct s3c_hsudc *hsudc = hsep->dev;
unsigned long flags;
- if (!_ep || !hsep->desc)
+ if (!_ep || !hsep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&hsudc->lock, flags);
@@ -816,7 +815,6 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
- hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 1;
@@ -1006,7 +1004,6 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
hsep->ep.maxpacket = epnum ? 512 : 64;
hsep->ep.ops = &s3c_hsudc_ep_ops;
hsep->fifo = hsudc->regs + S3C_BR(epnum);
- hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 0;
hsep->wedge = 0;
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 195524c..3de71d3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1062,7 +1062,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
ep = to_s3c2410_ep(_ep);
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
@@ -1075,7 +1075,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
local_irq_save (flags);
_ep->maxpacket = max & 0x7ff;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
ep->bEndpointAddress = desc->bEndpointAddress;
@@ -1136,7 +1136,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
unsigned long flags;
u32 int_en_reg;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
dprintk(DEBUG_NORMAL, "%s not enabled\n",
_ep ? ep->ep.name : NULL);
return -EINVAL;
@@ -1146,7 +1146,6 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 1;
@@ -1195,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
- if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+ if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name))
return;
WARN_ON (!list_empty (&req->queue));
@@ -1215,7 +1214,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
int fifo_count = 0;
unsigned long flags;
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
return -EINVAL;
}
@@ -1363,7 +1362,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
unsigned long flags;
u32 idx;
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
return -EINVAL;
}
@@ -1629,7 +1628,6 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
ep->dev = dev;
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 0;
INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
index 1653bae..3e80fd5 100644
--- a/drivers/usb/gadget/s3c2410_udc.h
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -19,7 +19,6 @@ struct s3c2410_ep {
unsigned long last_io; /* jiffies timestamp */
struct usb_gadget *gadget;
struct s3c2410_udc *dev;
- const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
u8 num;
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
new file mode 100644
index 0000000..c46439c
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -0,0 +1,2480 @@
+/* Target based USB-Gadget
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "usbstring.c"
+#include "epautoconf.c"
+#include "config.c"
+#include "composite.c"
+
+#include "tcm_usb_gadget.h"
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+ return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+ kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+ int ret;
+
+ if (fu->flags & USBG_BOT_CMD_PEND)
+ return 0;
+
+ ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+ if (!ret)
+ fu->flags |= USBG_BOT_CMD_PEND;
+ return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ usbg_cleanup_cmd(cmd);
+ if (req->status < 0) {
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+ return;
+ }
+
+ /* CSW completed, wait for next CBW */
+ bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+ u8 *sense;
+ unsigned int csw_stat;
+
+ csw_stat = cmd->csw_code;
+
+ /*
+ * We can't send SENSE as a response. So we take ASC & ASCQ from our
+ * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+ * command where it learns why we failed.
+ */
+ sense = cmd->sense_iu.sense;
+
+ csw->Tag = cmd->bot_tag;
+ csw->Status = csw_stat;
+ fu->bot_status.req->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ if (cmd->data_len) {
+ if (cmd->data_len > ep->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ return ;
+ }
+ bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ struct usb_request *req;
+ struct usb_ep *ep;
+
+ csw->Residue = cpu_to_le32(cmd->data_len);
+
+ if (cmd->data_len) {
+ if (cmd->is_read) {
+ ep = fu->ep_in;
+ req = fu->bot_req_in;
+ } else {
+ ep = fu->ep_out;
+ req = fu->bot_req_out;
+ }
+
+ if (cmd->data_len > fu->ep_in->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+ req->complete = bot_err_compl;
+ req->context = cmd;
+ req->buf = fu->cmd.buf;
+ usb_ep_queue(ep, req, GFP_KERNEL);
+ } else {
+ bot_enqueue_sense_code(fu, cmd);
+ }
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+
+ if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+ if (!moved_data && cmd->data_len) {
+ /*
+ * the host wants to move data, we don't. Fill / empty
+ * the pipe and then send the csw with reside set.
+ */
+ cmd->csw_code = US_BULK_STAT_OK;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ csw->Tag = cmd->bot_tag;
+ csw->Residue = cpu_to_le32(0);
+ csw->Status = US_BULK_STAT_OK;
+ fu->bot_status.req->context = cmd;
+
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+ } else {
+ cmd->csw_code = US_BULK_STAT_FAIL;
+ bot_send_bad_status(cmd);
+ }
+ return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+ bool moved_data = false;
+
+ if (!cmd->is_read)
+ moved_data = true;
+ return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ fu->bot_req_in->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_in->buf = NULL;
+ fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_in->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_in->complete = bot_read_compl;
+ fu->bot_req_in->length = se_cmd->data_length;
+ fu->bot_req_in->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ return -EINVAL;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ fu->bot_req_out->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_out->buf = NULL;
+ fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_out->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_out->complete = usbg_data_write_cmpl;
+ fu->bot_req_out->length = se_cmd->data_length;
+ fu->bot_req_out->context = cmd;
+
+ ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ fu->flags &= ~USBG_BOT_CMD_PEND;
+
+ if (req->status < 0)
+ return;
+
+ ret = bot_submit_command(fu, req->buf, req->actual);
+ if (ret)
+ pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+
+ fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_req_in)
+ goto err;
+
+ fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->bot_req_out)
+ goto err_out;
+
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err_cmd;
+
+ fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_status.req)
+ goto err_sts;
+
+ fu->bot_status.req->buf = &fu->bot_status.csw;
+ fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+ fu->bot_status.req->complete = bot_status_complete;
+ fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+ fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = bot_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_out->maxpacket;
+ fu->cmd.req->context = fu;
+
+ ret = bot_enqueue_cmd_cbw(fu);
+ if (ret)
+ goto err_queue;
+ return 0;
+err_queue:
+ kfree(fu->cmd.buf);
+ fu->cmd.buf = NULL;
+err_buf:
+ usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ fu->cmd.req = NULL;
+err_cmd:
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ fu->bot_req_out = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ fu->bot_req_in = NULL;
+err:
+ pr_err("BOT: endpoint setup failed\n");
+ return -ENOMEM;
+}
+
+void bot_cleanup_old_alt(struct f_uas *fu)
+{
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+
+ if (!fu->bot_req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+ kfree(fu->cmd.buf);
+
+ fu->bot_req_in = NULL;
+ fu->bot_req_out = NULL;
+ fu->cmd.req = NULL;
+ fu->bot_status.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_BOT;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ ret = bot_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+ pr_info("Using the BOT protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+ int luns;
+ u8 *ret_lun;
+
+ switch (ctrl->bRequest) {
+ case US_BULK_GET_MAX_LUN:
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ return -ENOTSUPP;
+
+ if (w_length < 1)
+ return -EINVAL;
+ if (w_value != 0)
+ return -EINVAL;
+ luns = atomic_read(&fu->tpg->tpg_port_count);
+ if (!luns) {
+ pr_err("No LUNs configured?\n");
+ return -EINVAL;
+ }
+ /*
+ * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+ * accessed. The upper limit is 0xf
+ */
+ luns--;
+ if (luns > 0xf) {
+ pr_info_once("Limiting the number of luns to 16\n");
+ luns = 0xf;
+ }
+ ret_lun = cdev->req->buf;
+ *ret_lun = luns;
+ cdev->req->length = 1;
+ return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ break;
+
+ case US_BULK_RESET_REQUEST:
+ /* XXX maybe we should remove previous requests for IN + OUT */
+ bot_enqueue_cmd_cbw(fu);
+ return 0;
+ break;
+ };
+ return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+ /* We have either all three allocated or none */
+ if (!stream->req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, stream->req_in);
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+
+ stream->req_in = NULL;
+ stream->req_out = NULL;
+ stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+ kfree(fu->cmd.buf);
+ fu->cmd.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+ int i;
+
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+ usb_ep_disable(fu->ep_status);
+ usb_ep_disable(fu->ep_cmd);
+
+ for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+ uasp_cleanup_one_stream(fu, &fu->stream[i]);
+ uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ struct uas_stream *stream = cmd->stream;
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ stream->req_in->buf = cmd->data_buf;
+ } else {
+ stream->req_in->buf = NULL;
+ stream->req_in->num_sgs = se_cmd->t_data_nents;
+ stream->req_in->sg = se_cmd->t_data_sg;
+ }
+
+ stream->req_in->complete = uasp_status_data_cmpl;
+ stream->req_in->length = se_cmd->data_length;
+ stream->req_in->context = cmd;
+
+ cmd->state = UASP_SEND_STATUS;
+ return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct sense_iu *iu = &cmd->sense_iu;
+ struct uas_stream *stream = cmd->stream;
+
+ cmd->state = UASP_QUEUE_COMMAND;
+ iu->iu_id = IU_ID_STATUS;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ /*
+ * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+ */
+ iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+ iu->status = se_cmd->scsi_status;
+ stream->req_status->context = cmd;
+ stream->req_status->length = se_cmd->scsi_sense_length + 16;
+ stream->req_status->buf = iu;
+ stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct uas_stream *stream = cmd->stream;
+ struct f_uas *fu = cmd->fu;
+ int ret;
+
+ if (req->status < 0)
+ goto cleanup;
+
+ switch (cmd->state) {
+ case UASP_SEND_DATA:
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_RECEIVE_DATA:
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_SEND_STATUS:
+ uasp_prepare_status(cmd);
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_QUEUE_COMMAND:
+ usbg_cleanup_cmd(cmd);
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ break;
+
+ default:
+ BUG();
+ };
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+ cmd->fu = fu;
+ uasp_prepare_status(cmd);
+ return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto out;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ kfree(cmd->data_buf);
+ cmd->data_buf = NULL;
+ }
+
+ } else {
+
+ iu->iu_id = IU_ID_READ_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_SEND_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ }
+out:
+ return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ } else {
+
+ iu->iu_id = IU_ID_WRITE_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_RECEIVE_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ }
+
+ wait_for_completion(&cmd->write_complete);
+ transport_generic_process_write(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ if (req->status < 0)
+ return;
+
+ ret = usbg_submit_command(fu, req->buf, req->actual);
+ /*
+ * Once we tune for performance enqueue the command req here again so
+ * we can receive a second command while we processing this one. Pay
+ * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+ * don't break HS.
+ */
+ if (!ret)
+ return;
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+ stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!stream->req_in)
+ goto out;
+
+ stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!stream->req_out)
+ goto err_out;
+
+ stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+ if (!stream->req_status)
+ goto err_sts;
+
+ return 0;
+err_sts:
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+ stream->req_status = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ stream->req_out = NULL;
+out:
+ return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err;
+
+ fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = uasp_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_cmd->maxpacket;
+ fu->cmd.req->context = fu;
+ return 0;
+
+err_buf:
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+ return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+ int i;
+
+ for (i = 0; i < max_streams; i++) {
+ struct uas_stream *s = &fu->stream[i];
+
+ s->req_in->stream_id = i + 1;
+ s->req_out->stream_id = i + 1;
+ s->req_status->stream_id = i + 1;
+ }
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+ int i;
+ int max_streams;
+
+ if (fu->flags & USBG_USE_STREAMS)
+ max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+ else
+ max_streams = 1;
+
+ for (i = 0; i < max_streams; i++) {
+ ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+ if (ret)
+ goto err_cleanup;
+ }
+
+ ret = uasp_alloc_cmd(fu);
+ if (ret)
+ goto err_free_stream;
+ uasp_setup_stream_res(fu, max_streams);
+
+ ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ if (ret)
+ goto err_free_stream;
+
+ return 0;
+
+err_free_stream:
+ uasp_free_cmdreq(fu);
+
+err_cleanup:
+ if (i) {
+ do {
+ uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+ i--;
+ } while (i);
+ }
+ pr_err("UASP: endpoint setup failed\n");
+ return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_UAS;
+
+ if (gadget->speed == USB_SPEED_SUPER)
+ fu->flags |= USBG_USE_STREAMS;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ config_ep_by_speed(gadget, f, fu->ep_cmd);
+ ret = usb_ep_enable(fu->ep_cmd);
+ if (ret)
+ goto err_cmd;
+ config_ep_by_speed(gadget, f, fu->ep_status);
+ ret = usb_ep_enable(fu->ep_status);
+ if (ret)
+ goto err_status;
+
+ ret = uasp_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+
+ pr_info("Using the UAS protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_status);
+err_status:
+ usb_ep_disable(fu->ep_cmd);
+err_cmd:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+ int ret;
+
+ switch (cdb[0]) {
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case INQUIRY:
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case SERVICE_ACTION_IN:
+ case MAINTENANCE_IN:
+ case PERSISTENT_RESERVE_IN:
+ case SECURITY_PROTOCOL_IN:
+ case ACCESS_CONTROL_IN:
+ case REPORT_LUNS:
+ case READ_BLOCK_LIMITS:
+ case READ_POSITION:
+ case READ_CAPACITY:
+ case READ_TOC:
+ case READ_FORMAT_CAPACITIES:
+ case REQUEST_SENSE:
+ ret = DMA_FROM_DEVICE;
+ break;
+
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case WRITE_VERIFY:
+ case WRITE_VERIFY_12:
+ case PERSISTENT_RESERVE_OUT:
+ case MAINTENANCE_OUT:
+ case SECURITY_PROTOCOL_OUT:
+ case ACCESS_CONTROL_OUT:
+ ret = DMA_TO_DEVICE;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case TEST_UNIT_READY:
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ ret = DMA_NONE;
+ break;
+ default:
+ pr_warn("target: Unknown data direction for SCSI Opcode "
+ "0x%02x\n", cdb[0]);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+
+ if (req->status < 0) {
+ pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+ goto cleanup;
+ }
+
+ if (req->num_sgs == 0) {
+ sg_copy_from_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+ }
+
+ complete(&cmd->write_complete);
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ req->buf = cmd->data_buf;
+ } else {
+ req->buf = NULL;
+ req->num_sgs = se_cmd->t_data_nents;
+ req->sg = se_cmd->t_data_sg;
+ }
+
+ req->complete = usbg_data_write_cmpl;
+ req->length = se_cmd->data_length;
+ req->context = cmd;
+ return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_status_response(cmd);
+ else
+ return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_write_request(cmd);
+ else
+ return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_read_response(cmd);
+ else
+ return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct command_iu *cmd_iu = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cmd_iu->iu_id != IU_ID_COMMAND) {
+ pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+ cmd_len = (cmd_iu->len & ~0x3) + 16;
+ if (cmd_len > USBG_MAX_CMD)
+ goto err;
+
+ memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+ cmd->tag = be16_to_cpup(&cmd_iu->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+ if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+ goto err;
+ if (!cmd->tag)
+ cmd->stream = &fu->stream[0];
+ else
+ cmd->stream = &fu->stream[cmd->tag - 1];
+ } else {
+ cmd->stream = &fu->stream[0];
+ }
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ switch (cmd_iu->prio_attr & 0x7) {
+ case UAS_HEAD_TAG:
+ cmd->prio_attr = MSG_HEAD_TAG;
+ break;
+ case UAS_ORDERED_TAG:
+ cmd->prio_attr = MSG_ORDERED_TAG;
+ break;
+ case UAS_ACA:
+ cmd->prio_attr = MSG_ACA_TAG;
+ break;
+ default:
+ pr_debug_once("Unsupported prio_attr: %02x.\n",
+ cmd_iu->prio_attr);
+ case UAS_SIMPLE_TAG:
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ break;
+ }
+
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+ INIT_WORK(&cmd->work, usbg_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+ return;
+ }
+
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ cmd->data_len, cmd->prio_attr, dir, 0);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct bulk_cb_wrap *cbw = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+ int ret;
+
+ if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+ pr_err("Wrong signature on CBW\n");
+ return -EINVAL;
+ }
+ if (len != 31) {
+ pr_err("Wrong length for CBW\n");
+ return -EINVAL;
+ }
+
+ cmd_len = cbw->Length;
+ if (cmd_len < 1 || cmd_len > 16)
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+
+ memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+ cmd->bot_tag = cbw->Tag;
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ cmd->prio_attr = MSG_SIMPLE_TAG;
+ se_cmd = &cmd->se_cmd;
+ cmd->unpacked_lun = cbw->Lun;
+ cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+ cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+ INIT_WORK(&cmd->work, bot_cmd_work);
+ ret = queue_work(tpg->workqueue, &cmd->work);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+ return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ u8 proto_id;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ proto_id = sas_get_fabric_proto_ident(se_tpg);
+ break;
+ }
+
+ return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+ format_code, buf);
+ break;
+ }
+
+ return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ int ret = 0;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+ format_code);
+ break;
+ }
+
+ return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+ char *tid = NULL;
+
+ switch (tport->tport_proto_id) {
+ case SCSI_PROTOCOL_SAS:
+ default:
+ tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+ port_nexus_ptr);
+ }
+
+ return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct usbg_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+ if (!nacl) {
+ printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct usbg_nacl *nacl = container_of(se_nacl,
+ struct usbg_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_new_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ int ret;
+
+ ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
+ if (ret)
+ return ret;
+
+ return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+ struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+ ref);
+
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ kfree(cmd->data_buf);
+ kfree(cmd);
+ return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return le32_to_cpu(cmd->bot_tag);
+ else
+ return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+ return 0;
+}
+
+static u16 usbg_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+ const char *n;
+ unsigned int len;
+
+ n = strstr(name, "naa.");
+ if (!n)
+ return NULL;
+ n += 4;
+ len = strlen(n);
+ if (len == 0 || len > USBG_NAMELEN - 1)
+ return NULL;
+ return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+ struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl, *se_nacl_new;
+ struct usbg_nacl *nacl;
+ u64 wwpn = 0;
+ u32 nexus_depth;
+ const char *wnn_name;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+ se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+ if (!(se_nacl_new))
+ return ERR_PTR(-ENOMEM);
+
+ nexus_depth = 1;
+ /*
+ * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+ * when converting a NodeACL from demo mode -> explict
+ */
+ se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+ name, nexus_depth);
+ if (IS_ERR(se_nacl)) {
+ usbg_release_fabric_acl(se_tpg, se_nacl_new);
+ return se_nacl;
+ }
+ /*
+ * Locate our struct usbg_nacl and set the FC Nport WWPN
+ */
+ nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+ nacl->iport_wwpn = wwpn;
+ snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+ return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+ struct usbg_nacl *nacl = container_of(se_acl,
+ struct usbg_nacl, se_node_acl);
+ core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+ kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+ tport_wwn);
+ struct usbg_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+ if (the_only_tpg_I_currently_have) {
+ pr_err("Until the gadget framework can't handle multiple\n");
+ pr_err("gadgets, you can't do this here.\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+ if (!tpg) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tpg");
+ return ERR_PTR(-ENOMEM);
+ }
+ mutex_init(&tpg->tpg_mutex);
+ atomic_set(&tpg->tpg_port_count, 0);
+ tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+ if (!tpg->workqueue) {
+ kfree(tpg);
+ return NULL;
+ }
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+
+ ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+ &tpg->se_tpg, tpg,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ return NULL;
+ }
+ the_only_tpg_I_currently_have = tpg;
+ return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+
+ core_tpg_deregister(se_tpg);
+ destroy_workqueue(tpg->workqueue);
+ kfree(tpg);
+ the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport;
+ const char *wnn_name;
+ u64 wwpn = 0;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+ if (!(tport)) {
+ printk(KERN_ERR "Unable to allocate struct usbg_tport");
+ return ERR_PTR(-ENOMEM);
+ }
+ tport->tport_wwpn = wwpn;
+ snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+ return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+ struct usbg_tport *tport = container_of(wwn,
+ struct usbg_tport, tport_wwn);
+ kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+ struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+ &usbg_wwn_version.attr,
+ NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
+static ssize_t tcm_usbg_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned long op;
+ ssize_t ret;
+
+ ret = kstrtoul(page, 0, &op);
+ if (ret < 0)
+ return -EINVAL;
+ if (op > 1)
+ return -EINVAL;
+
+ if (op && tpg->gadget_connect)
+ goto out;
+ if (!op && !tpg->gadget_connect)
+ goto out;
+
+ if (op) {
+ ret = usbg_attach(tpg);
+ if (ret)
+ goto out;
+ } else {
+ usbg_detach(tpg);
+ }
+ tpg->gadget_connect = op;
+out:
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ struct tcm_usbg_nexus *tv_nexus;
+ ssize_t ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = snprintf(page, PAGE_SIZE, "%s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+ struct se_portal_group *se_tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ if (tpg->tpg_nexus) {
+ ret = -EEXIST;
+ pr_debug("tpg->tpg_nexus already exists\n");
+ goto err_unlock;
+ }
+ se_tpg = &tpg->se_tpg;
+
+ ret = -ENOMEM;
+ tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+ if (!tv_nexus) {
+ pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+ goto err_unlock;
+ }
+ tv_nexus->tvn_se_sess = transport_init_session();
+ if (IS_ERR(tv_nexus->tvn_se_sess))
+ goto err_free;
+
+ /*
+ * Since we are running in 'demo mode' this call with generate a
+ * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * the SCSI Initiator port name of the passed configfs group 'name'.
+ */
+ tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+ se_tpg, name);
+ if (!tv_nexus->tvn_se_sess->se_node_acl) {
+ pr_debug("core_tpg_check_initiator_node_acl() failed"
+ " for %s\n", name);
+ goto err_session;
+ }
+ /*
+ * Now register the TCM vHost virtual I_T Nexus as active with the
+ * call to __transport_register_session()
+ */
+ __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+ tv_nexus->tvn_se_sess, tv_nexus);
+ tpg->tpg_nexus = tv_nexus;
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+
+err_session:
+ transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+ kfree(tv_nexus);
+err_unlock:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+ struct se_session *se_sess;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret = -ENODEV;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus)
+ goto out;
+
+ se_sess = tv_nexus->tvn_se_sess;
+ if (!se_sess)
+ goto out;
+
+ if (atomic_read(&tpg->tpg_port_count)) {
+ ret = -EPERM;
+ pr_err("Unable to remove Host I_T Nexus with"
+ " active TPG port count: %d\n",
+ atomic_read(&tpg->tpg_port_count));
+ goto out;
+ }
+
+ pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+ /*
+ * Release the SCSI I_T Nexus to the emulated vHost Target Port
+ */
+ transport_deregister_session(tv_nexus->tvn_se_sess);
+ tpg->tpg_nexus = NULL;
+
+ kfree(tv_nexus);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned char i_port[USBG_NAMELEN], *ptr;
+ int ret;
+
+ if (!strncmp(page, "NULL", 4)) {
+ ret = tcm_usbg_drop_nexus(tpg);
+ return (!ret) ? count : ret;
+ }
+ if (strlen(page) > USBG_NAMELEN) {
+ pr_err("Emulated NAA Sas Address: %s, exceeds"
+ " max: %d\n", page, USBG_NAMELEN);
+ return -EINVAL;
+ }
+ snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+ ptr = strstr(i_port, "naa.");
+ if (!ptr) {
+ pr_err("Missing 'naa.' prefix\n");
+ return -EINVAL;
+ }
+
+ if (i_port[strlen(i_port) - 1] == '\n')
+ i_port[strlen(i_port) - 1] = '\0';
+
+ ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+ &tcm_usbg_tpg_enable.attr,
+ &tcm_usbg_tpg_nexus.attr,
+ NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_inc(&tpg->tpg_port_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_dec(&tpg->tpg_port_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+
+ kref_put(&cmd->ref, usbg_cmd_release);
+ return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+ .get_fabric_name = usbg_get_fabric_name,
+ .get_fabric_proto_ident = usbg_get_fabric_proto_ident,
+ .tpg_get_wwn = usbg_get_fabric_wwn,
+ .tpg_get_tag = usbg_get_tag,
+ .tpg_get_default_depth = usbg_get_default_depth,
+ .tpg_get_pr_transport_id = usbg_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = usbg_check_true,
+ .tpg_check_demo_mode_cache = usbg_check_false,
+ .tpg_check_demo_mode_write_protect = usbg_check_false,
+ .tpg_check_prod_mode_write_protect = usbg_check_false,
+ .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl,
+ .tpg_release_fabric_acl = usbg_release_fabric_acl,
+ .tpg_get_inst_index = usbg_tpg_get_inst_index,
+ .new_cmd_map = usbg_new_cmd,
+ .release_cmd = usbg_release_cmd,
+ .shutdown_session = usbg_shutdown_session,
+ .close_session = usbg_close_session,
+ .sess_get_index = usbg_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = usbg_send_write_request,
+ .write_pending_status = usbg_write_pending_status,
+ .set_default_node_attributes = usbg_set_default_node_attrs,
+ .get_task_tag = usbg_get_task_tag,
+ .get_cmd_state = usbg_get_cmd_state,
+ .queue_data_in = usbg_send_read_response,
+ .queue_status = usbg_send_status_response,
+ .queue_tm_rsp = usbg_queue_tm_rsp,
+ .get_fabric_sense_len = usbg_get_fabric_sense_len,
+ .set_fabric_sense_len = usbg_set_fabric_sense_len,
+ .check_stop_free = usbg_check_stop_free,
+
+ .fabric_make_wwn = usbg_make_tport,
+ .fabric_drop_wwn = usbg_drop_tport,
+ .fabric_make_tpg = usbg_make_tpg,
+ .fabric_drop_tpg = usbg_drop_tpg,
+ .fabric_post_link = usbg_port_link,
+ .fabric_pre_unlink = usbg_port_unlink,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = usbg_make_nodeacl,
+ .fabric_drop_nodeacl = usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+ if (IS_ERR(fabric)) {
+ printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+ return PTR_ERR(fabric);
+ }
+
+ fabric->tf_ops = usbg_ops;
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ printk(KERN_ERR "target_fabric_configfs_register() failed"
+ " for usb-gadget\n");
+ return ret;
+ }
+ usbg_fabric_configfs = fabric;
+ return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+ if (!(usbg_fabric_configfs))
+ return;
+
+ target_fabric_configfs_deregister(usbg_fabric_configfs);
+ usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+ .bLength = sizeof(bot_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bAlternateSetting = USB_G_ALT_INT_BBB,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_BULK,
+ .iInterface = USB_G_STR_INT_UAS,
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+ .bLength = sizeof(uasp_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 4,
+ .bAlternateSetting = USB_G_ALT_INT_UAS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_UAS,
+ .iInterface = USB_G_STR_INT_BBB,
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+ .bLength = sizeof(uasp_bi_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+ .bLength = sizeof(uasp_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+ .wBytesPerInterval = 0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+ .bLength = sizeof(bot_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+ .bLength = sizeof(uasp_bo_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+ .bLength = sizeof(uasp_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+ .bLength = sizeof(bot_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+ .bLength = sizeof(uasp_status_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+ .bLength = sizeof(uasp_status_in_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+ .bLength = sizeof(uasp_cmd_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+ .bLength = sizeof(uasp_cmd_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+#define UAS_VENDOR_ID 0x0525 /* NetChip */
+#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
+
+static struct usb_device_descriptor usbg_device_desc = {
+ .bLength = sizeof(usbg_device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = cpu_to_le16(UAS_VENDOR_ID),
+ .idProduct = cpu_to_le16(UAS_PRODUCT_ID),
+ .iManufacturer = USB_G_STR_MANUFACTOR,
+ .iProduct = USB_G_STR_PRODUCT,
+ .iSerialNumber = USB_G_STR_SERIAL,
+
+ .bNumConfigurations = 1,
+};
+
+static struct usb_string usbg_us_strings[] = {
+ { USB_G_STR_MANUFACTOR, "Target Manufactor"},
+ { USB_G_STR_PRODUCT, "Target Product"},
+ { USB_G_STR_SERIAL, "000000000001"},
+ { USB_G_STR_CONFIG, "default config"},
+ { USB_G_STR_INT_UAS, "USB Attached SCSI"},
+ { USB_G_STR_INT_BBB, "Bulk Only Transport"},
+ { },
+};
+
+static struct usb_gadget_strings usbg_stringtab = {
+ .language = 0x0409,
+ .strings = usbg_us_strings,
+};
+
+static struct usb_gadget_strings *usbg_strings[] = {
+ &usbg_stringtab,
+ NULL,
+};
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
+ return 0;
+}
+
+static struct usb_configuration usbg_config_driver = {
+ .label = "Linux Target",
+ .bConfigurationValue = 1,
+ .iConfiguration = USB_G_STR_CONFIG,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+ struct usb_ep *ep = *pep;
+ if (!ep)
+ return;
+ ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep;
+ int iface;
+
+ iface = usb_interface_id(c, f);
+ if (iface < 0)
+ return iface;
+
+ bot_intf_desc.bInterfaceNumber = iface;
+ uasp_intf_desc.bInterfaceNumber = iface;
+ fu->iface = iface;
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+ &uasp_bi_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+
+ ep->driver_data = fu;
+ fu->ep_in = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+ &uasp_bo_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_out = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+ &uasp_status_in_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_status = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+ &uasp_cmd_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ ep->driver_data = fu;
+ fu->ep_cmd = ep;
+
+ /* Assume endpoint addresses are the same for both speeds */
+ uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_fs_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ return 0;
+ep_fail:
+ pr_err("Can't claim all required eps\n");
+
+ give_back_ep(&fu->ep_in);
+ give_back_ep(&fu->ep_out);
+ give_back_ep(&fu->ep_status);
+ give_back_ep(&fu->ep_cmd);
+ return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ kfree(fu);
+}
+
+struct guas_setup_wq {
+ struct work_struct work;
+ struct f_uas *fu;
+ unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+ struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+ work);
+ struct f_uas *fu = work->fu;
+ int alt = work->alt;
+
+ kfree(work);
+
+ if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+
+ if (alt == USB_G_ALT_INT_BBB)
+ bot_set_alt(fu);
+ else if (alt == USB_G_ALT_INT_UAS)
+ uasp_set_alt(fu);
+ usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+ struct guas_setup_wq *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+ INIT_WORK(&work->work, usbg_delayed_set_alt);
+ work->fu = fu;
+ work->alt = alt;
+ schedule_work(&work->work);
+ return USB_GADGET_DELAYED_STATUS;
+ }
+ return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+ else if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (!(fu->flags & USBG_IS_BOT))
+ return -EOPNOTSUPP;
+
+ return usbg_bot_setup(f, ctrl);
+}
+
+static int usbg_cfg_bind(struct usb_configuration *c)
+{
+ struct f_uas *fu;
+ int ret;
+
+ fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+ if (!fu)
+ return -ENOMEM;
+ fu->function.name = "Target Function";
+ fu->function.descriptors = uasp_fs_function_desc;
+ fu->function.hs_descriptors = uasp_hs_function_desc;
+ fu->function.ss_descriptors = uasp_ss_function_desc;
+ fu->function.bind = usbg_bind;
+ fu->function.unbind = usbg_unbind;
+ fu->function.set_alt = usbg_set_alt;
+ fu->function.setup = usbg_setup;
+ fu->function.disable = usbg_disable;
+ fu->tpg = the_only_tpg_I_currently_have;
+
+ ret = usb_add_function(c, &fu->function);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree(fu);
+ return ret;
+}
+
+static int usb_target_bind(struct usb_composite_dev *cdev)
+{
+ int ret;
+
+ ret = usb_add_config(cdev, &usbg_config_driver,
+ usbg_cfg_bind);
+ return 0;
+}
+
+static struct usb_composite_driver usbg_driver = {
+ .name = "g_target",
+ .dev = &usbg_device_desc,
+ .strings = usbg_strings,
+ .max_speed = USB_SPEED_SUPER,
+ .unbind = guas_unbind,
+};
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+ return usb_composite_probe(&usbg_driver, usb_target_bind);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+ usb_composite_unregister(&usbg_driver);
+}
+
+static int __init usb_target_gadget_init(void)
+{
+ int ret;
+
+ ret = usbg_register_configfs();
+ return ret;
+}
+module_init(usb_target_gadget_init);
+
+static void __exit usb_target_gadget_exit(void)
+{
+ usbg_deregister_configfs();
+}
+module_exit(usb_target_gadget_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION("usb-gadget fabric");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h
new file mode 100644
index 0000000..bb18999
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.h
@@ -0,0 +1,146 @@
+#ifndef __TARGET_USB_GADGET_H__
+#define __TARGET_USB_GADGET_H__
+
+#include <linux/kref.h>
+/* #include <linux/usb/uas.h> */
+#include <linux/usb/composite.h>
+#include <linux/usb/uas.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#define USBG_NAMELEN 32
+
+#define fuas_to_gadget(f) (f->function.config->cdev->gadget)
+#define UASP_SS_EP_COMP_LOG_STREAMS 4
+#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
+
+#define USB_G_STR_MANUFACTOR 1
+#define USB_G_STR_PRODUCT 2
+#define USB_G_STR_SERIAL 3
+#define USB_G_STR_CONFIG 4
+#define USB_G_STR_INT_UAS 5
+#define USB_G_STR_INT_BBB 6
+
+#define USB_G_ALT_INT_BBB 0
+#define USB_G_ALT_INT_UAS 1
+
+struct usbg_nacl {
+ /* Binary World Wide unique Port Name for SAS Initiator port */
+ u64 iport_wwpn;
+ /* ASCII formatted WWPN for Sas Initiator port */
+ char iport_name[USBG_NAMELEN];
+ /* Returned by usbg_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+struct tcm_usbg_nexus {
+ struct se_session *tvn_se_sess;
+};
+
+struct usbg_tpg {
+ struct mutex tpg_mutex;
+ /* SAS port target portal group tag for TCM */
+ u16 tport_tpgt;
+ /* Pointer back to usbg_tport */
+ struct usbg_tport *tport;
+ struct workqueue_struct *workqueue;
+ /* Returned by usbg_make_tpg() */
+ struct se_portal_group se_tpg;
+ u32 gadget_connect;
+ struct tcm_usbg_nexus *tpg_nexus;
+ atomic_t tpg_port_count;
+};
+
+struct usbg_tport {
+ /* SCSI protocol the tport is providing */
+ u8 tport_proto_id;
+ /* Binary World Wide unique Port Name for SAS Target port */
+ u64 tport_wwpn;
+ /* ASCII formatted WWPN for SAS Target port */
+ char tport_name[USBG_NAMELEN];
+ /* Returned by usbg_make_tport() */
+ struct se_wwn tport_wwn;
+};
+
+enum uas_state {
+ UASP_SEND_DATA,
+ UASP_RECEIVE_DATA,
+ UASP_SEND_STATUS,
+ UASP_QUEUE_COMMAND,
+};
+
+#define USBG_MAX_CMD 64
+struct usbg_cmd {
+ /* common */
+ u8 cmd_buf[USBG_MAX_CMD];
+ u32 data_len;
+ struct work_struct work;
+ int unpacked_lun;
+ struct se_cmd se_cmd;
+ void *data_buf; /* used if no sg support available */
+ struct f_uas *fu;
+ struct completion write_complete;
+ struct kref ref;
+
+ /* UAS only */
+ u16 tag;
+ u16 prio_attr;
+ struct sense_iu sense_iu;
+ enum uas_state state;
+ struct uas_stream *stream;
+
+ /* BOT only */
+ __le32 bot_tag;
+ unsigned int csw_code;
+ unsigned is_read:1;
+
+};
+
+struct uas_stream {
+ struct usb_request *req_in;
+ struct usb_request *req_out;
+ struct usb_request *req_status;
+};
+
+struct usbg_cdb {
+ struct usb_request *req;
+ void *buf;
+};
+
+struct bot_status {
+ struct usb_request *req;
+ struct bulk_cs_wrap csw;
+};
+
+struct f_uas {
+ struct usbg_tpg *tpg;
+ struct usb_function function;
+ u16 iface;
+
+ u32 flags;
+#define USBG_ENABLED (1 << 0)
+#define USBG_IS_UAS (1 << 1)
+#define USBG_USE_STREAMS (1 << 2)
+#define USBG_IS_BOT (1 << 3)
+#define USBG_BOT_CMD_PEND (1 << 4)
+
+ struct usbg_cdb cmd;
+ struct usb_ep *ep_in;
+ struct usb_ep *ep_out;
+
+ /* UAS */
+ struct usb_ep *ep_status;
+ struct usb_ep *ep_cmd;
+ struct uas_stream stream[UASP_SS_EP_COMP_NUM_STREAMS];
+
+ /* BOT */
+ struct bot_status bot_status;
+ struct usb_request *bot_req_in;
+ struct usb_request *bot_req_out;
+};
+
+extern struct usbg_tpg *the_only_tpg_I_currently_have;
+
+#endif
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 29c854b..47cf48b 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -744,10 +744,11 @@ static struct device_type gadget_type = {
};
/**
- * gether_setup - initialize one ethernet-over-usb link
+ * gether_setup_name - initialize one ethernet-over-usb link
* @g: gadget to associated with these links
* @ethaddr: NULL, or a buffer in which the ethernet address of the
* host side of the link is recorded
+ * @netname: name for network device (for example, "usb")
* Context: may sleep
*
* This sets up the single network link that may be exported by a
@@ -756,7 +757,8 @@ static struct device_type gadget_type = {
*
* Returns negative errno, or zero on success
*/
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+ const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
@@ -780,7 +782,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
/* network device setup */
dev->net = net;
- strcpy(net->name, "usb%d");
+ snprintf(net->name, sizeof(net->name), "%s%%d", netname);
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&g->dev,
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 8012357..6f4a1623 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -69,9 +69,28 @@ struct gether {
|USB_CDC_PACKET_TYPE_PROMISCUOUS \
|USB_CDC_PACKET_TYPE_DIRECTED)
+/* variant of gether_setup that allows customizing network device name */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+ const char *netname);
/* netdev setup/teardown as directed by the gadget driver */
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]);
+/* gether_setup - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ * host side of the link is recorded
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework. The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+{
+ return gether_setup_name(g, ethaddr, "usb");
+}
+
void gether_cleanup(void);
/* connect/disconnect is handled by individual functions */
@@ -99,16 +118,37 @@ int eem_bind_config(struct usb_configuration *c);
#ifdef USB_ETH_RNDIS
-int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer);
#else
static inline int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer)
{
return 0;
}
#endif
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ * side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup(). Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+ u8 ethaddr[ETH_ALEN])
+{
+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
#endif /* __U_ETHER_H */
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6c23938..5b3f5ff 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -94,17 +94,14 @@ struct gs_buf {
* (and thus for each /dev/ node).
*/
struct gs_port {
+ struct tty_port port;
spinlock_t port_lock; /* guard port_* access */
struct gserial *port_usb;
- struct tty_struct *port_tty;
- unsigned open_count;
bool openclose; /* open/close in progress */
u8 port_num;
- wait_queue_head_t close_wait; /* wait for last close */
-
struct list_head read_pool;
int read_started;
int read_allocated;
@@ -412,8 +409,8 @@ __acquires(&port->port_lock)
break;
}
- if (do_tty_wake && port->port_tty)
- tty_wakeup(port->port_tty);
+ if (do_tty_wake && port->port.tty)
+ tty_wakeup(port->port.tty);
return status;
}
@@ -435,7 +432,7 @@ __acquires(&port->port_lock)
struct tty_struct *tty;
/* no more rx if closed */
- tty = port->port_tty;
+ tty = port->port.tty;
if (!tty)
break;
@@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port)
/* hand any queued data to the tty */
spin_lock_irq(&port->port_lock);
- tty = port->port_tty;
+ tty = port->port.tty;
while (!list_empty(queue)) {
struct usb_request *req;
@@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port)
/* unblock any pending writes into our circular buffer */
if (started) {
- tty_wakeup(port->port_tty);
+ tty_wakeup(port->port.tty);
} else {
gs_free_requests(ep, head, &port->read_allocated);
gs_free_requests(port->port_usb->in, &port->write_pool,
@@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock);
/* already open? Great. */
- if (port->open_count) {
+ if (port->port.count) {
status = 0;
- port->open_count++;
+ port->port.count++;
/* currently opening/closing? wait ... */
} else if (port->openclose) {
@@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
/* REVISIT maybe wait for "carrier detect" */
tty->driver_data = port;
- port->port_tty = tty;
+ port->port.tty = tty;
- port->open_count = 1;
+ port->port.count = 1;
port->openclose = false;
/* if connected, start the I/O stream */
@@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock);
- if (port->open_count != 1) {
- if (port->open_count == 0)
+ if (port->port.count != 1) {
+ if (port->port.count == 0)
WARN_ON(1);
else
- --port->open_count;
+ --port->port.count;
goto exit;
}
@@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
* and sleep if necessary
*/
port->openclose = true;
- port->open_count = 0;
+ port->port.count = 0;
gser = port->port_usb;
if (gser && gser->disconnect)
@@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_buf_clear(&port->port_write_buf);
tty->driver_data = NULL;
- port->port_tty = NULL;
+ port->port.tty = NULL;
port->openclose = false;
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
port->port_num, tty, file);
- wake_up_interruptible(&port->close_wait);
+ wake_up_interruptible(&port->port.close_wait);
exit:
spin_unlock_irq(&port->port_lock);
}
@@ -917,7 +914,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch)
unsigned long flags;
int status;
- pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+ pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@@ -1025,7 +1022,7 @@ static const struct tty_operations gs_tty_ops = {
static struct tty_driver *gs_tty_driver;
-static int __init
+static int
gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
{
struct gs_port *port;
@@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
if (port == NULL)
return -ENOMEM;
+ tty_port_init(&port->port);
spin_lock_init(&port->port_lock);
- init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->drain_wait);
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
@@ -1071,7 +1068,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
*
* Returns negative errno or zero.
*/
-int __init gserial_setup(struct usb_gadget *g, unsigned count)
+int gserial_setup(struct usb_gadget *g, unsigned count)
{
unsigned i;
struct usb_cdc_line_coding coding;
@@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port)
int cond;
spin_lock_irq(&port->port_lock);
- cond = (port->open_count == 0) && !port->openclose;
+ cond = (port->port.count == 0) && !port->openclose;
spin_unlock_irq(&port->port_lock);
return cond;
}
@@ -1194,7 +1191,7 @@ void gserial_cleanup(void)
tasklet_kill(&port->push);
/* wait for old opens to finish */
- wait_event(port->close_wait, gs_closed(port));
+ wait_event(port->port.close_wait, gs_closed(port));
WARN_ON(port->port_usb != NULL);
@@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
/* if it's already open, start I/O ... and notify the serial
* protocol about open/close status (connect/disconnect).
*/
- if (port->open_count) {
+ if (port->port.count) {
pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
gs_start_io(port);
if (gser->connect)
@@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser)
port->port_usb = NULL;
gser->ioport = NULL;
- if (port->open_count > 0 || port->openclose) {
+ if (port->port.count > 0 || port->openclose) {
wake_up_interruptible(&port->drain_wait);
- if (port->port_tty)
- tty_hangup(port->port_tty);
+ if (port->port.tty)
+ tty_hangup(port->port.tty);
}
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser)
/* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags);
- if (port->open_count == 0 && !port->openclose)
+ if (port->port.count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf);
gs_free_requests(gser->out, &port->read_pool, NULL);
gs_free_requests(gser->out, &port->read_queue, NULL);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 31d3483..12ad516 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -72,7 +72,7 @@
static const char longname[] = "Gadget Zero";
-unsigned buflen = 4096;
+unsigned buflen = 4096; /* only used for bulk endpoints */
module_param(buflen, uint, 0);
/*
@@ -170,14 +170,17 @@ static struct usb_gadget_strings *dev_strings[] = {
/*-------------------------------------------------------------------------*/
-struct usb_request *alloc_ep_req(struct usb_ep *ep)
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
{
struct usb_request *req;
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
- req->length = buflen;
- req->buf = kmalloc(buflen, GFP_ATOMIC);
+ if (len)
+ req->length = len;
+ else
+ req->length = buflen;
+ req->buf = kmalloc(req->length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request(ep, req);
req = NULL;
@@ -206,10 +209,15 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
}
void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out)
+ struct usb_ep *in, struct usb_ep *out,
+ struct usb_ep *iso_in, struct usb_ep *iso_out)
{
disable_ep(cdev, in);
disable_ep(cdev, out);
+ if (iso_in)
+ disable_ep(cdev, iso_in);
+ if (iso_out)
+ disable_ep(cdev, iso_out);
}
/*-------------------------------------------------------------------------*/
@@ -311,7 +319,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
device_desc.bcdDevice = cpu_to_le16(0x9999);
}
-
INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f788eb8..83e58df 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -65,7 +65,7 @@ config USB_EHCI_HCD
config USB_EHCI_ROOT_HUB_TT
bool "Root Hub Transaction Translators"
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
---help---
Some EHCI chips have vendor-specific extensions to integrate
transaction translators, so that no OHCI or UHCI companion
@@ -77,7 +77,7 @@ config USB_EHCI_ROOT_HUB_TT
config USB_EHCI_TT_NEWSCHED
bool "Improved Transaction Translator scheduling"
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
default y
---help---
This changes the periodic scheduling code to fill more of the low
@@ -110,13 +110,14 @@ config USB_EHCI_BIG_ENDIAN_MMIO
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
- PMC_MSP || SPARC_LEON)
+ PMC_MSP || SPARC_LEON || MIPS_SEAD3)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
- PPC_MPC512x || PMC_MSP || SPARC_LEON)
+ PPC_MPC512x || PMC_MSP || SPARC_LEON || \
+ MIPS_SEAD3)
default y
config XPS_USB_HCD_XILINX
@@ -152,7 +153,7 @@ config USB_EHCI_HCD_OMAP
bool "EHCI support for OMAP3 and later chips"
depends on USB_EHCI_HCD && ARCH_OMAP
default y
- --- help ---
+ ---help---
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
@@ -291,6 +292,7 @@ config USB_OHCI_HCD
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
select USB_OTG_UTILS if ARCH_OMAP
+ select USB_ISP1301 if ARCH_LPC32XX || 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
@@ -373,10 +375,15 @@ config USB_OHCI_HCD_PCI
If unsure, say Y.
config USB_OHCI_HCD_SSB
- bool "OHCI support for Broadcom SSB OHCI core"
+ bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)"
depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL
+ select USB_HCD_SSB
+ select USB_OHCI_HCD_PLATFORM
default n
---help---
+ This option is deprecated now and the driver was removed, use
+ USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
+
Support for the Sonics Silicon Backplane (SSB) attached
Broadcom USB OHCI core.
@@ -638,3 +645,27 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_HCD_BCMA
+ tristate "BCMA usb host driver"
+ depends on BCMA && EXPERIMENTAL
+ select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+ select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+ help
+ Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ It converts the bcma driver into two platform device drivers
+ for ehci and ohci.
+
+ If unsure, say N.
+
+config USB_HCD_SSB
+ tristate "SSB usb host driver"
+ depends on SSB && EXPERIMENTAL
+ select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+ select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+ help
+ Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ It converts the bcma driver into two platform device drivers
+ for ehci and ohci.
+
+ If unsure, say N.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 0982bcc..9e0a89c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,3 +41,5 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o
+obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
+obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
new file mode 100644
index 0000000..443da21
--- /dev/null
+++ b/drivers/usb/host/bcma-hcd.c
@@ -0,0 +1,335 @@
+/*
+ * Broadcom specific Advanced Microcontroller Bus
+ * Broadcom USB-core driver (BCMA bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/bcma/bcma.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
+MODULE_LICENSE("GPL");
+
+struct bcma_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
+};
+
+/* Wait for bitmask in a register to get set or cleared.
+ * timeout is in units of ten-microseconds.
+ */
+static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
+ int timeout)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < timeout; i++) {
+ val = bcma_read32(dev, reg);
+ if ((val & bitmask) == bitmask)
+ return 0;
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
+{
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* Work around for 4716 failures. */
+ if (dev->bus->chipinfo.id == 0x4716) {
+ u32 tmp;
+
+ tmp = bcma_cpu_clock(&dev->bus->drv_mips);
+ if (tmp >= 480000000)
+ tmp = 0x1846b; /* set CDR to 0x11(fast) */
+ else if (tmp == 453000000)
+ tmp = 0x1046b; /* set CDR to 0x10(slow) */
+ else
+ tmp = 0;
+
+ /* Change Shim mdio control reg to fix host not acking at
+ * high frequencies
+ */
+ if (tmp) {
+ bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
+ udelay(500);
+
+ bcma_write32(dev, 0x524, tmp);
+ udelay(500);
+ bcma_write32(dev, 0x524, 0x4ab);
+ udelay(500);
+ bcma_read32(dev, 0x528);
+ bcma_write32(dev, 0x528, 0x80000000);
+ }
+ }
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
+{
+ u32 tmp;
+
+ /*
+ * USB 2.0 special considerations:
+ *
+ * 1. Since the core supports both OHCI and EHCI functions, it must
+ * only be reset once.
+ *
+ * 2. In addition to the standard SI reset sequence, the Host Control
+ * Register must be programmed to bring the USB core and various
+ * phy components out of reset.
+ */
+ if (!bcma_core_is_enabled(dev)) {
+ bcma_core_enable(dev, 0);
+ mdelay(10);
+ if (dev->id.rev >= 5) {
+ /* Enable Misc PLL */
+ tmp = bcma_read32(dev, 0x1e0);
+ tmp |= 0x100;
+ bcma_write32(dev, 0x1e0, tmp);
+ if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
+ printk(KERN_EMERG "Failed to enable misc PPL!\n");
+
+ /* Take out of resets */
+ bcma_write32(dev, 0x200, 0x4ff);
+ udelay(25);
+ bcma_write32(dev, 0x200, 0x6ff);
+ udelay(25);
+
+ /* Make sure digital and AFE are locked in USB PHY */
+ bcma_write32(dev, 0x524, 0x6b);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0xab);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0x2b);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0x10ab);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+
+ if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
+ tmp = bcma_read32(dev, 0x528);
+ printk(KERN_EMERG
+ "USB20H mdio_rddata 0x%08x\n", tmp);
+ }
+ bcma_write32(dev, 0x528, 0x80000000);
+ tmp = bcma_read32(dev, 0x314);
+ udelay(265);
+ bcma_write32(dev, 0x200, 0x7ff);
+ udelay(10);
+
+ /* Take USB and HSIC out of non-driving modes */
+ bcma_write32(dev, 0x510, 0);
+ } else {
+ bcma_write32(dev, 0x200, 0x7ff);
+
+ udelay(1);
+ }
+
+ bcma_hcd_4716wa(dev);
+ }
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
+{
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+ int ret = -ENOMEM;
+
+ memset(hci_res, 0, sizeof(hci_res));
+
+ hci_res[0].start = addr;
+ hci_res[0].end = hci_res[0].start + 0x1000 - 1;
+ hci_res[0].flags = IORESOURCE_MEM;
+
+ hci_res[1].start = dev->irq;
+ hci_res[1].flags = IORESOURCE_IRQ;
+
+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+ "ehci-platform" , 0);
+ if (!hci_dev)
+ return NULL;
+
+ hci_dev->dev.parent = &dev->dev;
+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+ ret = platform_device_add_resources(hci_dev, hci_res,
+ ARRAY_SIZE(hci_res));
+ if (ret)
+ goto err_alloc;
+ if (ohci)
+ ret = platform_device_add_data(hci_dev, &ohci_pdata,
+ sizeof(ohci_pdata));
+ else
+ ret = platform_device_add_data(hci_dev, &ehci_pdata,
+ sizeof(ehci_pdata));
+ if (ret)
+ goto err_alloc;
+ ret = platform_device_add(hci_dev);
+ if (ret)
+ goto err_alloc;
+
+ return hci_dev;
+
+err_alloc:
+ platform_device_put(hci_dev);
+ return ERR_PTR(ret);
+}
+
+static int __devinit bcma_hcd_probe(struct bcma_device *dev)
+{
+ int err;
+ u16 chipid_top;
+ u32 ohci_addr;
+ struct bcma_hcd_device *usb_dev;
+ struct bcma_chipinfo *chipinfo;
+
+ chipinfo = &dev->bus->chipinfo;
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (chipinfo->id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+ usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+
+ bcma_hcd_init_chip(dev);
+
+ /* In AI chips EHCI is addrspace 0, OHCI is 1 */
+ ohci_addr = dev->addr1;
+ if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
+ && chipinfo->rev == 0)
+ ohci_addr = 0x18009000;
+
+ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
+ if (IS_ERR(usb_dev->ohci_dev)) {
+ err = PTR_ERR(usb_dev->ohci_dev);
+ goto err_free_usb_dev;
+ }
+
+ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
+ if (IS_ERR(usb_dev->ehci_dev)) {
+ err = PTR_ERR(usb_dev->ehci_dev);
+ goto err_unregister_ohci_dev;
+ }
+
+ bcma_set_drvdata(dev, usb_dev);
+ return 0;
+
+err_unregister_ohci_dev:
+ platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+ kfree(usb_dev);
+ return err;
+}
+
+static void __devexit bcma_hcd_remove(struct bcma_device *dev)
+{
+ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+ if (ohci_dev)
+ platform_device_unregister(ohci_dev);
+ if (ehci_dev)
+ platform_device_unregister(ehci_dev);
+
+ bcma_core_disable(dev, 0);
+}
+
+static void bcma_hcd_shutdown(struct bcma_device *dev)
+{
+ bcma_core_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int bcma_hcd_suspend(struct bcma_device *dev)
+{
+ bcma_core_disable(dev, 0);
+
+ return 0;
+}
+
+static int bcma_hcd_resume(struct bcma_device *dev)
+{
+ bcma_core_enable(dev, 0);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define bcma_hcd_suspend NULL
+#define bcma_hcd_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct bcma_device_id bcma_hcd_table[] __devinitconst = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
+
+static struct bcma_driver bcma_hcd_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = bcma_hcd_table,
+ .probe = bcma_hcd_probe,
+ .remove = __devexit_p(bcma_hcd_remove),
+ .shutdown = bcma_hcd_shutdown,
+ .suspend = bcma_hcd_suspend,
+ .resume = bcma_hcd_resume,
+};
+
+static int __init bcma_hcd_init(void)
+{
+ return bcma_driver_register(&bcma_hcd_driver);
+}
+module_init(bcma_hcd_init);
+
+static void __exit bcma_hcd_exit(void)
+{
+ bcma_driver_unregister(&bcma_hcd_driver);
+}
+module_exit(bcma_hcd_exit);
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 680e1a3..7561966 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1025,10 +1025,8 @@ static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf,
if (strict_strtoul(buf + 5, 16, &hird))
return -EINVAL;
printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~CMD_HIRD;
- temp |= hird << 24;
- ehci_writel(ehci, temp, &ehci->regs->command);
+ ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
} else if (strncmp(buf, "disable", 7) == 0) {
if (strict_strtoul(buf + 8, 10, &port))
return -EINVAL;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d0a84bd..4336257 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,6 +1,6 @@
/*
* Copyright 2005-2009 MontaVista Software, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
+ * Copyright 2008,2012 Freescale Semiconductor, 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
@@ -150,8 +150,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
retval = otg_set_host(ehci->transceiver->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
- if (ehci->transceiver)
- put_device(ehci->transceiver->dev);
+ usb_put_transceiver(ehci->transceiver);
goto err4;
}
} else {
@@ -195,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
if (ehci->transceiver) {
otg_set_host(ehci->transceiver->otg, NULL);
- put_device(ehci->transceiver->dev);
+ usb_put_transceiver(ehci->transceiver);
}
usb_remove_hcd(hcd);
@@ -211,22 +210,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
usb_put_hcd(hcd);
}
-static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
enum fsl_usb2_phy_modes phy_mode,
unsigned int port_offset)
{
- u32 portsc;
- struct usb_hcd *hcd = ehci_to_hcd(ehci);
+ u32 portsc, temp;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
- struct fsl_usb2_platform_data *pdata;
+ struct device *dev = hcd->self.controller;
+ struct fsl_usb2_platform_data *pdata = dev->platform_data;
- pdata = hcd->self.controller->platform_data;
+ if (pdata->controller_ver < 0) {
+ dev_warn(hcd->self.controller, "Could not get controller version\n");
+ return;
+ }
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
switch (phy_mode) {
case FSL_USB2_PHY_ULPI:
+ if (pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+ USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+ }
portsc |= PORT_PTS_ULPI;
break;
case FSL_USB2_PHY_SERIAL:
@@ -236,6 +245,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ if (pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+ UTMI_PHY_EN | USB_CTRL_USB_EN);
+ mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to
+ become stable - 10ms*/
+ }
/* enable UTMI PHY */
if (pdata->have_sysif_regs)
setbits32(non_ehci + FSL_SOC_USB_CTRL,
@@ -276,7 +293,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
unsigned int chip, rev, svr;
@@ -290,9 +307,9 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
ehci->has_fsl_port_bug = 1;
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
}
if (pdata->have_sysif_regs) {
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 863fb0c..8840368 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
+/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc.
* Copyright (c) 2005 MontaVista Software
*
* This program is free software; you can redistribute it and/or modify it
@@ -50,4 +50,15 @@
#define CTRL_UTMI_PHY_EN (1<<9)
#define CTRL_PHY_CLK_VALID (1 << 17)
#define SNOOP_SIZE_2GB 0x1e
+
+/* control Register Bit Masks */
+#define ULPI_INT_EN (1<<0)
+#define WU_INT_EN (1<<1)
+#define USB_CTRL_USB_EN (1<<2)
+#define LINE_STATE_FILTER__EN (1<<3)
+#define KEEP_OTG_ON (1<<4)
+#define OTG_PORT (1<<5)
+#define PLL_RESET (1<<8)
+#define UTMI_PHY_EN (1<<9)
+#define ULPI_PHY_CLK_SEL (1<<10)
#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4a3bc5b..b100f5f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -226,8 +226,13 @@ static int ehci_halt (struct ehci_hcd *ehci)
if ((temp & STS_HALT) != 0)
return 0;
+ /*
+ * This routine gets called during probe before ehci->command
+ * has been initialized, so we can't rely on its value.
+ */
+ ehci->command &= ~CMD_RUN;
temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~CMD_RUN;
+ temp &= ~(CMD_RUN | CMD_IAAD);
ehci_writel(ehci, temp, &ehci->regs->command);
return handshake (ehci, &ehci->regs->status,
STS_HALT, STS_HALT, 16 * 125);
@@ -363,16 +368,14 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
- temp = ehci_readl(ehci, &ehci->regs->command) << 10;
- temp &= STS_ASS | STS_PSS;
+ temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_ASS | STS_PSS, temp, 16 * 125))
return;
/* then disable anything that's still active */
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
- ehci_writel(ehci, temp, &ehci->regs->command);
+ ehci->command &= ~(CMD_ASE | CMD_PSE);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
handshake_on_error_set_halt(ehci, &ehci->regs->status,
@@ -417,9 +420,6 @@ static void ehci_iaa_watchdog(unsigned long param)
* CMD_IAAD when it sets STS_IAA.)
*/
cmd = ehci_readl(ehci, &ehci->regs->command);
- if (cmd & CMD_IAAD)
- ehci_writel(ehci, cmd & ~CMD_IAAD,
- &ehci->regs->command);
/* If IAA is set here it either legitimately triggered
* before we cleared IAAD above (but _way_ late, so we'll
@@ -894,11 +894,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
/* guard against (alleged) silicon errata */
- if (cmd & CMD_IAAD) {
- ehci_writel(ehci, cmd & ~CMD_IAAD,
- &ehci->regs->command);
+ if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
- }
if (ehci->reclaim) {
COUNT(ehci->stats.reclaim);
end_unlink_async(ehci);
@@ -1248,6 +1245,13 @@ static int ehci_get_frame (struct usb_hcd *hcd)
}
/*-------------------------------------------------------------------------*/
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions and in order to facilitate role switching we cannot
+ * give the ehci driver exclusive access to those.
+ */
+#ifndef CHIPIDEA_EHCI
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -1378,6 +1382,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_ls1x_driver
#endif
+#ifdef CONFIG_MIPS_SEAD3
+#include "ehci-sead3.c"
+#define PLATFORM_DRIVER ehci_hcd_sead3_driver
+#endif
+
#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
#include "ehci-platform.c"
#define PLATFORM_DRIVER ehci_platform_driver
@@ -1501,3 +1510,4 @@ static void __exit ehci_hcd_cleanup(void)
}
module_exit(ehci_hcd_cleanup);
+#endif /* CHIPIDEA_EHCI */
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 38fe076..fc9e7cc 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -233,7 +233,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
/* stop schedules, clean any completed work */
if (ehci->rh_state == EHCI_RH_RUNNING)
ehci_quiesce (ehci);
- ehci->command = ehci_readl(ehci, &ehci->regs->command);
ehci_work(ehci);
/* Unlike other USB host controller types, EHCI doesn't have
@@ -374,6 +373,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
+ ehci->command |= CMD_RUN;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
ehci->rh_state = EHCI_RH_RUNNING;
@@ -531,7 +531,8 @@ static int check_reset_complete (
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 1);
} else {
- ehci_dbg (ehci, "port %d high speed\n", index + 1);
+ ehci_dbg(ehci, "port %d reset complete, port enabled\n",
+ index + 1);
/* ensure 440EPx ohci controller state is suspended */
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 0);
@@ -699,6 +700,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
temp = ehci_readl(ehci, status_reg);
+ temp &= ~PORT_RWC_BITS;
/*
* Even if OWNER is set, so the port is owned by the
@@ -712,8 +714,7 @@ static int ehci_hub_control (
ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_PEC, status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@@ -742,7 +743,7 @@ static int ehci_hub_control (
spin_lock_irqsave(&ehci->lock, flags);
}
/* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ temp &= ~PORT_WAKE_BITS;
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
@@ -752,9 +753,8 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_POWER),
- status_reg);
+ ehci_writel(ehci, temp & ~PORT_POWER,
+ status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
if (ehci->has_lpm) {
@@ -762,12 +762,10 @@ static int ehci_hub_control (
temp &= ~PORT_LPM;
temp &= ~PORT_DEV_ADDR;
}
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_CSC, status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_OCC, status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 5c78f9e..a44294d 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -242,15 +242,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
ehci_reset(omap_ehci);
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret) {
- dev_err(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
- }
-
- /* root ports should always stay powered */
- ehci_port_power(omap_ehci, 1);
-
if (pdata->phy_reset) {
/* Hold the PHY in RESET for enough time till
* PHY is settled and ready
@@ -258,12 +249,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
udelay(10);
if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value(pdata->reset_gpio_port[0], 1);
+ gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value(pdata->reset_gpio_port[1], 1);
+ gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
}
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(dev, "failed to add hcd with err %d\n", ret);
+ goto err_add_hcd;
+ }
+
+ /* root ports should always stay powered */
+ ehci_port_power(omap_ehci, 1);
+
return 0;
err_add_hcd:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index fe8dc06..bc94d7b 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
- pdev->device == 0x1E26;
+ (pdev->device == 0x1E26 ||
+ pdev->device == 0x8C2D ||
+ pdev->device == 0x8C26);
}
static void ehci_enable_xhci_companion(void)
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index d238b4e2..dfe881a 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -75,8 +75,6 @@ static const struct hc_driver ehci_platform_hc_driver = {
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
- .update_device = ehci_update_device,
-
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
@@ -94,12 +92,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
irq = platform_get_irq(dev, 0);
if (irq < 0) {
- pr_err("no irq provieded");
+ pr_err("no irq provided");
return irq;
}
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
- pr_err("no memory recourse provieded");
+ pr_err("no memory recourse provided");
return -ENXIO;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 36ca507..4378bf7 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -943,7 +943,8 @@ qh_make (
}
break;
default:
- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
+ urb->dev->speed);
done:
qh_put (qh);
return NULL;
@@ -981,14 +982,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
- u32 cmd = ehci_readl(ehci, &ehci->regs->command);
-
- if (!(cmd & CMD_ASE)) {
+ if (!(ehci->command & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
(void)handshake(ehci, &ehci->regs->status,
STS_ASS, 0, 150);
- cmd |= CMD_ASE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command |= CMD_ASE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write need not be known to HC yet ... */
}
}
@@ -1204,7 +1203,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@@ -1222,8 +1220,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci->rh_state != EHCI_RH_HALTED
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
- ehci_writel(ehci, cmd & ~CMD_ASE,
- &ehci->regs->command);
+ ehci->command &= ~CMD_ASE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1253,8 +1251,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
return;
}
- cmd |= CMD_IAAD;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
iaa_watchdog_start(ehci);
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index f098e2a..c474cec 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -232,6 +232,8 @@ static int s5p_ehci_suspend(struct device *dev)
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+ clk_disable(s5p_ehci->clk);
+
return rc;
}
@@ -243,6 +245,8 @@ static int s5p_ehci_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+ clk_enable(s5p_ehci->clk);
+
if (pdata && pdata->phy_init)
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a60679c..33182c6 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -481,7 +481,6 @@ static int tt_no_collision (
static int enable_periodic (struct ehci_hcd *ehci)
{
- u32 cmd;
int status;
if (ehci->periodic_sched++)
@@ -497,8 +496,8 @@ static int enable_periodic (struct ehci_hcd *ehci)
return status;
}
- cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command |= CMD_PSE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write ... PSS happens later */
/* make sure ehci_work scans these */
@@ -511,7 +510,6 @@ static int enable_periodic (struct ehci_hcd *ehci)
static int disable_periodic (struct ehci_hcd *ehci)
{
- u32 cmd;
int status;
if (--ehci->periodic_sched)
@@ -537,8 +535,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
return status;
}
- cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command &= ~CMD_PSE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write ... */
free_cached_lists(ehci);
@@ -1333,34 +1331,36 @@ sitd_slot_ok (
if (mask & ~0xffff)
return 0;
+ /* check bandwidth */
+ uframe %= period_uframes;
+ frame = uframe >> 3;
+
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+ /* The tt's fullspeed bus bandwidth must be available.
+ * tt_available scheduling guarantees 10+% for control/bulk.
+ */
+ uf = uframe & 7;
+ if (!tt_available(ehci, period_uframes >> 3,
+ stream->udev, frame, uf, stream->tt_usecs))
+ return 0;
+#else
+ /* tt must be idle for start(s), any gap, and csplit.
+ * assume scheduling slop leaves 10+% for control/bulk.
+ */
+ if (!tt_no_collision(ehci, period_uframes >> 3,
+ stream->udev, frame, mask))
+ return 0;
+#endif
+
/* this multi-pass logic is simple, but performance may
* suffer when the schedule data isn't cached.
*/
-
- /* check bandwidth */
- uframe %= period_uframes;
do {
u32 max_used;
frame = uframe >> 3;
uf = uframe & 7;
-#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
- /* The tt's fullspeed bus bandwidth must be available.
- * tt_available scheduling guarantees 10+% for control/bulk.
- */
- if (!tt_available (ehci, period_uframes << 3,
- stream->udev, frame, uf, stream->tt_usecs))
- return 0;
-#else
- /* tt must be idle for start(s), any gap, and csplit.
- * assume scheduling slop leaves 10+% for control/bulk.
- */
- if (!tt_no_collision (ehci, period_uframes << 3,
- stream->udev, frame, mask))
- return 0;
-#endif
-
/* check starts (OUT uses more than one) */
max_used = ehci->uframe_periodic_max - stream->usecs;
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
@@ -2358,7 +2358,8 @@ restart:
* in the previous frame for completions.
*/
if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
- dbg ("ignoring completions from FSTNs");
+ ehci_dbg(ehci,
+ "ignoring completions from FSTNs\n");
}
type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
q = q.fstn->fstn_next;
@@ -2441,7 +2442,7 @@ restart:
q = *q_p;
break;
default:
- dbg ("corrupt type %d frame %d shadow %p",
+ ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
type, frame, q.ptr);
// BUG ();
q.ptr = NULL;
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
new file mode 100644
index 0000000..cc199e8
--- /dev/null
+++ b/drivers/usb/host/ehci-sead3.c
@@ -0,0 +1,266 @@
+/*
+ * MIPS CI13320A EHCI Host Controller driver
+ * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
+ *
+ * Copyright (C) 2012 MIPS Technologies, 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_sead3_setup(struct usb_hcd *hcd)
+{
+ int ret;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs + 0x100;
+
+#ifdef __BIG_ENDIAN
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+#endif
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ehci->need_io_watchdog = 0;
+
+ /* Set burst length to 16 words. */
+ ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]);
+
+ return ret;
+}
+
+const struct hc_driver ehci_sead3_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SEAD-3 EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ *
+ */
+ .reset = ehci_sead3_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,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * 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,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+ hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3");
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ ret = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* Root hub has integrated TT. */
+ hcd->has_tt = 1;
+
+ ret = usb_add_hcd(hcd, pdev->resource[1].start,
+ IRQF_SHARED);
+ if (ret == 0) {
+ platform_set_drvdata(pdev, hcd);
+ return ret;
+ }
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ehci_hcd_sead3_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ unsigned long flags;
+ int rc = 0;
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(20);
+
+ /* Root hub was already suspended. Disable irq emission and
+ * mark HW unaccessible. The PM and USB cores make sure that
+ * the root hub is either suspended or stopped.
+ */
+ ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ /* could save FLADJ in case of Vaux power loss
+ * ... we'd only use it to handle clock skew
+ */
+
+ return rc;
+}
+
+static int ehci_hcd_sead3_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ /* maybe restore FLADJ. */
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(100);
+
+ /* Mark hardware accessible again as we are out of D3 state by now */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* If CF is still set, we maintained PCI Vaux power.
+ * Just undo the effect of ehci_pci_suspend().
+ */
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+ int mask = INTR_MASK;
+
+ ehci_prepare_ports_for_controller_resume(ehci);
+ if (!hcd->self.root_hub->do_remote_wakeup)
+ mask &= ~STS_PCD;
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
+ return 0;
+ }
+
+ ehci_dbg(ehci, "lost power, restarting\n");
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ /* Else reset, to cope with power loss or flush-to-storage
+ * style "resume" having let BIOS kick in during reboot.
+ */
+ (void) ehci_halt(ehci);
+ (void) ehci_reset(ehci);
+
+ /* emptying the schedule aborts any urbs */
+ spin_lock_irq(&ehci->lock);
+ if (ehci->reclaim)
+ end_unlink_async(ehci);
+ ehci_work(ehci);
+ spin_unlock_irq(&ehci->lock);
+
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+
+ /* here we "know" root ports should always stay powered */
+ ehci_port_power(ehci, 1);
+
+ ehci->rh_state = EHCI_RH_SUSPENDED;
+
+ return 0;
+}
+
+static const struct dev_pm_ops sead3_ehci_pmops = {
+ .suspend = ehci_hcd_sead3_drv_suspend,
+ .resume = ehci_hcd_sead3_drv_resume,
+};
+
+#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops)
+
+#else
+#define SEAD3_EHCI_PMOPS NULL
+#endif
+
+static struct platform_driver ehci_hcd_sead3_driver = {
+ .probe = ehci_hcd_sead3_drv_probe,
+ .remove = ehci_hcd_sead3_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "sead3-ehci",
+ .owner = THIS_MODULE,
+ .pm = SEAD3_EHCI_PMOPS,
+ }
+};
+
+MODULE_ALIAS("platform:sead3-ehci");
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 9d9cf47..ca819cd 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -11,6 +11,7 @@
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/platform_data/ehci-sh.h>
struct ehci_sh_priv {
struct clk *iclk, *fclk;
@@ -100,6 +101,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
const struct hc_driver *driver = &ehci_sh_hc_driver;
struct resource *res;
struct ehci_sh_priv *priv;
+ struct ehci_sh_platdata *pdata;
struct usb_hcd *hcd;
int irq, ret;
@@ -124,6 +126,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
+ if (pdev->dev.platform_data != NULL)
+ pdata = pdev->dev.platform_data;
+
/* initialize hcd */
hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
@@ -168,6 +173,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
clk_enable(priv->fclk);
clk_enable(priv->iclk);
+ if (pdata && pdata->phy_init)
+ pdata->phy_init();
+
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd");
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 6e92855..37ba8c8 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/jiffies.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -25,12 +26,12 @@ struct spear_ehci {
static void spear_start_ehci(struct spear_ehci *ehci)
{
- clk_enable(ehci->clk);
+ clk_prepare_enable(ehci->clk);
}
static void spear_stop_ehci(struct spear_ehci *ehci)
{
- clk_disable(ehci->clk);
+ clk_disable_unprepare(ehci->clk);
}
static int ehci_spear_setup(struct usb_hcd *hcd)
@@ -168,6 +169,8 @@ static int ehci_spear_drv_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
ehci_spear_drv_resume);
+static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
+
static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
@@ -175,12 +178,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
struct resource *res;
struct clk *usbh_clk;
const struct hc_driver *driver = &ehci_spear_hc_driver;
- int *pdata = pdev->dev.platform_data;
int irq, retval;
char clk_name[20] = "usbh_clk";
-
- if (pdata == NULL)
- return -EFAULT;
+ static int instance = -1;
if (usb_disabled())
return -ENODEV;
@@ -191,8 +191,22 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
goto fail_irq_get;
}
- if (*pdata >= 0)
- sprintf(clk_name, "usbh.%01d_clk", *pdata);
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &spear_ehci_dma_mask;
+
+ /*
+ * Increment the device instance, when probing via device-tree
+ */
+ if (pdev->id < 0)
+ instance++;
+ else
+ instance = pdev->id;
+ sprintf(clk_name, "usbh.%01d_clk", instance);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
@@ -277,6 +291,11 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
return 0;
}
+static struct of_device_id spear_ehci_id_table[] __devinitdata = {
+ { .compatible = "st,spear600-ehci", },
+ { },
+};
+
static struct platform_driver spear_ehci_hcd_driver = {
.probe = spear_ehci_hcd_drv_probe,
.remove = spear_ehci_hcd_drv_remove,
@@ -285,6 +304,7 @@ static struct platform_driver spear_ehci_hcd_driver = {
.name = "spear-ehci",
.bus = &platform_bus_type,
.pm = &ehci_spear_pm_ops,
+ .of_match_table = of_match_ptr(spear_ehci_id_table),
}
};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index f214a80..4a44bf8 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -147,18 +147,7 @@ static int tegra_ehci_hub_control(
spin_lock_irqsave(&ehci->lock, flags);
- /*
- * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
- * that are write on clear, by writing back the register read value, so
- * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
- */
- if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
- temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
- ehci_writel(ehci, temp & ~PORT_PE, status_reg);
- goto done;
- }
-
- else if (typeReq == GetPortStatus) {
+ if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* Resume completed, re-enable disconnect detection */
@@ -174,7 +163,7 @@ static int tegra_ehci_hub_control(
goto done;
}
- temp &= ~PORT_WKCONN_E;
+ temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
@@ -319,26 +308,23 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
return retval;
}
-struct temp_buffer {
+struct dma_aligned_buffer {
void *kmalloc_ptr;
void *old_xfer_buffer;
u8 data[0];
};
-static void free_temp_buffer(struct urb *urb)
+static void free_dma_aligned_buffer(struct urb *urb)
{
- enum dma_data_direction dir;
- struct temp_buffer *temp;
+ struct dma_aligned_buffer *temp;
if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return;
- dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
- temp = container_of(urb->transfer_buffer, struct temp_buffer,
- data);
+ temp = container_of(urb->transfer_buffer,
+ struct dma_aligned_buffer, data);
- if (dir == DMA_FROM_DEVICE)
+ if (usb_urb_dir_in(urb))
memcpy(temp->old_xfer_buffer, temp->data,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->old_xfer_buffer;
@@ -347,10 +333,9 @@ static void free_temp_buffer(struct urb *urb)
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}
-static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
{
- enum dma_data_direction dir;
- struct temp_buffer *temp, *kmalloc_ptr;
+ struct dma_aligned_buffer *temp, *kmalloc_ptr;
size_t kmalloc_size;
if (urb->num_sgs || urb->sg ||
@@ -358,22 +343,19 @@ static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
!((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
return 0;
- dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
/* Allocate a buffer with enough padding for alignment */
kmalloc_size = urb->transfer_buffer_length +
- sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1;
+ sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1;
kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM;
- /* Position our struct temp_buffer such that data is aligned */
+ /* Position our struct dma_aligned_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
-
temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
- if (dir == DMA_TO_DEVICE)
+ if (usb_urb_dir_out(urb))
memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;
@@ -388,13 +370,13 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
{
int ret;
- ret = alloc_temp_buffer(urb, mem_flags);
+ ret = alloc_dma_aligned_buffer(urb, mem_flags);
if (ret)
return ret;
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret)
- free_temp_buffer(urb);
+ free_dma_aligned_buffer(urb);
return ret;
}
@@ -402,49 +384,51 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
usb_hcd_unmap_urb_for_dma(hcd, urb);
- free_temp_buffer(urb);
+ free_dma_aligned_buffer(urb);
}
static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
-
.flags = HCD_USB2 | HCD_MEMORY,
- .reset = tegra_ehci_setup,
+ /* standard ehci functions */
.irq = ehci_irq,
-
.start = ehci_run,
.stop = ehci_stop,
- .shutdown = tegra_ehci_shutdown,
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
- .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
- .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
- .hub_control = tegra_ehci_hub_control,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /* modified ehci functions for tegra */
+ .reset = tegra_ehci_setup,
+ .shutdown = tegra_ehci_shutdown,
+ .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
+ .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
+ .hub_control = tegra_ehci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
};
-static int setup_vbus_gpio(struct platform_device *pdev)
+static int setup_vbus_gpio(struct platform_device *pdev,
+ struct tegra_ehci_platform_data *pdata)
{
int err = 0;
int gpio;
- if (!pdev->dev.of_node)
- return 0;
-
- gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0);
+ gpio = pdata->vbus_gpio;
+ if (!gpio_is_valid(gpio))
+ gpio = of_get_named_gpio(pdev->dev.of_node,
+ "nvidia,vbus-gpio", 0);
if (!gpio_is_valid(gpio))
return 0;
@@ -664,7 +648,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &tegra_ehci_dma_mask;
- setup_vbus_gpio(pdev);
+ setup_vbus_gpio(pdev, pdata);
tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
if (!tegra)
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 0ea577b..c5ed881 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -155,7 +155,7 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
struct endpoint *ep;
struct usb_td __iomem *td;
unsigned long ep_offset;
- char *err_for = "enpoint PRAM";
+ char *err_for = "endpoint PRAM";
int ep_mem_size;
u32 i;
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index ab333ac..22ff6b3a 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -119,6 +119,39 @@ error:
static const struct of_device_id fsl_usb2_mph_dr_of_match[];
+static int usb_get_ver_info(struct device_node *np)
+{
+ int ver = -1;
+
+ /*
+ * returns 1 for usb controller version 1.6
+ * returns 2 for usb controller version 2.2
+ * returns 0 otherwise
+ */
+ if (of_device_is_compatible(np, "fsl-usb2-dr")) {
+ if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
+ ver = FSL_USB_VER_1_6;
+ else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
+ ver = FSL_USB_VER_2_2;
+ else /* for previous controller versions */
+ ver = FSL_USB_VER_OLD;
+
+ if (ver > -1)
+ return ver;
+ }
+
+ if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+ if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
+ ver = FSL_USB_VER_1_6;
+ else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
+ ver = FSL_USB_VER_2_2;
+ else /* for previous controller versions */
+ ver = FSL_USB_VER_OLD;
+ }
+
+ return ver;
+}
+
static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
@@ -166,6 +199,14 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
prop = of_get_property(np, "phy_type", NULL);
pdata->phy_mode = determine_usb_phy(prop);
+ pdata->controller_ver = usb_get_ver_info(np);
+
+ if (pdata->have_sysif_regs) {
+ if (pdata->controller_ver < 0) {
+ dev_warn(&ofdev->dev, "Could not get controller version\n");
+ return -ENODEV;
+ }
+ }
for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
if (!dev_data->drivers[i])
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index fc72d44..a35bbdd 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -1562,11 +1562,14 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
retval = -ESHUTDOWN;
+ qtd_list_free(&new_qtds);
goto out;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval)
+ if (retval) {
+ qtd_list_free(&new_qtds);
goto out;
+ }
qh = urb->ep->hcpriv;
if (qh) {
@@ -1584,6 +1587,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
if (!qh) {
retval = -ENOMEM;
usb_hcd_unlink_urb_from_ep(hcd, urb);
+ qtd_list_free(&new_qtds);
goto out;
}
list_add_tail(&qh->qh_list, ep_queue);
@@ -1683,6 +1687,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
if (qtd->urb == urb) {
dequeue_urb_from_qtd(hcd, qh, qtd);
+ list_move(&qtd->qtd_list, &qh->qtd_list);
break;
}
@@ -2176,7 +2181,7 @@ static const struct hc_driver isp1760_hc_driver = {
int __init init_kmem_once(void)
{
- urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem",
+ urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
SLAB_MEM_SPREAD, NULL);
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 4592dc1..fff114f 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -398,6 +398,9 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, -ENOENT,
&pdev->dev, dev_name(&pdev->dev), devflags);
+
+ dev_set_drvdata(&pdev->dev, hcd);
+
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;
@@ -417,11 +420,16 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev)
{
struct resource *mem_res;
resource_size_t mem_size;
+ struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
+
+ usb_remove_hcd(hcd);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem_size = resource_size(mem_res);
release_mem_region(mem_res->start, mem_size);
+ usb_put_hcd(hcd);
+
return 0;
}
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 13ebeca..a665b3e 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver,
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ hcd->rsrc_len = resource_size(&pdev->resource[0]);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed\n");
@@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd,
/*-------------------------------------------------------------------------*/
static int __devinit
-ohci_at91_start (struct usb_hcd *hcd)
+ohci_at91_reset (struct usb_hcd *hcd)
{
struct at91_usbh_data *board = hcd->self.controller->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@@ -233,9 +233,18 @@ ohci_at91_start (struct usb_hcd *hcd)
return ret;
ohci->num_ports = board->ports;
+ return 0;
+}
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
@@ -418,6 +427,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
/*
* basic lifecycle operations
*/
+ .reset = ohci_at91_reset,
.start = ohci_at91_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 4ea63b2..c611699 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -37,7 +37,8 @@ static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c
index 5a00a1e..2c9f233 100644
--- a/drivers/usb/host/ohci-cns3xxx.c
+++ b/drivers/usb/host/ohci-cns3xxx.c
@@ -41,7 +41,8 @@ cns3xxx_ohci_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 8435097..269b1e0 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -454,3 +454,5 @@ static struct platform_driver ohci_hcd_da8xx_driver = {
.name = "ohci",
},
};
+
+MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index e4bcb62..31b81f9 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -29,14 +29,14 @@ urb_print(struct urb * urb, char * str, int small, int status)
unsigned int pipe= urb->pipe;
if (!urb->dev || !urb->dev->bus) {
- dbg("%s URB: no dev", str);
+ printk(KERN_DEBUG "%s URB: no dev\n", str);
return;
}
#ifndef OHCI_VERBOSE_DEBUG
if (status != 0)
#endif
- dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
+ printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n",
str,
urb,
usb_pipedevice (pipe),
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3d63574..dbfbd1d 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
struct usb_hcd *hcd;
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
- dbg("resource[1] is not IORESOURCE_IRQ");
+ dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
return -ENOMEM;
}
@@ -65,14 +65,14 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
- dbg("ioremap failed");
+ dev_dbg(&pdev->dev, "ioremap failed\n");
retval = -ENOMEM;
goto err2;
}
usb_host_clock = clk_get(&pdev->dev, NULL);
if (IS_ERR(usb_host_clock)) {
- dbg("clk_get failed");
+ dev_dbg(&pdev->dev, "clk_get failed\n");
retval = PTR_ERR(usb_host_clock);
goto err3;
}
@@ -116,7 +116,8 @@ static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 37bb20e..2909621 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -35,7 +35,8 @@ static int ohci_exynos_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 235171f..e0adf5c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1080,11 +1080,6 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
-#ifdef CONFIG_USB_OHCI_HCD_SSB
-#include "ohci-ssb.c"
-#define SSB_OHCI_DRIVER ssb_ohci_driver
-#endif
-
#ifdef CONFIG_MFD_SM501
#include "ohci-sm501.c"
#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver
@@ -1128,8 +1123,7 @@ MODULE_LICENSE ("GPL");
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(SM501_OHCI_DRIVER) && \
- !defined(TMIO_OHCI_DRIVER) && \
- !defined(SSB_OHCI_DRIVER)
+ !defined(TMIO_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -1195,12 +1189,6 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
-#ifdef SSB_OHCI_DRIVER
- retval = ssb_driver_register(&SSB_OHCI_DRIVER);
- if (retval)
- goto error_ssb;
-#endif
-
#ifdef SM501_OHCI_DRIVER
retval = platform_driver_register(&SM501_OHCI_DRIVER);
if (retval < 0)
@@ -1224,10 +1212,6 @@ static int __init ohci_hcd_mod_init(void)
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
pci_unregister_driver(&PCI_DRIVER);
error_pci:
@@ -1275,9 +1259,6 @@ static void __exit ohci_hcd_mod_exit(void)
#ifdef SM501_OHCI_DRIVER
platform_driver_unregister(&SM501_OHCI_DRIVER);
#endif
-#ifdef SSB_OHCI_DRIVER
- ssb_driver_unregister(&SSB_OHCI_DRIVER);
-#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 6618de1..1e364ec 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -22,6 +22,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -29,7 +31,6 @@
#include <mach/platform.h>
#include <mach/irqs.h>
-#include <asm/gpio.h>
#define USB_CONFIG_BASE 0x31020000
#define PWRMAN_BASE 0x40004000
@@ -38,7 +39,9 @@
/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_DEV_NEED_CLK_EN (1 << 22)
#define USB_HOST_NEED_CLK_EN (1 << 21)
+#define PAD_CONTROL_LAST_DRIVEN (1 << 19)
#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
@@ -56,54 +59,6 @@
#define TRANSPARENT_I2C_EN (1 << 7)
#define HOST_EN (1 << 0)
-/* ISP1301 USB transceiver I2C registers */
-#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
-
-#define MC1_SPEED_REG (1 << 0)
-#define MC1_SUSPEND_REG (1 << 1)
-#define MC1_DAT_SE0 (1 << 2)
-#define MC1_TRANSPARENT (1 << 3)
-#define MC1_BDIS_ACON_EN (1 << 4)
-#define MC1_OE_INT_EN (1 << 5)
-#define MC1_UART_EN (1 << 6)
-#define MC1_MASK 0x7f
-
-#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
-
-#define MC2_GLOBAL_PWR_DN (1 << 0)
-#define MC2_SPD_SUSP_CTRL (1 << 1)
-#define MC2_BI_DI (1 << 2)
-#define MC2_TRANSP_BDIR0 (1 << 3)
-#define MC2_TRANSP_BDIR1 (1 << 4)
-#define MC2_AUDIO_EN (1 << 5)
-#define MC2_PSW_EN (1 << 6)
-#define MC2_EN2V7 (1 << 7)
-
-#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
-# define OTG1_DP_PULLUP (1 << 0)
-# define OTG1_DM_PULLUP (1 << 1)
-# define OTG1_DP_PULLDOWN (1 << 2)
-# define OTG1_DM_PULLDOWN (1 << 3)
-# define OTG1_ID_PULLDOWN (1 << 4)
-# define OTG1_VBUS_DRV (1 << 5)
-# define OTG1_VBUS_DISCHRG (1 << 6)
-# define OTG1_VBUS_CHRG (1 << 7)
-#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
-# define OTG_B_SESS_END (1 << 6)
-# define OTG_B_SESS_VLD (1 << 7)
-
-#define ISP1301_I2C_ADDR 0x2C
-
-#define ISP1301_I2C_MODE_CONTROL_1 0x4
-#define ISP1301_I2C_MODE_CONTROL_2 0x12
-#define ISP1301_I2C_OTG_CONTROL_1 0x6
-#define ISP1301_I2C_OTG_CONTROL_2 0x10
-#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
-#define ISP1301_I2C_INTERRUPT_LATCH 0xA
-#define ISP1301_I2C_INTERRUPT_FALLING 0xC
-#define ISP1301_I2C_INTERRUPT_RISING 0xE
-#define ISP1301_I2C_REG_CLEAR_ADDR 1
-
/* On LPC32xx, those are undefined */
#ifndef start_int_set_falling_edge
#define start_int_set_falling_edge(irq)
@@ -113,42 +68,12 @@
#define start_int_umask(irq)
#endif
-static struct i2c_driver isp1301_driver;
static struct i2c_client *isp1301_i2c_client;
extern int usb_disabled(void);
-extern int ocpi_enable(void);
static struct clk *usb_clk;
-static const unsigned short normal_i2c[] =
- { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-
-static int isp1301_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
- return 0;
-}
-
-static const struct i2c_device_id isp1301_id[] = {
- { "isp1301_nxp", 0 },
- { }
-};
-
-static struct i2c_driver isp1301_driver = {
- .driver = {
- .name = "isp1301_nxp",
- },
- .probe = isp1301_probe,
- .remove = isp1301_remove,
- .id_table = isp1301_id,
-};
-
static void isp1301_configure_pnx4008(void)
{
/* PNX4008 only supports DAT_SE0 USB mode */
@@ -220,7 +145,7 @@ static void isp1301_configure_lpc32xx(void)
ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
/* Enable usb_need_clk clock after transceiver is initialized */
- __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+ __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n",
i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
@@ -372,65 +297,55 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
const struct hc_driver *driver = &ohci_nxp_hc_driver;
- struct i2c_adapter *i2c_adap;
- struct i2c_board_info i2c_info;
-
+ struct resource *res;
int ret = 0, irq;
+ struct device_node *isp1301_node;
- dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
- if (usb_disabled()) {
- err("USB is disabled");
- ret = -ENODEV;
- goto out;
+ if (pdev->dev.of_node) {
+ isp1301_node = of_parse_phandle(pdev->dev.of_node,
+ "transceiver", 0);
+ } else {
+ isp1301_node = NULL;
}
- if (pdev->num_resources != 2
- || pdev->resource[0].flags != IORESOURCE_MEM
- || pdev->resource[1].flags != IORESOURCE_IRQ) {
- err("Invalid resource configuration");
- ret = -ENODEV;
+ isp1301_i2c_client = isp1301_get_client(isp1301_node);
+ if (!isp1301_i2c_client) {
+ ret = -EPROBE_DEFER;
goto out;
}
- /* Enable AHB slave USB clock, needed for further USB clock control */
- __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
- ret = i2c_add_driver(&isp1301_driver);
- if (ret < 0) {
- err("failed to add ISP1301 driver");
- goto out;
- }
- i2c_adap = i2c_get_adapter(2);
- memset(&i2c_info, 0, sizeof(struct i2c_board_info));
- strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
- isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
- normal_i2c, NULL);
- i2c_put_adapter(i2c_adap);
- if (!isp1301_i2c_client) {
- err("failed to connect I2C to ISP1301 USB Transceiver");
+ dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
+ if (usb_disabled()) {
+ dev_err(&pdev->dev, "USB is disabled\n");
ret = -ENODEV;
- goto out_i2c_driver;
+ goto out;
}
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
+
isp1301_configure();
/* Enable USB PLL */
usb_clk = clk_get(&pdev->dev, "ck_pll5");
if (IS_ERR(usb_clk)) {
- err("failed to acquire USB PLL");
+ dev_err(&pdev->dev, "failed to acquire USB PLL\n");
ret = PTR_ERR(usb_clk);
goto out1;
}
ret = clk_enable(usb_clk);
if (ret < 0) {
- err("failed to start USB PLL");
+ dev_err(&pdev->dev, "failed to start USB PLL\n");
goto out2;
}
ret = clk_set_rate(usb_clk, 48000);
if (ret < 0) {
- err("failed to set USB clock rate");
+ dev_err(&pdev->dev, "failed to set USB clock rate\n");
goto out3;
}
@@ -442,9 +357,9 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
USB_CLOCK_MASK) ;
- hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
- err("Failed to allocate HC buffer");
+ dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM;
goto out3;
}
@@ -452,14 +367,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
/* Set all USB bits in the Start Enable register */
nxp_set_usb_bits();
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get MEM resource\n");
+ ret = -ENOMEM;
+ goto out4;
+ }
+
+ hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
ret = -ENOMEM;
goto out4;
}
- hcd->regs = (void __iomem *)pdev->resource[0].start;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -486,10 +408,7 @@ out3:
out2:
clk_put(usb_clk);
out1:
- i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
-out_i2c_driver:
- i2c_del_driver(&isp1301_driver);
out:
return ret;
}
@@ -507,7 +426,6 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
clk_put(usb_clk);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
- i2c_del_driver(&isp1301_driver);
platform_set_drvdata(pdev, NULL);
@@ -517,10 +435,19 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:usb-ohci");
+#ifdef CONFIG_OF
+static const struct of_device_id usb_hcd_nxp_match[] = {
+ { .compatible = "nxp,ohci-nxp" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match);
+#endif
+
static struct platform_driver usb_hcd_nxp_driver = {
.driver = {
.name = "usb-ohci",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(usb_hcd_nxp_match),
},
.probe = usb_hcd_nxp_probe,
.remove = usb_hcd_nxp_remove,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 96451e4..9ce35d0 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -205,8 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd)
need_transceiver = need_transceiver
|| machine_is_omap_h2() || machine_is_omap_h3();
- if (cpu_is_omap16xx())
- ocpi_enable();
+ /* XXX OMAP16xx only */
+ if (config->ocpi_enable)
+ config->ocpi_enable();
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
@@ -217,8 +218,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
if (status) {
- if (ohci->transceiver)
- put_device(ohci->transceiver->dev);
+ usb_put_transceiver(ohci->transceiver);
return status;
}
} else {
@@ -405,7 +405,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
usb_remove_hcd(hcd);
if (ohci->transceiver) {
(void) otg_set_host(ohci->transceiver->otg, 0);
- put_device(ohci->transceiver->dev);
+ usb_put_transceiver(ohci->transceiver);
}
if (machine_is_omap_osk())
gpio_free(9);
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index ec5c679..670c705 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -93,13 +93,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
irq = platform_get_irq(dev, 0);
if (irq < 0) {
- pr_err("no irq provieded");
+ pr_err("no irq provided");
return irq;
}
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
- pr_err("no memory recourse provieded");
+ pr_err("no memory recourse provided");
return -ENXIO;
}
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index f13d08f..148d27d 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -157,7 +157,8 @@ ohci_pnx8550_start (struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop (hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index d24cc89d..e27d5ae 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -29,7 +29,8 @@ ohci_ppc_of_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
@@ -236,7 +237,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
-#error "No endianess selected for ppc-of-ohci"
+#error "No endianness selected for ppc-of-ohci"
#endif
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1514b70..185c39e 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -130,7 +130,8 @@ ohci_ppc_soc_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 6fd4fa1..2ee1d8d 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -45,7 +45,8 @@ static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
result = ohci_run(ohci);
if (result < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
}
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index c31b281..e1a3cc6 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -419,7 +419,8 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop (hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 56dcf06..664c869 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -420,7 +420,8 @@ ohci_s3c2410_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index e1004fb..b6cc925 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -46,7 +46,7 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{
unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
- dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+ printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label,
((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
@@ -193,7 +193,7 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
hcd->rsrc_len = resource_size(&dev->res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dbg("request_mem_region failed");
+ dev_dbg(&dev->dev, "request_mem_region failed\n");
ret = -EBUSY;
goto err1;
}
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 84686d9..76a20c2 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -88,20 +88,20 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- err("platform_get_resource error.");
+ dev_err(&pdev->dev, "platform_get_resource error.\n");
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- err("platform_get_irq error.");
+ dev_err(&pdev->dev, "platform_get_irq error.\n");
return -ENODEV;
}
/* initialize hcd */
hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
if (!hcd) {
- err("Failed to create hcd");
+ dev_err(&pdev->dev, "Failed to create hcd\n");
return -ENOMEM;
}
@@ -110,7 +110,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
hcd->rsrc_len = resource_size(res);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
- err("Failed to add hcd");
+ dev_err(&pdev->dev, "Failed to add hcd\n");
usb_put_hcd(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 95c1648..fc7305e 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -14,6 +14,7 @@
#include <linux/signal.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/of.h>
struct spear_ohci {
struct ohci_hcd ohci;
@@ -24,12 +25,12 @@ struct spear_ohci {
static void spear_start_ohci(struct spear_ohci *ohci)
{
- clk_enable(ohci->clk);
+ clk_prepare_enable(ohci->clk);
}
static void spear_stop_ohci(struct spear_ohci *ohci)
{
- clk_disable(ohci->clk);
+ clk_disable_unprepare(ohci->clk);
}
static int __devinit ohci_spear_start(struct usb_hcd *hcd)
@@ -90,6 +91,8 @@ static const struct hc_driver ohci_spear_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
+static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32);
+
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
@@ -98,11 +101,8 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
struct spear_ohci *ohci_p;
struct resource *res;
int retval, irq;
- int *pdata = pdev->dev.platform_data;
char clk_name[20] = "usbh_clk";
-
- if (pdata == NULL)
- return -EFAULT;
+ static int instance = -1;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -110,8 +110,22 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
goto fail_irq_get;
}
- if (*pdata >= 0)
- sprintf(clk_name, "usbh.%01d_clk", *pdata);
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &spear_ohci_dma_mask;
+
+ /*
+ * Increment the device instance, when probing via device-tree
+ */
+ if (pdev->id < 0)
+ instance++;
+ else
+ instance = pdev->id;
+ sprintf(clk_name, "usbh.%01d_clk", instance);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
@@ -222,6 +236,11 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev)
}
#endif
+static struct of_device_id spear_ohci_id_table[] __devinitdata = {
+ { .compatible = "st,spear600-ohci", },
+ { },
+};
+
/* Driver definition to register with the platform bus */
static struct platform_driver spear_ohci_hcd_driver = {
.probe = spear_ohci_hcd_drv_probe,
@@ -233,6 +252,7 @@ static struct platform_driver spear_ohci_hcd_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "spear-ohci",
+ .of_match_table = of_match_ptr(spear_ohci_id_table),
},
};
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
deleted file mode 100644
index 5ba1859..0000000
--- a/drivers/usb/host/ohci-ssb.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Sonics Silicon Backplane
- * Broadcom USB-core OHCI driver
- *
- * Copyright 2007 Michael Buesch <m@bues.ch>
- *
- * Derived from the OHCI-PCI driver
- * Copyright 1999 Roman Weissgaerber
- * Copyright 2000-2002 David Brownell
- * Copyright 1999 Linus Torvalds
- * Copyright 1999 Gregory P. Smith
- *
- * Derived from the USBcore related parts of Broadcom-SB
- * Copyright 2005 Broadcom Corporation
- *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-#include <linux/ssb/ssb.h>
-
-
-#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
-
-struct ssb_ohci_device {
- struct ohci_hcd ohci; /* _must_ be at the beginning. */
-
- u32 enable_flags;
-};
-
-static inline
-struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
-{
- return (struct ssb_ohci_device *)(hcd->hcd_priv);
-}
-
-
-static int ssb_ohci_reset(struct usb_hcd *hcd)
-{
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
- struct ohci_hcd *ohci = &ohcidev->ohci;
- int err;
-
- ohci_hcd_init(ohci);
- err = ohci_init(ohci);
-
- return err;
-}
-
-static int ssb_ohci_start(struct usb_hcd *hcd)
-{
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
- struct ohci_hcd *ohci = &ohcidev->ohci;
- int err;
-
- err = ohci_run(ohci);
- if (err < 0) {
- ohci_err(ohci, "can't start\n");
- ohci_stop(hcd);
- }
-
- return err;
-}
-
-static const struct hc_driver ssb_ohci_hc_driver = {
- .description = "ssb-usb-ohci",
- .product_desc = "SSB OHCI Controller",
- .hcd_priv_size = sizeof(struct ssb_ohci_device),
-
- .irq = ohci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
-
- .reset = ssb_ohci_reset,
- .start = ssb_ohci_start,
- .stop = ohci_stop,
- .shutdown = ohci_shutdown,
-
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- .get_frame_number = ohci_get_frame,
-
- .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 void ssb_ohci_detach(struct ssb_device *dev)
-{
- struct usb_hcd *hcd = ssb_get_drvdata(dev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
- ssb_device_disable(dev, 0);
-}
-
-static int ssb_ohci_attach(struct ssb_device *dev)
-{
- struct ssb_ohci_device *ohcidev;
- struct usb_hcd *hcd;
- int err = -ENOMEM;
- u32 tmp, flags = 0;
-
- if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
- dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
- return -EOPNOTSUPP;
-
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
- /* Put the device into host-mode. */
- flags |= SSB_OHCI_TMSLOW_HOSTMODE;
- ssb_device_enable(dev, flags);
- } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
- /*
- * USB 2.0 special considerations:
- *
- * In addition to the standard SSB reset sequence, the Host
- * Control Register must be programmed to bring the USB core
- * and various phy components out of reset.
- */
- ssb_device_enable(dev, 0);
- ssb_write32(dev, 0x200, 0x7ff);
-
- /* Change Flush control reg */
- tmp = ssb_read32(dev, 0x400);
- tmp &= ~8;
- ssb_write32(dev, 0x400, tmp);
- tmp = ssb_read32(dev, 0x400);
-
- /* Change Shim control reg */
- tmp = ssb_read32(dev, 0x304);
- tmp &= ~0x100;
- ssb_write32(dev, 0x304, tmp);
- tmp = ssb_read32(dev, 0x304);
-
- udelay(1);
-
- /* Work around for 5354 failures */
- if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
- /* Change syn01 reg */
- tmp = 0x00fe00fe;
- ssb_write32(dev, 0x894, tmp);
-
- /* Change syn03 reg */
- tmp = ssb_read32(dev, 0x89c);
- tmp |= 0x1;
- ssb_write32(dev, 0x89c, tmp);
- }
- } else
- ssb_device_enable(dev, 0);
-
- hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
- dev_name(dev->dev));
- if (!hcd)
- goto err_dev_disable;
- ohcidev = hcd_to_ssb_ohci(hcd);
- ohcidev->enable_flags = flags;
-
- tmp = ssb_read32(dev, SSB_ADMATCH0);
- hcd->rsrc_start = ssb_admatch_base(tmp);
- hcd->rsrc_len = ssb_admatch_size(tmp);
- hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs)
- goto err_put_hcd;
- err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
- if (err)
- goto err_iounmap;
-
- ssb_set_drvdata(dev, hcd);
-
- return err;
-
-err_iounmap:
- iounmap(hcd->regs);
-err_put_hcd:
- usb_put_hcd(hcd);
-err_dev_disable:
- ssb_device_disable(dev, flags);
- return err;
-}
-
-static int ssb_ohci_probe(struct ssb_device *dev,
- const struct ssb_device_id *id)
-{
- int err;
- u16 chipid_top;
-
- /* USBcores are only connected on embedded devices. */
- chipid_top = (dev->bus->chip_id & 0xFF00);
- if (chipid_top != 0x4700 && chipid_top != 0x5300)
- return -ENODEV;
-
- /* TODO: Probably need checks here; is the core connected? */
-
- if (usb_disabled())
- return -ENODEV;
-
- /* We currently always attach SSB_DEV_USB11_HOSTDEV
- * as HOST OHCI. If we want to attach it as Client device,
- * we must branch here and call into the (yet to
- * be written) Client mode driver. Same for remove(). */
-
- err = ssb_ohci_attach(dev);
-
- return err;
-}
-
-static void ssb_ohci_remove(struct ssb_device *dev)
-{
- ssb_ohci_detach(dev);
-}
-
-#ifdef CONFIG_PM
-
-static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
-{
- ssb_device_disable(dev, 0);
-
- return 0;
-}
-
-static int ssb_ohci_resume(struct ssb_device *dev)
-{
- struct usb_hcd *hcd = ssb_get_drvdata(dev);
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-
- ssb_device_enable(dev, ohcidev->enable_flags);
-
- ohci_finish_controller_resume(hcd);
- return 0;
-}
-
-#else /* !CONFIG_PM */
-#define ssb_ohci_suspend NULL
-#define ssb_ohci_resume NULL
-#endif /* CONFIG_PM */
-
-static const struct ssb_device_id ssb_ohci_table[] = {
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
- SSB_DEVTABLE_END
-};
-MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
-
-static struct ssb_driver ssb_ohci_driver = {
- .name = KBUILD_MODNAME,
- .id_table = ssb_ohci_table,
- .probe = ssb_ohci_probe,
- .remove = ssb_ohci_remove,
- .suspend = ssb_ohci_suspend,
- .resume = ssb_ohci_resume,
-};
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index 120bfe6..60c2b07 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -140,7 +140,8 @@ static int ohci_tmio_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index a224786..41e378f 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -88,7 +88,8 @@ static int __devinit ohci_xls_start(struct usb_hcd *hcd)
ohci = hcd_to_ohci(hcd);
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 3b38030..4f0f033 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1399,8 +1399,8 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
- dbg("intr period %d uframes, NYET!",
- urb->interval);
+ oxu_dbg(oxu, "intr period %d uframes, NYET!\n",
+ urb->interval);
goto done;
}
} else {
@@ -1471,7 +1471,7 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
}
break;
default:
- dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed);
done:
qh_put(qh);
return NULL;
@@ -2307,7 +2307,7 @@ restart:
qh_put(temp.qh);
break;
default:
- dbg("corrupt type %d frame %d shadow %p",
+ oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n",
type, frame, q.ptr);
q.ptr = NULL;
}
@@ -2991,8 +2991,9 @@ static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* shouldn't happen often, but ...
* FIXME kill those tds' urbs
*/
- err("can't reschedule qh %p, err %d",
- qh, status);
+ dev_err(hcd->self.controller,
+ "can't reschedule qh %p, err %d\n", qh,
+ status);
}
return status;
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 32dada8..df0828c 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -9,6 +9,7 @@
*/
#include <linux/types.h>
+#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -712,12 +713,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
return -ETIMEDOUT;
}
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
+
+bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
}
+
+/* The Intel Lynx Point chipset also has switchable ports. */
+bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
+{
+ return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
+ pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI;
+}
+
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+{
+ return usb_is_intel_ppt_switchable_xhci(pdev) ||
+ usb_is_intel_lpt_switchable_xhci(pdev);
+}
EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
/*
@@ -742,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
{
u32 ports_available;
+ /* Don't switchover the ports if the user hasn't compiled the xHCI
+ * driver. Otherwise they will see "dead" USB ports that don't power
+ * the devices.
+ */
+ if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
+ dev_warn(&xhci_pdev->dev,
+ "CONFIG_USB_XHCI_HCD is turned off, "
+ "defaulting to EHCI.\n");
+ dev_warn(&xhci_pdev->dev,
+ "USB 3.0 devices will work at USB 2.0 speeds.\n");
+ return;
+ }
+
ports_available = 0xffffffff;
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
* Register, to turn on SuperSpeed terminations for all
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 2bf1320..c868be6 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -401,7 +401,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
if (r8a66597->address_map & (1 << addr))
continue;
- dbg("alloc_address: r8a66597_addr=%d", addr);
+ dev_dbg(&urb->dev->dev, "alloc_address: r8a66597_addr=%d\n", addr);
r8a66597->address_map |= 1 << addr;
if (make_r8a66597_device(r8a66597, urb, addr) < 0)
@@ -426,7 +426,7 @@ static void free_usb_address(struct r8a66597 *r8a66597,
if (!dev)
return;
- dbg("free_addr: addr=%d", dev->address);
+ dev_dbg(&dev->udev->dev, "free_addr: addr=%d\n", dev->address);
dev->state = USB_STATE_DEFAULT;
r8a66597->address_map &= ~(1 << dev->address);
@@ -819,7 +819,7 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
struct r8a66597_pipe *pipe = hep->hcpriv;
- dbg("enable_pipe:");
+ dev_dbg(&dev->udev->dev, "enable_pipe:\n");
pipe->info = *info;
set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
@@ -898,7 +898,7 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
force_dequeue(r8a66597, pipenum, dev->address);
}
- dbg("disable_pipe");
+ dev_dbg(&dev->udev->dev, "disable_pipe\n");
r8a66597->dma_map &= ~(dev->dma_map);
dev->dma_map = 0;
@@ -2264,7 +2264,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;
- dbg("%s", __func__);
+ dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2273,7 +2273,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
if (!(rh->port & USB_PORT_STAT_ENABLE))
continue;
- dbg("suspend port = %d", port);
+ dev_dbg(&rh->dev->udev->dev, "suspend port = %d\n", port);
r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */
rh->port |= USB_PORT_STAT_SUSPEND;
@@ -2295,7 +2295,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;
- dbg("%s", __func__);
+ dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2304,7 +2304,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
if (!(rh->port & USB_PORT_STAT_SUSPEND))
continue;
- dbg("resume port = %d", port);
+ dev_dbg(&rh->dev->udev->dev, "resume port = %d\n", port);
rh->port &= ~USB_PORT_STAT_SUSPEND;
rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
@@ -2360,7 +2360,7 @@ static int r8a66597_suspend(struct device *dev)
struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
int port;
- dbg("%s", __func__);
+ dev_dbg(dev, "%s\n", __func__);
disable_controller(r8a66597);
@@ -2378,7 +2378,7 @@ static int r8a66597_resume(struct device *dev)
struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
- dbg("%s", __func__);
+ dev_dbg(dev, "%s\n", __func__);
enable_controller(r8a66597);
usb_root_hub_lost_power(hcd->self.root_hub);
diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c
new file mode 100644
index 0000000..c2a29fa
--- /dev/null
+++ b/drivers/usb/host/ssb-hcd.c
@@ -0,0 +1,280 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core driver (SSB bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for SSB Bus");
+MODULE_LICENSE("GPL");
+
+#define SSB_HCD_TMSLOW_HOSTMODE (1 << 29)
+
+struct ssb_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
+
+ u32 enable_flags;
+};
+
+static void __devinit ssb_hcd_5354wa(struct ssb_device *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_MIPS
+ /* Work around for 5354 failures */
+ if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
+ /* Change syn01 reg */
+ ssb_write32(dev, 0x894, 0x00fe00fe);
+
+ /* Change syn03 reg */
+ ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1);
+ }
+#endif
+}
+
+static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev)
+{
+ if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+ /*
+ * USB 2.0 special considerations:
+ *
+ * In addition to the standard SSB reset sequence, the Host
+ * Control Register must be programmed to bring the USB core
+ * and various phy components out of reset.
+ */
+ ssb_write32(dev, 0x200, 0x7ff);
+
+ /* Change Flush control reg */
+ ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8);
+ ssb_read32(dev, 0x400);
+
+ /* Change Shim control reg */
+ ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100);
+ ssb_read32(dev, 0x304);
+
+ udelay(1);
+
+ ssb_hcd_5354wa(dev);
+ }
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev)
+{
+ u32 flags = 0;
+
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+ /* Put the device into host-mode. */
+ flags |= SSB_HCD_TMSLOW_HOSTMODE;
+
+ ssb_device_enable(dev, flags);
+
+ ssb_hcd_usb20wa(dev);
+
+ return flags;
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len)
+{
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+ int ret = -ENOMEM;
+
+ memset(hci_res, 0, sizeof(hci_res));
+
+ hci_res[0].start = addr;
+ hci_res[0].end = hci_res[0].start + len - 1;
+ hci_res[0].flags = IORESOURCE_MEM;
+
+ hci_res[1].start = dev->irq;
+ hci_res[1].flags = IORESOURCE_IRQ;
+
+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+ "ehci-platform" , 0);
+ if (!hci_dev)
+ return NULL;
+
+ hci_dev->dev.parent = dev->dev;
+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+ ret = platform_device_add_resources(hci_dev, hci_res,
+ ARRAY_SIZE(hci_res));
+ if (ret)
+ goto err_alloc;
+ if (ohci)
+ ret = platform_device_add_data(hci_dev, &ohci_pdata,
+ sizeof(ohci_pdata));
+ else
+ ret = platform_device_add_data(hci_dev, &ehci_pdata,
+ sizeof(ehci_pdata));
+ if (ret)
+ goto err_alloc;
+ ret = platform_device_add(hci_dev);
+ if (ret)
+ goto err_alloc;
+
+ return hci_dev;
+
+err_alloc:
+ platform_device_put(hci_dev);
+ return ERR_PTR(ret);
+}
+
+static int __devinit ssb_hcd_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ int err, tmp;
+ int start, len;
+ u16 chipid_top;
+ u16 coreid = dev->id.coreid;
+ struct ssb_hcd_device *usb_dev;
+
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (dev->bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+ usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
+ * as HOST OHCI. If we want to attach it as Client device,
+ * we must branch here and call into the (yet to
+ * be written) Client mode driver. Same for remove(). */
+ usb_dev->enable_flags = ssb_hcd_init_chip(dev);
+
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
+
+ start = ssb_admatch_base(tmp);
+ len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
+ usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
+ if (IS_ERR(usb_dev->ohci_dev)) {
+ err = PTR_ERR(usb_dev->ohci_dev);
+ goto err_free_usb_dev;
+ }
+
+ if (coreid == SSB_DEV_USB20_HOST) {
+ start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
+ usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len);
+ if (IS_ERR(usb_dev->ehci_dev)) {
+ err = PTR_ERR(usb_dev->ehci_dev);
+ goto err_unregister_ohci_dev;
+ }
+ }
+
+ ssb_set_drvdata(dev, usb_dev);
+ return 0;
+
+err_unregister_ohci_dev:
+ platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+ kfree(usb_dev);
+ return err;
+}
+
+static void __devexit ssb_hcd_remove(struct ssb_device *dev)
+{
+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+ if (ohci_dev)
+ platform_device_unregister(ohci_dev);
+ if (ehci_dev)
+ platform_device_unregister(ehci_dev);
+
+ ssb_device_disable(dev, 0);
+}
+
+static void __devexit ssb_hcd_shutdown(struct ssb_device *dev)
+{
+ ssb_device_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ ssb_device_disable(dev, 0);
+
+ return 0;
+}
+
+static int ssb_hcd_resume(struct ssb_device *dev)
+{
+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+
+ ssb_device_enable(dev, usb_dev->enable_flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_hcd_suspend NULL
+#define ssb_hcd_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_hcd_table[] __devinitconst = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
+
+static struct ssb_driver ssb_hcd_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ssb_hcd_table,
+ .probe = ssb_hcd_probe,
+ .remove = __devexit_p(ssb_hcd_remove),
+ .shutdown = ssb_hcd_shutdown,
+ .suspend = ssb_hcd_suspend,
+ .resume = ssb_hcd_resume,
+};
+
+static int __init ssb_hcd_init(void)
+{
+ return ssb_driver_register(&ssb_hcd_driver);
+}
+module_init(ssb_hcd_init);
+
+static void __exit ssb_hcd_exit(void)
+{
+ ssb_driver_unregister(&ssb_hcd_driver);
+}
+module_exit(ssb_hcd_exit);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad12..2732ef6 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -475,6 +475,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct xhci_bus_state *bus_state;
u16 link_state = 0;
u16 wake_mask = 0;
+ u16 timeout = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -558,6 +559,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0);
xhci_dbg(xhci, "set port %d resume\n",
@@ -622,6 +624,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
+ /* The MSB of wIndex is the U1/U2 timeout */
+ timeout = (wIndex & 0xff00) >> 8;
wIndex &= 0xff;
if (!wIndex || wIndex > max_ports)
goto error;
@@ -746,6 +750,22 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
break;
+ case USB_PORT_FEAT_U1_TIMEOUT:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+ temp = xhci_readl(xhci, port_array[wIndex] + 1);
+ temp &= ~PORT_U1_TIMEOUT_MASK;
+ temp |= PORT_U1_TIMEOUT(timeout);
+ xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ break;
+ case USB_PORT_FEAT_U2_TIMEOUT:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+ temp = xhci_readl(xhci, port_array[wIndex] + 1);
+ temp &= ~PORT_U2_TIMEOUT_MASK;
+ temp |= PORT_U2_TIMEOUT(timeout);
+ xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ break;
default:
goto error;
}
@@ -845,7 +865,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* Initial status is no changes */
retval = (max_ports + 8) / 8;
memset(buf, 0, retval);
- status = 0;
+
+ /*
+ * Inform the usbcore about resume-in-progress by returning
+ * a non-zero value even if there are no status changes.
+ */
+ status = bus_state->resuming_ports;
mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
@@ -885,15 +910,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);
if (hcd->self.root_hub->do_remote_wakeup) {
- port_index = max_ports;
- while (port_index--) {
- if (bus_state->resume_done[port_index] != 0) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "suspend failed because "
- "port %d is resuming\n",
- port_index + 1);
- return -EBUSY;
- }
+ if (bus_state->resuming_ports) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_dbg(xhci, "suspend failed because "
+ "a port is resuming\n");
+ return -EBUSY;
}
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 68eaa90..ec4338e 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next;
+ struct list_head *tt_list_head;
+ struct list_head *tt;
+ struct list_head *endpoints;
+ struct list_head *ep, *q;
+ struct xhci_tt_bw_info *tt_info;
+ struct xhci_interval_bw_table *bwt;
+ struct xhci_virt_ep *virt_ep;
+
unsigned long flags;
int size;
int i;
@@ -1807,6 +1815,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
+ if (xhci->lpm_command)
+ xhci_free_command(xhci, xhci->lpm_command);
+ xhci->cmd_ring_reserved_trbs = 0;
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -1849,8 +1860,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
spin_unlock_irqrestore(&xhci->lock, flags);
+ bwt = &xhci->rh_bw->bw_table;
+ for (i = 0; i < XHCI_MAX_INTERVAL; i++) {
+ endpoints = &bwt->interval_bw[i].endpoints;
+ list_for_each_safe(ep, q, endpoints) {
+ virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list);
+ list_del(&virt_ep->bw_endpoint_list);
+ kfree(virt_ep);
+ }
+ }
+
+ tt_list_head = &xhci->rh_bw->tts;
+ list_for_each_safe(tt, q, tt_list_head) {
+ tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
+ list_del(tt);
+ kfree(tt_info);
+ }
+
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
+ xhci->num_active_eps = 0;
kfree(xhci->usb2_ports);
kfree(xhci->usb3_ports);
kfree(xhci->port_array);
@@ -2350,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
+ xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
+ if (!xhci->lpm_command)
+ goto fail;
+
+ /* Reserve one command ring TRB for disabling LPM.
+ * Since the USB core grabs the shared usb_bus bandwidth mutex before
+ * disabling LPM, we only need to reserve one TRB for all devices.
+ */
+ xhci->cmd_ring_reserved_trbs++;
+
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
val &= DBOFF_MASK;
xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7a856a7..18b231b 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
"has broken MSI implementation\n",
pdev->revision);
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_NEC)
@@ -83,6 +84,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
/* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ xhci->quirks |= XHCI_LPM_SUPPORT;
+ xhci->quirks |= XHCI_INTEL_HOST;
+ }
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
@@ -169,6 +174,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
+
+ /* We know the LPM timeout algorithms for this host, let the USB core
+ * enable and disable LPM for devices under the USB 3.0 roothub.
+ */
+ if (xhci->quirks & XHCI_LPM_SUPPORT)
+ hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1;
+
return 0;
put_usb3_hcd:
@@ -292,6 +304,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
+ .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
+ .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3d9422f..23b4aef 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
msecs_to_jiffies(20);
+ set_bit(faked_port_index, &bus_state->resuming_ports);
mod_timer(&hcd->rh_timer,
bus_state->resume_done[faked_port_index]);
/* Do the rest in GetPortStatus */
@@ -1786,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* handle completion code */
switch (trb_comp_code) {
case COMP_SUCCESS:
- frame->status = 0;
- break;
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+ frame->status = 0;
+ break;
+ }
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
case COMP_SHORT_TX:
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
-EREMOTEIO : 0;
@@ -1803,6 +1808,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
break;
case COMP_DEV_ERR:
case COMP_STALL:
+ case COMP_TX_ERR:
frame->status = -EPROTO;
skip_td = true;
break;
@@ -1883,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
- if (event_trb != td->last_trb) {
+ if (event_trb != td->last_trb ||
+ TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
xhci_warn(xhci, "WARN Successful completion "
"on short TX\n");
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
else
*status = 0;
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
} else {
*status = 0;
}
@@ -2048,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+ break;
+ if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
+ trb_comp_code = COMP_SHORT_TX;
+ else
+ xhci_warn(xhci, "WARN Successful completion on short TX: "
+ "needs XHCI_TRUST_TX_LENGTH quirk?\n");
case COMP_SHORT_TX:
break;
case COMP_STOP:
@@ -2270,7 +2286,7 @@ cleanup:
(status != 0 &&
!usb_endpoint_xfer_isoc(&urb->ep->desc)))
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
- "expected = %x, status = %d\n",
+ "expected = %d, status = %d\n",
urb, urb->actual_length,
urb->transfer_buffer_length,
status);
@@ -3593,12 +3609,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
/* Queue an evaluate context command TRB */
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
- u32 slot_id)
+ u32 slot_id, bool command_must_succeed)
{
return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),
- false);
+ command_must_succeed);
}
/*
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7..afdc73e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci)
{
u32 command;
u32 state;
- int ret;
+ int ret, i;
state = xhci_readl(xhci, &xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
@@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci)
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
*/
- return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+ ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+
+ for (i = 0; i < 2; ++i) {
+ xhci->bus_state[i].port_c_suspend = 0;
+ xhci->bus_state[i].suspended_ports = 0;
+ xhci->bus_state[i].resuming_ports = 0;
+ }
+
+ return ret;
}
#ifdef CONFIG_PCI
@@ -2438,7 +2446,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
udev->slot_id, must_succeed);
else
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
- udev->slot_id);
+ udev->slot_id, must_succeed);
if (ret < 0) {
if (command)
list_del(&command->cmd_list);
@@ -3863,6 +3871,474 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
#endif /* CONFIG_USB_SUSPEND */
+/*---------------------- USB 3.0 Link PM functions ------------------------*/
+
+#ifdef CONFIG_PM
+/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */
+static unsigned long long xhci_service_interval_to_ns(
+ struct usb_endpoint_descriptor *desc)
+{
+ return (1 << (desc->bInterval - 1)) * 125 * 1000;
+}
+
+static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ unsigned long long sel;
+ unsigned long long pel;
+ unsigned int max_sel_pel;
+ char *state_name;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ /* Convert SEL and PEL stored in nanoseconds to microseconds */
+ sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+ max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL;
+ state_name = "U1";
+ break;
+ case USB3_LPM_U2:
+ sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+ max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL;
+ state_name = "U2";
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (sel <= max_sel_pel && pel <= max_sel_pel)
+ return USB3_LPM_DEVICE_INITIATED;
+
+ if (sel > max_sel_pel)
+ dev_dbg(&udev->dev, "Device-initiated %s disabled "
+ "due to long SEL %llu ms\n",
+ state_name, sel);
+ else
+ dev_dbg(&udev->dev, "Device-initiated %s disabled "
+ "due to long PEL %llu\n ms",
+ state_name, pel);
+ return USB3_LPM_DISABLED;
+}
+
+/* Returns the hub-encoded U1 timeout value.
+ * The U1 timeout should be the maximum of the following values:
+ * - For control endpoints, U1 system exit latency (SEL) * 3
+ * - For bulk endpoints, U1 SEL * 5
+ * - For interrupt endpoints:
+ * - Notification EPs, U1 SEL * 3
+ * - Periodic EPs, max(105% of bInterval, U1 SEL * 2)
+ * - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2)
+ */
+static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+ int ep_type;
+ int intr_type;
+
+ ep_type = usb_endpoint_type(desc);
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ timeout_ns = udev->u1_params.sel * 3;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ timeout_ns = udev->u1_params.sel * 5;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ intr_type = usb_endpoint_interrupt_type(desc);
+ if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) {
+ timeout_ns = udev->u1_params.sel * 3;
+ break;
+ }
+ /* Otherwise the calculation is the same as isoc eps */
+ case USB_ENDPOINT_XFER_ISOC:
+ timeout_ns = xhci_service_interval_to_ns(desc);
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100);
+ if (timeout_ns < udev->u1_params.sel * 2)
+ timeout_ns = udev->u1_params.sel * 2;
+ break;
+ default:
+ return 0;
+ }
+
+ /* The U1 timeout is encoded in 1us intervals. */
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000);
+ /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */
+ if (timeout_ns == USB3_LPM_DISABLED)
+ timeout_ns++;
+
+ /* If the necessary timeout value is bigger than what we can set in the
+ * USB 3.0 hub, we have to disable hub-initiated U1.
+ */
+ if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT)
+ return timeout_ns;
+ dev_dbg(&udev->dev, "Hub-initiated U1 disabled "
+ "due to long timeout %llu ms\n", timeout_ns);
+ return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
+}
+
+/* Returns the hub-encoded U2 timeout value.
+ * The U2 timeout should be the maximum of:
+ * - 10 ms (to avoid the bandwidth impact on the scheduler)
+ * - largest bInterval of any active periodic endpoint (to avoid going
+ * into lower power link states between intervals).
+ * - the U2 Exit Latency of the device
+ */
+static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+ unsigned long long u2_del_ns;
+
+ timeout_ns = 10 * 1000 * 1000;
+
+ if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) &&
+ (xhci_service_interval_to_ns(desc) > timeout_ns))
+ timeout_ns = xhci_service_interval_to_ns(desc);
+
+ u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000;
+ if (u2_del_ns > timeout_ns)
+ timeout_ns = u2_del_ns;
+
+ /* The U2 timeout is encoded in 256us intervals */
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
+ /* If the necessary timeout value is bigger than what we can set in the
+ * USB 3.0 hub, we have to disable hub-initiated U2.
+ */
+ if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT)
+ return timeout_ns;
+ dev_dbg(&udev->dev, "Hub-initiated U2 disabled "
+ "due to long timeout %llu ms\n", timeout_ns);
+ return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2);
+}
+
+static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ if (state == USB3_LPM_U1) {
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_calculate_intel_u1_timeout(udev, desc);
+ } else {
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_calculate_intel_u2_timeout(udev, desc);
+ }
+
+ return USB3_LPM_DISABLED;
+}
+
+static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ u16 alt_timeout;
+
+ alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
+ desc, state, timeout);
+
+ /* If we found we can't enable hub-initiated LPM, or
+ * the U1 or U2 exit latency was too high to allow
+ * device-initiated LPM as well, just stop searching.
+ */
+ if (alt_timeout == USB3_LPM_DISABLED ||
+ alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+ *timeout = alt_timeout;
+ return -E2BIG;
+ }
+ if (alt_timeout > *timeout)
+ *timeout = alt_timeout;
+ return 0;
+}
+
+static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_host_interface *alt,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ int j;
+
+ for (j = 0; j < alt->desc.bNumEndpoints; j++) {
+ if (xhci_update_timeout_for_endpoint(xhci, udev,
+ &alt->endpoint[j].desc, state, timeout))
+ return -E2BIG;
+ continue;
+ }
+ return 0;
+}
+
+static int xhci_check_intel_tier_policy(struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ struct usb_device *parent;
+ unsigned int num_hubs;
+
+ if (state == USB3_LPM_U2)
+ return 0;
+
+ /* Don't enable U1 if the device is on a 2nd tier hub or lower. */
+ for (parent = udev->parent, num_hubs = 0; parent->parent;
+ parent = parent->parent)
+ num_hubs++;
+
+ if (num_hubs < 2)
+ return 0;
+
+ dev_dbg(&udev->dev, "Disabling U1 link state for device"
+ " below second-tier hub.\n");
+ dev_dbg(&udev->dev, "Plug device into first-tier hub "
+ "to decrease power consumption.\n");
+ return -E2BIG;
+}
+
+static int xhci_check_tier_policy(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_check_intel_tier_policy(udev, state);
+ return -EINVAL;
+}
+
+/* Returns the U1 or U2 timeout that should be enabled.
+ * If the tier check or timeout setting functions return with a non-zero exit
+ * code, that means the timeout value has been finalized and we shouldn't look
+ * at any more endpoints.
+ */
+static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_host_config *config;
+ char *state_name;
+ int i;
+ u16 timeout = USB3_LPM_DISABLED;
+
+ if (state == USB3_LPM_U1)
+ state_name = "U1";
+ else if (state == USB3_LPM_U2)
+ state_name = "U2";
+ else {
+ dev_warn(&udev->dev, "Can't enable unknown link state %i\n",
+ state);
+ return timeout;
+ }
+
+ if (xhci_check_tier_policy(xhci, udev, state) < 0)
+ return timeout;
+
+ /* Gather some information about the currently installed configuration
+ * and alternate interface settings.
+ */
+ if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc,
+ state, &timeout))
+ return timeout;
+
+ config = udev->actconfig;
+ if (!config)
+ return timeout;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ struct usb_driver *driver;
+ struct usb_interface *intf = config->interface[i];
+
+ if (!intf)
+ continue;
+
+ /* Check if any currently bound drivers want hub-initiated LPM
+ * disabled.
+ */
+ if (intf->dev.driver) {
+ driver = to_usb_driver(intf->dev.driver);
+ if (driver && driver->disable_hub_initiated_lpm) {
+ dev_dbg(&udev->dev, "Hub-initiated %s disabled "
+ "at request of driver %s\n",
+ state_name, driver->name);
+ return xhci_get_timeout_no_hub_lpm(udev, state);
+ }
+ }
+
+ /* Not sure how this could happen... */
+ if (!intf->cur_altsetting)
+ continue;
+
+ if (xhci_update_timeout_for_interface(xhci, udev,
+ intf->cur_altsetting,
+ state, &timeout))
+ return timeout;
+ }
+ return timeout;
+}
+
+/*
+ * Issue an Evaluate Context command to change the Maximum Exit Latency in the
+ * slot context. If that succeeds, store the new MEL in the xhci_virt_device.
+ */
+static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
+ struct usb_device *udev, u16 max_exit_latency)
+{
+ struct xhci_virt_device *virt_dev;
+ struct xhci_command *command;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_slot_ctx *slot_ctx;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return 0;
+ }
+
+ /* Attempt to issue an Evaluate Context command to change the MEL. */
+ virt_dev = xhci->devs[udev->slot_id];
+ command = xhci->lpm_command;
+ xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
+ slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
+ slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
+ slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
+
+ xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+ xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, command->in_ctx, 0);
+
+ /* Issue and wait for the evaluate context command. */
+ ret = xhci_configure_endpoint(xhci, udev, command,
+ true, true);
+ xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
+
+ if (!ret) {
+ spin_lock_irqsave(&xhci->lock, flags);
+ virt_dev->current_mel = max_exit_latency;
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ }
+ return ret;
+}
+
+static int calculate_max_exit_latency(struct usb_device *udev,
+ enum usb3_link_state state_changed,
+ u16 hub_encoded_timeout)
+{
+ unsigned long long u1_mel_us = 0;
+ unsigned long long u2_mel_us = 0;
+ unsigned long long mel_us = 0;
+ bool disabling_u1;
+ bool disabling_u2;
+ bool enabling_u1;
+ bool enabling_u2;
+
+ disabling_u1 = (state_changed == USB3_LPM_U1 &&
+ hub_encoded_timeout == USB3_LPM_DISABLED);
+ disabling_u2 = (state_changed == USB3_LPM_U2 &&
+ hub_encoded_timeout == USB3_LPM_DISABLED);
+
+ enabling_u1 = (state_changed == USB3_LPM_U1 &&
+ hub_encoded_timeout != USB3_LPM_DISABLED);
+ enabling_u2 = (state_changed == USB3_LPM_U2 &&
+ hub_encoded_timeout != USB3_LPM_DISABLED);
+
+ /* If U1 was already enabled and we're not disabling it,
+ * or we're going to enable U1, account for the U1 max exit latency.
+ */
+ if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) ||
+ enabling_u1)
+ u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000);
+ if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) ||
+ enabling_u2)
+ u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000);
+
+ if (u1_mel_us > u2_mel_us)
+ mel_us = u1_mel_us;
+ else
+ mel_us = u2_mel_us;
+ /* xHCI host controller max exit latency field is only 16 bits wide. */
+ if (mel_us > MAX_EXIT) {
+ dev_warn(&udev->dev, "Link PM max exit latency of %lluus "
+ "is too big.\n", mel_us);
+ return -E2BIG;
+ }
+ return mel_us;
+}
+
+/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci;
+ u16 hub_encoded_timeout;
+ int mel;
+ int ret;
+
+ xhci = hcd_to_xhci(hcd);
+ /* The LPM timeout values are pretty host-controller specific, so don't
+ * enable hub-initiated timeouts unless the vendor has provided
+ * information about their timeout algorithm.
+ */
+ if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+ !xhci->devs[udev->slot_id])
+ return USB3_LPM_DISABLED;
+
+ hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
+ mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
+ if (mel < 0) {
+ /* Max Exit Latency is too big, disable LPM. */
+ hub_encoded_timeout = USB3_LPM_DISABLED;
+ mel = 0;
+ }
+
+ ret = xhci_change_max_exit_latency(xhci, udev, mel);
+ if (ret)
+ return ret;
+ return hub_encoded_timeout;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci;
+ u16 mel;
+ int ret;
+
+ xhci = hcd_to_xhci(hcd);
+ if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+ !xhci->devs[udev->slot_id])
+ return 0;
+
+ mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED);
+ ret = xhci_change_max_exit_latency(xhci, udev, mel);
+ if (ret)
+ return ret;
+ return 0;
+}
+#else /* CONFIG_PM */
+
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ return USB3_LPM_DISABLED;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
* internal data structures for the device.
*/
@@ -4090,7 +4566,6 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
- BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
return 0;
unreg_pci:
xhci_unregister_pci();
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b..de3d6e3 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -362,8 +362,10 @@ struct xhci_op_regs {
* Timeout can be up to 127us. 0xFF means an infinite timeout.
*/
#define PORT_U1_TIMEOUT(p) ((p) & 0xff)
+#define PORT_U1_TIMEOUT_MASK 0xff
/* Inactivity timer value for transitions into U2 */
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
+#define PORT_U2_TIMEOUT_MASK (0xff << 8)
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
@@ -914,6 +916,8 @@ struct xhci_virt_device {
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
+ /* The current max exit latency for the enabled USB3 link states. */
+ u16 current_mel;
};
/*
@@ -1362,6 +1366,8 @@ struct xhci_bus_state {
u32 suspended_ports;
u32 port_remote_wakeup;
unsigned long resume_done[USB_MAXCHILDREN];
+ /* which ports have started to resume */
+ unsigned long resuming_ports;
};
static inline unsigned int hcd_index(struct usb_hcd *hcd)
@@ -1422,6 +1428,8 @@ struct xhci_hcd {
/* slot enabling and address device helpers */
struct completion addr_dev;
int slot_id;
+ /* For USB 3.0 LPM enable/disable. */
+ struct xhci_command *lpm_command;
/* Internal mirror of the HW's dcbaa */
struct xhci_virt_device *devs[MAX_HC_SLOTS];
/* For keeping track of bandwidth domains per roothub. */
@@ -1479,6 +1487,9 @@ struct xhci_hcd {
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_SW_BW_CHECKING (1 << 8)
#define XHCI_AMD_0x96_HOST (1 << 9)
+#define XHCI_TRUST_TX_LENGTH (1 << 10)
+#define XHCI_LPM_SUPPORT (1 << 11)
+#define XHCI_INTEL_HOST (1 << 12)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1752,7 +1763,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
- u32 slot_id);
+ u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
@@ -1776,6 +1787,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 link_state);
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state);
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state);
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit);
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 575b56c..7121b50 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,18 +284,16 @@ static void mdc800_usb_irq (struct urb *urb)
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
struct mdc800_data* mdc800=urb->context;
+ struct device *dev = &mdc800->dev->dev;
int status = urb->status;
if (status >= 0) {
-
- //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
-
if (mdc800_isBusy (b))
{
if (!mdc800->camera_busy)
{
mdc800->camera_busy=1;
- dbg ("gets busy");
+ dev_dbg(dev, "gets busy\n");
}
}
else
@@ -303,13 +301,13 @@ static void mdc800_usb_irq (struct urb *urb)
if (mdc800->camera_busy && mdc800_isReady (b))
{
mdc800->camera_busy=0;
- dbg ("gets ready");
+ dev_dbg(dev, "gets ready\n");
}
}
if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
{
/* Store Data in camera_answer field */
- dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+ dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
memcpy (mdc800->camera_response,b,8);
data_received=1;
@@ -441,7 +439,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
int irq_interval=0;
int retval;
- dbg ("(mdc800_usb_probe) called.");
+ dev_dbg(&intf->dev, "(%s) called.\n", __func__);
if (mdc800->dev != NULL)
@@ -554,7 +552,7 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
{
struct mdc800_data* mdc800 = usb_get_intfdata(intf);
- dbg ("(mdc800_usb_disconnect) called");
+ dev_dbg(&intf->dev, "(%s) called\n", __func__);
if (mdc800) {
if (mdc800->state == NOT_CONNECTED)
@@ -656,7 +654,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
}
mdc800->open=1;
- dbg ("Mustek MDC800 device opened.");
+ dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n");
error_out:
mutex_unlock(&mdc800->io_lock);
@@ -670,7 +668,6 @@ error_out:
static int mdc800_device_release (struct inode* inode, struct file *file)
{
int retval=0;
- dbg ("Mustek MDC800 device closed.");
mutex_lock(&mdc800->io_lock);
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
@@ -927,7 +924,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
{
mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
- dbg ("cached imagesize = %i",mdc800->pic_len);
+ dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len);
}
}
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index ac0d75a..0fc6e5f 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,6 +88,7 @@ static struct workqueue_struct *wq;
static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
+ struct device *dev = &pdata->udev->dev;
unsigned long flags;
int status = urb->status;
int retval;
@@ -97,18 +98,18 @@ static void appledisplay_complete(struct urb *urb)
/* success */
break;
case -EOVERFLOW:
- printk(KERN_ERR "appletouch: OVERFLOW with data "
- "length %d, actual length is %d\n",
+ dev_err(dev,
+ "OVERFLOW with data length %d, actual length is %d\n",
ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shuttingdown with status: %d",
+ dev_dbg(dev, "%s - urb shuttingdown with status: %d\n",
__func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
+ dev_dbg(dev, "%s - nonzero urb status received: %d/n",
__func__, status);
goto exit;
}
@@ -132,8 +133,7 @@ static void appledisplay_complete(struct urb *urb)
exit:
retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
if (retval) {
- dev_err(&pdata->udev->dev,
- "%s - usb_submit_urb failed with result %d\n",
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
}
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index da97dce..d65984d 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -78,18 +78,14 @@ static int emi26_load_firmware (struct usb_device *dev)
const struct firmware *bitstream_fw = NULL;
const struct firmware *firmware_fw = NULL;
const struct ihex_binrec *rec;
- int err;
+ int err = -ENOMEM;
int i;
__u32 addr; /* Address to write */
__u8 *buf;
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
- if (!buf) {
- dev_err(&dev->dev, "%s - error loading firmware: error = %d\n",
- __func__, -ENOMEM);
- err = -ENOMEM;
+ if (!buf)
goto wraperr;
- }
err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev);
if (err)
@@ -111,11 +107,8 @@ static int emi26_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
- if (err < 0) {
- dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
- __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = (const struct ihex_binrec *)loader_fw->data;
/* 1. We need to put the loader for the FPGA into the EZ-USB */
@@ -123,19 +116,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = ihex_next_binrec(rec);
}
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -153,18 +142,14 @@ static int emi26_load_firmware (struct usb_device *dev)
rec = ihex_next_binrec(rec);
}
err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
} while (rec);
/* 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);
+ if (err < 0)
goto wraperr;
- }
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -172,19 +157,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
msleep(250); /* let device settle */
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -194,19 +175,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
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);
+ if (err < 0)
goto wraperr;
- }
for (rec = (const struct ihex_binrec *)firmware_fw->data;
rec; rec = ihex_next_binrec(rec)) {
@@ -214,19 +191,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* return 1 to fail the driver inialization
@@ -234,6 +207,10 @@ static int emi26_load_firmware (struct usb_device *dev)
err = 1;
wraperr:
+ if (err < 0)
+ dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+ __func__, err);
+
release_firmware(loader_fw);
release_firmware(bitstream_fw);
release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 4e0f167..ff08015 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -56,7 +56,7 @@ static int emi62_writememory(struct usb_device *dev, int address,
unsigned char *buffer = kmemdup(data, length, GFP_KERNEL);
if (!buffer) {
- err("emi62: 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
@@ -73,9 +73,8 @@ static int emi62_set_reset (struct usb_device *dev, unsigned char 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) {
- err("emi62: set_reset (%d) failed", reset_bit);
- }
+ if (response < 0)
+ dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit);
return response;
}
@@ -87,18 +86,15 @@ static int emi62_load_firmware (struct usb_device *dev)
const struct firmware *bitstream_fw = NULL;
const struct firmware *firmware_fw = NULL;
const struct ihex_binrec *rec;
- int err;
+ int err = -ENOMEM;
int i;
__u32 addr; /* Address to write */
__u8 *buf;
dev_dbg(&dev->dev, "load_firmware\n");
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
- if (!buf) {
- err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
- err = -ENOMEM;
+ if (!buf)
goto wraperr;
- }
err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev);
if (err)
@@ -112,16 +108,13 @@ static int emi62_load_firmware (struct usb_device *dev)
err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev);
if (err) {
nofw:
- err( "%s - request_firmware() failed", __func__);
goto wraperr;
}
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = (const struct ihex_binrec *)loader_fw->data;
@@ -130,19 +123,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = ihex_next_binrec(rec);
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -160,18 +149,14 @@ static int emi62_load_firmware (struct usb_device *dev)
rec = ihex_next_binrec(rec);
}
err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
} while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -179,18 +164,14 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -201,19 +182,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
for (rec = (const struct ihex_binrec *)firmware_fw->data;
rec; rec = ihex_next_binrec(rec)) {
@@ -221,19 +198,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
release_firmware(loader_fw);
@@ -247,6 +220,9 @@ static int emi62_load_firmware (struct usb_device *dev)
return 1;
wraperr:
+ if (err < 0)
+ dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+ __func__, err);
release_firmware(loader_fw);
release_firmware(bitstream_fw);
release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 0dee246..ce97838 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -200,7 +200,8 @@ reset:
return -EAGAIN;
/* should be IMGSIZE == 65040 */
- dbg("read %d bytes fingerprint data", bytes_read);
+ dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n",
+ bytes_read);
return result;
}
@@ -366,14 +367,14 @@ static int idmouse_probe(struct usb_interface *interface,
kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Unable to allocate input buffer.");
+ dev_err(&interface->dev, "Unable to allocate input buffer.\n");
idmouse_delete(dev);
return -ENOMEM;
}
}
if (!(dev->bulk_in_endpointAddr)) {
- err("Unable to find bulk-in endpoint.");
+ dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
idmouse_delete(dev);
return -ENODEV;
}
@@ -385,7 +386,7 @@ static int idmouse_probe(struct usb_interface *interface,
result = usb_register_dev(interface, &idmouse_class);
if (result) {
/* something prevented us from registering this device */
- err("Unble to allocate minor number.");
+ dev_err(&interface->dev, "Unble to allocate minor number.\n");
usb_set_intfdata(interface, NULL);
idmouse_delete(dev);
return result;
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 4fd0dc8..db46143 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -610,8 +610,8 @@ static int iowarrior_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
mutex_unlock(&iowarrior_mutex);
- err("%s - error, can't find device for minor %d", __func__,
- subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5db4ab5..ac76229 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -334,8 +334,8 @@ static int ld_usb_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&ld_usb_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
@@ -485,7 +485,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -565,7 +565,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -603,7 +603,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
bytes_to_write,
USB_CTRL_SET_TIMEOUT * HZ);
if (retval < 0)
- err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit HID_REQ_SET_REPORT %d\n",
+ retval);
goto unlock_exit;
}
@@ -624,7 +626,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 5752220..a2702cb 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -354,8 +354,8 @@ static int tower_open (struct inode *inode, struct file *file)
interface = usb_find_interface (&tower_driver, subminor);
if (!interface) {
- err ("%s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -397,7 +397,8 @@ static int tower_open (struct inode *inode, struct file *file)
sizeof(reset_reply),
1000);
if (result < 0) {
- err("LEGO USB Tower reset control request failed");
+ dev_err(&dev->udev->dev,
+ "LEGO USB Tower reset control request failed\n");
retval = result;
goto unlock_exit;
}
@@ -420,7 +421,8 @@ static int tower_open (struct inode *inode, struct file *file)
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
if (retval) {
- err("Couldn't submit interrupt_in_urb %d", retval);
+ dev_err(&dev->udev->dev,
+ "Couldn't submit interrupt_in_urb %d\n", retval);
dev->interrupt_in_running = 0;
dev->open_count = 0;
goto unlock_exit;
@@ -608,7 +610,7 @@ static ssize_t tower_read (struct file *file, char __user *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 "legousbtower: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -697,7 +699,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d", retval);
+ printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -744,7 +746,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d", retval);
+ dev_err(&dev->udev->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
@@ -803,9 +806,10 @@ resubmit:
/* resubmit if we're still running */
if (dev->interrupt_in_running && dev->udev) {
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
- if (retval) {
- err("%s: usb_submit_urb failed (%d)", __func__, retval);
- }
+ if (retval)
+ dev_err(&dev->udev->dev,
+ "%s: usb_submit_urb failed (%d)\n",
+ __func__, retval);
}
exit:
@@ -852,6 +856,7 @@ static void tower_interrupt_out_callback (struct urb *urb)
*/
static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id)
{
+ struct device *idev = &interface->dev;
struct usb_device *udev = interface_to_usbdev(interface);
struct lego_usb_tower *dev = NULL;
struct usb_host_interface *iface_desc;
@@ -871,7 +876,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
if (dev == NULL) {
- err ("Out of memory");
+ dev_err(idev, "Out of memory\n");
goto exit;
}
@@ -915,37 +920,37 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
}
}
if(dev->interrupt_in_endpoint == NULL) {
- err("interrupt in endpoint not found");
+ dev_err(idev, "interrupt in endpoint not found\n");
goto error;
}
if (dev->interrupt_out_endpoint == NULL) {
- err("interrupt out endpoint not found");
+ dev_err(idev, "interrupt out endpoint not found\n");
goto error;
}
dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);
if (!dev->read_buffer) {
- err("Couldn't allocate read_buffer");
+ dev_err(idev, "Couldn't allocate read_buffer\n");
goto error;
}
dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
if (!dev->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
+ dev_err(idev, "Couldn't allocate interrupt_in_buffer\n");
goto error;
}
dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->interrupt_in_urb) {
- err("Couldn't allocate interrupt_in_urb");
+ dev_err(idev, "Couldn't allocate interrupt_in_urb\n");
goto error;
}
dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);
if (!dev->interrupt_out_buffer) {
- err("Couldn't allocate interrupt_out_buffer");
+ dev_err(idev, "Couldn't allocate interrupt_out_buffer\n");
goto error;
}
dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->interrupt_out_urb) {
- err("Couldn't allocate interrupt_out_urb");
+ dev_err(idev, "Couldn't allocate interrupt_out_urb\n");
goto error;
}
dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
@@ -958,7 +963,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
if (retval) {
/* something prevented us from registering this driver */
- err ("Not able to get a minor for this device.");
+ dev_err(idev, "Not able to get a minor for this device.\n");
usb_set_intfdata (interface, NULL);
goto error;
}
@@ -980,7 +985,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
sizeof(get_version_reply),
1000);
if (result < 0) {
- err("LEGO USB Tower get version control request failed");
+ dev_err(idev, "LEGO USB Tower get version control request failed\n");
retval = result;
goto error;
}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 487a8ce..1084124 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -153,10 +153,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
requesttype = rio_cmd.requesttype | USB_DIR_IN |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dbg
- ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
+ dev_dbg(&rio->rio_dev->dev,
+ "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+ requesttype, rio_cmd.request, rio_cmd.value,
+ rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
@@ -171,11 +171,14 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d", result);
+ dev_err(&rio->rio_dev->dev,
+ "Error executing ioctrl. code = %d\n",
+ result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d (data=%02x)",
- result, buffer[0]);
+ dev_dbg(&rio->rio_dev->dev,
+ "Executed ioctl. Result = %d (data=%02x)\n",
+ result, buffer[0]);
if (copy_to_user(rio_cmd.buffer, buffer,
rio_cmd.length)) {
free_page((unsigned long) buffer);
@@ -221,9 +224,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
requesttype = rio_cmd.requesttype | USB_DIR_OUT |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
+ dev_dbg(&rio->rio_dev->dev,
+ "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+ requesttype, rio_cmd.request, rio_cmd.value,
+ rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
@@ -238,10 +242,13 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d", result);
+ dev_err(&rio->rio_dev->dev,
+ "Error executing ioctrl. code = %d\n",
+ result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d", result);
+ dev_dbg(&rio->rio_dev->dev,
+ "Executed ioctl. Result = %d\n", result);
retries = 0;
}
@@ -313,8 +320,9 @@ write_rio(struct file *file, const char __user *buffer,
usb_sndbulkpipe(rio->rio_dev, 2),
obuf, thistime, &partial, 5000);
- dbg("write stats: result:%d thistime:%lu partial:%u",
- result, thistime, partial);
+ dev_dbg(&rio->rio_dev->dev,
+ "write stats: result:%d thistime:%lu partial:%u\n",
+ result, thistime, partial);
if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
if (!maxretry--) {
@@ -332,7 +340,8 @@ write_rio(struct file *file, const char __user *buffer,
break;
};
if (result) {
- err("Write Whoops - %x", result);
+ dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
+ result);
errn = -EIO;
goto error;
}
@@ -393,15 +402,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
ibuf, this_read, &partial,
8000);
- dbg("read stats: result:%d this_read:%u partial:%u",
- result, this_read, partial);
+ dev_dbg(&rio->rio_dev->dev,
+ "read stats: result:%d this_read:%u partial:%u\n",
+ result, this_read, partial);
if (partial) {
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
mutex_unlock(&(rio->lock));
- err("read_rio: maxretry timeout");
+ dev_err(&rio->rio_dev->dev,
+ "read_rio: maxretry timeout\n");
return -ETIME;
}
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
@@ -410,8 +421,9 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
continue;
} else if (result != -EREMOTEIO) {
mutex_unlock(&(rio->lock));
- err("Read Whoops - result:%u partial:%u this_read:%u",
- result, partial, this_read);
+ dev_err(&rio->rio_dev->dev,
+ "Read Whoops - result:%u partial:%u this_read:%u\n",
+ result, partial, this_read);
return -EIO;
} else {
mutex_unlock(&(rio->lock));
@@ -459,26 +471,29 @@ static int probe_rio(struct usb_interface *intf,
retval = usb_register_dev(intf, &usb_rio_class);
if (retval) {
- err("Not able to get a minor for this device.");
+ dev_err(&dev->dev,
+ "Not able to get a minor for this device.\n");
return -ENOMEM;
}
rio->rio_dev = dev;
if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) {
- err("probe_rio: Not enough memory for the output buffer");
+ dev_err(&dev->dev,
+ "probe_rio: Not enough memory for the output buffer\n");
usb_deregister_dev(intf, &usb_rio_class);
return -ENOMEM;
}
- dbg("probe_rio: obuf address:%p", rio->obuf);
+ dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf);
if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) {
- err("probe_rio: Not enough memory for the input buffer");
+ dev_err(&dev->dev,
+ "probe_rio: Not enough memory for the input buffer\n");
usb_deregister_dev(intf, &usb_rio_class);
kfree(rio->obuf);
return -ENOMEM;
}
- dbg("probe_rio: ibuf address:%p", rio->ibuf);
+ dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf);
mutex_init(&(rio->lock));
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index e2b4bd3..89927bc 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -87,8 +87,8 @@ static int lcd_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
mutex_unlock(&lcd_mutex);
- err("USBLCD: %s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
@@ -209,8 +209,8 @@ static void lcd_write_bulk_callback(struct urb *urb)
!(status == -ENOENT ||
status == -ECONNRESET ||
status == -ESHUTDOWN)) {
- dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __func__, status);
+ dev_dbg(&dev->interface->dev,
+ "nonzero write bulk status received: %d\n", status);
}
/* free up our allocated buffer */
@@ -268,8 +268,9 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
- err("USBLCD: %s - failed submitting write urb, error %d",
- __func__, retval);
+ dev_err(&dev->udev->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, retval);
goto error_unanchor;
}
@@ -322,7 +323,7 @@ static int lcd_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -352,7 +353,8 @@ static int lcd_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Could not allocate bulk_in_buffer");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_buffer\n");
goto error;
}
}
@@ -364,7 +366,8 @@ static int lcd_probe(struct usb_interface *interface,
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
- err("Could not find both bulk-in and bulk-out endpoints");
+ dev_err(&interface->dev,
+ "Could not find both bulk-in and bulk-out endpoints\n");
goto error;
}
@@ -375,7 +378,8 @@ static int lcd_probe(struct usb_interface *interface,
retval = usb_register_dev(interface, &lcd_class);
if (retval) {
/* something prevented us from registering this driver */
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 9dcb68f..055b84a 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1028,7 +1028,10 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
case 13: /* short read, resembling case 10 */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
/* last data packet "should" be DATA1, not DATA0 */
- len = 1024 - udev->descriptor.bMaxPacketSize0;
+ if (udev->speed == USB_SPEED_SUPER)
+ len = 1024 - 512;
+ else
+ len = 1024 - udev->descriptor.bMaxPacketSize0;
expected = -EREMOTEIO;
break;
case 14: /* short read; try to fill the last packet */
@@ -1387,11 +1390,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
static int halt_simple(struct usbtest_dev *dev)
{
- int ep;
- int retval = 0;
- struct urb *urb;
+ int ep;
+ int retval = 0;
+ struct urb *urb;
+ struct usb_device *udev = testdev_to_usbdev(dev);
- urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512);
+ if (udev->speed == USB_SPEED_SUPER)
+ urb = simple_alloc_urb(udev, 0, 1024);
+ else
+ urb = simple_alloc_urb(udev, 0, 512);
if (urb == NULL)
return -ENOMEM;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 8b1d94a..29cad9e 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -85,9 +85,9 @@ static void destroy_priv(struct kref *kref)
{
struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
+ dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n");
usb_put_dev(priv->usbdev);
kfree(priv);
- dbg("destroying priv datastructure");
}
static void destroy_async(struct kref *kref)
@@ -118,14 +118,17 @@ static void async_complete(struct urb *urb)
priv = rq->priv;
pp = priv->pp;
if (status) {
- err("async_complete: urb error %d", status);
+ dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
+ status);
} else if (rq->dr.bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
- dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
- (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
- (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
- (unsigned int)priv->reg[6]);
+ dev_dbg(&priv->usbdev->dev,
+ "async_complete regs %02x %02x %02x %02x %02x %02x %02x\n",
+ (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+ (unsigned int)priv->reg[2], (unsigned int)priv->reg[3],
+ (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
+ (unsigned int)priv->reg[6]);
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
@@ -151,7 +154,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
return NULL;
rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
if (!rq) {
- err("submit_async_request out of memory");
+ dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
}
kref_init(&rq->ref_count);
@@ -162,7 +165,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
rq->urb = usb_alloc_urb(0, mem_flags);
if (!rq->urb) {
kref_put(&rq->ref_count, destroy_async);
- err("submit_async_request out of memory");
+ dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
}
rq->dr.bRequestType = requesttype;
@@ -182,7 +185,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
if (!ret)
return rq;
destroy_async(&rq->ref_count);
- err("submit_async_request submit_urb failed with %d", ret);
+ dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret);
return NULL;
}
@@ -217,7 +220,8 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha
priv = pp->private_data;
rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
if (!rq) {
- err("get_1284_register(%u) failed", (unsigned int)reg);
+ dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed",
+ (unsigned int)reg);
return -EIO;
}
if (!val) {
@@ -248,7 +252,8 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha
priv = pp->private_data;
rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
if (!rq) {
- err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
+ dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed",
+ (unsigned int)reg, (unsigned int)val);
return -EIO;
}
kref_put(&rq->ref_count, destroy_async);
@@ -690,9 +695,9 @@ static int uss720_probe(struct usb_interface *intf,
unsigned char reg;
int i;
- dbg("probe: vendor id 0x%x, device id 0x%x\n",
- le16_to_cpu(usbdev->descriptor.idVendor),
- le16_to_cpu(usbdev->descriptor.idProduct));
+ dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n",
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct));
/* our known interfaces have 3 alternate settings */
if (intf->num_altsetting != 3) {
@@ -700,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf,
return -ENODEV;
}
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
- dbg("set inteface result %d", i);
+ dev_dbg(&intf->dev, "set inteface result %d\n", i);
interface = intf->cur_altsetting;
@@ -731,11 +736,13 @@ static int uss720_probe(struct usb_interface *intf,
set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
/* debugging */
get_1284_register(pp, 0, &reg, GFP_KERNEL);
- dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
- priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+ dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n",
+ priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3],
+ priv->reg[4], priv->reg[5], priv->reg[6]);
endpoint = &interface->endpoint[2];
- dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
+ dev_dbg(&intf->dev, "epaddr %d interval %d\n",
+ endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
parport_announce_port(pp);
usb_set_intfdata(intf, pp);
@@ -753,20 +760,20 @@ static void uss720_disconnect(struct usb_interface *intf)
struct parport_uss720_private *priv;
struct usb_device *usbdev;
- dbg("disconnect");
+ dev_dbg(&intf->dev, "disconnect\n");
usb_set_intfdata(intf, NULL);
if (pp) {
priv = pp->private_data;
usbdev = priv->usbdev;
priv->usbdev = NULL;
priv->pp = NULL;
- dbg("parport_remove_port");
+ dev_dbg(&intf->dev, "parport_remove_port\n");
parport_remove_port(pp);
parport_put_port(pp);
kill_all_async_requests_priv(priv);
kref_put(&priv->ref_count, destroy_priv);
}
- dbg("disconnect done");
+ dev_dbg(&intf->dev, "disconnect done\n");
}
/* table of cables that work through this driver */
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 7020146..42ad2e6 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -83,7 +83,8 @@ static void yurex_control_callback(struct urb *urb)
int status = urb->status;
if (status) {
- err("%s - control failed: %d\n", __func__, status);
+ dev_err(&urb->dev->dev, "%s - control failed: %d\n",
+ __func__, status);
wake_up_interruptible(&dev->waitq);
return;
}
@@ -94,7 +95,7 @@ static void yurex_delete(struct kref *kref)
{
struct usb_yurex *dev = to_yurex_dev(kref);
- dbg("yurex_delete");
+ dev_dbg(&dev->interface->dev, "%s\n", __func__);
usb_put_dev(dev->udev);
if (dev->cntl_urb) {
@@ -137,8 +138,9 @@ static void yurex_interrupt(struct urb *urb)
case 0: /*success*/
break;
case -EOVERFLOW:
- err("%s - overflow with length %d, actual length is %d",
- __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
+ dev_err(&dev->interface->dev,
+ "%s - overflow with length %d, actual length is %d\n",
+ __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
@@ -146,7 +148,8 @@ static void yurex_interrupt(struct urb *urb)
/* The device is terminated, clean up */
return;
default:
- err("%s - unknown status received: %d", __func__, status);
+ dev_err(&dev->interface->dev,
+ "%s - unknown status received: %d\n", __func__, status);
goto exit;
}
@@ -162,16 +165,19 @@ static void yurex_interrupt(struct urb *urb)
if (i != 5)
dev->bbu <<= 8;
}
- dbg("%s count: %lld", __func__, dev->bbu);
+ dev_dbg(&dev->interface->dev, "%s count: %lld\n",
+ __func__, dev->bbu);
spin_unlock_irqrestore(&dev->lock, flags);
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
else
- dbg("data format error - no EOF");
+ dev_dbg(&dev->interface->dev,
+ "data format error - no EOF\n");
break;
case CMD_ACK:
- dbg("%s ack: %c", __func__, buf[1]);
+ dev_dbg(&dev->interface->dev, "%s ack: %c\n",
+ __func__, buf[1]);
wake_up_interruptible(&dev->waitq);
break;
}
@@ -179,7 +185,7 @@ static void yurex_interrupt(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval) {
- err("%s - usb_submit_urb failed: %d",
+ dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
__func__, retval);
}
}
@@ -196,7 +202,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -219,7 +225,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
}
if (!dev->int_in_endpointAddr) {
retval = -ENODEV;
- err("Could not find endpoints");
+ dev_err(&interface->dev, "Could not find endpoints\n");
goto error;
}
@@ -227,14 +233,14 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate control URB */
dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->cntl_urb) {
- err("Could not allocate control URB");
+ dev_err(&interface->dev, "Could not allocate control URB\n");
goto error;
}
/* allocate buffer for control req */
dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL);
if (!dev->cntl_req) {
- err("Could not allocate cntl_req");
+ dev_err(&interface->dev, "Could not allocate cntl_req\n");
goto error;
}
@@ -243,7 +249,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
GFP_KERNEL,
&dev->cntl_urb->transfer_dma);
if (!dev->cntl_buffer) {
- err("Could not allocate cntl_buffer");
+ dev_err(&interface->dev, "Could not allocate cntl_buffer\n");
goto error;
}
@@ -265,7 +271,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate interrupt URB */
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb) {
- err("Could not allocate URB");
+ dev_err(&interface->dev, "Could not allocate URB\n");
goto error;
}
@@ -273,7 +279,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
GFP_KERNEL, &dev->urb->transfer_dma);
if (!dev->int_buffer) {
- err("Could not allocate int_buffer");
+ dev_err(&interface->dev, "Could not allocate int_buffer\n");
goto error;
}
@@ -285,7 +291,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
retval = -EIO;
- err("Could not submitting URB");
+ dev_err(&interface->dev, "Could not submitting URB\n");
goto error;
}
@@ -295,7 +301,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &yurex_class);
if (retval) {
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
@@ -368,8 +375,8 @@ static int yurex_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&yurex_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -505,7 +512,8 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co
/* send the data as the control msg */
prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
- dbg("%s - submit %c", __func__, dev->cntl_buffer[0]);
+ dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
+ dev->cntl_buffer[0]);
retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
if (retval >= 0)
timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
@@ -514,7 +522,9 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co
mutex_unlock(&dev->io_mutex);
if (retval < 0) {
- err("%s - failed to send bulk msg, error %d", __func__, retval);
+ dev_err(&dev->interface->dev,
+ "%s - failed to send bulk msg, error %d\n",
+ __func__, retval);
goto error;
}
if (set && timeout)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index f70cab3..ef0c3f9 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -8,6 +8,7 @@ config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
depends on USB && USB_GADGET
select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+ select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX)
select TWL4030_USB if MACH_OMAP_3430SDP
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
select USB_OTG_UTILS
@@ -54,6 +55,10 @@ config USB_MUSB_AM35X
tristate "AM35x"
depends on ARCH_OMAP
+config USB_MUSB_DSPS
+ tristate "TI DSPS platforms"
+ depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX
+
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
@@ -70,7 +75,8 @@ choice
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
- default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+ default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \
+ || USB_MUSB_DSPS
help
Unfortunately, only one option can be enabled here. Ideally one
should be able to build all these drivers into one kernel to
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 88bfb9d..3b85871 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -13,6 +13,7 @@ musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
# Hardware Glue Layer
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
+obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 66bc376..8637c1f 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
* The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb.h>
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 66aaccf..db3dff8 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1034,7 +1034,9 @@ static void musb_shutdown(struct platform_device *pdev)
|| defined(CONFIG_USB_MUSB_OMAP2PLUS) \
|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \
|| defined(CONFIG_USB_MUSB_AM35X) \
- || defined(CONFIG_USB_MUSB_AM35X_MODULE)
+ || defined(CONFIG_USB_MUSB_AM35X_MODULE) \
+ || defined(CONFIG_USB_MUSB_DSPS) \
+ || defined(CONFIG_USB_MUSB_DSPS_MODULE)
static ushort __devinitdata fifo_mode = 4;
#elif defined(CONFIG_USB_MUSB_UX500) \
|| defined(CONFIG_USB_MUSB_UX500_MODULE)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
new file mode 100644
index 0000000..23db42d
--- /dev/null
+++ b/drivers/usb/musb/musb_dsps.c
@@ -0,0 +1,711 @@
+/*
+ * Texas Instruments DSPS platforms "glue layer"
+ *
+ * Copyright (C) 2012, by Texas Instruments
+ *
+ * Based on the am35x "glue layer" code.
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * musb_dsps.c will be a common file for all the TI DSPS platforms
+ * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
+ * For now only ti81x is using this and in future davinci.c, am35x.c
+ * da8xx.c would be merged to this file after testing.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#include <plat/usb.h>
+
+#include "musb_core.h"
+
+/**
+ * avoid using musb_readx()/musb_writex() as glue layer should not be
+ * dependent on musb core layer symbols.
+ */
+static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
+ { return __raw_readb(addr + offset); }
+
+static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
+ { return __raw_readl(addr + offset); }
+
+static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
+ { __raw_writeb(data, addr + offset); }
+
+static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
+ { __raw_writel(data, addr + offset); }
+
+/**
+ * DSPS musb wrapper register offset.
+ * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
+ * musb ips.
+ */
+struct dsps_musb_wrapper {
+ u16 revision;
+ u16 control;
+ u16 status;
+ u16 eoi;
+ u16 epintr_set;
+ u16 epintr_clear;
+ u16 epintr_status;
+ u16 coreintr_set;
+ u16 coreintr_clear;
+ u16 coreintr_status;
+ u16 phy_utmi;
+ u16 mode;
+
+ /* bit positions for control */
+ unsigned reset:5;
+
+ /* bit positions for interrupt */
+ unsigned usb_shift:5;
+ u32 usb_mask;
+ u32 usb_bitmap;
+ unsigned drvvbus:5;
+
+ unsigned txep_shift:5;
+ u32 txep_mask;
+ u32 txep_bitmap;
+
+ unsigned rxep_shift:5;
+ u32 rxep_mask;
+ u32 rxep_bitmap;
+
+ /* bit positions for phy_utmi */
+ unsigned otg_disable:5;
+
+ /* bit positions for mode */
+ unsigned iddig:5;
+ /* miscellaneous stuff */
+ u32 musb_core_offset;
+ u8 poll_seconds;
+};
+
+/**
+ * DSPS glue structure.
+ */
+struct dsps_glue {
+ struct device *dev;
+ struct platform_device *musb; /* child musb pdev */
+ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
+ struct timer_list timer; /* otg_workaround timer */
+};
+
+/**
+ * dsps_musb_enable - enable interrupts
+ */
+static void dsps_musb_enable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+ u32 epmask, coremask;
+
+ /* Workaround: setup IRQs through both register sets. */
+ epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
+ ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
+ coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
+
+ dsps_writel(reg_base, wrp->epintr_set, epmask);
+ dsps_writel(reg_base, wrp->coreintr_set, coremask);
+ /* Force the DRVVBUS IRQ so we can start polling for ID change. */
+ if (is_otg_enabled(musb))
+ dsps_writel(reg_base, wrp->coreintr_set,
+ (1 << wrp->drvvbus) << wrp->usb_shift);
+}
+
+/**
+ * dsps_musb_disable - disable HDRC and flush interrupts
+ */
+static void dsps_musb_disable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+
+ dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
+ dsps_writel(reg_base, wrp->epintr_clear,
+ wrp->txep_bitmap | wrp->rxep_bitmap);
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ dsps_writel(reg_base, wrp->eoi, 0);
+}
+
+static void otg_timer(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ void __iomem *mregs = musb->mregs;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ u8 devctl;
+ unsigned long flags;
+
+ /*
+ * We poll because DSPS IP's won't expose several OTG-critical
+ * status change events (from the transceiver) otherwise.
+ */
+ devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+ otg_state_string(musb->xceiv->state));
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ } else {
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ }
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ dsps_writel(musb->ctrl_base, wrp->coreintr_set,
+ MUSB_INTR_VBUSERROR << wrp->usb_shift);
+ break;
+ case OTG_STATE_B_IDLE:
+ if (!is_peripheral_enabled(musb))
+ break;
+
+ devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ mod_timer(&glue->timer,
+ jiffies + wrp->poll_seconds * HZ);
+ else
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ static unsigned long last_timer;
+
+ if (!is_otg_enabled(musb))
+ return;
+
+ if (timeout == 0)
+ timeout = jiffies + msecs_to_jiffies(3);
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || (musb->a_wait_bcon == 0 &&
+ musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ dev_dbg(musb->controller, "%s active, deleting timer\n",
+ otg_state_string(musb->xceiv->state));
+ del_timer(&glue->timer);
+ last_timer = jiffies;
+ return;
+ }
+
+ if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
+ dev_dbg(musb->controller,
+ "Longer idle timer already pending, ignoring...\n");
+ return;
+ }
+ last_timer = timeout;
+
+ dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
+ otg_state_string(musb->xceiv->state),
+ jiffies_to_msecs(timeout - jiffies));
+ mod_timer(&glue->timer, timeout);
+}
+
+static irqreturn_t dsps_interrupt(int irq, void *hci)
+{
+ struct musb *musb = hci;
+ void __iomem *reg_base = musb->ctrl_base;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ u32 epintr, usbintr;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* Get endpoint interrupts */
+ epintr = dsps_readl(reg_base, wrp->epintr_status);
+ musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
+ musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
+
+ if (epintr)
+ dsps_writel(reg_base, wrp->epintr_status, epintr);
+
+ /* Get usb core interrupts */
+ usbintr = dsps_readl(reg_base, wrp->coreintr_status);
+ if (!usbintr && !epintr)
+ goto eoi;
+
+ musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
+ if (usbintr)
+ dsps_writel(reg_base, wrp->coreintr_status, usbintr);
+
+ dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
+ usbintr, epintr);
+ /*
+ * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+ * DSPS IP's missing ID change IRQ. We need an ID change IRQ to
+ * switch appropriately between halves of the OTG state machine.
+ * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+ * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+ * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+ */
+ if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
+ pr_info("CAUTION: musb: Babble Interrupt Occured\n");
+
+ if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
+ int drvvbus = dsps_readl(reg_base, wrp->status);
+ void __iomem *mregs = musb->mregs;
+ u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ int err;
+
+ err = is_host_enabled(musb) && (musb->int_usb &
+ MUSB_INTR_VBUSERROR);
+ if (err) {
+ /*
+ * The Mentor core doesn't debounce VBUS as needed
+ * to cope with device connect current spikes. This
+ * means it's not uncommon for bus-powered devices
+ * to get VBUS errors during enumeration.
+ *
+ * This is a workaround, but newer RTL from Mentor
+ * seems to allow a better one: "re"-starting sessions
+ * without waiting for VBUS to stop registering in
+ * devctl.
+ */
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ mod_timer(&glue->timer,
+ jiffies + wrp->poll_seconds * HZ);
+ WARNING("VBUS error workaround (delay coming)\n");
+ } else if (is_host_enabled(musb) && drvvbus) {
+ musb->is_active = 1;
+ MUSB_HST_MODE(musb);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ del_timer(&glue->timer);
+ } else {
+ musb->is_active = 0;
+ MUSB_DEV_MODE(musb);
+ musb->xceiv->otg->default_a = 0;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
+
+ /* NOTE: this must complete power-on within 100 ms. */
+ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+ drvvbus ? "on" : "off",
+ otg_state_string(musb->xceiv->state),
+ err ? " ERROR" : "",
+ devctl);
+ ret = IRQ_HANDLED;
+ }
+
+ if (musb->int_tx || musb->int_rx || musb->int_usb)
+ ret |= musb_interrupt(musb);
+
+ eoi:
+ /* EOI needs to be written for the IRQ to be re-asserted. */
+ if (ret == IRQ_HANDLED || epintr || usbintr)
+ dsps_writel(reg_base, wrp->eoi, 1);
+
+ /* Poll for ID change */
+ if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return ret;
+}
+
+static int dsps_musb_init(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ struct omap_musb_board_data *data = plat->board_data;
+ void __iomem *reg_base = musb->ctrl_base;
+ u32 rev, val;
+ int status;
+
+ /* mentor core register starts at offset of 0x400 from musb base */
+ musb->mregs += wrp->musb_core_offset;
+
+ /* NOP driver needs change if supporting dual instance */
+ usb_nop_xceiv_register();
+ musb->xceiv = usb_get_transceiver();
+ if (!musb->xceiv)
+ return -ENODEV;
+
+ /* Returns zero if e.g. not clocked */
+ rev = dsps_readl(reg_base, wrp->revision);
+ if (!rev) {
+ status = -ENODEV;
+ goto err0;
+ }
+
+ if (is_host_enabled(musb))
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+
+ /* Reset the musb */
+ dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+
+ /* Start the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(1);
+
+ musb->isr = dsps_interrupt;
+
+ /* reset the otgdisable bit, needed for host mode to work */
+ val = dsps_readl(reg_base, wrp->phy_utmi);
+ val &= ~(1 << wrp->otg_disable);
+ dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+
+ /* clear level interrupt */
+ dsps_writel(reg_base, wrp->eoi, 0);
+
+ return 0;
+err0:
+ usb_put_transceiver(musb->xceiv);
+ usb_nop_xceiv_unregister();
+ return status;
+}
+
+static int dsps_musb_exit(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+ if (is_host_enabled(musb))
+ del_timer_sync(&glue->timer);
+
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
+
+ /* NOP driver needs change if supporting dual instance */
+ usb_put_transceiver(musb->xceiv);
+ usb_nop_xceiv_unregister();
+
+ return 0;
+}
+
+static struct musb_platform_ops dsps_ops = {
+ .init = dsps_musb_init,
+ .exit = dsps_musb_exit,
+
+ .enable = dsps_musb_enable,
+ .disable = dsps_musb_disable,
+
+ .try_idle = dsps_musb_try_idle,
+};
+
+static u64 musb_dmamask = DMA_BIT_MASK(32);
+
+static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+{
+ struct device *dev = glue->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct platform_device *musb;
+ struct resource *res;
+ struct resource resources[2];
+ char res_name[10];
+ int ret;
+
+ /* get memory resource */
+ sprintf(res_name, "musb%d", id);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+ if (!res) {
+ dev_err(dev, "%s get mem resource failed\n", res_name);
+ ret = -ENODEV;
+ goto err0;
+ }
+ res->parent = NULL;
+ resources[0] = *res;
+
+ /* get irq resource */
+ sprintf(res_name, "musb%d-irq", id);
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+ if (!res) {
+ dev_err(dev, "%s get irq resource failed\n", res_name);
+ ret = -ENODEV;
+ goto err0;
+ }
+ strcpy((u8 *)res->name, "mc");
+ res->parent = NULL;
+ resources[1] = *res;
+
+ /* allocate the child platform device */
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(dev, "failed to allocate musb device\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ musb->dev.parent = dev;
+ musb->dev.dma_mask = &musb_dmamask;
+ musb->dev.coherent_dma_mask = musb_dmamask;
+
+ glue->musb = musb;
+
+ pdata->platform_ops = &dsps_ops;
+
+ ret = platform_device_add_resources(musb, resources, 2);
+ if (ret) {
+ dev_err(dev, "failed to add resources\n");
+ goto err1;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(dev, "failed to add platform_data\n");
+ goto err1;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(dev, "failed to register musb device\n");
+ goto err1;
+ }
+
+ return 0;
+
+err1:
+ platform_device_put(musb);
+err0:
+ return ret;
+}
+
+static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
+{
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+}
+
+static int __devinit dsps_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ const struct dsps_musb_wrapper *wrp =
+ (struct dsps_musb_wrapper *)id->driver_data;
+ struct dsps_glue *glue;
+ struct resource *iomem;
+ int ret;
+
+ /* allocate glue */
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "unable to allocate glue memory\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ /* get memory resource */
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ glue->dev = &pdev->dev;
+
+ glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
+ if (!glue->wrp) {
+ dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+ platform_set_drvdata(pdev, glue);
+
+ /* create the child platform device for first instances of musb */
+ ret = dsps_create_musb_pdev(glue, 0);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to create child pdev\n");
+ goto err2;
+ }
+
+ /* enable the usbss clocks */
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+ goto err3;
+ }
+
+ return 0;
+
+err3:
+ pm_runtime_disable(&pdev->dev);
+err2:
+ kfree(glue->wrp);
+err1:
+ kfree(glue);
+err0:
+ return ret;
+}
+static int __devexit dsps_remove(struct platform_device *pdev)
+{
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+ /* delete the child platform device */
+ dsps_delete_musb_pdev(glue);
+
+ /* disable usbss clocks */
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ kfree(glue->wrp);
+ kfree(glue);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dsps_suspend(struct device *dev)
+{
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
+
+ return 0;
+}
+
+static int dsps_resume(struct device *dev)
+{
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
+ /* Start the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(1);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
+
+static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
+ .revision = 0x00,
+ .control = 0x14,
+ .status = 0x18,
+ .eoi = 0x24,
+ .epintr_set = 0x38,
+ .epintr_clear = 0x40,
+ .epintr_status = 0x30,
+ .coreintr_set = 0x3c,
+ .coreintr_clear = 0x44,
+ .coreintr_status = 0x34,
+ .phy_utmi = 0xe0,
+ .mode = 0xe8,
+ .reset = 0,
+ .otg_disable = 21,
+ .iddig = 8,
+ .usb_shift = 0,
+ .usb_mask = 0x1ff,
+ .usb_bitmap = (0x1ff << 0),
+ .drvvbus = 8,
+ .txep_shift = 0,
+ .txep_mask = 0xffff,
+ .txep_bitmap = (0xffff << 0),
+ .rxep_shift = 16,
+ .rxep_mask = 0xfffe,
+ .rxep_bitmap = (0xfffe << 16),
+ .musb_core_offset = 0x400,
+ .poll_seconds = 2,
+};
+
+static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
+ {
+ .name = "musb-ti81xx",
+ .driver_data = (kernel_ulong_t) &ti81xx_driver_data,
+ },
+ { }, /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
+
+static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
+ { .compatible = "musb-ti81xx", },
+ { .compatible = "ti,ti81xx-musb", },
+ { .compatible = "ti,am335x-musb", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
+
+static struct platform_driver dsps_usbss_driver = {
+ .probe = dsps_probe,
+ .remove = __devexit_p(dsps_remove),
+ .driver = {
+ .name = "musb-dsps",
+ .pm = &dsps_pm_ops,
+ .of_match_table = musb_dsps_of_match,
+ },
+ .id_table = musb_dsps_id_table,
+};
+
+MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
+MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init dsps_init(void)
+{
+ return platform_driver_register(&dsps_usbss_driver);
+}
+subsys_initcall(dsps_init);
+
+static void __exit dsps_exit(void)
+{
+ platform_driver_unregister(&dsps_usbss_driver);
+}
+module_exit(dsps_exit);
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index 1d5eda2..f7c1c8e2 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -40,7 +40,7 @@
#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
&& !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \
- && !defined(CONFIG_MIPS)
+ && !defined(CONFIG_MIPS) && !defined(CONFIG_M68K)
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/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index a0a2178..bde6298 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -37,7 +37,9 @@ struct gpio_vbus_data {
struct regulator *vbus_draw;
int vbus_draw_enabled;
unsigned mA;
- struct work_struct work;
+ struct delayed_work work;
+ int vbus;
+ int irq;
};
@@ -51,8 +53,7 @@ struct gpio_vbus_data {
* edges might be workable.
*/
#define VBUS_IRQ_FLAGS \
- ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \
- | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING )
+ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
/* interface to regulator framework */
@@ -94,20 +95,26 @@ static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
static void gpio_vbus_work(struct work_struct *work)
{
struct gpio_vbus_data *gpio_vbus =
- container_of(work, struct gpio_vbus_data, work);
+ container_of(work, struct gpio_vbus_data, work.work);
struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
- int gpio, status;
+ int gpio, status, vbus;
if (!gpio_vbus->phy.otg->gadget)
return;
+ vbus = is_vbus_powered(pdata);
+ if ((vbus ^ gpio_vbus->vbus) == 0)
+ return;
+ gpio_vbus->vbus = vbus;
+
/* Peripheral controllers which manage the pullup themselves won't have
* gpio_pullup configured here. If it's configured here, we'll do what
* isp1301_omap::b_peripheral() does and enable the pullup here... although
* that may complicate usb_gadget_{,dis}connect() support.
*/
gpio = pdata->gpio_pullup;
- if (is_vbus_powered(pdata)) {
+
+ if (vbus) {
status = USB_EVENT_VBUS;
gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
gpio_vbus->phy.last_event = status;
@@ -152,7 +159,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
otg->gadget ? otg->gadget->name : "none");
if (otg->gadget)
- schedule_work(&gpio_vbus->work);
+ schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
return IRQ_HANDLED;
}
@@ -166,12 +173,11 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
struct gpio_vbus_data *gpio_vbus;
struct gpio_vbus_mach_info *pdata;
struct platform_device *pdev;
- int gpio, irq;
+ int gpio;
gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
pdev = to_platform_device(gpio_vbus->dev);
pdata = gpio_vbus->dev->platform_data;
- irq = gpio_to_irq(pdata->gpio_vbus);
gpio = pdata->gpio_pullup;
if (!gadget) {
@@ -195,7 +201,8 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
/* initialize connection state */
- gpio_vbus_irq(irq, pdev);
+ gpio_vbus->vbus = 0; /* start with disconnected */
+ gpio_vbus_irq(gpio_vbus->irq, pdev);
return 0;
}
@@ -235,6 +242,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
struct gpio_vbus_data *gpio_vbus;
struct resource *res;
int err, gpio, irq;
+ unsigned long irqflags;
if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
return -EINVAL;
@@ -271,10 +279,13 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
irq = res->start;
- res->flags &= IRQF_TRIGGER_MASK;
- res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
- } else
+ irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
+ } else {
irq = gpio_to_irq(gpio);
+ irqflags = VBUS_IRQ_FLAGS;
+ }
+
+ gpio_vbus->irq = irq;
/* if data line pullup is in use, initialize it to "not pulling up" */
gpio = pdata->gpio_pullup;
@@ -290,8 +301,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
}
- err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
- "vbus_detect", pdev);
+ err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev);
if (err) {
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
irq, err);
@@ -300,7 +310,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
- INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
+ INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
if (IS_ERR(gpio_vbus->vbus_draw)) {
@@ -317,9 +327,12 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
goto err_otg;
}
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
return 0;
err_otg:
- free_irq(irq, &pdev->dev);
+ regulator_put(gpio_vbus->vbus_draw);
+ free_irq(irq, pdev);
err_irq:
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
@@ -337,11 +350,13 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
int gpio = pdata->gpio_vbus;
+ device_init_wakeup(&pdev->dev, 0);
+ cancel_delayed_work_sync(&gpio_vbus->work);
regulator_put(gpio_vbus->vbus_draw);
usb_set_transceiver(NULL);
- free_irq(gpio_to_irq(gpio), &pdev->dev);
+ free_irq(gpio_vbus->irq, pdev);
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
gpio_free(gpio);
@@ -352,6 +367,33 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int gpio_vbus_pm_suspend(struct device *dev)
+{
+ struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(gpio_vbus->irq);
+
+ return 0;
+}
+
+static int gpio_vbus_pm_resume(struct device *dev)
+{
+ struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(gpio_vbus->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
+ .suspend = gpio_vbus_pm_suspend,
+ .resume = gpio_vbus_pm_resume,
+};
+#endif
+
/* NOTE: the gpio-vbus device may *NOT* be hotplugged */
MODULE_ALIAS("platform:gpio-vbus");
@@ -360,6 +402,9 @@ static struct platform_driver gpio_vbus_driver = {
.driver = {
.name = "gpio-vbus",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_vbus_dev_pm_ops,
+#endif
},
.remove = __exit_p(gpio_vbus_remove),
};
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index e3fa387..d2a9a8e 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -455,7 +455,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
twl->irq_enabled = true;
status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"twl6030_usb", twl);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
@@ -467,7 +467,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
}
status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"twl6030_usb", twl);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
new file mode 100644
index 0000000..3cfabcb
--- /dev/null
+++ b/drivers/usb/phy/Kconfig
@@ -0,0 +1,17 @@
+#
+# Physical Layer USB driver configuration
+#
+comment "USB Physical Layer drivers"
+ depends on USB
+
+config USB_ISP1301
+ tristate "NXP ISP1301 USB transceiver support"
+ depends on USB
+ depends on I2C
+ help
+ Say Y here to add support for the NXP ISP1301 USB transceiver driver.
+ This chip is typically used as USB transceiver for USB host, gadget
+ and OTG drivers (to be selected separately).
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1301.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644
index 0000000..eca095b
--- /dev/null
+++ b/drivers/usb/phy/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for physical layer USB drivers
+#
+
+ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_ISP1301) += isp1301.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
new file mode 100644
index 0000000..b19f493
--- /dev/null
+++ b/drivers/usb/phy/isp1301.c
@@ -0,0 +1,77 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#define DRV_NAME "isp1301"
+
+#define ISP1301_I2C_ADDR 0x2C
+
+static const unsigned short normal_i2c[] = {
+ ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301", 0 },
+ { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int isp1301_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ isp1301_i2c_client = client;
+ return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .probe = isp1301_probe,
+ .remove = isp1301_remove,
+ .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return (dev->of_node == node) &&
+ (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+ if (node) { /* reference of ISP1301 I2C node via DT */
+ struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+ node, match);
+ if (!dev)
+ return NULL;
+ return to_i2c_client(dev);
+ } else { /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
+ }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 00bd2a5..28478ce 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -55,6 +55,7 @@ struct usbhsg_gpriv {
#define USBHSG_STATUS_STARTED (1 << 0)
#define USBHSG_STATUS_REGISTERD (1 << 1)
#define USBHSG_STATUS_WEDGE (1 << 2)
+#define USBHSG_STATUS_SELF_POWERED (1 << 3)
};
struct usbhsg_recip_handle {
@@ -333,7 +334,10 @@ static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv,
struct usb_ctrlrequest *ctrl)
{
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+ unsigned short status = 0;
+
+ if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED))
+ status = 1 << USB_DEVICE_SELF_POWERED;
__usbhsg_recip_send_status(gpriv, status);
@@ -879,8 +883,21 @@ static int usbhsg_get_frame(struct usb_gadget *gadget)
return usbhs_frame_get_num(priv);
}
+static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
+
+ if (is_self)
+ usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED);
+ else
+ usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
+
+ return 0;
+}
+
static struct usb_gadget_ops usbhsg_gadget_ops = {
.get_frame = usbhsg_get_frame,
+ .set_selfpowered = usbhsg_set_selfpowered,
.udc_start = usbhsg_gadget_start,
.udc_stop = usbhsg_gadget_stop,
};
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 7141d65..325d291 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -669,6 +669,15 @@ config USB_SERIAL_SSU100
To compile this driver as a module, choose M here: the
module will be called ssu100.
+config USB_SERIAL_QT2
+ tristate "USB Quatech Serial Driver for USB 2 devices"
+ help
+ Say Y here if you want to use the Quatech USB 2
+ serial adapters.
+
+ To compile this driver as a module, choose M here: the
+ module will be called quatech-serial.
+
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07f198e..1dc483a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
+obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index eec4fb9..d634e66 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -111,13 +111,14 @@ static int aircable_probe(struct usb_serial *serial,
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_out(endpoint)) {
- dbg("found bulk out on endpoint %d", i);
+ dev_dbg(&serial->dev->dev,
+ "found bulk out on endpoint %d\n", i);
++num_bulk_out;
}
}
if (num_bulk_out == 0) {
- dbg("Invalid interface, discarding");
+ dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n");
return -ENODEV;
}
@@ -133,7 +134,7 @@ static int aircable_process_packet(struct tty_struct *tty,
packet += HCI_HEADER_LENGTH;
}
if (len <= 0) {
- dbg("%s - malformed packet", __func__);
+ dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
return 0;
}
@@ -170,13 +171,6 @@ static void aircable_process_read_urb(struct urb *urb)
tty_kref_put(tty);
}
-static struct usb_driver aircable_driver = {
- .name = "aircable",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver aircable_device = {
.driver = {
.owner = THIS_MODULE,
@@ -196,7 +190,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&aircable_device, NULL
};
-module_usb_serial_driver(aircable_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index f99f4710..f8ce97d 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -265,7 +265,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
hcr = (cflag & CRTSCTS) ? 0x03 : 0x00;
/* calc baudrate */
- dbg("%s - setting bps to %d", __func__, bps);
+ dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps);
eval = 0;
switch (bps) {
case 0:
@@ -292,8 +292,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
/* keep old LCR_SBC bit */
lcr |= (priv->lcr & UART_LCR_SBC);
- dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d",
- __func__, hcr, lcr, quot);
+ dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n",
+ __func__, hcr, lcr, quot);
/* handshake control */
if (priv->hcr != hcr) {
@@ -375,8 +375,9 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
result = usb_serial_generic_open(tty, port);
if (result) {
- dbg("%s - usb_serial_generic_open failed: %d",
- __func__, result);
+ dev_dbg(&port->dev,
+ "%s - usb_serial_generic_open failed: %d\n",
+ __func__, result);
goto err_out;
}
@@ -622,24 +623,26 @@ static void ark3116_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
break;
case 0: /* success */
/* discovered this by trail and error... */
if ((urb->actual_length == 4) && (data[0] == 0xe8)) {
const __u8 id = data[1]&UART_IIR_ID;
- dbg("%s: iir=%02x", __func__, data[1]);
+ dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]);
if (id == UART_IIR_MSI) {
- dbg("%s: msr=%02x", __func__, data[3]);
+ dev_dbg(&port->dev, "%s: msr=%02x\n",
+ __func__, data[3]);
ark3116_update_msr(port, data[3]);
break;
} else if (id == UART_IIR_RLSI) {
- dbg("%s: lsr=%02x", __func__, data[2]);
+ dev_dbg(&port->dev, "%s: lsr=%02x\n",
+ __func__, data[2]);
ark3116_update_lsr(port, data[2]);
break;
}
@@ -714,13 +717,6 @@ static void ark3116_process_read_urb(struct urb *urb)
tty_kref_put(tty);
}
-static struct usb_driver ark3116_driver = {
- .name = "ark3116",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver ark3116_device = {
.driver = {
.owner = THIS_MODULE,
@@ -747,7 +743,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ark3116_device, NULL
};
-module_usb_serial_driver(ark3116_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a52e0d2..6b73656 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -2,17 +2,17 @@
* Belkin USB Serial Adapter Driver
*
* Copyright (C) 2000 William Greathouse (wgreathouse@smva.com)
- * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
*
* This program is largely derived from work by the linux-usb group
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this
* driver
@@ -62,7 +62,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
@@ -71,14 +71,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver belkin_driver = {
- .name = "belkin",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
/* All of the device info needed for the serial converters */
static struct usb_serial_driver belkin_device = {
@@ -87,7 +80,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
- .id_table = id_table_combined,
+ .id_table = id_table,
.num_ports = 1,
.open = belkin_sa_open,
.close = belkin_sa_close,
@@ -159,8 +152,6 @@ static void belkin_sa_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -170,8 +161,6 @@ static int belkin_sa_open(struct tty_struct *tty,
{
int retval;
- dbg("%s port %d", __func__, port->number);
-
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
@@ -187,8 +176,6 @@ static int belkin_sa_open(struct tty_struct *tty,
static void belkin_sa_close(struct usb_serial_port *port)
{
- dbg("%s port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -210,12 +197,12 @@ static void belkin_sa_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -403,7 +390,9 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
case CS8:
urb_value = BELKIN_SA_DATA_BITS(8);
break;
- default: dbg("CSIZE was not CS5-CS8, using default of 8");
+ default:
+ dev_dbg(&port->dev,
+ "CSIZE was not CS5-CS8, using default of 8\n");
urb_value = BELKIN_SA_DATA_BITS(8);
break;
}
@@ -463,8 +452,6 @@ static int belkin_sa_tiocmget(struct tty_struct *tty)
unsigned long control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -484,8 +471,6 @@ static int belkin_sa_tiocmset(struct tty_struct *tty,
int rts = 0;
int dtr = 0;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -524,7 +509,7 @@ exit:
return retval;
}
-module_usb_serial_driver(belkin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index ed8adb0..f398d1e 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -124,8 +124,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
}
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+ struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+
+ return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
static struct driver_attribute drv_attrs[] = {
- __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+ __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
__ATTR_NULL,
};
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index aaab32d..cabd1b1 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -125,8 +125,6 @@ static int ch341_set_baudrate(struct usb_device *dev,
unsigned long factor;
short divisor;
- dbg("ch341_set_baudrate(%d)", priv->baud_rate);
-
if (!priv->baud_rate)
return -EINVAL;
factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
@@ -153,7 +151,6 @@ static int ch341_set_baudrate(struct usb_device *dev,
static int ch341_set_handshake(struct usb_device *dev, u8 control)
{
- dbg("ch341_set_handshake(0x%02x)", control);
return ch341_control_out(dev, 0xa4, ~control, 0);
}
@@ -164,8 +161,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
const unsigned size = 8;
unsigned long flags;
- dbg("ch341_get_status()");
-
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -196,8 +191,6 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
int r;
const unsigned size = 8;
- dbg("ch341_configure()");
-
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -254,8 +247,6 @@ static int ch341_attach(struct usb_serial *serial)
struct ch341_private *priv;
int r;
- dbg("ch341_attach()");
-
/* private data */
priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
if (!priv)
@@ -290,7 +281,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
@@ -304,8 +294,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
static void ch341_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -318,8 +306,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
int r;
- dbg("ch341_open()");
-
priv->baud_rate = DEFAULT_BAUD_RATE;
r = ch341_configure(serial->dev, priv);
@@ -358,8 +344,6 @@ static void ch341_set_termios(struct tty_struct *tty,
unsigned baud_rate;
unsigned long flags;
- dbg("ch341_set_termios()");
-
baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate;
@@ -393,8 +377,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
uint16_t reg_contents;
uint8_t *break_reg;
- dbg("%s()", __func__);
-
break_reg = kmalloc(2, GFP_KERNEL);
if (!break_reg) {
dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
@@ -461,8 +443,6 @@ static void ch341_read_int_callback(struct urb *urb)
unsigned int actual_length = urb->actual_length;
int status;
- dbg("%s (%d)", __func__, port->number);
-
switch (urb->status) {
case 0:
/* success */
@@ -580,8 +560,6 @@ static int ch341_tiocmget(struct tty_struct *tty)
u8 status;
unsigned int result;
- dbg("%s (%d)", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
@@ -599,35 +577,18 @@ static int ch341_tiocmget(struct tty_struct *tty)
return result;
}
-
-static int ch341_reset_resume(struct usb_interface *intf)
+static int ch341_reset_resume(struct usb_serial *serial)
{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_serial *serial = NULL;
struct ch341_private *priv;
- serial = usb_get_intfdata(intf);
priv = usb_get_serial_port_data(serial->port[0]);
- /*reconfigure ch341 serial port after bus-reset*/
- ch341_configure(dev, priv);
-
- usb_serial_resume(intf);
+ /* reconfigure ch341 serial port after bus-reset */
+ ch341_configure(serial->dev, priv);
return 0;
}
-static struct usb_driver ch341_driver = {
- .name = "ch341",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .reset_resume = ch341_reset_resume,
- .id_table = id_table,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver ch341_device = {
.driver = {
.owner = THIS_MODULE,
@@ -646,13 +607,14 @@ static struct usb_serial_driver ch341_device = {
.tiocmset = ch341_tiocmset,
.read_int_callback = ch341_read_int_callback,
.attach = ch341_attach,
+ .reset_resume = ch341_reset_resume,
};
static struct usb_serial_driver * const serial_drivers[] = {
&ch341_device, NULL
};
-module_usb_serial_driver(ch341_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 1ee6b2a..b9cca6d 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -113,7 +113,8 @@ static int usb_console_setup(struct console *co, char *options)
serial = usb_serial_get_by_index(co->index);
if (serial == NULL) {
/* no device is connected yet, sorry :( */
- err("No USB device connected to ttyUSB%i", co->index);
+ printk(KERN_ERR "No USB device connected to ttyUSB%i\n",
+ co->index);
return -ENODEV;
}
@@ -137,7 +138,7 @@ static int usb_console_setup(struct console *co, char *options)
tty = kzalloc(sizeof(*tty), GFP_KERNEL);
if (!tty) {
retval = -ENOMEM;
- err("no more memory");
+ dev_err(&port->dev, "no more memory\n");
goto reset_open_count;
}
kref_init(&tty->kref);
@@ -146,7 +147,7 @@ static int usb_console_setup(struct console *co, char *options)
tty->index = co->index;
if (tty_init_termios(tty)) {
retval = -ENOMEM;
- err("no more memory");
+ dev_err(&port->dev, "no more memory\n");
goto free_tty;
}
}
@@ -159,7 +160,7 @@ static int usb_console_setup(struct console *co, char *options)
retval = usb_serial_generic_open(NULL, port);
if (retval) {
- err("could not open USB console port");
+ dev_err(&port->dev, "could not open USB console port\n");
goto fail;
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ec30f95..1b19262 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -156,13 +156,6 @@ struct cp210x_port_private {
__u8 bInterfaceNumber;
};
-static struct usb_driver cp210x_driver = {
- .name = "cp210x",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver cp210x_device = {
.driver = {
.owner = THIS_MODULE,
@@ -188,8 +181,10 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
/* Config request types */
-#define REQTYPE_HOST_TO_DEVICE 0x41
-#define REQTYPE_DEVICE_TO_HOST 0xc1
+#define REQTYPE_HOST_TO_INTERFACE 0x41
+#define REQTYPE_INTERFACE_TO_HOST 0xc1
+#define REQTYPE_HOST_TO_DEVICE 0x40
+#define REQTYPE_DEVICE_TO_HOST 0xc0
/* Config request codes */
#define CP210X_IFC_ENABLE 0x00
@@ -286,7 +281,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- request, REQTYPE_DEVICE_TO_HOST, 0x0000,
+ request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_GET_TIMEOUT);
@@ -340,13 +335,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
if (size > 2) {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+ request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_SET_TIMEOUT);
} else {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_DEVICE, data[0],
+ request, REQTYPE_HOST_TO_INTERFACE, data[0],
port_priv->bInterfaceNumber, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
@@ -422,8 +417,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result;
- dbg("%s - port %d", __func__, port->number);
-
result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
UART_ENABLE);
if (result) {
@@ -443,8 +436,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
mutex_lock(&port->serial->disc_mutex);
@@ -488,8 +479,6 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int baud;
unsigned int bits;
- dbg("%s - port %d", __func__, port->number);
-
cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
dbg("%s - baud rate = %d", __func__, baud);
@@ -787,8 +776,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
{
unsigned int control = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (set & TIOCM_RTS) {
control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
@@ -825,8 +812,6 @@ static int cp210x_tiocmget (struct tty_struct *tty)
unsigned int control;
int result;
- dbg("%s - port %d", __func__, port->number);
-
cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
@@ -846,7 +831,6 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
struct usb_serial_port *port = tty->driver_data;
unsigned int state;
- dbg("%s - port %d", __func__, port->number);
if (break_state == 0)
state = BREAK_OFF;
else
@@ -891,7 +875,7 @@ static void cp210x_release(struct usb_serial *serial)
}
}
-module_usb_serial_driver(cp210x_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index d39b941..3aa0b53 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -77,13 +77,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver cyberjack_driver = {
- .name = "cyberjack",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver cyberjack_device = {
.driver = {
.owner = THIS_MODULE,
@@ -122,8 +115,6 @@ static int cyberjack_startup(struct usb_serial *serial)
struct cyberjack_private *priv;
int i;
- dbg("%s", __func__);
-
/* allocate the private data structure */
priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
if (!priv)
@@ -155,8 +146,6 @@ static void cyberjack_disconnect(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
usb_kill_urb(serial->port[i]->interrupt_in_urb);
}
@@ -165,8 +154,6 @@ static void cyberjack_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
/* My special items, the standard routines free my urbs */
kfree(usb_get_serial_port_data(serial->port[i]));
@@ -180,8 +167,6 @@ static int cyberjack_open(struct tty_struct *tty,
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
dbg("%s - usb_clear_halt", __func__);
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
@@ -197,8 +182,6 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
if (port->serial->dev) {
/* shutdown any bulk reads that might be going on */
usb_kill_urb(port->write_urb);
@@ -214,8 +197,6 @@ static int cyberjack_write(struct tty_struct *tty,
int result;
int wrexpected;
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -307,8 +288,6 @@ static void cyberjack_read_int_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s - port %d", __func__, port->number);
-
/* the urb might have been killed. */
if (status)
return;
@@ -367,8 +346,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
if (status) {
@@ -417,8 +394,6 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
struct cyberjack_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
set_bit(0, &port->write_urbs_free);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
@@ -475,7 +450,7 @@ exit:
usb_serial_port_softint(port);
}
-module_usb_serial_driver(cyberjack_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index afc886c..b78c34e 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -89,13 +89,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver cypress_driver = {
- .name = "cypress",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
enum packet_format {
packet_format_1, /* b0:status, b1:payload count */
packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */
@@ -305,8 +298,6 @@ static int cypress_serial_control(struct tty_struct *tty,
const unsigned int feature_len = 5;
unsigned long flags;
- dbg("%s", __func__);
-
priv = usb_get_serial_port_data(port);
if (!priv->comm_is_ok)
@@ -451,8 +442,6 @@ static int generic_startup(struct usb_serial *serial)
struct cypress_private *priv;
struct usb_serial_port *port = serial->port[0];
- dbg("%s - port %d", __func__, port->number);
-
priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -505,8 +494,6 @@ static int cypress_earthmate_startup(struct usb_serial *serial)
struct cypress_private *priv;
struct usb_serial_port *port = serial->port[0];
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
port->number);
@@ -537,8 +524,6 @@ static int cypress_hidcom_startup(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
@@ -556,8 +541,6 @@ static int cypress_ca42v2_startup(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
@@ -575,10 +558,7 @@ static void cypress_release(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s - port %d", __func__, serial->port[0]->number);
-
/* all open ports are closed at this point */
-
priv = usb_get_serial_port_data(serial->port[0]);
if (priv) {
@@ -595,8 +575,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (!priv->comm_is_ok)
return -EIO;
@@ -661,8 +639,6 @@ static void cypress_close(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
@@ -720,7 +696,6 @@ static void cypress_send(struct usb_serial_port *port)
if (!priv->comm_is_ok)
return;
- dbg("%s - port %d", __func__, port->number);
dbg("%s - interrupt out size is %d", __func__,
port->interrupt_out_size);
@@ -828,8 +803,6 @@ static int cypress_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
room = kfifo_avail(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -847,8 +820,6 @@ static int cypress_tiocmget(struct tty_struct *tty)
unsigned int result = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
status = priv->current_status;
@@ -874,8 +845,6 @@ static int cypress_tiocmset(struct tty_struct *tty,
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
@@ -948,8 +917,6 @@ static void cypress_set_termios(struct tty_struct *tty,
__u8 oldlines;
int linechange = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
/* We can't clean this one up as we don't know the device type
early enough */
@@ -1096,8 +1063,6 @@ static int cypress_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
chars = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1112,8 +1077,6 @@ static void cypress_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->rx_flags = THROTTLED;
spin_unlock_irq(&priv->lock);
@@ -1126,8 +1089,6 @@ static void cypress_unthrottle(struct tty_struct *tty)
struct cypress_private *priv = usb_get_serial_port_data(port);
int actually_throttled, result;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags = 0;
@@ -1161,8 +1122,6 @@ static void cypress_read_int_callback(struct urb *urb)
int i = 0;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0: /* success */
break;
@@ -1303,8 +1262,6 @@ static void cypress_write_int_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -1346,7 +1303,7 @@ static void cypress_write_int_callback(struct urb *urb)
cypress_send(port);
}
-module_usb_serial_driver(cypress_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 999f91b..b5cd838 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -271,14 +271,6 @@ static const struct usb_device_id id_table_4[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver digi_driver = {
- .name = "digi_acceleport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
-
/* device info needed for the Digi serial converter */
static struct usb_serial_driver digi_acceleport_2_device = {
@@ -657,9 +649,6 @@ static void digi_rx_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
-
- dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);
-
/* stop receiving characters by not resubmitting the read urb */
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_throttled = 1;
@@ -675,8 +664,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
- dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* restart read chain */
@@ -904,8 +891,6 @@ static int digi_tiocmget(struct tty_struct *tty)
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = priv->dp_modem_signals;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -921,8 +906,6 @@ static int digi_tiocmset(struct tty_struct *tty,
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = (priv->dp_modem_signals & ~clear) | set;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -1013,8 +996,6 @@ static void digi_write_bulk_callback(struct urb *urb)
int ret = 0;
int status = urb->status;
- dbg("digi_write_bulk_callback: TOP, status=%d", status);
-
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
pr_err("%s: port or port->private is NULL, status=%d\n",
@@ -1121,8 +1102,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
- dbg("digi_open: TOP: port=%d", priv->dp_port_num);
-
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
return -ENXIO;
@@ -1160,8 +1139,6 @@ static void digi_close(struct usb_serial_port *port)
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- dbg("digi_close: TOP: port=%d", priv->dp_port_num);
-
mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
if (port->serial->disconnected)
@@ -1220,7 +1197,6 @@ exit:
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
- dbg("digi_close: done");
}
@@ -1269,8 +1245,6 @@ static int digi_startup(struct usb_serial *serial)
struct digi_port *priv;
struct digi_serial *serial_priv;
- dbg("digi_startup: TOP");
-
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1325,7 +1299,6 @@ static int digi_startup(struct usb_serial *serial)
static void digi_disconnect(struct usb_serial *serial)
{
int i;
- dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt());
/* stop reads and writes on all ports */
for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1338,7 +1311,6 @@ static void digi_disconnect(struct usb_serial *serial)
static void digi_release(struct usb_serial *serial)
{
int i;
- dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt());
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
@@ -1356,8 +1328,6 @@ static void digi_read_bulk_callback(struct urb *urb)
int ret;
int status = urb->status;
- dbg("digi_read_bulk_callback: TOP");
-
/* port sanity check, do not resubmit if port is not valid */
if (port == NULL)
return;
@@ -1507,9 +1477,6 @@ static int digi_read_oob_callback(struct urb *urb)
int i;
unsigned int rts;
- dbg("digi_read_oob_callback: port=%d, len=%d",
- priv->dp_port_num, urb->actual_length);
-
/* handle each oob command */
for (i = 0; i < urb->actual_length - 3;) {
opcode = ((unsigned char *)urb->transfer_buffer)[i++];
@@ -1580,7 +1547,7 @@ static int digi_read_oob_callback(struct urb *urb)
}
-module_usb_serial_driver(digi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 5b99fc0..cdf61dd 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver empeg_driver = {
- .name = "empeg",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver empeg_device = {
.driver = {
.owner = THIS_MODULE,
@@ -80,14 +73,12 @@ static int empeg_startup(struct usb_serial *serial)
{
int r;
- dbg("%s", __func__);
-
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
- dbg("%s - reset config", __func__);
+
r = usb_reset_configuration(serial->dev);
/* continue on with initialization */
@@ -138,7 +129,7 @@ static void empeg_init_termios(struct tty_struct *tty)
tty_encode_baud_rate(tty, 115200, 115200);
}
-module_usb_serial_driver(empeg_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 3cfc762..800e8eb 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -26,7 +26,6 @@ int ezusb_writememory(struct usb_serial *serial, int address,
int result;
unsigned char *transfer_buffer;
- /* dbg("ezusb_writememory %x, %d", address, length); */
if (!serial->dev) {
printk(KERN_ERR "ezusb: %s - no physical device present, "
"failing.\n", __func__);
@@ -50,7 +49,6 @@ int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit)
{
int response;
- /* dbg("%s - %d", __func__, reset_bit); */
response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0)
dev_err(&serial->dev->dev, "%s- %d failed\n",
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 88c0b19..499b15f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -68,8 +68,6 @@ static void f81232_read_int_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s (%d)", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -78,12 +76,12 @@ static void f81232_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -133,7 +131,7 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __func__, tty_flag);
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
@@ -203,7 +201,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
f81232_set_termios(tty, port, &tmp_termios);
- dbg("%s - submitting interrupt urb", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -293,7 +290,9 @@ static int f81232_ioctl(struct tty_struct *tty,
{
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+ port->number, cmd);
switch (cmd) {
case TIOCGSERIAL:
@@ -309,10 +308,12 @@ static int f81232_ioctl(struct tty_struct *tty,
return 0;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+ port->number);
return wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
+ __func__, cmd);
break;
}
return -ENOIOCTLCMD;
@@ -353,24 +354,12 @@ static void f81232_release(struct usb_serial *serial)
}
}
-static struct usb_driver f81232_driver = {
- .name = "f81232",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .no_dynamic_id = 1,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver f81232_device = {
.driver = {
.owner = THIS_MODULE,
.name = "f81232",
},
.id_table = id_table,
- .usb_driver = &f81232_driver,
.num_ports = 1,
.bulk_in_size = 256,
.bulk_out_size = 256,
@@ -394,7 +383,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL,
};
-module_usb_serial_driver(f81232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 02e7f2d..8c084ea 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -809,6 +809,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
+ { USB_DEVICE(PI_VID, PI_E861_PID) },
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -861,13 +862,6 @@ static struct usb_device_id id_table_combined [] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver ftdi_driver = {
- .name = "ftdi_sio",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static const char *ftdi_chip_name[] = {
[SIO] = "SIO", /* the serial part of FT8U100AX */
[FT8U232AM] = "FT8U232AM",
@@ -1285,8 +1279,6 @@ static int read_latency_timer(struct usb_serial_port *port)
unsigned char *buf;
int rv;
- dbg("%s", __func__);
-
buf = kmalloc(1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -1593,8 +1585,6 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int retval = 0;
- dbg("%s", __func__);
-
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) {
@@ -1619,8 +1609,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
@@ -1667,8 +1655,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
- dbg("%s", __func__);
-
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv) {
dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -1704,8 +1690,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
/* Called from usbserial:serial_probe */
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
{
- dbg("%s", __func__);
-
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = 38400;
@@ -1716,8 +1700,6 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
{
- dbg("%s", __func__);
-
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = 38400;
@@ -1767,8 +1749,6 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- dbg("%s", __func__);
-
if (interface == udev->actconfig->interface[0]) {
dev_info(&udev->dev,
"Ignoring serial port reserved for JTAG\n");
@@ -1782,8 +1762,6 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
- dbg("%s", __func__);
-
if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
(udev->product && !strcmp(udev->product, "BeagleBone/XDS100")))
return ftdi_jtag_probe(serial);
@@ -1800,8 +1778,6 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- dbg("%s", __func__);
-
if (interface == udev->actconfig->interface[2])
return 0;
@@ -1839,8 +1815,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
priv->dev_gone = true;
wake_up_interruptible_all(&priv->delta_msr_wait);
@@ -1858,8 +1832,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int result;
- dbg("%s", __func__);
-
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1918,8 +1890,6 @@ static void ftdi_close(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
usb_serial_generic_close(port);
kref_put(&priv->kref, ftdi_sio_priv_release);
}
@@ -1976,8 +1946,6 @@ static int ftdi_process_packet(struct tty_struct *tty,
char flag;
char *ch;
- dbg("%s - port %d", __func__, port->number);
-
if (len < 2) {
dbg("malformed packet");
return 0;
@@ -2121,8 +2089,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
unsigned char vstop;
unsigned char vstart;
- dbg("%s", __func__);
-
/* Force baud rate if this device requires it, unless it is set to
B0. */
if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
@@ -2295,8 +2261,6 @@ static int ftdi_tiocmget(struct tty_struct *tty)
int len;
int ret;
- dbg("%s TIOCMGET", __func__);
-
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -2346,7 +2310,7 @@ static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- dbg("%s TIOCMSET", __func__);
+
return update_mctrl(port, set, clear);
}
@@ -2435,7 +2399,6 @@ static int __init ftdi_init(void)
{
int retval;
- dbg("%s", __func__);
if (vendor > 0 && product > 0) {
/* Add user specified VID/PID to reserved element of table. */
int i;
@@ -2445,7 +2408,7 @@ static int __init ftdi_init(void)
id_table_combined[i].idVendor = vendor;
id_table_combined[i].idProduct = product;
}
- retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
if (retval == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
@@ -2454,9 +2417,7 @@ static int __init ftdi_init(void)
static void __exit ftdi_exit(void)
{
- dbg("%s", __func__);
-
- usb_serial_deregister_drivers(&ftdi_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 0838baf8..f3c7c78 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -785,6 +785,14 @@
#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
+
+/*
+ * Physik Instrumente
+ * http://www.physikinstrumente.com/en/products/
+ */
+#define PI_VID 0x1a72 /* Vendor ID */
+#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */
+
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
* http://winglucofacts.com/cables/
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4577b36..2357079 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,13 +24,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver funsoft_driver = {
- .name = "funsoft",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver funsoft_device = {
.driver = {
.owner = THIS_MODULE,
@@ -44,7 +37,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&funsoft_device, NULL
};
-module_usb_serial_driver(funsoft_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index e8eb634..346c15a 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -216,16 +216,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(GARMIN_VENDOR_ID, 3) },
{ } /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver garmin_driver = {
- .name = "garmin_gps",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static inline int getLayerId(const __u8 *usbPacket)
{
@@ -345,8 +337,6 @@ static void pkt_clear(struct garmin_data *garmin_data_p)
unsigned long flags;
struct garmin_packet *result = NULL;
- dbg("%s", __func__);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
while (!list_empty(&garmin_data_p->pktlist)) {
result = (struct garmin_packet *)garmin_data_p->pktlist.next;
@@ -939,8 +929,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
int status = 0;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
@@ -996,8 +984,6 @@ static void garmin_write_bulk_callback(struct urb *urb)
struct garmin_data *garmin_data_p =
usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
@@ -1027,9 +1013,6 @@ static int garmin_write_bulk(struct usb_serial_port *port,
unsigned char *buffer;
int status;
- dbg("%s - port %d, state %d", __func__, port->number,
- garmin_data_p->state);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_DROP_DATA;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1224,8 +1207,6 @@ static void garmin_read_bulk_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s - port %d", __func__, port->number);
-
if (!serial) {
dbg("%s - bad serial pointer, exiting", __func__);
return;
@@ -1384,7 +1365,6 @@ static void garmin_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
/* set flag, data received will be put into a queue
for later processing */
spin_lock_irq(&garmin_data_p->lock);
@@ -1399,7 +1379,6 @@ static void garmin_unthrottle(struct tty_struct *tty)
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
int status;
- dbg("%s - port %d", __func__, port->number);
spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
spin_unlock_irq(&garmin_data_p->lock);
@@ -1441,8 +1420,6 @@ static int garmin_attach(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = NULL;
- dbg("%s", __func__);
-
garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
if (garmin_data_p == NULL) {
dev_err(&port->dev, "%s - Out of memory\n", __func__);
@@ -1471,8 +1448,6 @@ static void garmin_disconnect(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
usb_kill_urb(port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer);
}
@@ -1483,8 +1458,6 @@ static void garmin_release(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
kfree(garmin_data_p);
}
@@ -1516,7 +1489,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&garmin_device, NULL
};
-module_usb_serial_driver(garmin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 664deb6..105a6d8 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -28,9 +28,6 @@ static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
-static int generic_probe(struct usb_interface *interface,
- const struct usb_device_id *id);
-
static __u16 vendor = 0x05f9;
static __u16 product = 0xffff;
@@ -49,13 +46,6 @@ static const struct usb_device_id generic_serial_ids[] = {
{}
};
-static struct usb_driver generic_driver = {
- .name = "usbserial_generic",
- .probe = generic_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = generic_serial_ids,
-};
-
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@@ -75,16 +65,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
&usb_serial_generic_device, NULL
};
-static int generic_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- const struct usb_device_id *id_pattern;
-
- id_pattern = usb_match_id(interface, generic_device_ids);
- if (id_pattern != NULL)
- return usb_serial_probe(interface, id);
- return -ENODEV;
-}
#endif
int usb_serial_generic_register(int _debug)
@@ -99,7 +79,7 @@ int usb_serial_generic_register(int _debug)
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
- retval = usb_serial_register_drivers(&generic_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, "usbserial_generic", generic_serial_ids);
#endif
return retval;
}
@@ -108,7 +88,7 @@ void usb_serial_generic_deregister(void)
{
#ifdef CONFIG_USB_SERIAL_GENERIC
/* remove our generic driver */
- usb_serial_deregister_drivers(&generic_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
#endif
}
@@ -117,8 +97,6 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
int result = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
port->throttled = 0;
@@ -139,12 +117,9 @@ static void generic_cleanup(struct usb_serial_port *port)
unsigned long flags;
int i;
- dbg("%s - port %d", __func__, port->number);
-
if (serial->dev) {
/* shutdown any bulk transfers that might be going on */
if (port->bulk_out_size) {
- usb_kill_urb(port->write_urb);
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
usb_kill_urb(port->write_urbs[i]);
@@ -161,7 +136,6 @@ static void generic_cleanup(struct usb_serial_port *port)
void usb_serial_generic_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
generic_cleanup(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -249,8 +223,6 @@ int usb_serial_generic_write(struct tty_struct *tty,
{
int result;
- dbg("%s - port %d", __func__, port->number);
-
/* only do something if we have a bulk out endpoint */
if (!port->bulk_out_size)
return -ENODEV;
@@ -273,8 +245,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
unsigned long flags;
int room;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->bulk_out_size)
return 0;
@@ -282,7 +252,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - returns %d", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
return room;
}
@@ -292,8 +262,6 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
int chars;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->bulk_out_size)
return 0;
@@ -301,7 +269,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - returns %d", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
@@ -313,7 +281,8 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
if (!test_and_clear_bit(index, &port->read_urbs_free))
return 0;
- dbg("%s - port %d, urb %d\n", __func__, port->number, index);
+ dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
+ port->number, index);
res = usb_submit_urb(port->read_urbs[index], mem_flags);
if (res) {
@@ -335,8 +304,6 @@ int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
int res;
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
if (res)
@@ -395,10 +362,12 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
}
set_bit(i, &port->read_urbs_free);
- dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
- urb->actual_length);
+ dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
+ __func__, port->number, i, urb->actual_length);
+
if (urb->status) {
- dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
+ dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+ __func__, urb->status);
return;
}
@@ -424,8 +393,6 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
int status = urb->status;
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
if (port->write_urbs[i] == urb)
break;
@@ -436,7 +403,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&port->lock, flags);
if (status) {
- dbg("%s - non-zero urb status: %d", __func__, status);
+ dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+ __func__, status);
spin_lock_irqsave(&port->lock, flags);
kfifo_reset_out(&port->write_fifo);
@@ -454,8 +422,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* Set the throttle request flag. It will be picked up
* by usb_serial_generic_read_bulk_callback(). */
spin_lock_irqsave(&port->lock, flags);
@@ -469,8 +435,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
int was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
/* Clear the throttle flags */
spin_lock_irq(&port->lock);
was_throttled = port->throttled;
@@ -525,7 +489,8 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
{
struct tty_port *port = &usb_port->port;
- dbg("%s - port %d, status %d", __func__, usb_port->number, status);
+ dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
+ usb_port->number, status);
if (status)
wake_up_interruptible(&port->open_wait);
@@ -566,8 +531,6 @@ void usb_serial_generic_disconnect(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
/* stop reads and writes on all ports */
for (i = 0; i < serial->num_ports; ++i)
generic_cleanup(serial->port[i]);
@@ -576,5 +539,4 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
void usb_serial_generic_release(struct usb_serial *serial)
{
- dbg("%s", __func__);
}
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 2563e78..0bbaf21 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -36,13 +36,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver hp49gp_driver = {
- .name = "hp4X",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver hp49gp_device = {
.driver = {
.owner = THIS_MODULE,
@@ -56,7 +49,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&hp49gp_device, NULL
};
-module_usb_serial_driver(hp49gp_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 323e872..e1f5ccd 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3181,7 +3181,7 @@ static void edge_release(struct usb_serial *serial)
kfree(edge_serial);
}
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index d0e7c9a..350afdd 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -95,13 +95,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver io_driver = {
- .name = "io_edgeport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static struct usb_serial_driver edgeport_2port_device = {
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 40a95a7..3936904 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -197,14 +197,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver io_driver = {
- .name = "io_ti",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
-
static unsigned char OperationalMajorVersion;
static unsigned char OperationalMinorVersion;
static unsigned short OperationalBuildNumber;
@@ -547,6 +539,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
{
int baud_rate;
struct tty_struct *tty = tty_port_tty_get(&port->port->port);
+ struct usb_serial *serial = port->port->serial;
wait_queue_t wait;
unsigned long flags;
@@ -561,7 +554,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
set_current_state(TASK_INTERRUPTIBLE);
if (kfifo_len(&port->write_fifo) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->port->serial->interface))
+ || serial->disconnected)
/* disconnect */
break;
spin_unlock_irqrestore(&port->ep_lock, flags);
@@ -578,7 +571,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
/* wait for data to drain from the device */
timeout += jiffies;
while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && usb_get_intfdata(port->port->serial->interface)) {
+ && !serial->disconnected) {
/* not disconnected */
if (!tx_active(port))
break;
@@ -586,7 +579,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
}
/* disconnected */
- if (!usb_get_intfdata(port->port->serial->interface))
+ if (serial->disconnected)
return;
/* wait one more character time, based on baud rate */
@@ -2003,8 +1996,8 @@ static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
+ struct usb_serial *serial = port->serial;
int port_number;
- int status;
dbg("%s - port %d", __func__, port->number);
@@ -2028,12 +2021,18 @@ static void edge_close(struct usb_serial_port *port)
* send a close port command to it */
dbg("%s - send umpc_close_port", __func__);
port_number = port->number - port->serial->minor;
- status = send_cmd(port->serial->dev,
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected) {
+ send_cmd(serial->dev,
UMPC_CLOSE_PORT,
(__u8)(UMPM_UART1_PORT + port_number),
0,
NULL,
0);
+ }
+ mutex_unlock(&serial->disc_mutex);
+
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
@@ -2783,7 +2782,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&edgeport_1port_device, &edgeport_2port_device, NULL
};
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 10c02b8..c85a7eb 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -33,7 +33,6 @@
#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
#define DRIVER_DESC "USB PocketPC PDA driver"
-static __u16 product, vendor;
static bool debug;
static int connect_retries = KP_RETRIES;
static int initial_wait;
@@ -45,8 +44,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
static struct usb_device_id ipaq_id_table [] = {
- /* The first entry is a placeholder for the insmod-specified device */
- { USB_DEVICE(0x049F, 0x0003) },
{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */
{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */
@@ -505,13 +502,6 @@ static struct usb_device_id ipaq_id_table [] = {
MODULE_DEVICE_TABLE(usb, ipaq_id_table);
-static struct usb_driver ipaq_driver = {
- .name = "ipaq",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ipaq_id_table,
-};
-
/* All of the device info needed for the Compaq iPAQ */
static struct usb_serial_driver ipaq_device = {
@@ -539,8 +529,6 @@ static int ipaq_open(struct tty_struct *tty,
int result = 0;
int retries = connect_retries;
- dbg("%s - port %d", __func__, port->number);
-
msleep(1000*initial_wait);
/*
@@ -577,7 +565,7 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
*/
int ipaq_num_ports = 1;
- dbg("%s - numberofendpoints: %d", __FUNCTION__,
+ dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__,
(int)serial->interface->cur_altsetting->desc.bNumEndpoints);
/*
@@ -596,8 +584,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
static int ipaq_startup(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
/* Some of the devices in ipaq_id_table[] are composite, and we
* shouldn't bind to all the interfaces. This test will rule out
* some obviously invalid possibilities.
@@ -617,36 +603,14 @@ static int ipaq_startup(struct usb_serial *serial)
return -ENODEV;
}
- dbg("%s - iPAQ module configured for %d ports",
- __FUNCTION__, serial->num_ports);
+ dev_dbg(&serial->dev->dev,
+ "%s - iPAQ module configured for %d ports\n", __func__,
+ serial->num_ports);
return usb_reset_configuration(serial->dev);
}
-static int __init ipaq_init(void)
-{
- int retval;
-
- if (vendor) {
- ipaq_id_table[0].idVendor = vendor;
- ipaq_id_table[0].idProduct = product;
- }
-
- retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers);
- if (retval == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return retval;
-}
-
-static void __exit ipaq_exit(void)
-{
- usb_serial_deregister_drivers(&ipaq_driver, serial_drivers);
-}
-
-
-module_init(ipaq_init);
-module_exit(ipaq_exit);
+module_usb_serial_driver(serial_drivers, ipaq_id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -655,12 +619,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-
module_param(connect_retries, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(connect_retries,
"Maximum number of connect retries (one second each)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 76a0640..5811d34 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -132,19 +132,11 @@ enum {
#define IPW_WANTS_TO_SEND 0x30
-static const struct usb_device_id usb_ipw_ids[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(IPW_VID, IPW_PID) },
{ },
};
-
-MODULE_DEVICE_TABLE(usb, usb_ipw_ids);
-
-static struct usb_driver usb_ipw_driver = {
- .name = "ipwtty",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = usb_ipw_ids,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
static bool debug;
@@ -155,8 +147,6 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
u8 *buf_flow_init;
int result;
- dbg("%s", __func__);
-
buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL);
if (!buf_flow_init)
return -ENOMEM;
@@ -317,7 +307,7 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
- .id_table = usb_ipw_ids,
+ .id_table = id_table,
.num_ports = 1,
.disconnect = usb_wwan_disconnect,
.open = ipw_open,
@@ -333,7 +323,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ipw_device, NULL
};
-module_usb_serial_driver(usb_ipw_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 84965cd..fc09414 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -77,13 +77,6 @@ static const struct usb_device_id ir_id_table[] = {
MODULE_DEVICE_TABLE(usb, ir_id_table);
-static struct usb_driver ir_driver = {
- .name = "ir-usb",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ir_id_table,
-};
-
static struct usb_serial_driver ir_device = {
.driver = {
.owner = THIS_MODULE,
@@ -103,18 +96,21 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ir_device, NULL
};
-static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
+static inline void irda_usb_dump_class_desc(struct usb_serial *serial,
+ struct usb_irda_cs_descriptor *desc)
{
- dbg("bLength=%x", desc->bLength);
- dbg("bDescriptorType=%x", desc->bDescriptorType);
- dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision));
- dbg("bmDataSize=%x", desc->bmDataSize);
- dbg("bmWindowSize=%x", desc->bmWindowSize);
- dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime);
- dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate));
- dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs);
- dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff);
- dbg("bMaxUnicastList=%x", desc->bMaxUnicastList);
+ struct device *dev = &serial->dev->dev;
+
+ dev_dbg(dev, "bLength=%x\n", desc->bLength);
+ dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType);
+ dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision));
+ dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize);
+ dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize);
+ dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+ dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate));
+ dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
+ dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
+ dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList);
}
/*------------------------------------------------------------------*/
@@ -130,8 +126,9 @@ static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
* Based on the same function in drivers/net/irda/irda-usb.c
*/
static struct usb_irda_cs_descriptor *
-irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum)
{
+ struct usb_device *dev = serial->dev;
struct usb_irda_cs_descriptor *desc;
int ret;
@@ -144,20 +141,20 @@ irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), 1000);
- dbg("%s - ret=%d", __func__, ret);
+ dev_dbg(&serial->dev->dev, "%s - ret=%d\n", __func__, ret);
if (ret < sizeof(*desc)) {
- dbg("%s - class descriptor read %s (%d)",
- __func__,
- (ret < 0) ? "failed" : "too short",
- ret);
+ dev_dbg(&serial->dev->dev,
+ "%s - class descriptor read %s (%d)\n", __func__,
+ (ret < 0) ? "failed" : "too short", ret);
goto error;
}
if (desc->bDescriptorType != USB_DT_CS_IRDA) {
- dbg("%s - bad class descriptor type", __func__);
+ dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n",
+ __func__);
goto error;
}
- irda_usb_dump_class_desc(desc);
+ irda_usb_dump_class_desc(serial, desc);
return desc;
error:
@@ -207,14 +204,15 @@ static int ir_startup(struct usb_serial *serial)
{
struct usb_irda_cs_descriptor *irda_desc;
- irda_desc = irda_usb_find_class_desc(serial->dev, 0);
+ irda_desc = irda_usb_find_class_desc(serial, 0);
if (!irda_desc) {
dev_err(&serial->dev->dev,
"IRDA class descriptor not found, device not bound\n");
return -ENODEV;
}
- dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+ dev_dbg(&serial->dev->dev,
+ "%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n",
__func__,
(irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "",
(irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "",
@@ -264,8 +262,6 @@ static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
@@ -322,15 +318,11 @@ static void ir_process_read_urb(struct urb *urb)
static void ir_set_termios_callback(struct urb *urb)
{
- struct usb_serial_port *port = urb->context;
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
kfree(urb->transfer_buffer);
- if (status)
- dbg("%s - non-zero urb status: %d", __func__, status);
+ if (urb->status)
+ dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n",
+ __func__, urb->status);
}
static void ir_set_termios(struct tty_struct *tty,
@@ -342,8 +334,6 @@ static void ir_set_termios(struct tty_struct *tty,
speed_t baud;
int ir_baud;
- dbg("%s - port %d", __func__, port->number);
-
baud = tty_get_baud_rate(tty);
/*
@@ -447,7 +437,7 @@ static int __init ir_init(void)
ir_device.bulk_out_size = buffer_size;
}
- retval = usb_serial_register_drivers(&ir_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table);
if (retval == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
@@ -456,7 +446,7 @@ static int __init ir_init(void)
static void __exit ir_exit(void)
{
- usb_serial_deregister_drivers(&ir_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index f2192d5..22b1eb5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver iuu_driver = {
- .name = "iuu_phoenix",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
/* turbo parameter */
static int boost = 100;
static int clockmode = 1;
@@ -135,8 +128,6 @@ static void iuu_release(struct usb_serial *serial)
if (!port)
return;
- dbg("%s", __func__);
-
if (priv) {
iuu_free_buf(priv);
dbg("%s - I will free all", __func__);
@@ -198,8 +189,6 @@ static void iuu_rxcmd(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -221,7 +210,6 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt)
struct iuu_private *priv = usb_get_serial_port_data(port);
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __func__);
/* Prepare the reset sequence */
@@ -255,8 +243,6 @@ static void iuu_update_status_callback(struct urb *urb)
u8 *st;
int status = urb->status;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -299,8 +285,6 @@ static int iuu_status(struct usb_serial_port *port)
{
int result;
- dbg("%s - enter", __func__);
-
memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
@@ -318,8 +302,6 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __func__);
-
/* send the data out the bulk port */
status =
@@ -341,10 +323,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __func__);
-
/* send the data out the bulk port */
-
status =
usb_bulk_msg(serial->dev,
usb_rcvbulkpipe(serial->dev,
@@ -367,8 +346,6 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R,
if (!buf)
return -ENOMEM;
- dbg("%s - enter", __func__);
-
buf[0] = IUU_SET_LED;
buf[1] = R & 0xFF;
buf[2] = (R >> 8) & 0xFF;
@@ -460,8 +437,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq)
unsigned int P2 = 0;
int frq = (int)dwFrq;
- dbg("%s - enter", __func__);
-
if (frq == 0) {
priv->buf[Count++] = IUU_UART_WRITE_I2C;
priv->buf[Count++] = FrqGenAdr << 1;
@@ -590,8 +565,6 @@ static int iuu_uart_flush(struct usb_serial_port *port)
u8 rxcmd = IUU_UART_RX;
struct iuu_private *priv = usb_get_serial_port_data(port);
- dbg("%s - enter", __func__);
-
if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
return -EIO;
@@ -630,8 +603,6 @@ static void read_buf_callback(struct urb *urb)
struct tty_struct *tty;
int status = urb->status;
- dbg("%s - status = %d", __func__, status);
-
if (status) {
if (status == -EPROTO) {
/* reschedule needed */
@@ -659,7 +630,6 @@ static int iuu_bulk_write(struct usb_serial_port *port)
int i;
int buf_len;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __func__);
spin_lock_irqsave(&priv->lock, flags);
*buf_ptr++ = IUU_UART_ESC;
@@ -691,7 +661,6 @@ static int iuu_bulk_write(struct usb_serial_port *port)
static int iuu_read_buf(struct usb_serial_port *port, int len)
{
int result;
- dbg("%s - enter", __func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
@@ -713,8 +682,6 @@ static void iuu_uart_read_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
priv->poll++;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -771,7 +738,6 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port,
{
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - enter", __func__);
if (count > 256)
return -ENOMEM;
@@ -792,8 +758,6 @@ static void read_rxcmd_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - status = %d", __func__, status);
-
if (status) {
/* error stop all */
return;
@@ -1015,8 +979,6 @@ static void iuu_close(struct usb_serial_port *port)
if (!serial)
return;
- dbg("%s - port %d", __func__, port->number);
-
iuu_uart_off(port);
if (serial->dev) {
/* free writebuf */
@@ -1031,7 +993,6 @@ static void iuu_close(struct usb_serial_port *port)
static void iuu_init_termios(struct tty_struct *tty)
{
- dbg("%s - enter", __func__);
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
| TIOCM_CTS | CSTOPB | PARENB;
@@ -1188,8 +1149,6 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc)
if (!buf)
return -ENOMEM;
- dbg("%s - enter", __func__);
-
buf[0] = IUU_SET_VCC;
buf[1] = vcc & 0xFF;
buf[2] = (vcc >> 8) & 0xFF;
@@ -1250,15 +1209,11 @@ static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
{
- dbg("%s", __func__);
-
return device_create_file(&port->dev, &dev_attr_vcc_mode);
}
static int iuu_remove_sysfs_attrs(struct usb_serial_port *port)
{
- dbg("%s", __func__);
-
device_remove_file(&port->dev, &dev_attr_vcc_mode);
return 0;
}
@@ -1294,7 +1249,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&iuu_device, NULL
};
-module_usb_serial_driver(iuu_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index a39ddd1..a1b9924 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -130,15 +130,13 @@ struct keyspan_port_private {
#include "keyspan_usa67msg.h"
-module_usb_serial_driver(keyspan_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
-
p_priv = usb_get_serial_port_data(port);
if (break_state == -1)
@@ -158,8 +156,6 @@ static void keyspan_set_termios(struct tty_struct *tty,
const struct keyspan_device_details *d_details;
unsigned int cflag;
- dbg("%s", __func__);
-
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
cflag = tty->termios->c_cflag;
@@ -306,8 +302,6 @@ static void usa26_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -369,8 +363,6 @@ static void usa2x_outdat_callback(struct urb *urb)
static void usa26_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
-
}
static void usa26_outcont_callback(struct urb *urb)
@@ -452,7 +444,6 @@ exit: ;
static void usa26_glocont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
@@ -465,8 +456,6 @@ static void usa28_indat_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int status = urb->status;
- dbg("%s", __func__);
-
port = urb->context;
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
@@ -505,7 +494,6 @@ static void usa28_indat_callback(struct urb *urb)
static void usa28_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa28_outcont_callback(struct urb *urb)
@@ -585,7 +573,6 @@ exit: ;
static void usa28_glocont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
@@ -596,8 +583,6 @@ static void usa49_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg("%s", __func__);
-
serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -625,8 +610,6 @@ static void usa49_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -679,7 +662,6 @@ exit: ;
static void usa49_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa49_indat_callback(struct urb *urb)
@@ -691,8 +673,6 @@ static void usa49_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -742,8 +722,6 @@ static void usa49wg_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -806,7 +784,6 @@ static void usa49wg_indat_callback(struct urb *urb)
/* not used, usa-49 doesn't have per-port control endpoints */
static void usa49_outcont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa90_indat_callback(struct urb *urb)
@@ -819,8 +796,6 @@ static void usa90_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -957,8 +932,6 @@ static void usa67_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -1010,8 +983,6 @@ static void usa67_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg("%s", __func__);
-
serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -1035,7 +1006,6 @@ static int keyspan_write_room(struct tty_struct *tty)
int data_len;
struct urb *this_urb;
- dbg("%s", __func__);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
@@ -1078,8 +1048,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- dbg("%s - port%d.", __func__, port->number);
-
/* Set some sane defaults */
p_priv->rts_state = 1;
p_priv->dtr_state = 1;
@@ -1165,7 +1133,6 @@ static void keyspan_close(struct usb_serial_port *port)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -1438,8 +1405,6 @@ static void keyspan_setup_urbs(struct usb_serial *serial)
struct callbacks *cback;
int endp;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -1853,8 +1818,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int device_port, err;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -1980,8 +1943,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2168,8 +2129,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
int err;
u8 prescaler;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2300,8 +2259,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2442,8 +2399,6 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
struct keyspan_serial_private *s_priv;
const struct keyspan_device_details *d_details;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -2477,8 +2432,6 @@ static int keyspan_startup(struct usb_serial *serial)
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- dbg("%s", __func__);
-
for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
if (d_details->product_id ==
le16_to_cpu(serial->dev->descriptor.idProduct))
@@ -2538,8 +2491,6 @@ static void keyspan_disconnect(struct usb_serial *serial)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
/* Stop reading/writing urbs */
@@ -2579,8 +2530,6 @@ static void keyspan_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct keyspan_serial_private *s_priv;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
/* dbg("Freeing serial->private."); */
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 622853c..fe1c5d9 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -487,13 +487,6 @@ static const struct usb_device_id keyspan_ids_combined[] = {
MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
-static struct usb_driver keyspan_driver = {
- .name = "keyspan",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = keyspan_ids_combined,
-};
-
/* usb_device_id table for the pre-firmware download keyspan devices */
static const struct usb_device_id keyspan_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 693bcdf..a4ac3cf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -86,13 +86,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver keyspan_pda_driver = {
- .name = "keyspan_pda",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static const struct usb_device_id id_table_std[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
{ } /* Terminating entry */
@@ -131,7 +124,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
struct usb_serial *serial = priv->serial;
int result;
- dbg(" request_unthrottle");
/* ask the device to tell us when the tx buffer becomes
sufficiently empty */
result = usb_control_msg(serial->dev,
@@ -226,7 +218,7 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty)
send an XOFF, although it might make sense to foist that off
upon the device too. */
struct usb_serial_port *port = tty->driver_data;
- dbg("keyspan_pda_rx_throttle port %d", port->number);
+
usb_kill_urb(port->interrupt_in_urb);
}
@@ -235,7 +227,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
/* just restart the receive interrupt URB */
- dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dbg(" usb_submit_urb(read urb) failed");
}
@@ -466,7 +458,6 @@ static int keyspan_pda_write(struct tty_struct *tty,
select() or poll() too) until we receive that unthrottle interrupt.
Block if we can't write anything at all, otherwise write as much as
we can. */
- dbg("keyspan_pda_write(%d)", count);
if (count == 0) {
dbg(" write request of 0 bytes");
return 0;
@@ -766,8 +757,6 @@ static int keyspan_pda_startup(struct usb_serial *serial)
static void keyspan_pda_release(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
kfree(usb_get_serial_port_data(serial->port[0]));
}
@@ -834,7 +823,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL
};
-module_usb_serial_driver(keyspan_pda_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 10f0540..5bed59c 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -86,13 +86,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver kl5kusb105d_driver = {
- .name = "kl5kusb105d",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver kl5kusb105d_device = {
.driver = {
.owner = THIS_MODULE,
@@ -282,8 +275,6 @@ static void klsi_105_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -298,8 +289,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
struct klsi_105_port_settings *cfg;
unsigned long flags;
- dbg("%s port %d", __func__, port->number);
-
/* Do a defined restart:
* Set up sane default baud rate and send the 'READ_ON'
* vendor command.
@@ -376,8 +365,6 @@ static void klsi_105_close(struct usb_serial_port *port)
{
int rc;
- dbg("%s port %d", __func__, port->number);
-
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* send READ_OFF */
@@ -646,7 +633,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty)
unsigned long flags;
int rc;
unsigned long line_state;
- dbg("%s - request, just guessing", __func__);
rc = klsi_105_get_line_state(port, &line_state);
if (rc < 0) {
@@ -668,8 +654,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty,
{
int retval = -EINVAL;
- dbg("%s", __func__);
-
/* if this ever gets implemented, it should be done something like this:
struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = usb_get_serial_port_data(port);
@@ -692,7 +676,7 @@ static int klsi_105_tiocmset(struct tty_struct *tty,
return retval;
}
-module_usb_serial_driver(kl5kusb105d_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 4a9a75e..fafeabb 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -81,18 +81,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
{ } /* Terminating entry */
};
-
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver kobil_driver = {
- .name = "kobil",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
static struct usb_serial_driver kobil_device = {
.driver = {
.owner = THIS_MODULE,
@@ -193,7 +183,6 @@ static int kobil_startup(struct usb_serial *serial)
static void kobil_release(struct usb_serial *serial)
{
int i;
- dbg("%s - port %d", __func__, serial->port[0]->number);
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
@@ -217,7 +206,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
int transfer_buffer_length = 8;
int write_urb_transfer_buffer_length = 8;
- dbg("%s - port %d", __func__, port->number);
priv = usb_get_serial_port_data(port);
/* allocate memory for transfer buffer */
@@ -327,8 +315,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
static void kobil_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
/* FIXME: Add rts/dtr methods */
if (port->write_urb) {
usb_poison_urb(port->write_urb);
@@ -349,8 +335,6 @@ static void kobil_read_int_callback(struct urb *urb)
int status = urb->status;
/* char *dbg_data; */
- dbg("%s - port %d", __func__, port->number);
-
if (status) {
dbg("%s - port %d Read int status not zero: %d",
__func__, port->number, status);
@@ -474,7 +458,6 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
static int kobil_write_room(struct tty_struct *tty)
{
- /* dbg("%s - port %d", __func__, port->number); */
/* FIXME */
return 8;
}
@@ -683,7 +666,7 @@ static int kobil_ioctl(struct tty_struct *tty,
}
}
-module_usb_serial_driver(kobil_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 6edd261..d0ec1aa 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -73,22 +73,14 @@ static void mct_u232_unthrottle(struct tty_struct *tty);
/*
* All of the device info needed for the MCT USB-RS232 converter.
*/
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
{ } /* Terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver mct_u232_driver = {
- .name = "mct_u232",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_serial_driver mct_u232_device = {
.driver = {
@@ -96,7 +88,7 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
- .id_table = id_table_combined,
+ .id_table = id_table,
.num_ports = 1,
.open = mct_u232_open,
.close = mct_u232_close,
@@ -427,8 +419,6 @@ static void mct_u232_release(struct usb_serial *serial)
struct mct_u232_private *priv;
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
/* My special items, the standard routines free my urbs */
priv = usb_get_serial_port_data(serial->port[i]);
@@ -446,8 +436,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned char last_lcr;
unsigned char last_msr;
- dbg("%s port %d", __func__, port->number);
-
/* Compensate for a hardware bug: although the Sitecom U232-P25
* device reports a maximum output packet size of 32 bytes,
* it seems to be able to accept only 16 bytes (and that's what
@@ -528,8 +516,6 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
static void mct_u232_close(struct usb_serial_port *port)
{
- dbg("%s port %d", __func__, port->number);
-
if (port->serial->dev) {
/* shutdown our urbs */
usb_kill_urb(port->write_urb);
@@ -572,7 +558,6 @@ static void mct_u232_read_int_callback(struct urb *urb)
return;
}
- dbg("%s - port %d", __func__, port->number);
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
@@ -733,8 +718,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
unsigned char lcr;
unsigned long flags;
- dbg("%sstate=%d", __func__, break_state);
-
spin_lock_irqsave(&priv->lock, flags);
lcr = priv->last_lcr;
@@ -753,8 +736,6 @@ static int mct_u232_tiocmget(struct tty_struct *tty)
unsigned int control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -771,8 +752,6 @@ static int mct_u232_tiocmset(struct tty_struct *tty,
unsigned int control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -796,8 +775,6 @@ static void mct_u232_throttle(struct tty_struct *tty)
struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned int control_state;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->rx_flags |= THROTTLED;
if (C_CRTSCTS(tty)) {
@@ -816,8 +793,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned int control_state;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
priv->rx_flags &= ~THROTTLED;
@@ -906,7 +881,7 @@ static int mct_u232_get_icount(struct tty_struct *tty,
return 0;
}
-module_usb_serial_driver(mct_u232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 08d16e8..81423f7 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -17,7 +17,6 @@
#include <linux/tty_flip.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
-#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/usb/serial.h>
@@ -56,6 +55,47 @@ MODULE_DEVICE_TABLE(usb, id_table);
/* Input parameter constants. */
static bool debug;
+/* UNI-Directional mode commands for device configure */
+#define UNI_CMD_OPEN 0x80
+#define UNI_CMD_CLOSE 0xFF
+
+inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+{
+ __u16 product_id = le16_to_cpu(
+ port->serial->dev->descriptor.idProduct);
+
+ return product_id == FOCUS_PRODUCT_ID_UNI;
+}
+
+static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
+{
+ int ret;
+ int actual_len;
+ u8 *buffer_cmd = NULL;
+
+ if (!metrousb_is_unidirectional_mode(port))
+ return 0;
+
+ buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
+ if (!buffer_cmd)
+ return -ENOMEM;
+
+ *buffer_cmd = cmd;
+
+ ret = usb_interrupt_msg(port->serial->dev,
+ usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+ buffer_cmd, sizeof(cmd),
+ &actual_len, USB_CTRL_SET_TIMEOUT);
+
+ kfree(buffer_cmd);
+
+ if (ret < 0)
+ return ret;
+ else if (actual_len != sizeof(cmd))
+ return -EIO;
+ return 0;
+}
+
static void metrousb_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -78,12 +118,12 @@ static void metrousb_read_int_callback(struct urb *urb)
/* urb has been terminated. */
dev_dbg(&port->dev,
"%s - urb shutting down, error code=%d\n",
- __func__, result);
+ __func__, urb->status);
return;
default:
dev_dbg(&port->dev,
"%s - non-zero urb received, error code=%d\n",
- __func__, result);
+ __func__, urb->status);
goto exit;
}
@@ -91,7 +131,7 @@ static void metrousb_read_int_callback(struct urb *urb)
/* Set the data read from the usb port into the serial port buffer. */
tty = tty_port_tty_get(&port->port);
if (!tty) {
- dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
+ dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
__func__);
return;
}
@@ -121,7 +161,7 @@ static void metrousb_read_int_callback(struct urb *urb)
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
}
@@ -131,11 +171,19 @@ exit:
/* Try to resubmit the urb. */
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
}
+static void metrousb_write_int_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+
+ dev_warn(&port->dev, "%s not implemented yet.\n",
+ __func__);
+}
+
static void metrousb_cleanup(struct usb_serial_port *port)
{
dev_dbg(&port->dev, "%s\n", __func__);
@@ -146,6 +194,9 @@ static void metrousb_cleanup(struct usb_serial_port *port)
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
}
+
+ /* Send deactivate cmd to device */
+ metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
}
}
@@ -160,7 +211,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
/* Make sure the urb is initialized. */
if (!port->interrupt_in_urb) {
- dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
+ dev_err(&port->dev, "%s - interrupt urb not initialized\n",
__func__);
return -ENODEV;
}
@@ -191,12 +242,21 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
goto exit;
}
+ /* Send activate cmd to device */
+ result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed to configure device for port number=%d, error code=%d\n",
+ __func__, port->number, result);
+ goto exit;
+ }
+
dev_dbg(&port->dev, "%s - port open\n", __func__);
exit:
return result;
@@ -221,7 +281,7 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr
METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
control_state, 0, NULL, 0, WDR_TIMEOUT);
if (retval < 0)
- dev_dbg(&serial->dev->dev,
+ dev_err(&serial->dev->dev,
"%s - set modem ctrl=0x%x failed, error code=%d\n",
__func__, mcr, retval);
@@ -354,29 +414,23 @@ static void metrousb_unthrottle(struct tty_struct *tty)
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_dbg(tty->dev,
+ dev_err(tty->dev,
"failed submitting interrupt in urb error code=%d\n",
result);
}
-static struct usb_driver metrousb_driver = {
- .name = "metro-usb",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table
-};
-
static struct usb_serial_driver metrousb_device = {
.driver = {
.owner = THIS_MODULE,
.name = "metro-usb",
},
- .description = "Metrologic USB to serial converter.",
+ .description = "Metrologic USB to Serial",
.id_table = id_table,
.num_ports = 1,
.open = metrousb_open,
.close = metrousb_cleanup,
.read_int_callback = metrousb_read_int_callback,
+ .write_int_callback = metrousb_write_int_callback,
.attach = metrousb_startup,
.release = metrousb_shutdown,
.throttle = metrousb_throttle,
@@ -390,7 +444,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL,
};
-module_usb_serial_driver(metrousb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Philip Nicastro");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index bdce820..a07dd3c 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -79,12 +79,12 @@ static struct usb_serial_driver moschip7720_2port_driver;
#define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715
-static const struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
{ } /* terminating entry */
};
-MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
@@ -257,7 +257,6 @@ static void destroy_mos_parport(struct kref *kref)
struct mos7715_parport *mos_parport =
container_of(kref, struct mos7715_parport, ref_count);
- dbg("%s called", __func__);
kfree(mos_parport);
}
@@ -266,7 +265,7 @@ static void destroy_urbtracker(struct kref *kref)
struct urbtracker *urbtrack =
container_of(kref, struct urbtracker, ref_count);
struct mos7715_parport *mos_parport = urbtrack->mos_parport;
- dbg("%s called", __func__);
+
usb_free_urb(urbtrack->urb);
kfree(urbtrack);
kref_put(&mos_parport->ref_count, destroy_mos_parport);
@@ -285,8 +284,6 @@ static void send_deferred_urbs(unsigned long _mos_parport)
struct urbtracker *urbtrack;
struct list_head *cursor, *next;
- dbg("%s called", __func__);
-
/* if release function ran, game over */
if (unlikely(mos_parport->serial == NULL))
return;
@@ -335,7 +332,7 @@ static void async_complete(struct urb *urb)
{
struct urbtracker *urbtrack = urb->context;
int status = urb->status;
- dbg("%s called", __func__);
+
if (unlikely(status))
dbg("%s - nonzero urb status received: %d", __func__, status);
@@ -355,7 +352,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
struct usb_ctrlrequest setup;
struct usb_serial *serial = mos_parport->serial;
struct usb_device *usbdev = serial->dev;
- dbg("%s called", __func__);
/* create and initialize the control urb and containing urbtracker */
urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
@@ -476,7 +472,7 @@ static inline void parport_epilogue(struct parport *pp)
static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called: %2.2x", __func__, d);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, SPP);
@@ -488,7 +484,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
unsigned char d;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return 0;
read_mos_reg(mos_parport->serial, dummy, DPR, &d);
@@ -500,7 +496,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 data;
- dbg("%s called: %2.2x", __func__, d);
+
if (parport_prologue(pp) < 0)
return;
data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
@@ -513,7 +509,7 @@ static unsigned char parport_mos7715_read_control(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 dcr;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) {
@@ -531,7 +527,7 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp,
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 dcr;
- dbg("%s called", __func__);
+
mask &= 0x0f;
val &= 0x0f;
if (parport_prologue(pp) < 0)
@@ -547,7 +543,7 @@ static unsigned char parport_mos7715_read_status(struct parport *pp)
{
unsigned char status;
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -561,17 +557,16 @@ static unsigned char parport_mos7715_read_status(struct parport *pp)
static void parport_mos7715_enable_irq(struct parport *pp)
{
- dbg("%s called", __func__);
}
+
static void parport_mos7715_disable_irq(struct parport *pp)
{
- dbg("%s called", __func__);
}
static void parport_mos7715_data_forward(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, PS2);
@@ -583,7 +578,7 @@ static void parport_mos7715_data_forward(struct parport *pp)
static void parport_mos7715_data_reverse(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, PS2);
@@ -595,7 +590,6 @@ static void parport_mos7715_data_reverse(struct parport *pp)
static void parport_mos7715_init_state(struct pardevice *dev,
struct parport_state *s)
{
- dbg("%s called", __func__);
s->u.pc.ctr = DCR_INIT_VAL;
s->u.pc.ecr = ECR_INIT_VAL;
}
@@ -605,7 +599,7 @@ static void parport_mos7715_save_state(struct parport *pp,
struct parport_state *s)
{
struct mos7715_parport *mos_parport;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -622,7 +616,7 @@ static void parport_mos7715_restore_state(struct parport *pp,
struct parport_state *s)
{
struct mos7715_parport *mos_parport;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -641,7 +635,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp,
int retval;
struct mos7715_parport *mos_parport = pp->private_data;
int actual_len;
- dbg("%s called: %u chars", __func__, (unsigned int)len);
+
if (parport_prologue(pp) < 0)
return 0;
mos7715_change_mode(mos_parport, PPF);
@@ -2164,20 +2158,13 @@ static void mos7720_release(struct usb_serial *serial)
kfree(usb_get_serial_port_data(serial->port[i]));
}
-static struct usb_driver usb_driver = {
- .name = "moschip7720",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_port_id_table,
-};
-
static struct usb_serial_driver moschip7720_2port_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
- .id_table = moschip_port_id_table,
+ .id_table = id_table,
.calc_num_ports = mos77xx_calc_num_ports,
.open = mos7720_open,
.close = mos7720_close,
@@ -2203,7 +2190,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moschip7720_2port_driver, NULL
};
-module_usb_serial_driver(usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c526550..29160f8 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -114,10 +114,10 @@
#define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7840 0x7840
#define MOSCHIP_DEVICE_ID_7820 0x7820
+#define MOSCHIP_DEVICE_ID_7810 0x7810
/* The native component can have its vendor/device id's overridden
* in vendor-specific implementations. Such devices can be handled
- * by making a change here, in moschip_port_id_table, and in
- * moschip_id_table_combined
+ * by making a change here, in id_table.
*/
#define USB_VENDOR_ID_BANDB 0x0856
#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22
@@ -184,31 +184,16 @@
#define NUM_URBS 16 /* URB Count */
#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+/* LED on/off milliseconds*/
+#define LED_ON_MS 500
+#define LED_OFF_MS 500
-static const struct usb_device_id moschip_port_id_table[] = {
- {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
- {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
- {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
- {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
- {} /* terminating entry */
-};
+static int device_type;
-static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
+static const struct usb_device_id id_table[] __devinitconst = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
@@ -226,8 +211,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
+MODULE_DEVICE_TABLE(usb, id_table);
/* This structure holds all of the local port information */
@@ -261,8 +245,13 @@ struct moschip_port {
struct urb *write_urb_pool[NUM_URBS];
char busy[NUM_URBS];
bool read_urb_busy;
-};
+ /* For device(s) with LED indicator */
+ bool has_led;
+ bool led_flag;
+ struct timer_list led_timer1; /* Timer for LED on */
+ struct timer_list led_timer2; /* Timer for LED off */
+};
static bool debug;
@@ -572,6 +561,69 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
return ret;
}
+static void mos7840_set_led_callback(struct urb *urb)
+{
+ switch (urb->status) {
+ case 0:
+ /* Success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* This urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __func__,
+ urb->status);
+ break;
+ default:
+ dbg("%s - nonzero urb status received: %d", __func__,
+ urb->status);
+ }
+}
+
+static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
+ __u16 reg)
+{
+ struct usb_device *dev = mcs->port->serial->dev;
+ struct usb_ctrlrequest *dr = mcs->dr;
+
+ dr->bRequestType = MCS_WR_RTYPE;
+ dr->bRequest = MCS_WRREQ;
+ dr->wValue = cpu_to_le16(wval);
+ dr->wIndex = cpu_to_le16(reg);
+ dr->wLength = cpu_to_le16(0);
+
+ usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+ (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
+
+ usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+}
+
+static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+ struct usb_device *dev = port->serial->dev;
+
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE,
+ val, reg, NULL, 0, MOS_WDR_TIMEOUT);
+}
+
+static void mos7840_led_off(unsigned long arg)
+{
+ struct moschip_port *mcs = (struct moschip_port *) arg;
+
+ /* Turn off LED */
+ mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER);
+ mod_timer(&mcs->led_timer2,
+ jiffies + msecs_to_jiffies(LED_OFF_MS));
+}
+
+static void mos7840_led_flag_off(unsigned long arg)
+{
+ struct moschip_port *mcs = (struct moschip_port *) arg;
+
+ mcs->led_flag = false;
+}
+
/*****************************************************************************
* mos7840_interrupt_callback
* this is the callback function for when we have received data on the
@@ -591,8 +643,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
__u16 wval, wreg = 0;
int status = urb->status;
- dbg("%s", " : Entering");
-
switch (status) {
case 0:
/* success */
@@ -766,12 +816,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
- dbg("%s", "Entering... ");
-
data = urb->transfer_buffer;
- dbg("%s", "Entering ...........");
-
if (urb->actual_length) {
tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty) {
@@ -792,6 +838,14 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
+ /* Turn on LED */
+ if (mos7840_port->has_led && !mos7840_port->led_flag) {
+ mos7840_port->led_flag = true;
+ mos7840_set_led_async(mos7840_port, 0x0301,
+ MODEM_CONTROL_REGISTER);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
+ }
mos7840_port->read_urb_busy = true;
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -835,8 +889,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
return;
}
- dbg("%s", "Entering .........");
-
tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty && mos7840_port->open)
tty_wakeup(tty);
@@ -878,8 +930,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
struct moschip_port *mos7840_port;
struct moschip_port *port0;
- dbg ("%s enter", __func__);
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return -ENODEV;
@@ -1151,10 +1201,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p",
serial, mos7840_port, port);
- dbg ("%s leave", __func__);
-
return 0;
-
}
/*****************************************************************************
@@ -1175,18 +1222,14 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " mos7840_chars_in_buffer:entering ...........");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
return 0;
}
mos7840_port = mos7840_get_port_private(port);
- if (mos7840_port == NULL) {
- dbg("%s", "mos7840_break:leaving ...........");
+ if (mos7840_port == NULL)
return 0;
- }
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
for (i = 0; i < NUM_URBS; ++i)
@@ -1211,8 +1254,6 @@ static void mos7840_close(struct usb_serial_port *port)
int j;
__u16 Data;
- dbg("%s", "mos7840_close:entering...");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return;
@@ -1287,8 +1328,6 @@ static void mos7840_close(struct usb_serial_port *port)
mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
mos7840_port->open = 0;
-
- dbg("%s", "Leaving ............");
}
/************************************************************************
@@ -1343,9 +1382,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
struct usb_serial *serial;
struct moschip_port *mos7840_port;
- dbg("%s", "Entering ...........");
- dbg("mos7840_break: Start");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return;
@@ -1395,8 +1431,6 @@ static int mos7840_write_room(struct tty_struct *tty)
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " mos7840_write_room:entering ...........");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
dbg("%s", " mos7840_write_room:leaving ...........");
@@ -1445,9 +1479,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
/* __u16 Data; */
const unsigned char *current_position = data;
unsigned char *data1;
- dbg("%s", "entering ...........");
- /* dbg("mos7840_write: mos7840_port->shadowLCR is %x",
- mos7840_port->shadowLCR); */
#ifdef NOTMOS7840
Data = 0x00;
@@ -1554,6 +1585,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
data1 = urb->transfer_buffer;
dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
+ /* Turn on LED */
+ if (mos7840_port->has_led && !mos7840_port->led_flag) {
+ mos7840_port->led_flag = true;
+ mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
+ }
+
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1602,8 +1641,6 @@ static void mos7840_throttle(struct tty_struct *tty)
return;
}
- dbg("%s", "Entering ..........");
-
/* if we are implementing XON/XOFF, send the stop character */
if (I_IXOFF(tty)) {
unsigned char stop_char = STOP_CHAR(tty);
@@ -1646,8 +1683,6 @@ static void mos7840_unthrottle(struct tty_struct *tty)
return;
}
- dbg("%s", "Entering ..........");
-
/* if we are implementing XON/XOFF, send the start character */
if (I_IXOFF(tty)) {
unsigned char start_char = START_CHAR(tty);
@@ -1676,8 +1711,6 @@ static int mos7840_tiocmget(struct tty_struct *tty)
int status;
mos7840_port = mos7840_get_port_private(port);
- dbg("%s - port %d", __func__, port->number);
-
if (mos7840_port == NULL)
return -ENODEV;
@@ -1704,8 +1737,6 @@ static int mos7840_tiocmset(struct tty_struct *tty,
unsigned int mcr;
int status;
- dbg("%s - port %d", __func__, port->number);
-
mos7840_port = mos7840_get_port_private(port);
if (mos7840_port == NULL)
@@ -1746,7 +1777,6 @@ static int mos7840_tiocmset(struct tty_struct *tty,
static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
__u16 *clk_sel_val)
{
-
dbg("%s - %d", __func__, baudRate);
if (baudRate <= 115200) {
@@ -1839,8 +1869,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
return -1;
}
- dbg("%s", "Entering ..........");
-
number = mos7840_port->port->number - mos7840_port->port->serial->minor;
dbg("%s - port = %d, baud = %d", __func__,
@@ -1966,8 +1994,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
return;
}
- dbg("%s", "Entering ..........");
-
lData = LCR_BITS_8;
lStop = LCR_STOP_1;
lParity = LCR_PAR_NONE;
@@ -2108,7 +2134,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
unsigned int cflag;
struct usb_serial *serial;
struct moschip_port *mos7840_port;
- dbg("mos7840_set_termios: START");
+
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
return;
@@ -2327,28 +2353,74 @@ static int mos7840_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+static int mos7810_check(struct usb_serial *serial)
+{
+ int i, pass_count = 0;
+ __u16 data = 0, mcr_data = 0;
+ __u16 test_pattern = 0x55AA;
+
+ /* Store MCR setting */
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
+ &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+ for (i = 0; i < 16; i++) {
+ /* Send the 1-bit test pattern out to MCS7810 test pin */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ MCS_WRREQ, MCS_WR_RTYPE,
+ (0x0300 | (((test_pattern >> i) & 0x0001) << 1)),
+ MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
+
+ /* Read the test pattern back */
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+ /* If this is a MCS7810 device, both test patterns must match */
+ if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
+ break;
+
+ pass_count++;
+ }
+
+ /* Restore MCR setting */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
+ 0, MOS_WDR_TIMEOUT);
+
+ if (pass_count == 16)
+ return 1;
+
+ return 0;
+}
+
static int mos7840_calc_num_ports(struct usb_serial *serial)
{
- __u16 Data = 0x00;
- int ret = 0;
+ __u16 data = 0x00;
int mos7840_num_ports;
- ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
- if ((Data & 0x01) == 0) {
- mos7840_num_ports = 2;
- serial->num_bulk_in = 2;
- serial->num_bulk_out = 2;
- serial->num_ports = 2;
+ if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
+ serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
+ device_type = serial->dev->descriptor.idProduct;
} else {
- mos7840_num_ports = 4;
- serial->num_bulk_in = 4;
- serial->num_bulk_out = 4;
- serial->num_ports = 4;
+ /* For a MCS7840 device GPIO0 must be set to 1 */
+ if ((data & 0x01) == 1)
+ device_type = MOSCHIP_DEVICE_ID_7840;
+ else if (mos7810_check(serial))
+ device_type = MOSCHIP_DEVICE_ID_7810;
+ else
+ device_type = MOSCHIP_DEVICE_ID_7820;
}
+ mos7840_num_ports = (device_type >> 4) & 0x000F;
+ serial->num_bulk_in = mos7840_num_ports;
+ serial->num_bulk_out = mos7840_num_ports;
+ serial->num_ports = mos7840_num_ports;
+
return mos7840_num_ports;
}
@@ -2361,9 +2433,7 @@ static int mos7840_startup(struct usb_serial *serial)
struct moschip_port *mos7840_port;
struct usb_device *dev;
int i, status;
-
__u16 Data;
- dbg("%s", "mos7840_startup :Entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2372,9 +2442,6 @@ static int mos7840_startup(struct usb_serial *serial)
dev = serial->dev;
- dbg("%s", "Entering...");
- dbg ("mos7840_startup: serial = %p", serial);
-
/* we set up the pointers to the endpoints in the mos7840_open *
* function, as the structures aren't created yet. */
@@ -2563,6 +2630,34 @@ static int mos7840_startup(struct usb_serial *serial)
status = -ENOMEM;
goto error;
}
+
+ mos7840_port->has_led = false;
+
+ /* Initialize LED timers */
+ if (device_type == MOSCHIP_DEVICE_ID_7810) {
+ mos7840_port->has_led = true;
+
+ init_timer(&mos7840_port->led_timer1);
+ mos7840_port->led_timer1.function = mos7840_led_off;
+ mos7840_port->led_timer1.expires =
+ jiffies + msecs_to_jiffies(LED_ON_MS);
+ mos7840_port->led_timer1.data =
+ (unsigned long)mos7840_port;
+
+ init_timer(&mos7840_port->led_timer2);
+ mos7840_port->led_timer2.function =
+ mos7840_led_flag_off;
+ mos7840_port->led_timer2.expires =
+ jiffies + msecs_to_jiffies(LED_OFF_MS);
+ mos7840_port->led_timer2.data =
+ (unsigned long)mos7840_port;
+
+ mos7840_port->led_flag = false;
+
+ /* Turn off LED */
+ mos7840_set_led_sync(serial->port[i],
+ MODEM_CONTROL_REGISTER, 0x0300);
+ }
}
dbg ("mos7840_startup: all ports configured...........");
@@ -2602,7 +2697,6 @@ static void mos7840_disconnect(struct usb_serial *serial)
int i;
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " disconnect :entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2624,9 +2718,6 @@ static void mos7840_disconnect(struct usb_serial *serial)
usb_kill_urb(mos7840_port->control_urb);
}
}
-
- dbg("%s", "Thank u :: ");
-
}
/****************************************************************************
@@ -2638,7 +2729,6 @@ static void mos7840_release(struct usb_serial *serial)
{
int i;
struct moschip_port *mos7840_port;
- dbg("%s", " release :entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2654,30 +2744,28 @@ static void mos7840_release(struct usb_serial *serial)
mos7840_port = mos7840_get_port_private(serial->port[i]);
dbg("mos7840_port %d = %p", i, mos7840_port);
if (mos7840_port) {
+ if (mos7840_port->has_led) {
+ /* Turn off LED */
+ mos7840_set_led_sync(mos7840_port->port,
+ MODEM_CONTROL_REGISTER, 0x0300);
+
+ del_timer_sync(&mos7840_port->led_timer1);
+ del_timer_sync(&mos7840_port->led_timer2);
+ }
kfree(mos7840_port->ctrl_buf);
kfree(mos7840_port->dr);
kfree(mos7840_port);
}
}
-
- dbg("%s", "Thank u :: ");
-
}
-static struct usb_driver io_driver = {
- .name = "mos7840",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_id_table_combined,
-};
-
static struct usb_serial_driver moschip7840_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "mos7840",
},
.description = DRIVER_DESC,
- .id_table = moschip_port_id_table,
+ .id_table = id_table,
.num_ports = 4,
.open = mos7840_open,
.close = mos7840_close,
@@ -2707,7 +2795,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moschip7840_4port_device, NULL
};
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index 3ab6214..c5ff6c7 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -31,13 +31,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver moto_driver = {
- .name = "moto-modem",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver moto_device = {
.driver = {
.owner = THIS_MODULE,
@@ -51,5 +44,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moto_device, NULL
};
-module_usb_serial_driver(moto_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 29ab6eb..d95452c 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -30,13 +30,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver navman_driver = {
- .name = "navman",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static void navman_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -53,12 +46,12 @@ static void navman_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -84,10 +77,9 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __func__);
+ dev_dbg(&port->dev, "%s - adding interrupt input for treo\n",
+ __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
@@ -99,16 +91,12 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port)
static void navman_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_kill_urb(port->interrupt_in_urb);
}
static int navman_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- dbg("%s - port %d", __func__, port->number);
-
/*
* This device can't write any data, only read from the device
*/
@@ -132,7 +120,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&navman_device, NULL
};
-module_usb_serial_driver(navman_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 88dc785..6f3d705 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -54,17 +54,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
{ } /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver omninet_driver = {
- .name = "omninet",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
static struct usb_serial_driver zyxel_omninet_device = {
.driver = {
.owner = THIS_MODULE,
@@ -144,8 +135,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
struct usb_serial_port *wport;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
wport = serial->port[1];
tty_port_tty_set(&wport->port, tty);
@@ -160,7 +149,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
static void omninet_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);
}
@@ -178,8 +166,6 @@ static void omninet_read_bulk_callback(struct urb *urb)
int result;
int i;
- dbg("%s - port %d", __func__, port->number);
-
if (status) {
dbg("%s - nonzero read bulk status received: %d",
__func__, status);
@@ -225,8 +211,6 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -289,8 +273,6 @@ static void omninet_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %0x", __func__, port->number);
-
set_bit(0, &port->write_urbs_free);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
@@ -306,8 +288,6 @@ static void omninet_disconnect(struct usb_serial *serial)
{
struct usb_serial_port *wport = serial->port[1];
- dbg("%s", __func__);
-
usb_kill_urb(wport->write_urb);
}
@@ -316,12 +296,10 @@ static void omninet_release(struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
- dbg("%s", __func__);
-
kfree(usb_get_serial_port_data(port));
}
-module_usb_serial_driver(omninet_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 82cc9d2..02cb1b7 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -70,8 +70,6 @@ static void opticon_read_bulk_callback(struct urb *urb)
int data_length;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -179,8 +177,6 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
@@ -216,8 +212,6 @@ static void opticon_close(struct usb_serial_port *port)
{
struct opticon_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_kill_urb(priv->bulk_read_urb);
}
@@ -256,8 +250,6 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
int status;
struct usb_ctrlrequest *dr;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -338,8 +330,6 @@ static int opticon_write_room(struct tty_struct *tty)
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/*
* We really can take almost anything the user throws at us
* but let's pick a nice big number to tell the tty
@@ -362,7 +352,6 @@ static void opticon_throttle(struct tty_struct *tty)
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = true;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -376,8 +365,6 @@ static void opticon_unthrottle(struct tty_struct *tty)
unsigned long flags;
int result, was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
was_throttled = priv->actually_throttled;
@@ -400,10 +387,6 @@ static int opticon_tiocmget(struct tty_struct *tty)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->rts)
result |= TIOCM_RTS;
@@ -419,13 +402,13 @@ static int opticon_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
bool rts;
bool changed = false;
+ int ret;
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
/* We only support RTS so we only handle that */
spin_lock_irqsave(&priv->lock, flags);
@@ -441,7 +424,14 @@ static int opticon_tiocmset(struct tty_struct *tty,
return 0;
/* Send the new RTS state to the connected device */
- return send_control_msg(port, CONTROL_RTS, !rts);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ ret = send_control_msg(port, CONTROL_RTS, !rts);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&serial->disc_mutex);
+
+ return ret;
}
static int get_serial_info(struct opticon_private *priv,
@@ -555,8 +545,6 @@ static void opticon_disconnect(struct usb_serial *serial)
{
struct opticon_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
usb_kill_urb(priv->bulk_read_urb);
usb_free_urb(priv->bulk_read_urb);
}
@@ -565,24 +553,20 @@ static void opticon_release(struct usb_serial *serial)
{
struct opticon_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
kfree(priv->bulk_in_buffer);
kfree(priv);
}
-static int opticon_suspend(struct usb_interface *intf, pm_message_t message)
+static int opticon_suspend(struct usb_serial *serial, pm_message_t message)
{
- struct usb_serial *serial = usb_get_intfdata(intf);
struct opticon_private *priv = usb_get_serial_data(serial);
usb_kill_urb(priv->bulk_read_urb);
return 0;
}
-static int opticon_resume(struct usb_interface *intf)
+static int opticon_resume(struct usb_serial *serial)
{
- struct usb_serial *serial = usb_get_intfdata(intf);
struct opticon_private *priv = usb_get_serial_data(serial);
struct usb_serial_port *port = serial->port[0];
int result;
@@ -597,15 +581,6 @@ static int opticon_resume(struct usb_interface *intf)
return result;
}
-static struct usb_driver opticon_driver = {
- .name = "opticon",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = opticon_suspend,
- .resume = opticon_resume,
- .id_table = id_table,
-};
-
static struct usb_serial_driver opticon_device = {
.driver = {
.owner = THIS_MODULE,
@@ -625,13 +600,15 @@ static struct usb_serial_driver opticon_device = {
.ioctl = opticon_ioctl,
.tiocmget = opticon_tiocmget,
.tiocmset = opticon_tiocmset,
+ .suspend = opticon_suspend,
+ .resume = opticon_resume,
};
static struct usb_serial_driver * const serial_drivers[] = {
&opticon_device, NULL
};
-module_usb_serial_driver(opticon_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f4465cc..1aae902 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1220,18 +1220,6 @@ static const struct usb_device_id option_ids[] = {
};
MODULE_DEVICE_TABLE(usb, option_ids);
-static struct usb_driver option_driver = {
- .name = "option",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
-#ifdef CONFIG_PM
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-#endif
- .id_table = option_ids,
-};
-
/* The card has three separate interfaces, which the serial driver
* recognizes separately, thus num_port=1.
*/
@@ -1300,7 +1288,7 @@ struct option_port_private {
unsigned long tx_start_time[N_OUT_URB];
};
-module_usb_serial_driver(option_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, option_ids);
static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
const struct option_blacklist_info *blacklist)
@@ -1375,7 +1363,6 @@ static void option_instat_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct option_port_private *portdata = usb_get_serial_port_data(port);
- dbg("%s", __func__);
dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
if (status == 0) {
@@ -1413,7 +1400,7 @@ static void option_instat_callback(struct urb *urb)
req_pkt->bRequestType, req_pkt->bRequest);
}
} else
- err("%s: error %d", __func__, status);
+ dev_err(&port->dev, "%s: error %d\n", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN && status != -ENOENT) {
@@ -1437,7 +1424,6 @@ static int option_send_setup(struct usb_serial_port *port)
struct option_port_private *portdata;
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
- dbg("%s", __func__);
if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
(struct option_blacklist_info *) intfdata->private)) {
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 5fdc33c..5976b65 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -66,13 +66,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver oti6858_driver = {
- .name = "oti6858",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static bool debug;
/* requests */
@@ -211,8 +204,6 @@ static void setup_line(struct work_struct *work)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __func__, port->number);
-
new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
if (new_setup == NULL) {
dev_err(&port->dev, "%s(): out of memory!\n", __func__);
@@ -282,8 +273,6 @@ static void send_data(struct work_struct *work)
unsigned long flags;
u8 *allow;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -379,8 +368,6 @@ static int oti6858_startup(struct usb_serial *serial)
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- dbg("%s(port = %d, count = %d)", __func__, port->number, count);
-
if (!count)
return count;
@@ -395,8 +382,6 @@ static int oti6858_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
@@ -410,8 +395,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
@@ -437,8 +420,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
__le16 divisor;
int br;
- dbg("%s(port = %d)", __func__, port->number);
-
if (!tty) {
dbg("%s(): no tty structures", __func__);
return;
@@ -545,8 +526,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __func__, port->number);
-
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -602,8 +581,6 @@ static void oti6858_close(struct usb_serial_port *port)
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
/* clear out any remaining data in the buffer */
kfifo_reset_out(&port->write_fifo);
@@ -633,9 +610,6 @@ static int oti6858_tiocmset(struct tty_struct *tty,
dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
__func__, port->number, set, clear);
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
/* FIXME: check if this is correct (active high/low) */
spin_lock_irqsave(&priv->lock, flags);
control = priv->pending_setup.control;
@@ -663,11 +637,6 @@ static int oti6858_tiocmget(struct tty_struct *tty)
unsigned pin_state;
unsigned result = 0;
- dbg("%s(port = %d)", __func__, port->number);
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
pin_state = priv->status.pin_state & PIN_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -750,8 +719,6 @@ static void oti6858_release(struct usb_serial *serial)
{
int i;
- dbg("%s()", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -763,9 +730,6 @@ static void oti6858_read_int_callback(struct urb *urb)
int transient = 0, can_recv = 0, resubmit = 1;
int status = urb->status;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
switch (status) {
case 0:
/* success */
@@ -882,9 +846,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
spin_lock_irqsave(&priv->lock, flags);
priv->flags.read_urb_in_use = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -916,9 +877,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
switch (status) {
case 0:
/* success */
@@ -958,7 +916,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
}
}
-module_usb_serial_driver(oti6858_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
MODULE_AUTHOR(OTI6858_AUTHOR);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index a1a9062..13b8dd6 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -38,8 +38,6 @@
static bool debug;
-#define PL2303_CLOSING_WAIT (30*HZ)
-
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -97,16 +95,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver pl2303_driver = {
- .name = "pl2303",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-};
-
#define SET_LINE_REQUEST_TYPE 0x21
#define SET_LINE_REQUEST 0x20
@@ -161,8 +149,9 @@ static int pl2303_vendor_read(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
value, index, buf, 1, 100);
- dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
- VENDOR_READ_REQUEST, value, index, res, buf[0]);
+ dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
+ VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
+ res, buf[0]);
return res;
}
@@ -172,8 +161,9 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
- dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
- VENDOR_WRITE_REQUEST, value, index, res);
+ dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
+ VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
+ res);
return res;
}
@@ -196,7 +186,7 @@ static int pl2303_startup(struct usb_serial *serial)
type = type_1;
else if (serial->dev->descriptor.bDeviceClass == 0xFF)
type = type_1;
- dbg("device type: %d", type);
+ dev_dbg(&serial->interface->dev, "device type: %d\n", type);
for (i = 0; i < serial->num_ports; ++i) {
priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
@@ -243,7 +233,8 @@ static int set_control_lines(struct usb_device *dev, u8 value)
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dbg("%s - value = %d, retval = %d", __func__, value, retval);
+ dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+ value, retval);
return retval;
}
@@ -265,8 +256,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
int baud_floor, baud_ceil;
int k;
- dbg("%s - port %d", __func__, port->number);
-
/* The PL2303 is reported to lose bytes if you change
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
@@ -287,7 +276,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CSIZE) {
@@ -306,7 +295,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
buf[6] = 8;
break;
}
- dbg("%s - data bits = %d", __func__, buf[6]);
+ dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
}
/* For reference buf[0]:buf[3] baud rate value */
@@ -315,7 +304,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
* 9600 baud (at least my PL2303X always does)
*/
baud = tty_get_baud_rate(tty);
- dbg("%s - baud requested = %d", __func__, baud);
+ dev_dbg(&port->dev, "baud requested = %d\n", baud);
if (baud) {
/* Set baudrate to nearest supported value */
for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
@@ -341,7 +330,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
else if (baud > 6000000)
baud = 6000000;
}
- dbg("%s - baud set = %d", __func__, baud);
+ dev_dbg(&port->dev, "baud set = %d\n", baud);
if (baud <= 115200) {
buf[0] = baud & 0xff;
buf[1] = (baud >> 8) & 0xff;
@@ -372,14 +361,14 @@ static void pl2303_set_termios(struct tty_struct *tty,
*/
if ((cflag & CSIZE) == CS5) {
buf[4] = 1;
- dbg("%s - stop bits = 1.5", __func__);
+ dev_dbg(&port->dev, "stop bits = 1.5\n");
} else {
buf[4] = 2;
- dbg("%s - stop bits = 2", __func__);
+ dev_dbg(&port->dev, "stop bits = 2\n");
}
} else {
buf[4] = 0;
- dbg("%s - stop bits = 1", __func__);
+ dev_dbg(&port->dev, "stop bits = 1\n");
}
if (cflag & PARENB) {
@@ -391,29 +380,29 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (cflag & PARODD) {
if (cflag & CMSPAR) {
buf[5] = 3;
- dbg("%s - parity = mark", __func__);
+ dev_dbg(&port->dev, "parity = mark\n");
} else {
buf[5] = 1;
- dbg("%s - parity = odd", __func__);
+ dev_dbg(&port->dev, "parity = odd\n");
}
} else {
if (cflag & CMSPAR) {
buf[5] = 4;
- dbg("%s - parity = space", __func__);
+ dev_dbg(&port->dev, "parity = space\n");
} else {
buf[5] = 2;
- dbg("%s - parity = even", __func__);
+ dev_dbg(&port->dev, "parity = even\n");
}
}
} else {
buf[5] = 0;
- dbg("%s - parity = none", __func__);
+ dev_dbg(&port->dev, "parity = none\n");
}
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0x21:0x20:0:0 %d", i);
+ dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i);
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
@@ -435,7 +424,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
@@ -473,8 +462,6 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
static void pl2303_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -486,8 +473,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
struct pl2303_private *priv = usb_get_serial_port_data(port);
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -501,7 +486,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
pl2303_set_termios(tty, port, &tmp_termios);
- dbg("%s - submitting interrupt urb", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -523,12 +507,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
+ int ret;
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
@@ -542,7 +525,14 @@ static int pl2303_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- return set_control_lines(port->serial->dev, control);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ ret = set_control_lines(serial->dev, control);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&serial->disc_mutex);
+
+ return ret;
}
static int pl2303_tiocmget(struct tty_struct *tty)
@@ -554,11 +544,6 @@ static int pl2303_tiocmget(struct tty_struct *tty)
unsigned int status;
unsigned int result;
- dbg("%s (%d)", __func__, port->number);
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
@@ -571,7 +556,7 @@ static int pl2303_tiocmget(struct tty_struct *tty)
| ((status & UART_RING) ? TIOCM_RI : 0)
| ((status & UART_DCD) ? TIOCM_CD : 0);
- dbg("%s - result = %x", __func__, result);
+ dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
return result;
}
@@ -625,7 +610,8 @@ static int pl2303_ioctl(struct tty_struct *tty,
{
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
switch (cmd) {
case TIOCGSERIAL:
@@ -641,10 +627,10 @@ static int pl2303_ioctl(struct tty_struct *tty,
return 0;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
return wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
break;
}
return -ENOIOCTLCMD;
@@ -657,20 +643,18 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
u16 state;
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
- dbg("%s - turning break %s", __func__,
+ dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
state == BREAK_OFF ? "off" : "on");
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result)
- dbg("%s - error sending break = %d", __func__, result);
+ dev_err(&port->dev, "error sending break = %d\n", result);
}
static void pl2303_release(struct usb_serial *serial)
@@ -678,8 +662,6 @@ static void pl2303_release(struct usb_serial *serial)
int i;
struct pl2303_private *priv;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
kfree(priv);
@@ -742,8 +724,6 @@ static void pl2303_read_int_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s (%d)", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -752,12 +732,12 @@ static void pl2303_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -769,7 +749,7 @@ static void pl2303_read_int_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- dev_err(&urb->dev->dev,
+ dev_err(&port->dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
@@ -807,7 +787,7 @@ static void pl2303_process_read_urb(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __func__, tty_flag);
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
@@ -855,7 +835,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&pl2303_device, NULL
};
-module_usb_serial_driver(pl2303_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 9662456..a4edc7e 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -77,13 +77,6 @@ static struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver qcaux_driver = {
- .name = "qcaux",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver qcaux_device = {
.driver = {
.owner = THIS_MODULE,
@@ -97,5 +90,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&qcaux_device, NULL
};
-module_usb_serial_driver(qcaux_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 0206b10..0d5fe59 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -112,32 +112,22 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver qcdriver = {
- .name = "qcserial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = true,
-};
-
static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
{
struct usb_wwan_intf_private *data;
struct usb_host_interface *intf = serial->interface->cur_altsetting;
+ struct device *dev = &serial->dev->dev;
int retval = -ENODEV;
__u8 nintf;
__u8 ifnum;
bool is_gobi1k = id->driver_info ? true : false;
- dbg("%s", __func__);
- dbg("Is Gobi 1000 = %d", is_gobi1k);
+ dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k);
nintf = serial->dev->actconfig->desc.bNumInterfaces;
- dbg("Num Interfaces = %d", nintf);
+ dev_dbg(dev, "Num Interfaces = %d\n", nintf);
ifnum = intf->desc.bInterfaceNumber;
- dbg("This Interface = %d", ifnum);
+ dev_dbg(dev, "This Interface = %d\n", ifnum);
data = kzalloc(sizeof(struct usb_wwan_intf_private),
GFP_KERNEL);
@@ -158,7 +148,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
if (intf->desc.bNumEndpoints == 2 &&
usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
- dbg("QDL port found");
+ dev_dbg(dev, "QDL port found\n");
if (serial->interface->num_altsetting == 1) {
retval = 0; /* Success */
@@ -167,7 +157,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
retval = usb_set_interface(serial->dev, ifnum, 1);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -196,20 +186,20 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
*/
if (ifnum == 1 && !is_gobi1k) {
- dbg("Gobi 2K+ DM/DIAG interface found");
+ dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
kfree(data);
}
} else if (ifnum == 2) {
- dbg("Modem port found");
+ dev_dbg(dev, "Modem port found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -221,10 +211,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
* # echo "\$GPS_START" > /dev/ttyUSBx
* # echo "\$GPS_STOP" > /dev/ttyUSBx
*/
- dbg("Gobi 2K+ NMEA GPS interface found");
+ dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -234,8 +224,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
break;
default:
- dev_err(&serial->dev->dev,
- "unknown number of interfaces: %d\n", nintf);
+ dev_err(dev, "unknown number of interfaces: %d\n", nintf);
kfree(data);
retval = -ENODEV;
}
@@ -250,8 +239,6 @@ static void qc_release(struct usb_serial *serial)
{
struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
/* Call usb_wwan release & free the private data allocated in qcprobe */
usb_wwan_release(serial);
usb_set_serial_data(serial, NULL);
@@ -285,7 +272,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&qcdevice, NULL
};
-module_usb_serial_driver(qcdriver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
new file mode 100644
index 0000000..8dd88eb
--- /dev/null
+++ b/drivers/usb/serial/quatech2.c
@@ -0,0 +1,1155 @@
+/*
+ * usb-serial driver for Quatech USB 2 devices
+ *
+ * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu)
+ *
+ * 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.
+ *
+ *
+ * These devices all have only 1 bulk in and 1 bulk out that is shared
+ * for all serial ports.
+ *
+ */
+
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/uaccess.h>
+
+static bool debug;
+
+/* default urb timeout for usb operations */
+#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
+
+#define QT_OPEN_CLOSE_CHANNEL 0xca
+#define QT_SET_GET_DEVICE 0xc2
+#define QT_SET_GET_REGISTER 0xc0
+#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
+#define QT_SET_ATF 0xcd
+#define QT_TRANSFER_IN 0xc0
+#define QT_HW_FLOW_CONTROL_MASK 0xc5
+#define QT_SW_FLOW_CONTROL_MASK 0xc6
+#define QT2_BREAK_CONTROL 0xc8
+#define QT2_GET_SET_UART 0xc1
+#define QT2_FLUSH_DEVICE 0xc4
+#define QT2_GET_SET_QMCR 0xe1
+#define QT2_QMCR_RS232 0x40
+#define QT2_QMCR_RS422 0x10
+
+#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
+
+#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
+
+/* status bytes for the device */
+#define QT2_CONTROL_BYTE 0x1b
+#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */
+#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */
+#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */
+#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */
+#define QT2_REC_FLUSH 0x04 /* no following info */
+#define QT2_XMIT_FLUSH 0x05 /* no following info */
+#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */
+
+#define MAX_BAUD_RATE 921600
+#define DEFAULT_BAUD_RATE 9600
+
+#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
+#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
+
+/* Version Information */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver"
+
+#define USB_VENDOR_ID_QUATECH 0x061d
+#define QUATECH_SSU2_100 0xC120 /* RS232 single port */
+#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
+#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
+#define QUATECH_QSU2_100 0xC160 /* RS232 four port */
+#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
+#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
+#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
+
+struct qt2_device_detail {
+ int product_id;
+ int num_ports;
+};
+
+#define QT_DETAILS(prod, ports) \
+ .product_id = (prod), \
+ .num_ports = (ports)
+
+static const struct qt2_device_detail qt2_device_details[] = {
+ {QT_DETAILS(QUATECH_SSU2_100, 1)},
+ {QT_DETAILS(QUATECH_DSU2_400, 2)},
+ {QT_DETAILS(QUATECH_DSU2_100, 2)},
+ {QT_DETAILS(QUATECH_QSU2_400, 4)},
+ {QT_DETAILS(QUATECH_QSU2_100, 4)},
+ {QT_DETAILS(QUATECH_ESU2_400, 8)},
+ {QT_DETAILS(QUATECH_ESU2_100, 8)},
+ {QT_DETAILS(0, 0)} /* Terminating entry */
+};
+
+static const struct usb_device_id id_table[] = {
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct qt2_serial_private {
+ unsigned char current_port; /* current port for incoming data */
+
+ struct urb *read_urb; /* shared among all ports */
+ char read_buffer[512];
+};
+
+struct qt2_port_private {
+ bool is_open;
+ u8 device_port;
+
+ spinlock_t urb_lock;
+ bool urb_in_use;
+ struct urb *write_urb;
+ char write_buffer[QT2_WRITE_BUFFER_SIZE];
+
+ spinlock_t lock;
+ u8 shadowLSR;
+ u8 shadowMSR;
+
+ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ struct async_icount icount;
+
+ struct usb_serial_port *port;
+};
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_write_bulk_callback(struct urb *urb);
+static void qt2_read_bulk_callback(struct urb *urb);
+
+static void qt2_release(struct usb_serial *serial)
+{
+ int i;
+
+ kfree(usb_get_serial_data(serial));
+
+ for (i = 0; i < serial->num_ports; i++)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+}
+
+static inline int calc_baud_divisor(int baudrate)
+{
+ int divisor, rem;
+
+ divisor = MAX_BAUD_RATE / baudrate;
+ rem = MAX_BAUD_RATE % baudrate;
+ /* Round to nearest divisor */
+ if (((rem * 2) >= baudrate) && (baudrate != 110))
+ divisor++;
+
+ return divisor;
+}
+
+static inline int qt2_set_port_config(struct usb_device *dev,
+ unsigned char port_number,
+ u16 baudrate, u16 lcr)
+{
+ int divisor = calc_baud_divisor(baudrate);
+ u16 index = ((u16) (lcr << 8) | (u16) (port_number));
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ QT2_GET_SET_UART, 0x40,
+ divisor, index, NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_control_msg(struct usb_device *dev,
+ u8 request, u16 data, u16 index)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ request, 0x40, data, index,
+ NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_setdevice(struct usb_device *dev, u8 *data)
+{
+ u16 x = ((u16) (data[1] << 8) | (u16) (data[0]));
+
+ return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
+}
+
+
+static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ QT_SET_GET_DEVICE, 0xc0, 0, 0,
+ data, 3, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_getregister(struct usb_device *dev,
+ u8 uart,
+ u8 reg,
+ u8 *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ QT_SET_GET_REGISTER, 0xc0, reg,
+ uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+
+}
+
+static inline int qt2_setregister(struct usb_device *dev,
+ u8 uart, u8 reg, u16 data)
+{
+ u16 value = (data << 8) | reg;
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ QT_SET_GET_REGISTER, 0x40, value, uart,
+ NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int update_mctrl(struct qt2_port_private *port_priv,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = port_priv->port;
+ struct usb_device *dev = port->serial->dev;
+ unsigned urb_value;
+ int status;
+
+ if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+ dev_dbg(&port->dev,
+ "update_mctrl - DTR|RTS not being set|cleared\n");
+ return 0; /* no change */
+ }
+
+ clear &= ~set; /* 'set' takes precedence over 'clear' */
+ urb_value = 0;
+ if (set & TIOCM_DTR)
+ urb_value |= UART_MCR_DTR;
+ if (set & TIOCM_RTS)
+ urb_value |= UART_MCR_RTS;
+
+ status = qt2_setregister(dev, port_priv->device_port, UART_MCR,
+ urb_value);
+ if (status < 0)
+ dev_err(&port->dev,
+ "update_mctrl - Error from MODEM_CTRL urb: %i\n",
+ status);
+ return status;
+}
+
+static int qt2_calc_num_ports(struct usb_serial *serial)
+{
+ struct qt2_device_detail d;
+ int i;
+
+ for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) {
+ if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
+ return d.num_ports;
+ }
+
+ /* we didn't recognize the device */
+ dev_err(&serial->dev->dev,
+ "don't know the number of ports, assuming 1\n");
+
+ return 1;
+}
+
+static void qt2_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv;
+ struct ktermios *termios = tty->termios;
+ u16 baud;
+ unsigned int cflag = termios->c_cflag;
+ u16 new_lcr = 0;
+ int status;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (cflag & PARENB) {
+ if (cflag & PARODD)
+ new_lcr |= UART_LCR_PARITY;
+ else
+ new_lcr |= SERIAL_EVEN_PARITY;
+ }
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ new_lcr |= UART_LCR_WLEN5;
+ break;
+ case CS6:
+ new_lcr |= UART_LCR_WLEN6;
+ break;
+ case CS7:
+ new_lcr |= UART_LCR_WLEN7;
+ break;
+ default:
+ case CS8:
+ new_lcr |= UART_LCR_WLEN8;
+ break;
+ }
+
+ baud = tty_get_baud_rate(tty);
+ if (!baud)
+ baud = 9600;
+
+ status = qt2_set_port_config(dev, port_priv->device_port, baud,
+ new_lcr);
+ if (status < 0)
+ dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n",
+ __func__, status);
+
+ if (cflag & CRTSCTS)
+ status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+ SERIAL_CRTSCTS,
+ port_priv->device_port);
+ else
+ status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+ 0, port_priv->device_port);
+ if (status < 0)
+ dev_err(&port->dev, "%s - set HW flow control failed: %i\n",
+ __func__, status);
+
+ if (I_IXOFF(tty) || I_IXON(tty)) {
+ u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty)));
+
+ status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+ x, port_priv->device_port);
+ } else
+ status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+ 0, port_priv->device_port);
+
+ if (status < 0)
+ dev_err(&port->dev, "%s - set SW flow control failed: %i\n",
+ __func__, status);
+
+}
+
+static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ u8 *data;
+ u16 device_port;
+ int status;
+ unsigned long flags;
+
+ device_port = (u16) (port->number - port->serial->minor);
+
+ serial = port->serial;
+
+ port_priv = usb_get_serial_port_data(port);
+ serial_priv = usb_get_serial_data(serial);
+
+ /* set the port to RS232 mode */
+ status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
+ QT2_QMCR_RS232, device_port);
+ if (status < 0) {
+ dev_err(&port->dev,
+ "%s failed to set RS232 mode for port %i error %i\n",
+ __func__, device_port, status);
+ return status;
+ }
+
+ data = kzalloc(2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* open the port */
+ status = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT_OPEN_CLOSE_CHANNEL,
+ 0xc0, 0,
+ device_port, data, 2, QT2_USB_TIMEOUT);
+
+ if (status < 0) {
+ dev_err(&port->dev, "%s - open port failed %i", __func__,
+ status);
+ kfree(data);
+ return status;
+ }
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowLSR = data[0];
+ port_priv->shadowMSR = data[1];
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ kfree(data);
+
+ /* set to default speed and 8bit word size */
+ status = qt2_set_port_config(serial->dev, device_port,
+ DEFAULT_BAUD_RATE, UART_LCR_WLEN8);
+ if (status < 0) {
+ dev_err(&port->dev,
+ "%s - initial setup failed for port %i (%i)\n",
+ __func__, port->number, device_port);
+ return status;
+ }
+
+ port_priv->is_open = true;
+ port_priv->device_port = (u8) device_port;
+
+ if (tty)
+ qt2_set_termios(tty, port, tty->termios);
+
+ return 0;
+
+}
+
+static void qt2_close(struct usb_serial_port *port)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ unsigned long flags;
+ int i;
+
+ serial = port->serial;
+ serial_priv = usb_get_serial_data(serial);
+ port_priv = usb_get_serial_port_data(port);
+
+ port_priv->is_open = false;
+
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+ if (port_priv->write_urb->status == -EINPROGRESS)
+ usb_kill_urb(port_priv->write_urb);
+ port_priv->urb_in_use = false;
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+ /* flush the port transmit buffer */
+ i = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT2_FLUSH_DEVICE, 0x40, 1,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n",
+ __func__, i);
+
+ /* flush the port receive buffer */
+ i = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT2_FLUSH_DEVICE, 0x40, 0,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - receive buffer flush failed: %i\n",
+ __func__, i);
+
+ /* close the port */
+ i = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ QT_OPEN_CLOSE_CHANNEL,
+ 0x40, 0,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - close port failed %i\n",
+ __func__, i);
+
+}
+
+static void qt2_disconnect(struct usb_serial *serial)
+{
+ struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
+ struct qt2_port_private *port_priv;
+ int i;
+
+ if (serial_priv->read_urb->status == -EINPROGRESS)
+ usb_kill_urb(serial_priv->read_urb);
+
+ usb_free_urb(serial_priv->read_urb);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port_priv = usb_get_serial_port_data(serial->port[i]);
+
+ if (port_priv->write_urb->status == -EINPROGRESS)
+ usb_kill_urb(port_priv->write_urb);
+ usb_free_urb(port_priv->write_urb);
+ }
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = 0;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = port->bulk_out_size;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5*HZ;
+ tmp.closing_wait = 30*HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+ struct qt2_port_private *priv = usb_get_serial_port_data(port);
+ struct async_icount prev, cur;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ prev = priv->icount;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ wait_event_interruptible(priv->delta_msr_wait,
+ ((priv->icount.rng != prev.rng) ||
+ (priv->icount.dsr != prev.dsr) ||
+ (priv->icount.dcd != prev.dcd) ||
+ (priv->icount.cts != prev.cts)));
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ cur = priv->icount;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if ((prev.rng == cur.rng) &&
+ (prev.dsr == cur.dsr) &&
+ (prev.dcd == cur.dcd) &&
+ (prev.cts == cur.cts))
+ return -EIO;
+
+ if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
+ (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
+ (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
+ (arg & TIOCM_CTS && (prev.cts != cur.cts)))
+ return 0;
+ }
+ return 0;
+}
+
+static int qt2_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *priv = usb_get_serial_port_data(port);
+ struct async_icount cnow = priv->icount;
+
+ icount->cts = cnow.cts;
+ icount->dsr = cnow.dsr;
+ icount->rng = cnow.rng;
+ icount->dcd = cnow.dcd;
+ icount->rx = cnow.rx;
+ icount->tx = cnow.tx;
+ icount->frame = cnow.frame;
+ icount->overrun = cnow.overrun;
+ icount->parity = cnow.parity;
+ icount->brk = cnow.brk;
+ icount->buf_overrun = cnow.buf_overrun;
+
+ return 0;
+}
+
+static int qt2_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *)arg);
+
+ case TIOCMIWAIT:
+ return wait_modem_info(port, arg);
+
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
+{
+ switch (*ch) {
+ case QT2_LINE_STATUS:
+ qt2_update_lsr(port, ch + 1);
+ break;
+ case QT2_MODEM_STATUS:
+ qt2_update_msr(port, ch + 1);
+ break;
+ }
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_xmit_empty(struct usb_serial_port *port,
+ unsigned char *ch)
+{
+ int bytes_written;
+
+ bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4);
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch)
+{
+ return;
+}
+
+void qt2_process_read_urb(struct urb *urb)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct usb_serial_port *port;
+ struct qt2_port_private *port_priv;
+ struct tty_struct *tty;
+ bool escapeflag;
+ unsigned char *ch;
+ int i;
+ unsigned char newport;
+ int len = urb->actual_length;
+
+ if (!len)
+ return;
+
+ ch = urb->transfer_buffer;
+ tty = NULL;
+ serial = urb->context;
+ serial_priv = usb_get_serial_data(serial);
+ port = serial->port[serial_priv->current_port];
+ port_priv = usb_get_serial_port_data(port);
+
+ if (port_priv->is_open)
+ tty = tty_port_tty_get(&port->port);
+
+ for (i = 0; i < urb->actual_length; i++) {
+ ch = (unsigned char *)urb->transfer_buffer + i;
+ if ((i <= (len - 3)) &&
+ (*ch == QT2_CONTROL_BYTE) &&
+ (*(ch + 1) == QT2_CONTROL_BYTE)) {
+ escapeflag = false;
+ switch (*(ch + 2)) {
+ case QT2_LINE_STATUS:
+ case QT2_MODEM_STATUS:
+ if (i > (len - 4)) {
+ dev_warn(&port->dev,
+ "%s - status message too short\n",
+ __func__);
+ break;
+ }
+ qt2_process_status(port, ch + 2);
+ i += 3;
+ escapeflag = true;
+ break;
+ case QT2_XMIT_HOLD:
+ if (i > (len - 5)) {
+ dev_warn(&port->dev,
+ "%s - xmit_empty message too short\n",
+ __func__);
+ break;
+ }
+ qt2_process_xmit_empty(port, ch + 3);
+ i += 4;
+ escapeflag = true;
+ break;
+ case QT2_CHANGE_PORT:
+ if (i > (len - 4)) {
+ dev_warn(&port->dev,
+ "%s - change_port message too short\n",
+ __func__);
+ break;
+ }
+ if (tty) {
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+
+ newport = *(ch + 3);
+
+ if (newport > serial->num_ports) {
+ dev_err(&port->dev,
+ "%s - port change to invalid port: %i\n",
+ __func__, newport);
+ break;
+ }
+
+ serial_priv->current_port = newport;
+ port = serial->port[serial_priv->current_port];
+ port_priv = usb_get_serial_port_data(port);
+ if (port_priv->is_open)
+ tty = tty_port_tty_get(&port->port);
+ else
+ tty = NULL;
+ i += 3;
+ escapeflag = true;
+ break;
+ case QT2_REC_FLUSH:
+ case QT2_XMIT_FLUSH:
+ qt2_process_flush(port, ch + 2);
+ i += 2;
+ escapeflag = true;
+ break;
+ case QT2_CONTROL_ESCAPE:
+ tty_buffer_request_room(tty, 2);
+ tty_insert_flip_string(tty, ch, 2);
+ i += 2;
+ escapeflag = true;
+ break;
+ default:
+ dev_warn(&port->dev,
+ "%s - unsupported command %i\n",
+ __func__, *(ch + 2));
+ break;
+ }
+ if (escapeflag)
+ continue;
+ }
+
+ if (tty) {
+ tty_buffer_request_room(tty, 1);
+ tty_insert_flip_string(tty, ch, 1);
+ }
+ }
+
+ if (tty) {
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+}
+
+static void qt2_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct qt2_port_private *port_priv;
+
+ port = urb->context;
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock(&port_priv->urb_lock);
+
+ port_priv->urb_in_use = false;
+ usb_serial_port_softint(port);
+
+ spin_unlock(&port_priv->urb_lock);
+
+}
+
+static void qt2_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial *serial = urb->context;
+ int status;
+
+ if (urb->status) {
+ dev_warn(&serial->dev->dev,
+ "%s - non-zero urb status: %i\n", __func__,
+ urb->status);
+ return;
+ }
+
+ qt2_process_read_urb(urb);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status != 0)
+ dev_err(&serial->dev->dev,
+ "%s - resubmit read urb failed: %i\n",
+ __func__, status);
+}
+
+static int qt2_setup_urbs(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ struct usb_serial_port *port0;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ int pcount, status;
+
+ port0 = serial->port[0];
+
+ serial_priv = usb_get_serial_data(serial);
+ serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!serial_priv->read_urb) {
+ dev_err(&serial->dev->dev, "No free urbs available\n");
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port0->bulk_in_endpointAddress),
+ serial_priv->read_buffer,
+ sizeof(serial_priv->read_buffer),
+ qt2_read_bulk_callback, serial);
+
+ /* setup write_urb for each port */
+ for (pcount = 0; pcount < serial->num_ports; pcount++) {
+
+ port = serial->port[pcount];
+ port_priv = usb_get_serial_port_data(port);
+
+ port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!port_priv->write_urb) {
+ dev_err(&serial->dev->dev,
+ "failed to alloc write_urb for port %i\n",
+ pcount);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(port_priv->write_urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port0->
+ bulk_out_endpointAddress),
+ port_priv->write_buffer,
+ sizeof(port_priv->write_buffer),
+ qt2_write_bulk_callback, port);
+ }
+
+ status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
+ if (status != 0) {
+ dev_err(&serial->dev->dev,
+ "%s - submit read urb failed %i\n", __func__, status);
+ return status;
+ }
+
+ return 0;
+
+}
+
+static int qt2_attach(struct usb_serial *serial)
+{
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ int status, pcount;
+
+ /* power on unit */
+ status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 0xc2, 0x40, 0x8000, 0, NULL, 0,
+ QT2_USB_TIMEOUT);
+ if (status < 0) {
+ dev_err(&serial->dev->dev,
+ "%s - failed to power on unit: %i\n", __func__, status);
+ return status;
+ }
+
+ serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
+ if (!serial_priv) {
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ usb_set_serial_data(serial, serial_priv);
+
+ for (pcount = 0; pcount < serial->num_ports; pcount++) {
+ port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+ if (!port_priv) {
+ dev_err(&serial->dev->dev,
+ "%s- kmalloc(%Zd) failed.\n", __func__,
+ sizeof(*port_priv));
+ pcount--;
+ status = -ENOMEM;
+ goto attach_failed;
+ }
+
+ spin_lock_init(&port_priv->lock);
+ spin_lock_init(&port_priv->urb_lock);
+ init_waitqueue_head(&port_priv->delta_msr_wait);
+
+ port_priv->port = serial->port[pcount];
+
+ usb_set_serial_port_data(serial->port[pcount], port_priv);
+ }
+
+ status = qt2_setup_urbs(serial);
+ if (status != 0)
+ goto attach_failed;
+
+ return 0;
+
+attach_failed:
+ for (/* empty */; pcount >= 0; pcount--) {
+ port_priv = usb_get_serial_port_data(serial->port[pcount]);
+ kfree(port_priv);
+ }
+ kfree(serial_priv);
+ return status;
+}
+
+static int qt2_tiocmget(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+ u8 *d;
+ int r;
+
+ d = kzalloc(2, GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d);
+ if (r < 0)
+ goto mget_out;
+
+ r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1);
+ if (r < 0)
+ goto mget_out;
+
+ r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
+ (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
+ (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
+ (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
+ (d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
+ (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+mget_out:
+ kfree(d);
+ return r;
+}
+
+static int qt2_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct qt2_port_private *port_priv;
+
+ port_priv = usb_get_serial_port_data(tty->driver_data);
+ return update_mctrl(port_priv, set, clear);
+}
+
+static void qt2_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *port_priv;
+ int status;
+ u16 val;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (!port_priv->is_open) {
+ dev_err(&port->dev,
+ "%s - port is not open\n", __func__);
+ return;
+ }
+
+ val = (break_state == -1) ? 1 : 0;
+
+ status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
+ val, port_priv->device_port);
+ if (status < 0)
+ dev_warn(&port->dev,
+ "%s - failed to send control message: %i\n", __func__,
+ status);
+}
+
+
+
+static void qt2_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* Disable flow control */
+ if (!on && qt2_setregister(dev, port_priv->device_port,
+ UART_MCR, 0) < 0)
+ dev_warn(&port->dev, "error from flowcontrol urb\n");
+ /* drop RTS and DTR */
+ if (on)
+ update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
+ else
+ update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
+ }
+ mutex_unlock(&port->serial->disc_mutex);
+}
+
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
+{
+ struct qt2_port_private *port_priv;
+ u8 newMSR = (u8) *ch;
+ unsigned long flags;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowMSR = newMSR;
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ if (newMSR & UART_MSR_ANY_DELTA) {
+ /* update input line counters */
+ if (newMSR & UART_MSR_DCTS)
+ port_priv->icount.cts++;
+
+ if (newMSR & UART_MSR_DDSR)
+ port_priv->icount.dsr++;
+
+ if (newMSR & UART_MSR_DDCD)
+ port_priv->icount.dcd++;
+
+ if (newMSR & UART_MSR_TERI)
+ port_priv->icount.rng++;
+
+ wake_up_interruptible(&port_priv->delta_msr_wait);
+ }
+}
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
+{
+ struct qt2_port_private *port_priv;
+ struct async_icount *icount;
+ unsigned long flags;
+ u8 newLSR = (u8) *ch;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (newLSR & UART_LSR_BI)
+ newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowLSR = newLSR;
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ icount = &port_priv->icount;
+
+ if (newLSR & UART_LSR_BRK_ERROR_BITS) {
+
+ if (newLSR & UART_LSR_BI)
+ icount->brk++;
+
+ if (newLSR & UART_LSR_OE)
+ icount->overrun++;
+
+ if (newLSR & UART_LSR_PE)
+ icount->parity++;
+
+ if (newLSR & UART_LSR_FE)
+ icount->frame++;
+ }
+
+}
+
+static int qt2_write_room(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *port_priv;
+ unsigned long flags = 0;
+ int r;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+
+ if (port_priv->urb_in_use)
+ r = 0;
+ else
+ r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE;
+
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+ return r;
+}
+
+static int qt2_write(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct qt2_port_private *port_priv;
+ struct urb *write_urb;
+ unsigned char *data;
+ unsigned long flags;
+ int status;
+ int bytes_out = 0;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (port_priv->write_urb == NULL) {
+ dev_err(&port->dev, "%s - no output urb\n", __func__);
+ return 0;
+ }
+ write_urb = port_priv->write_urb;
+
+ count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE);
+
+ data = write_urb->transfer_buffer;
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+ if (port_priv->urb_in_use == true) {
+ printk(KERN_INFO "qt2_write - urb is in use\n");
+ goto write_out;
+ }
+
+ *data++ = QT2_CONTROL_BYTE;
+ *data++ = QT2_CONTROL_BYTE;
+ *data++ = port_priv->device_port;
+ put_unaligned_le16(count, data);
+ data += 2;
+ memcpy(data, buf, count);
+
+ write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE;
+
+ status = usb_submit_urb(write_urb, GFP_ATOMIC);
+ if (status == 0) {
+ port_priv->urb_in_use = true;
+ bytes_out += count;
+ }
+
+write_out:
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+ return bytes_out;
+}
+
+
+static struct usb_serial_driver qt2_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "quatech-serial",
+ },
+ .description = DRIVER_DESC,
+ .id_table = id_table,
+ .open = qt2_open,
+ .close = qt2_close,
+ .write = qt2_write,
+ .write_room = qt2_write_room,
+ .calc_num_ports = qt2_calc_num_ports,
+ .attach = qt2_attach,
+ .release = qt2_release,
+ .disconnect = qt2_disconnect,
+ .dtr_rts = qt2_dtr_rts,
+ .break_ctl = qt2_break_ctl,
+ .tiocmget = qt2_tiocmget,
+ .tiocmset = qt2_tiocmset,
+ .get_icount = qt2_get_icount,
+ .ioctl = qt2_ioctl,
+ .set_termios = qt2_set_termios,
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+ &qt2_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index ae4ee30..36e9d9f 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -151,13 +151,6 @@ static struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver safe_driver = {
- .name = "safe_serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static const __u16 crc10_table[256] = {
0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff,
0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
@@ -339,12 +332,12 @@ static int __init safe_init(void)
}
}
- return usb_serial_register_drivers(&safe_driver, serial_drivers);
+ return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
}
static void __exit safe_exit(void)
{
- usb_serial_deregister_drivers(&safe_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
module_init(safe_init);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 46c0430..e4a1787 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -29,13 +29,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver siemens_usb_mpi_driver = {
- .name = "siemens_mpi",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver siemens_usb_mpi_device = {
.driver = {
.owner = THIS_MODULE,
@@ -49,7 +42,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&siemens_usb_mpi_device, NULL
};
-module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 8c8bf80..ba54a0a 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -63,9 +63,7 @@ struct sierra_intf_private {
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
{
- int result;
- dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetPower, /* __u8 request */
USB_TYPE_VENDOR, /* __u8 request type */
swiState, /* __u16 value */
@@ -73,14 +71,11 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
- return result;
}
static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
{
- int result;
- dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
USB_TYPE_VENDOR, /* __u8 request type */
enable, /* __u16 value */
@@ -88,7 +83,6 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
- return result;
}
static int sierra_calc_num_ports(struct usb_serial *serial)
@@ -96,8 +90,6 @@ static int sierra_calc_num_ports(struct usb_serial *serial)
int num_ports = 0;
u8 ifnum, numendpoints;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
@@ -150,7 +142,6 @@ static int sierra_calc_interface(struct usb_serial *serial)
int interface;
struct usb_interface *p_interface;
struct usb_host_interface *p_host_interface;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
/* Get the interface structure pointer from the serial struct */
p_interface = serial->interface;
@@ -175,9 +166,8 @@ static int sierra_probe(struct usb_serial *serial,
u8 ifnum;
udev = serial->dev;
- dev_dbg(&udev->dev, "%s\n", __func__);
-
ifnum = sierra_calc_interface(serial);
+
/*
* If this interface supports more than 1 alternate
* select the 2nd one
@@ -344,8 +334,6 @@ static int sierra_send_setup(struct usb_serial_port *port)
int do_send = 0;
int retval;
- dev_dbg(&port->dev, "%s\n", __func__);
-
portdata = usb_get_serial_port_data(port);
if (portdata->dtr_state)
@@ -393,7 +381,6 @@ static int sierra_send_setup(struct usb_serial_port *port)
static void sierra_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
- dev_dbg(&port->dev, "%s\n", __func__);
tty_termios_copy_hw(tty->termios, old_termios);
sierra_send_setup(port);
}
@@ -404,7 +391,6 @@ static int sierra_tiocmget(struct tty_struct *tty)
unsigned int value;
struct sierra_port_private *portdata;
- dev_dbg(&port->dev, "%s\n", __func__);
portdata = usb_get_serial_port_data(port);
value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
@@ -441,8 +427,7 @@ static void sierra_release_urb(struct urb *urb)
{
struct usb_serial_port *port;
if (urb) {
- port = urb->context;
- dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
+ port = urb->context;
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
@@ -455,7 +440,6 @@ static void sierra_outdat_callback(struct urb *urb)
struct sierra_intf_private *intfdata;
int status = urb->status;
- dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
intfdata = port->serial->private;
/* free up the transfer buffer, as usb_free_urb() does not do this */
@@ -598,8 +582,6 @@ static void sierra_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
- dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
-
if (status) {
dev_dbg(&port->dev, "%s: nonzero status: %d on"
" endpoint %02x\n", __func__, status, endpoint);
@@ -697,8 +679,6 @@ static int sierra_write_room(struct tty_struct *tty)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- dev_dbg(&port->dev, "%s - port %d\n", __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);
@@ -805,8 +785,6 @@ static void sierra_close(struct usb_serial_port *port)
struct sierra_port_private *portdata;
struct sierra_intf_private *intfdata = port->serial->private;
-
- dev_dbg(&port->dev, "%s\n", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
@@ -851,8 +829,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- dev_dbg(&port->dev, "%s\n", __func__);
-
/* Set some sane defaults */
portdata->rts_state = 1;
portdata->dtr_state = 1;
@@ -915,8 +891,6 @@ static int sierra_startup(struct usb_serial *serial)
int i;
u8 ifnum;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
/* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
@@ -977,8 +951,6 @@ static void sierra_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct sierra_port_private *portdata;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (!port)
@@ -1067,29 +1039,11 @@ static int sierra_resume(struct usb_serial *serial)
return ec ? -EIO : 0;
}
-static int sierra_reset_resume(struct usb_interface *intf)
-{
- struct usb_serial *serial = usb_get_intfdata(intf);
- dev_err(&serial->dev->dev, "%s\n", __func__);
- return usb_serial_resume(intf);
-}
#else
#define sierra_suspend NULL
#define sierra_resume NULL
-#define sierra_reset_resume NULL
#endif
-static struct usb_driver sierra_driver = {
- .name = "sierra",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .reset_resume = sierra_reset_resume,
- .id_table = id_table,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver sierra_device = {
.driver = {
.owner = THIS_MODULE,
@@ -1118,7 +1072,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&sierra_device, NULL
};
-module_usb_serial_driver(sierra_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index f06c9a8..cad6089 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -151,14 +151,6 @@ enum spcp8x5_type {
SPCP835_TYPE,
};
-static struct usb_driver spcp8x5_driver = {
- .name = "spcp8x5",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
struct spcp8x5_private {
spinlock_t lock;
enum spcp8x5_type type;
@@ -433,7 +425,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (i < 0)
dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
uartdata, i);
- dbg("0x21:0x40:0:0 %d", i);
+ dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i);
if (cflag & CRTSCTS) {
/* enable hardware flow control */
@@ -454,8 +446,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
u8 status = 0x30;
/* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
- dbg("%s - port %d", __func__, port->number);
-
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -579,15 +569,19 @@ static int spcp8x5_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+ port->number, cmd);
switch (cmd) {
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+ port->number);
return spcp8x5_wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
+ cmd);
break;
}
@@ -666,7 +660,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&spcp8x5_device, NULL
};
-module_usb_serial_driver(spcp8x5_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 3cdc8a5..3fee23b 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -59,20 +59,8 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
{} /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_driver ssu100_driver = {
- .name = "ssu100",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-};
-
struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
@@ -85,7 +73,6 @@ static void ssu100_release(struct usb_serial *serial)
{
struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
- dbg("%s", __func__);
kfree(priv);
}
@@ -171,8 +158,6 @@ static int ssu100_initdevice(struct usb_device *dev)
u8 *data;
int result = 0;
- dbg("%s", __func__);
-
data = kzalloc(3, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -237,8 +222,6 @@ static void ssu100_set_termios(struct tty_struct *tty,
u16 urb_value = 0; /* will hold the new flags */
int result;
- dbg("%s", __func__);
-
if (cflag & PARENB) {
if (cflag & PARODD)
urb_value |= UART_LCR_PARITY;
@@ -312,8 +295,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
int result;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
data = kzalloc(2, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -348,7 +329,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
static void ssu100_close(struct usb_serial_port *port)
{
- dbg("%s", __func__);
usb_serial_generic_close(port);
}
@@ -467,8 +447,6 @@ static int ssu100_attach(struct usb_serial *serial)
struct ssu100_port_private *priv;
struct usb_serial_port *port = *serial->port;
- dbg("%s", __func__);
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -490,8 +468,6 @@ static int ssu100_tiocmget(struct tty_struct *tty)
u8 *d;
int r;
- dbg("%s\n", __func__);
-
d = kzalloc(2, GFP_KERNEL);
if (!d)
return -ENOMEM;
@@ -522,7 +498,6 @@ static int ssu100_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct usb_device *dev = port->serial->dev;
- dbg("%s\n", __func__);
return update_mctrl(dev, set, clear);
}
@@ -530,8 +505,6 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_device *dev = port->serial->dev;
- dbg("%s\n", __func__);
-
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* Disable flow control */
@@ -618,8 +591,6 @@ static int ssu100_process_packet(struct urb *urb,
int i;
char *ch;
- dbg("%s - port %d", __func__, port->number);
-
if ((len >= 4) &&
(packet[0] == 0x1b) && (packet[1] == 0x1b) &&
((packet[2] == 0x00) || (packet[2] == 0x01))) {
@@ -656,8 +627,6 @@ static void ssu100_process_read_urb(struct urb *urb)
struct tty_struct *tty;
int count;
- dbg("%s", __func__);
-
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
@@ -695,7 +664,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ssu100_device, NULL
};
-module_usb_serial_driver(ssu100_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 1a5be13..e53d2aa 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -54,8 +54,6 @@ static void symbol_int_callback(struct urb *urb)
int result;
int data_length;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -64,12 +62,12 @@ static void symbol_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -125,8 +123,6 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
@@ -150,8 +146,6 @@ static void symbol_close(struct usb_serial_port *port)
{
struct symbol_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_kill_urb(priv->int_urb);
}
@@ -161,7 +155,6 @@ static void symbol_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
spin_lock_irq(&priv->lock);
priv->throttled = true;
spin_unlock_irq(&priv->lock);
@@ -174,8 +167,6 @@ static void symbol_unthrottle(struct tty_struct *tty)
int result;
bool was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->throttled = false;
was_throttled = priv->actually_throttled;
@@ -266,8 +257,6 @@ static void symbol_disconnect(struct usb_serial *serial)
{
struct symbol_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
usb_kill_urb(priv->int_urb);
usb_free_urb(priv->int_urb);
}
@@ -276,19 +265,10 @@ static void symbol_release(struct usb_serial *serial)
{
struct symbol_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
kfree(priv->int_buffer);
kfree(priv);
}
-static struct usb_driver symbol_driver = {
- .name = "symbol",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver symbol_device = {
.driver = {
.owner = THIS_MODULE,
@@ -309,7 +289,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&symbol_device, NULL
};
-module_usb_serial_driver(symbol_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ab74123..a4404f5 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -165,7 +165,7 @@ static unsigned int product_5052_count;
/* the array dimension is the number of default entries plus */
/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
/* null entry */
-static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
};
static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
@@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
};
-static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -208,16 +209,10 @@ static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1]
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ }
};
-static struct usb_driver ti_usb_driver = {
- .name = "ti_usb_3410_5052",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ti_id_table_combined,
-};
-
static struct usb_serial_driver ti_1port_device = {
.driver = {
.owner = THIS_MODULE,
@@ -344,20 +339,18 @@ static int __init ti_init(void)
ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
}
- ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers);
+ ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
if (ret == 0)
printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
TI_DRIVER_DESC "\n");
return ret;
}
-
static void __exit ti_exit(void)
{
- usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
-
module_init(ti_init);
module_exit(ti_exit);
@@ -394,7 +387,9 @@ static int ti_startup(struct usb_serial *serial)
/* if we have only 1 configuration, download firmware */
if (dev->descriptor.bNumConfigurations == 1) {
- if ((status = ti_download_firmware(tdev)) != 0)
+ status = ti_download_firmware(tdev);
+
+ if (status != 0)
goto free_tdev;
/* 3410 must be reset, 5052 resets itself */
@@ -463,8 +458,6 @@ static void ti_release(struct usb_serial *serial)
struct ti_device *tdev = usb_get_serial_data(serial);
struct ti_port *tport;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
tport = usb_get_serial_port_data(serial->port[i]);
if (tport) {
@@ -489,8 +482,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
TI_PIPE_TIMEOUT_ENABLE |
(TI_TRANSFER_TIMEOUT << 2));
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -631,8 +622,6 @@ static void ti_close(struct usb_serial_port *port)
int status;
int do_unlock;
- dbg("%s - port %d", __func__, port->number);
-
tdev = usb_get_serial_data(port->serial);
tport = usb_get_serial_port_data(port);
if (tdev == NULL || tport == NULL)
@@ -666,8 +655,6 @@ static void ti_close(struct usb_serial_port *port)
}
if (do_unlock)
mutex_unlock(&tdev->td_open_close_lock);
-
- dbg("%s - exit", __func__);
}
@@ -676,8 +663,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
{
struct ti_port *tport = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -701,8 +686,6 @@ static int ti_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return 0;
@@ -722,8 +705,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return 0;
@@ -741,8 +722,6 @@ static void ti_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return;
@@ -758,8 +737,6 @@ static void ti_unthrottle(struct tty_struct *tty)
struct ti_port *tport = usb_get_serial_port_data(port);
int status;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return;
@@ -854,8 +831,6 @@ static void ti_set_termios(struct tty_struct *tty,
int port_number = port->number - port->serial->minor;
unsigned int mcr;
- dbg("%s - port %d", __func__, port->number);
-
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
@@ -988,8 +963,6 @@ static int ti_tiocmget(struct tty_struct *tty)
unsigned int mcr;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -1020,8 +993,6 @@ static int ti_tiocmset(struct tty_struct *tty,
unsigned int mcr;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -1084,8 +1055,6 @@ static void ti_interrupt_callback(struct urb *urb)
int retval;
__u8 msr;
- dbg("%s", __func__);
-
switch (status) {
case 0:
break;
@@ -1165,8 +1134,6 @@ static void ti_bulk_in_callback(struct urb *urb)
int retval = 0;
struct tty_struct *tty;
- dbg("%s", __func__);
-
switch (status) {
case 0:
break;
@@ -1233,8 +1200,6 @@ static void ti_bulk_out_callback(struct urb *urb)
struct usb_serial_port *port = tport->tp_port;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
tport->tp_write_urb_in_use = 0;
switch (status) {
@@ -1287,9 +1252,6 @@ static void ti_send(struct ti_port *tport)
struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&tport->tp_lock, flags);
if (tport->tp_write_urb_in_use)
@@ -1366,8 +1328,6 @@ static int ti_get_lsr(struct ti_port *tport)
int port_number = port->number - port->serial->minor;
struct ti_port_status *data;
- dbg("%s - port %d", __func__, port->number);
-
size = sizeof(struct ti_port_status);
data = kmalloc(size, GFP_KERNEL);
if (!data) {
@@ -1480,8 +1440,6 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&tport->tp_lock);
/* wait for data to drain from the buffer */
@@ -1679,11 +1637,12 @@ static int ti_download_firmware(struct ti_device *tdev)
const struct firmware *fw_p;
char buf[32];
- dbg("%s\n", __func__);
/* try ID specific firmware first, then try generic firmware */
sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
dev->descriptor.idProduct);
- if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) {
+ status = request_firmware(&fw_p, buf, &dev->dev);
+
+ if (status != 0) {
buf[0] = '\0';
if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
switch (dev->descriptor.idProduct) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index f140f1b..b353e7e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -37,6 +37,7 @@
#define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */
#define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */
#define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */
+#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */
/* Multi-Tech vendor and product ids */
#define MTS_VENDOR_ID 0x06E0
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 97355a1..6a1b609 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
*
@@ -43,17 +43,6 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
-/* Driver structure we register with the USB core */
-static struct usb_driver usb_serial_driver = {
- .name = "usbserial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .no_dynamic_id = 1,
- .supports_autosuspend = 1,
-};
-
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
the MODULE_DEVICE_TABLE declarations in each serial driver
cause the "hotplug" program to pull in whatever module is necessary
@@ -710,7 +699,7 @@ static const struct tty_port_operations serial_port_ops = {
.shutdown = serial_down,
};
-int usb_serial_probe(struct usb_interface *interface,
+static int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(interface);
@@ -856,6 +845,8 @@ int usb_serial_probe(struct usb_interface *interface,
module_put(type->driver.owner);
return -EIO;
}
+ dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
+ dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
}
#endif
if (!num_ports) {
@@ -1043,6 +1034,8 @@ int usb_serial_probe(struct usb_interface *interface,
dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
}
+ usb_set_intfdata(interface, serial);
+
/* if this device type has an attach function, call it */
if (type->attach) {
retval = type->attach(serial);
@@ -1087,10 +1080,7 @@ int usb_serial_probe(struct usb_interface *interface,
serial->disconnected = 0;
usb_serial_console_init(debug, minor);
-
exit:
- /* success */
- usb_set_intfdata(interface, serial);
module_put(type->driver.owner);
return 0;
@@ -1099,9 +1089,8 @@ probe_error:
module_put(type->driver.owner);
return -EIO;
}
-EXPORT_SYMBOL_GPL(usb_serial_probe);
-void usb_serial_disconnect(struct usb_interface *interface)
+static void usb_serial_disconnect(struct usb_interface *interface)
{
int i;
struct usb_serial *serial = usb_get_intfdata(interface);
@@ -1112,7 +1101,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
dbg("%s", __func__);
mutex_lock(&serial->disc_mutex);
- usb_set_intfdata(interface, NULL);
/* must set a flag, to signal subdrivers */
serial->disconnected = 1;
mutex_unlock(&serial->disc_mutex);
@@ -1137,7 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
-EXPORT_SYMBOL_GPL(usb_serial_disconnect);
int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
@@ -1181,6 +1168,22 @@ int usb_serial_resume(struct usb_interface *intf)
}
EXPORT_SYMBOL(usb_serial_resume);
+static int usb_serial_reset_resume(struct usb_interface *intf)
+{
+ struct usb_serial *serial = usb_get_intfdata(intf);
+ int rv;
+
+ serial->suspending = 0;
+ if (serial->type->reset_resume)
+ rv = serial->type->reset_resume(serial);
+ else {
+ rv = -EOPNOTSUPP;
+ intf->needs_binding = 1;
+ }
+
+ return rv;
+}
+
static const struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
@@ -1204,6 +1207,17 @@ static const struct tty_operations serial_ops = {
struct tty_driver *usb_serial_tty_driver;
+/* Driver structure we register with the USB core */
+static struct usb_driver usb_serial_driver = {
+ .name = "usbserial",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
+ .no_dynamic_id = 1,
+ .supports_autosuspend = 1,
+};
+
static int __init usb_serial_init(void)
{
int i;
@@ -1338,7 +1352,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)
driver->description);
return -EINVAL;
}
- driver->usb_driver->supports_autosuspend = 1;
/* Add this device to our list of devices */
mutex_lock(&table_lock);
@@ -1369,18 +1382,19 @@ static void usb_serial_deregister(struct usb_serial_driver *device)
/**
* usb_serial_register_drivers - register drivers for a usb-serial module
- * @udriver: usb_driver used for matching devices/interfaces
* @serial_drivers: NULL-terminated array of pointers to drivers to be registered
+ * @name: name of the usb_driver for this set of @serial_drivers
+ * @id_table: list of all devices this @serial_drivers set binds to
*
- * Registers @udriver and all the drivers in the @serial_drivers array.
- * Automatically fills in the .no_dynamic_id field in @udriver and
- * the .usb_driver field in each serial driver.
+ * Registers all the drivers in the @serial_drivers array, and dynamically
+ * creates a struct usb_driver with the name @name and id_table of @id_table.
*/
-int usb_serial_register_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[])
+int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
+ const char *name,
+ const struct usb_device_id *id_table)
{
int rc;
- const struct usb_device_id *saved_id_table;
+ struct usb_driver *udriver;
struct usb_serial_driver * const *sd;
/*
@@ -1391,12 +1405,30 @@ int usb_serial_register_drivers(struct usb_driver *udriver,
* Performance hack: We don't want udriver to be probed until
* the serial drivers are registered, because the probe would
* simply fail for lack of a matching serial driver.
- * Therefore save off udriver's id_table until we are all set.
+ * So we leave udriver's id_table set to NULL until we are all set.
+ *
+ * Suspend/resume support is implemented in the usb-serial core,
+ * so fill in the PM-related fields in udriver.
*/
- saved_id_table = udriver->id_table;
- udriver->id_table = NULL;
+ udriver = kzalloc(sizeof(*udriver), GFP_KERNEL);
+ if (!udriver)
+ return -ENOMEM;
+ udriver->name = name;
udriver->no_dynamic_id = 1;
+ udriver->supports_autosuspend = 1;
+ udriver->suspend = usb_serial_suspend;
+ udriver->resume = usb_serial_resume;
+ udriver->probe = usb_serial_probe;
+ udriver->disconnect = usb_serial_disconnect;
+
+ /* we only set the reset_resume field if the serial_driver has one */
+ for (sd = serial_drivers; *sd; ++sd) {
+ if ((*sd)->reset_resume)
+ udriver->reset_resume = usb_serial_reset_resume;
+ break;
+ }
+
rc = usb_register(udriver);
if (rc)
return rc;
@@ -1408,8 +1440,8 @@ int usb_serial_register_drivers(struct usb_driver *udriver,
goto failed;
}
- /* Now restore udriver's id_table and look for matches */
- udriver->id_table = saved_id_table;
+ /* Now set udriver's id_table and look for matches */
+ udriver->id_table = id_table;
rc = driver_attach(&udriver->drvwrap.driver);
return 0;
@@ -1423,17 +1455,20 @@ EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
/**
* usb_serial_deregister_drivers - deregister drivers for a usb-serial module
- * @udriver: usb_driver to unregister
* @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
*
- * Deregisters @udriver and all the drivers in the @serial_drivers array.
+ * Deregisters all the drivers in the @serial_drivers array and deregisters and
+ * frees the struct usb_driver that was created by the call to
+ * usb_serial_register_drivers().
*/
-void usb_serial_deregister_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[])
+void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[])
{
+ struct usb_driver *udriver = (*serial_drivers)->usb_driver;
+
for (; *serial_drivers; ++serial_drivers)
usb_serial_deregister(*serial_drivers);
usb_deregister(udriver);
+ kfree(udriver);
}
EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index e3e8995..5760f97 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -35,13 +35,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver debug_driver = {
- .name = "debug",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
/* This HW really does not support a serial break, so one will be
* emulated when ever the break state is set to true.
*/
@@ -83,5 +76,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&debug_device, NULL
};
-module_usb_serial_driver(debug_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index c88657d..f35971d 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -43,11 +43,8 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
struct usb_wwan_port_private *portdata;
-
struct usb_wwan_intf_private *intfdata;
- dbg("%s", __func__);
-
intfdata = port->serial->private;
if (!intfdata->send_setup)
@@ -69,8 +66,6 @@ void usb_wwan_set_termios(struct tty_struct *tty,
{
struct usb_wwan_intf_private *intfdata = port->serial->private;
- dbg("%s", __func__);
-
/* Doesn't support option setting */
tty_termios_copy_hw(tty->termios, old_termios);
@@ -286,8 +281,6 @@ static void usb_wwan_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s: %p", __func__, urb);
-
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
@@ -307,20 +300,17 @@ static void usb_wwan_indat_callback(struct urb *urb)
}
/* Resubmit urb so we continue receiving */
- if (status != -ESHUTDOWN) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err) {
- if (err != -EPERM) {
- printk(KERN_ERR "%s: resubmit read urb failed. "
- "(%d)", __func__, err);
- /* busy also in error unless we are killed */
- usb_mark_last_busy(port->serial->dev);
- }
- } else {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ if (err != -EPERM) {
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __func__, err);
+ /* busy also in error unless we are killed */
usb_mark_last_busy(port->serial->dev);
}
+ } else {
+ usb_mark_last_busy(port->serial->dev);
}
-
}
}
@@ -331,8 +321,6 @@ static void usb_wwan_outdat_callback(struct urb *urb)
struct usb_wwan_intf_private *intfdata;
int i;
- dbg("%s", __func__);
-
port = urb->context;
intfdata = port->serial->private;
@@ -406,8 +394,6 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
intfdata = serial->private;
- dbg("%s", __func__);
-
/* Start reading from the IN endpoint */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
@@ -441,7 +427,6 @@ void usb_wwan_close(struct usb_serial_port *port)
struct usb_wwan_port_private *portdata;
struct usb_wwan_intf_private *intfdata = port->serial->private;
- dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
if (serial->dev) {
@@ -492,8 +477,6 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial)
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
@@ -534,8 +517,6 @@ int usb_wwan_startup(struct usb_serial *serial)
struct usb_wwan_port_private *portdata;
u8 *buffer;
- dbg("%s", __func__);
-
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -603,8 +584,6 @@ static void stop_read_write_urbs(struct usb_serial *serial)
void usb_wwan_disconnect(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
stop_read_write_urbs(serial);
}
EXPORT_SYMBOL(usb_wwan_disconnect);
@@ -615,8 +594,6 @@ void usb_wwan_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
- dbg("%s", __func__);
-
/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -649,8 +626,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
struct usb_wwan_intf_private *intfdata = serial->private;
int b;
- dbg("%s entered", __func__);
-
if (PMSG_IS_AUTO(message)) {
spin_lock_irq(&intfdata->susp_lock);
b = intfdata->in_flight;
@@ -714,7 +689,6 @@ int usb_wwan_resume(struct usb_serial *serial)
struct urb *urb;
int err = 0;
- dbg("%s entered", __func__);
/* get the interrupt URBs resubmitted unconditionally */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -725,8 +699,8 @@ int usb_wwan_resume(struct usb_serial *serial)
err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
dbg("Submitted interrupt URB for port %d (result %d)", i, err);
if (err < 0) {
- err("%s: Error %d for interrupt URB of port%d",
- __func__, err, i);
+ dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
+ __func__, err);
goto err_out;
}
}
@@ -747,8 +721,8 @@ int usb_wwan_resume(struct usb_serial *serial)
urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- err("%s: Error %d for bulk URB %d",
- __func__, err, i);
+ dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
+ __func__, err, i);
spin_unlock_irq(&intfdata->susp_lock);
goto err_out;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 71d6964..f253c91 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -53,8 +53,6 @@ static int palm_os_4_probe(struct usb_serial *serial,
/* Parameters that may be passed into the module. */
static bool debug;
-static __u16 vendor;
-static __u16 product;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
@@ -115,14 +113,12 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
static struct usb_device_id clie_id_5_table [] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
@@ -162,19 +158,11 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver visor_driver = {
- .name = "visor",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
/* All of the device info needed for the Handspring Visor,
and Palm 4.0 devices */
static struct usb_serial_driver handspring_device = {
@@ -244,8 +232,6 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->read_urb) {
/* this is needed for some brain dead Sony devices */
dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
@@ -258,7 +244,7 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
goto exit;
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __func__);
+ dev_dbg(&port->dev, "adding interrupt input for treo\n");
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
@@ -274,8 +260,6 @@ static void visor_close(struct usb_serial_port *port)
{
unsigned char *transfer_buffer;
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
@@ -310,12 +294,12 @@ static void visor_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -348,8 +332,6 @@ static int palm_os_3_probe(struct usb_serial *serial,
int i;
int num_ports = 0;
- dbg("%s", __func__);
-
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -445,8 +427,6 @@ static int palm_os_4_probe(struct usb_serial *serial,
unsigned char *transfer_buffer;
int retval;
- dbg("%s", __func__);
-
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -478,8 +458,6 @@ static int visor_probe(struct usb_serial *serial,
int (*startup)(struct usb_serial *serial,
const struct usb_device_id *id);
- dbg("%s", __func__);
-
/*
* some Samsung Android phones in modem mode have the same ID
* as SPH-I500, but they are ACM devices, so dont bind to them
@@ -521,8 +499,6 @@ static int clie_3_5_startup(struct usb_serial *serial)
int result;
u8 *data;
- dbg("%s", __func__);
-
data = kmalloc(1, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -585,8 +561,6 @@ static int treo_attach(struct usb_serial *serial)
(serial->num_interrupt_in == 0))
return 0;
- dbg("%s", __func__);
-
/*
* It appears that Treos and Kyoceras want to use the
* 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
@@ -622,8 +596,6 @@ static int clie_5_attach(struct usb_serial *serial)
unsigned int pipe;
int j;
- dbg("%s", __func__);
-
/* TH55 registers 2 ports.
Communication in from the UX50/TH55 uses bulk_in_endpointAddress
from port 0. Communication out to the UX50/TH55 uses
@@ -648,59 +620,7 @@ static int clie_5_attach(struct usb_serial *serial)
return 0;
}
-static int __init visor_init(void)
-{
- int i, retval;
- /* Only if parameters were passed to us */
- if (vendor > 0 && product > 0) {
- struct usb_device_id usb_dev_temp[] = {
- {
- USB_DEVICE(vendor, product),
- .driver_info =
- (kernel_ulong_t) &palm_os_4_probe
- }
- };
-
- /* Find the last entry in id_table */
- for (i = 0;; i++) {
- if (id_table[i].idVendor == 0) {
- id_table[i] = usb_dev_temp[0];
- break;
- }
- }
- /* Find the last entry in id_table_combined */
- for (i = 0;; i++) {
- if (id_table_combined[i].idVendor == 0) {
- id_table_combined[i] = usb_dev_temp[0];
- break;
- }
- }
- 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_drivers(&visor_driver, serial_drivers);
- if (retval == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
- return retval;
-}
-
-
-static void __exit visor_exit (void)
-{
- usb_serial_deregister_drivers(&visor_driver, serial_drivers);
-}
-
-
-module_init(visor_init);
-module_exit(visor_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -708,9 +628,3 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
index 078f338..0c0aa87 100644
--- a/drivers/usb/serial/vivopay-serial.c
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -25,13 +25,6 @@ static struct usb_device_id id_table [] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver vivopay_serial_driver = {
- .name = "vivopay-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver vivopay_serial_device = {
.driver = {
.owner = THIS_MODULE,
@@ -45,7 +38,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&vivopay_serial_device, NULL
};
-module_usb_serial_driver(vivopay_serial_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 407e23c..473635e 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -45,7 +45,6 @@ static bool debug;
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
@@ -78,12 +77,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver whiteheat_driver = {
- .name = "whiteheat",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
static int whiteheat_firmware_download(struct usb_serial *serial,
@@ -96,10 +89,6 @@ static void whiteheat_release(struct usb_serial *serial);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
-static int whiteheat_write(struct tty_struct *tty,
- struct usb_serial_port *port,
- const unsigned char *buf, int count);
-static int whiteheat_write_room(struct tty_struct *tty);
static int whiteheat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void whiteheat_set_termios(struct tty_struct *tty,
@@ -108,11 +97,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty);
static int whiteheat_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static void whiteheat_break_ctl(struct tty_struct *tty, int break_state);
-static int whiteheat_chars_in_buffer(struct tty_struct *tty);
-static void whiteheat_throttle(struct tty_struct *tty);
-static void whiteheat_unthrottle(struct tty_struct *tty);
-static void whiteheat_read_callback(struct urb *urb);
-static void whiteheat_write_callback(struct urb *urb);
static struct usb_serial_driver whiteheat_fake_device = {
.driver = {
@@ -138,18 +122,13 @@ static struct usb_serial_driver whiteheat_device = {
.release = whiteheat_release,
.open = whiteheat_open,
.close = whiteheat_close,
- .write = whiteheat_write,
- .write_room = whiteheat_write_room,
.ioctl = whiteheat_ioctl,
.set_termios = whiteheat_set_termios,
.break_ctl = whiteheat_break_ctl,
.tiocmget = whiteheat_tiocmget,
.tiocmset = whiteheat_tiocmset,
- .chars_in_buffer = whiteheat_chars_in_buffer,
- .throttle = whiteheat_throttle,
- .unthrottle = whiteheat_unthrottle,
- .read_bulk_callback = whiteheat_read_callback,
- .write_bulk_callback = whiteheat_write_callback,
+ .throttle = usb_serial_generic_throttle,
+ .unthrottle = usb_serial_generic_unthrottle,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -166,29 +145,8 @@ struct whiteheat_command_private {
__u8 result_buffer[64];
};
-
-#define THROTTLED 0x01
-#define ACTUALLY_THROTTLED 0x02
-
-static int urb_pool_size = 8;
-
-struct whiteheat_urb_wrap {
- struct list_head list;
- struct urb *urb;
-};
-
struct whiteheat_private {
- spinlock_t lock;
- __u8 flags;
__u8 mcr; /* FIXME: no locking on mcr */
- struct list_head rx_urbs_free;
- struct list_head rx_urbs_submitted;
- struct list_head rx_urb_q;
- struct work_struct rx_work;
- struct usb_serial_port *port;
- struct list_head tx_urbs_free;
- struct list_head tx_urbs_submitted;
- struct mutex deathwarrant;
};
@@ -198,12 +156,6 @@ static void stop_command_port(struct usb_serial *serial);
static void command_port_write_callback(struct urb *urb);
static void command_port_read_callback(struct urb *urb);
-static int start_port_read(struct usb_serial_port *port);
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
- struct list_head *head);
-static struct list_head *list_first(struct list_head *head);
-static void rx_data_softint(struct work_struct *work);
-
static int firm_send_command(struct usb_serial_port *port, __u8 command,
__u8 *data, __u8 datasize);
static int firm_open(struct usb_serial_port *port);
@@ -247,8 +199,6 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
const struct ihex_binrec *record;
- dbg("%s", __func__);
-
if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
&serial->dev->dev)) {
dev_err(&serial->dev->dev,
@@ -349,11 +299,6 @@ static int whiteheat_attach(struct usb_serial *serial)
__u8 *command;
__u8 *result;
int i;
- int j;
- struct urb *urb;
- int buf_size;
- struct whiteheat_urb_wrap *wrap;
- struct list_head *tmp;
command_port = serial->port[COMMAND_PORT];
@@ -408,8 +353,8 @@ static int whiteheat_attach(struct usb_serial *serial)
hw_info = (struct whiteheat_hw_info *)&result[1];
- dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n",
- serial->type->description, DRIVER_VERSION,
+ dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n",
+ serial->type->description,
hw_info->sw_major_rev, hw_info->sw_minor_rev);
for (i = 0; i < serial->num_ports; i++) {
@@ -423,72 +368,7 @@ static int whiteheat_attach(struct usb_serial *serial)
goto no_private;
}
- spin_lock_init(&info->lock);
- mutex_init(&info->deathwarrant);
- info->flags = 0;
info->mcr = 0;
- INIT_WORK(&info->rx_work, rx_data_softint);
- info->port = port;
-
- INIT_LIST_HEAD(&info->rx_urbs_free);
- INIT_LIST_HEAD(&info->rx_urbs_submitted);
- INIT_LIST_HEAD(&info->rx_urb_q);
- INIT_LIST_HEAD(&info->tx_urbs_free);
- INIT_LIST_HEAD(&info->tx_urbs_submitted);
-
- for (j = 0; j < urb_pool_size; j++) {
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- 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) {
- dev_err(&port->dev,
- "Couldn't allocate urb buffer\n");
- goto no_rx_buf;
- }
- wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
- if (!wrap) {
- dev_err(&port->dev,
- "Couldn't allocate urb wrapper\n");
- goto no_rx_wrap;
- }
- usb_fill_bulk_urb(urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->bulk_in_endpointAddress),
- urb->transfer_buffer, buf_size,
- whiteheat_read_callback, port);
- wrap->urb = urb;
- list_add(&wrap->list, &info->rx_urbs_free);
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- 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) {
- dev_err(&port->dev,
- "Couldn't allocate urb buffer\n");
- goto no_tx_buf;
- }
- wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
- if (!wrap) {
- dev_err(&port->dev,
- "Couldn't allocate urb wrapper\n");
- goto no_tx_wrap;
- }
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
- urb->transfer_buffer, buf_size,
- whiteheat_write_callback, port);
- wrap->urb = urb;
- list_add(&wrap->list, &info->tx_urbs_free);
- }
usb_set_serial_port_data(port, info);
}
@@ -531,29 +411,6 @@ no_command_private:
for (i = serial->num_ports - 1; i >= 0; i--) {
port = serial->port[i];
info = usb_get_serial_port_data(port);
- for (j = urb_pool_size - 1; j >= 0; j--) {
- tmp = list_first(&info->tx_urbs_free);
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
-no_tx_wrap:
- kfree(urb->transfer_buffer);
-no_tx_buf:
- usb_free_urb(urb);
-no_tx_urb:
- tmp = list_first(&info->rx_urbs_free);
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
-no_rx_wrap:
- kfree(urb->transfer_buffer);
-no_rx_buf:
- usb_free_urb(urb);
-no_rx_urb:
- ;
- }
kfree(info);
no_private:
;
@@ -569,56 +426,27 @@ no_command_buffer:
static void whiteheat_release(struct usb_serial *serial)
{
struct usb_serial_port *command_port;
- struct usb_serial_port *port;
struct whiteheat_private *info;
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- struct list_head *tmp;
- struct list_head *tmp2;
int i;
- dbg("%s", __func__);
-
/* free up our private data for our command port */
command_port = serial->port[COMMAND_PORT];
kfree(usb_get_serial_port_data(command_port));
for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- info = usb_get_serial_port_data(port);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- }
- list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- }
+ info = usb_get_serial_port_data(serial->port[i]);
kfree(info);
}
}
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- int retval = 0;
-
- dbg("%s - port %d", __func__, port->number);
+ int retval;
retval = start_command_port(port->serial);
if (retval)
goto exit;
- if (tty)
- tty->low_latency = 1;
-
/* send an open port command */
retval = firm_open(port);
if (retval) {
@@ -640,144 +468,25 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
- /* Start reading from the device */
- retval = start_port_read(port);
+ retval = usb_serial_generic_open(tty, port);
if (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;
}
-
exit:
- dbg("%s - exit, retval = %d", __func__, retval);
return retval;
}
static void whiteheat_close(struct usb_serial_port *port)
{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- struct list_head *tmp;
- struct list_head *tmp2;
-
- dbg("%s - port %d", __func__, port->number);
-
firm_report_tx_done(port);
firm_close(port);
- /* shutdown our bulk reads and writes */
- mutex_lock(&info->deathwarrant);
- spin_lock_irq(&info->lock);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irq(&info->lock);
- usb_kill_urb(urb);
- spin_lock_irq(&info->lock);
- list_add(tmp, &info->rx_urbs_free);
- }
- list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
- list_move(tmp, &info->rx_urbs_free);
- list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irq(&info->lock);
- usb_kill_urb(urb);
- spin_lock_irq(&info->lock);
- list_add(tmp, &info->tx_urbs_free);
- }
- spin_unlock_irq(&info->lock);
- mutex_unlock(&info->deathwarrant);
- stop_command_port(port->serial);
-}
-
-
-static int whiteheat_write(struct tty_struct *tty,
- struct usb_serial_port *port, const unsigned char *buf, int count)
-{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- int result;
- int bytes;
- int sent = 0;
- unsigned long flags;
- struct list_head *tmp;
-
- dbg("%s - port %d", __func__, port->number);
-
- if (count == 0) {
- dbg("%s - write request of 0 bytes", __func__);
- return (0);
- }
-
- while (count) {
- spin_lock_irqsave(&info->lock, flags);
- if (list_empty(&info->tx_urbs_free)) {
- spin_unlock_irqrestore(&info->lock, flags);
- break;
- }
- tmp = list_first(&info->tx_urbs_free);
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
-
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- bytes = (count > port->bulk_out_size) ?
- port->bulk_out_size : count;
- memcpy(urb->transfer_buffer, buf + sent, bytes);
-
- usb_serial_debug_data(debug, &port->dev,
- __func__, bytes, urb->transfer_buffer);
-
- urb->transfer_buffer_length = bytes;
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- dev_err_console(port,
- "%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);
- spin_unlock_irqrestore(&info->lock, flags);
- break;
- } else {
- sent += bytes;
- count -= bytes;
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->tx_urbs_submitted);
- spin_unlock_irqrestore(&info->lock, flags);
- }
- }
-
- return sent;
-}
-
-static int whiteheat_write_room(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct list_head *tmp;
- int room = 0;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
+ usb_serial_generic_close(port);
- spin_lock_irqsave(&info->lock, flags);
- list_for_each(tmp, &info->tx_urbs_free)
- room++;
- spin_unlock_irqrestore(&info->lock, flags);
- room *= port->bulk_out_size;
-
- dbg("%s - returns %d", __func__, room);
- return (room);
+ stop_command_port(port->serial);
}
static int whiteheat_tiocmget(struct tty_struct *tty)
@@ -786,8 +495,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty)
struct whiteheat_private *info = usb_get_serial_port_data(port);
unsigned int modem_signals = 0;
- dbg("%s - port %d", __func__, port->number);
-
firm_get_dtr_rts(port);
if (info->mcr & UART_MCR_DTR)
modem_signals |= TIOCM_DTR;
@@ -803,8 +510,6 @@ static int whiteheat_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR)
@@ -837,7 +542,7 @@ static int whiteheat_ioctl(struct tty_struct *tty,
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
- serstruct.xmit_fifo_size = port->bulk_out_size;
+ serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
serstruct.close_delay = CLOSING_DELAY;
@@ -867,60 +572,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state)
}
-static int whiteheat_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct list_head *tmp;
- struct whiteheat_urb_wrap *wrap;
- int chars = 0;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irqsave(&info->lock, flags);
- list_for_each(tmp, &info->tx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- chars += wrap->urb->transfer_buffer_length;
- }
- spin_unlock_irqrestore(&info->lock, flags);
-
- dbg("%s - returns %d", __func__, chars);
- return chars;
-}
-
-
-static void whiteheat_throttle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irq(&info->lock);
- info->flags |= THROTTLED;
- spin_unlock_irq(&info->lock);
-}
-
-
-static void whiteheat_unthrottle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- int actually_throttled;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irq(&info->lock);
- actually_throttled = info->flags & ACTUALLY_THROTTLED;
- info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irq(&info->lock);
-
- if (actually_throttled)
- rx_data_softint(&info->rx_work);
-}
-
-
/*****************************************************************************
* Connect Tech's White Heat callback routines
*****************************************************************************/
@@ -928,8 +579,6 @@ static void command_port_write_callback(struct urb *urb)
{
int status = urb->status;
- dbg("%s", __func__);
-
if (status) {
dbg("nonzero urb status: %d", status);
return;
@@ -945,8 +594,6 @@ static void command_port_read_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int result;
- dbg("%s", __func__);
-
command_info = usb_get_serial_port_data(command_port);
if (!command_info) {
dbg("%s - command_info is NULL, exiting.", __func__);
@@ -989,80 +636,6 @@ static void command_port_read_callback(struct urb *urb)
}
-static void whiteheat_read_callback(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct whiteheat_urb_wrap *wrap;
- unsigned char *data = urb->transfer_buffer;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock(&info->lock);
- wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
- if (!wrap) {
- spin_unlock(&info->lock);
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
- return;
- }
- list_del(&wrap->list);
- spin_unlock(&info->lock);
-
- if (status) {
- dbg("%s - nonzero read bulk status received: %d",
- __func__, status);
- spin_lock(&info->lock);
- list_add(&wrap->list, &info->rx_urbs_free);
- spin_unlock(&info->lock);
- return;
- }
-
- usb_serial_debug_data(debug, &port->dev,
- __func__, urb->actual_length, data);
-
- spin_lock(&info->lock);
- list_add_tail(&wrap->list, &info->rx_urb_q);
- if (info->flags & THROTTLED) {
- info->flags |= ACTUALLY_THROTTLED;
- spin_unlock(&info->lock);
- return;
- }
- spin_unlock(&info->lock);
-
- schedule_work(&info->rx_work);
-}
-
-
-static void whiteheat_write_callback(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock(&info->lock);
- wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
- if (!wrap) {
- spin_unlock(&info->lock);
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
- return;
- }
- list_move(&wrap->list, &info->tx_urbs_free);
- spin_unlock(&info->lock);
-
- if (status) {
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
- return;
- }
-
- usb_serial_port_softint(port);
-}
-
-
/*****************************************************************************
* Connect Tech's White Heat firmware interface
*****************************************************************************/
@@ -1337,124 +910,7 @@ static void stop_command_port(struct usb_serial *serial)
mutex_unlock(&command_info->mutex);
}
-
-static int start_port_read(struct usb_serial_port *port)
-{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- int retval = 0;
- unsigned long flags;
- struct list_head *tmp;
- struct list_head *tmp2;
-
- spin_lock_irqsave(&info->lock, flags);
-
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- spin_unlock_irqrestore(&info->lock, flags);
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_free);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
- usb_kill_urb(urb);
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_free);
- }
- break;
- }
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_submitted);
- }
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- return retval;
-}
-
-
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
- struct list_head *head)
-{
- struct whiteheat_urb_wrap *wrap;
- struct list_head *tmp;
-
- list_for_each(tmp, head) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- if (wrap->urb == urb)
- return wrap;
- }
-
- return NULL;
-}
-
-
-static struct list_head *list_first(struct list_head *head)
-{
- return head->next;
-}
-
-
-static void rx_data_softint(struct work_struct *work)
-{
- struct whiteheat_private *info =
- container_of(work, struct whiteheat_private, rx_work);
- struct usb_serial_port *port = info->port;
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- unsigned long flags;
- struct list_head *tmp;
- struct list_head *tmp2;
- int result;
- int sent = 0;
-
- spin_lock_irqsave(&info->lock, flags);
- if (info->flags & THROTTLED) {
- spin_unlock_irqrestore(&info->lock, flags);
- goto out;
- }
-
- list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
-
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
-
- if (tty && urb->actual_length)
- sent += tty_insert_flip_string(tty,
- urb->transfer_buffer, urb->actual_length);
-
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- 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);
- continue;
- }
-
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_submitted);
- }
- spin_unlock_irqrestore(&info->lock, flags);
-
- if (sent)
- tty_flip_buffer_push(tty);
-out:
- tty_kref_put(tty);
-}
-
-module_usb_serial_driver(whiteheat_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -1463,8 +919,5 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE("whiteheat.fw");
MODULE_FIRMWARE("whiteheat_loader.fw");
-module_param(urb_pool_size, int, 0);
-MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering");
-
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
index 9d0bb37..c043aa8 100644
--- a/drivers/usb/serial/zio.c
+++ b/drivers/usb/serial/zio.c
@@ -22,13 +22,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver zio_driver = {
- .name = "zio",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver zio_device = {
.driver = {
.owner = THIS_MODULE,
@@ -42,5 +35,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&zio_device, NULL
};
-module_usb_serial_driver(zio_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index e7e6781..b28f2ad 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1933,11 +1933,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
kfree(buf);
nofw:
- if (sd_fw != NULL) {
- release_firmware(sd_fw);
- sd_fw = NULL;
- }
-
+ release_firmware(sd_fw);
return result;
}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 856ad92..1719886 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -110,7 +110,7 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+/* Deduced by Jonathan Woithe <jwoithe@just42.net>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
*/
@@ -1885,6 +1885,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Jesse Feddema <jdfeddema@gmail.com> */
+UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000,
+ "Yarvik",
+ "PMP400",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
/* Reported by Hans de Goede <hdegoede@redhat.com>
* These Appotech controllers are found in Picture Frames, they provide a
* (buggy) emulation of a cdrom drive which contains the windows software
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 2653e73..e23c30a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -121,7 +121,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
}
static struct us_unusual_dev us_unusual_dev_list[] = {
-# include "unusual_devs.h"
+# include "unusual_devs.h"
{ } /* Terminating entry */
};
@@ -261,17 +261,17 @@ EXPORT_SYMBOL_GPL(usb_stor_post_reset);
void fill_inquiry_response(struct us_data *us, unsigned char *data,
unsigned int data_len)
{
- if (data_len<36) // You lose.
+ if (data_len < 36) /* You lose. */
return;
memset(data+8, ' ', 28);
- if(data[0]&0x20) { /* USB device currently not connected. Return
+ if (data[0]&0x20) { /* USB device currently not connected. Return
peripheral qualifier 001b ("...however, the
physical device is not currently connected
to this logical unit") and leave vendor and
product identification empty. ("If the target
does store some of the INQUIRY data on the
- device, it may return zeros or ASCII spaces
+ device, it may return zeros or ASCII spaces
(20h) in those fields until the data is
available from the device."). */
} else {
@@ -298,7 +298,7 @@ static int usb_stor_control_thread(void * __us)
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- for(;;) {
+ for (;;) {
US_DEBUGP("*** thread sleeping.\n");
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
@@ -327,7 +327,7 @@ static int usb_stor_control_thread(void * __us)
scsi_unlock(host);
- /* reject the command if the direction indicator
+ /* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
@@ -338,7 +338,7 @@ static int usb_stor_control_thread(void * __us)
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
- else if (us->srb->device->id &&
+ else if (us->srb->device->id &&
!(us->fflags & US_FL_SCM_MULT_TARG)) {
US_DEBUGP("Bad target number (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
@@ -351,7 +351,7 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = DID_BAD_TARGET << 16;
}
- /* Handle those devices which need us to fake
+ /* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->fflags & US_FL_FIX_INQUIRY)) {
@@ -376,7 +376,7 @@ static int usb_stor_control_thread(void * __us)
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
- US_DEBUGP("scsi cmd done, result=0x%x\n",
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
} else {
@@ -414,7 +414,7 @@ SkipForAbort:
}
__set_current_state(TASK_RUNNING);
return 0;
-}
+}
/***********************************************************************
* Device probing and disconnecting
@@ -732,7 +732,7 @@ static int get_pipes(struct us_data *us)
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_out));
- us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
+ us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_in));
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b4a7167..0616f23 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -93,8 +93,8 @@ static int skel_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d",
- __func__, subminor);
+ pr_err("%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -179,8 +179,9 @@ static void skel_read_bulk_callback(struct urb *urb)
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
- err("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ dev_err(&dev->interface->dev,
+ "%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
dev->errors = urb->status;
} else {
@@ -213,7 +214,8 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)
/* do it */
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
if (rv < 0) {
- err("%s - failed submitting read urb, error %d",
+ dev_err(&dev->interface->dev,
+ "%s - failed submitting read urb, error %d\n",
__func__, rv);
dev->bulk_in_filled = 0;
rv = (rv == -ENOMEM) ? rv : -EIO;
@@ -364,8 +366,9 @@ static void skel_write_bulk_callback(struct urb *urb)
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
- err("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ dev_err(&dev->interface->dev,
+ "%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
spin_lock(&dev->err_lock);
dev->errors = urb->status;
@@ -459,8 +462,9 @@ static ssize_t skel_write(struct file *file, const char *user_buffer,
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
- err("%s - failed submitting write urb, error %d", __func__,
- retval);
+ dev_err(&dev->interface->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, retval);
goto error_unanchor;
}
@@ -519,7 +523,7 @@ static int skel_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -546,12 +550,14 @@ static int skel_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Could not allocate bulk_in_buffer");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_buffer\n");
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->bulk_in_urb) {
- err("Could not allocate bulk_in_urb");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_urb\n");
goto error;
}
}
@@ -563,7 +569,8 @@ static int skel_probe(struct usb_interface *interface,
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
- err("Could not find both bulk-in and bulk-out endpoints");
+ dev_err(&interface->dev,
+ "Could not find both bulk-in and bulk-out endpoints\n");
goto error;
}
@@ -574,7 +581,8 @@ static int skel_probe(struct usb_interface *interface,
retval = usb_register_dev(interface, &skel_class);
if (retval) {
/* something prevented us from registering this driver */
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index ffbce45..fe3b6ec 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -536,7 +536,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
for (page = (unsigned long)fbdev->fb_mem;
page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
page += PAGE_SIZE) {
-#if CONFIG_DMA_NONCOHERENT
+#ifdef CONFIG_DMA_NONCOHERENT
SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
#else
SetPageReserved(virt_to_page(page));
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 99b354b..f994c8b 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -33,7 +33,6 @@
#include <asm/mach-types.h>
#include <linux/uaccess.h>
-#include <asm/hardware/clps7111.h>
#include <mach/syspld.h>
struct fb_info *cfb;
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 4a89f88..6c6bc57 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/mxsfb.h>
#define REG_SET 4
@@ -756,6 +757,7 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
struct mxsfb_info *host;
struct fb_info *fb_info;
struct fb_modelist *modelist;
+ struct pinctrl *pinctrl;
int i, ret;
if (!pdata) {
@@ -793,6 +795,12 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto error_getpin;
+ }
+
host->clk = clk_get(&host->pdev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
@@ -848,6 +856,7 @@ error_init_fb:
error_pseudo_pallette:
clk_put(host->clk);
error_getclock:
+error_getpin:
iounmap(host->base);
error_ioremap:
framebuffer_release(fb_info);
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 408a992..c3853c9 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -10,12 +10,12 @@ config PANEL_GENERIC_DPI
Supports LCD Panel used in TI SDP3430 and EVM boards,
OMAP3517 EVM boards and CM-T35.
-config PANEL_DVI
- tristate "DVI output"
+config PANEL_TFP410
+ tristate "TFP410 DPI-to-DVI chip"
depends on OMAP2_DSS_DPI && I2C
help
- Driver for external monitors, connected via DVI. The driver uses i2c
- to read EDID information from the monitor.
+ Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID
+ information from the monitor.
config PANEL_LGPHILIPS_LB035Q02
tristate "LG.Philips LB035Q02 LCD Panel"
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index fbfafc6..58a5176 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
-obj-$(CONFIG_PANEL_DVI) += panel-dvi.o
+obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o
obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 0f21fa5..b2dd88b 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -993,6 +993,15 @@ static int taal_probe(struct omap_dss_device *dssdev)
dev_set_drvdata(&dssdev->dev, td);
+ if (gpio_is_valid(panel_data->reset_gpio)) {
+ r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW,
+ "taal rst");
+ if (r) {
+ dev_err(&dssdev->dev, "failed to request reset gpio\n");
+ goto err_rst_gpio;
+ }
+ }
+
taal_hw_reset(dssdev);
if (panel_data->use_dsi_backlight) {
@@ -1073,6 +1082,9 @@ err_gpio:
if (bldev != NULL)
backlight_device_unregister(bldev);
err_bl:
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_free(panel_data->reset_gpio);
+err_rst_gpio:
destroy_workqueue(td->workqueue);
err_wq:
free_regulators(panel_config->regulators, panel_config->num_regulators);
@@ -1116,15 +1128,25 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
free_regulators(td->panel_config->regulators,
td->panel_config->num_regulators);
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_free(panel_data->reset_gpio);
+
kfree(td);
}
static int taal_power_on(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 id1, id2, id3;
int r;
+ r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to configure DSI pins\n");
+ goto err0;
+ };
+
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-tfp410.c
index 03eb14a..52637fa 100644
--- a/drivers/video/omap2/displays/panel-dvi.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -1,5 +1,5 @@
/*
- * DVI output support
+ * TFP410 DPI-to-DVI chip
*
* Copyright (C) 2011 Texas Instruments Inc
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
@@ -21,11 +21,12 @@
#include <linux/slab.h>
#include <video/omapdss.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <drm/drm_edid.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
-static const struct omap_video_timings panel_dvi_default_timings = {
+static const struct omap_video_timings tfp410_default_timings = {
.x_res = 640,
.y_res = 480,
@@ -44,17 +45,19 @@ struct panel_drv_data {
struct omap_dss_device *dssdev;
struct mutex lock;
+
+ int pd_gpio;
};
-static inline struct panel_dvi_platform_data
+static inline struct tfp410_platform_data
*get_pdata(const struct omap_dss_device *dssdev)
{
return dssdev->data;
}
-static int panel_dvi_power_on(struct omap_dss_device *dssdev)
+static int tfp410_power_on(struct omap_dss_device *dssdev)
{
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
@@ -64,57 +67,72 @@ static int panel_dvi_power_on(struct omap_dss_device *dssdev)
if (r)
goto err0;
- if (pdata->platform_enable) {
- r = pdata->platform_enable(dssdev);
- if (r)
- goto err1;
- }
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value(ddata->pd_gpio, 1);
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
-static void panel_dvi_power_off(struct omap_dss_device *dssdev)
+static void tfp410_power_off(struct omap_dss_device *dssdev)
{
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (pdata->platform_disable)
- pdata->platform_disable(dssdev);
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value(ddata->pd_gpio, 0);
omapdss_dpi_display_disable(dssdev);
}
-static int panel_dvi_probe(struct omap_dss_device *dssdev)
+static int tfp410_probe(struct omap_dss_device *dssdev)
{
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct panel_drv_data *ddata;
+ int r;
ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
- dssdev->panel.timings = panel_dvi_default_timings;
+ dssdev->panel.timings = tfp410_default_timings;
dssdev->panel.config = OMAP_DSS_LCD_TFT;
ddata->dssdev = dssdev;
mutex_init(&ddata->lock);
+ if (pdata)
+ ddata->pd_gpio = pdata->power_down_gpio;
+ else
+ ddata->pd_gpio = -1;
+
+ if (gpio_is_valid(ddata->pd_gpio)) {
+ r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
+ "tfp410 pd");
+ if (r) {
+ dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
+ ddata->pd_gpio);
+ ddata->pd_gpio = -1;
+ }
+ }
+
dev_set_drvdata(&dssdev->dev, ddata);
return 0;
}
-static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
+static void __exit tfp410_remove(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_free(ddata->pd_gpio);
+
dev_set_drvdata(&dssdev->dev, NULL);
mutex_unlock(&ddata->lock);
@@ -122,14 +140,14 @@ static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
kfree(ddata);
}
-static int panel_dvi_enable(struct omap_dss_device *dssdev)
+static int tfp410_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ddata->lock);
- r = panel_dvi_power_on(dssdev);
+ r = tfp410_power_on(dssdev);
if (r == 0)
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@@ -138,26 +156,26 @@ static int panel_dvi_enable(struct omap_dss_device *dssdev)
return r;
}
-static void panel_dvi_disable(struct omap_dss_device *dssdev)
+static void tfp410_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
- panel_dvi_power_off(dssdev);
+ tfp410_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&ddata->lock);
}
-static int panel_dvi_suspend(struct omap_dss_device *dssdev)
+static int tfp410_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
- panel_dvi_power_off(dssdev);
+ tfp410_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -166,14 +184,14 @@ static int panel_dvi_suspend(struct omap_dss_device *dssdev)
return 0;
}
-static int panel_dvi_resume(struct omap_dss_device *dssdev)
+static int tfp410_resume(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ddata->lock);
- r = panel_dvi_power_on(dssdev);
+ r = tfp410_power_on(dssdev);
if (r == 0)
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@@ -182,7 +200,7 @@ static int panel_dvi_resume(struct omap_dss_device *dssdev)
return r;
}
-static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
+static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -192,7 +210,7 @@ static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
mutex_unlock(&ddata->lock);
}
-static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
+static void tfp410_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -202,7 +220,7 @@ static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
mutex_unlock(&ddata->lock);
}
-static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
+static int tfp410_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -216,7 +234,7 @@ static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
}
-static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
+static int tfp410_ddc_read(struct i2c_adapter *adapter,
unsigned char *buf, u16 count, u8 offset)
{
int r, retries;
@@ -247,11 +265,11 @@ static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
return r < 0 ? r : -EIO;
}
-static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
+static int tfp410_read_edid(struct omap_dss_device *dssdev,
u8 *edid, int len)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct i2c_adapter *adapter;
int r, l, bytes_read;
@@ -271,7 +289,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
}
l = min(EDID_LENGTH, len);
- r = panel_dvi_ddc_read(adapter, edid, l, 0);
+ r = tfp410_ddc_read(adapter, edid, l, 0);
if (r)
goto err;
@@ -281,7 +299,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
if (len > EDID_LENGTH && edid[0x7e] > 0) {
l = min(EDID_LENGTH, len - EDID_LENGTH);
- r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
+ r = tfp410_ddc_read(adapter, edid + EDID_LENGTH,
l, EDID_LENGTH);
if (r)
goto err;
@@ -298,10 +316,10 @@ err:
return r;
}
-static bool panel_dvi_detect(struct omap_dss_device *dssdev)
+static bool tfp410_detect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct i2c_adapter *adapter;
unsigned char out;
int r;
@@ -315,7 +333,7 @@ static bool panel_dvi_detect(struct omap_dss_device *dssdev)
if (!adapter)
goto out;
- r = panel_dvi_ddc_read(adapter, &out, 1, 0);
+ r = tfp410_ddc_read(adapter, &out, 1, 0);
mutex_unlock(&ddata->lock);
@@ -326,38 +344,38 @@ out:
return true;
}
-static struct omap_dss_driver panel_dvi_driver = {
- .probe = panel_dvi_probe,
- .remove = __exit_p(panel_dvi_remove),
+static struct omap_dss_driver tfp410_driver = {
+ .probe = tfp410_probe,
+ .remove = __exit_p(tfp410_remove),
- .enable = panel_dvi_enable,
- .disable = panel_dvi_disable,
- .suspend = panel_dvi_suspend,
- .resume = panel_dvi_resume,
+ .enable = tfp410_enable,
+ .disable = tfp410_disable,
+ .suspend = tfp410_suspend,
+ .resume = tfp410_resume,
- .set_timings = panel_dvi_set_timings,
- .get_timings = panel_dvi_get_timings,
- .check_timings = panel_dvi_check_timings,
+ .set_timings = tfp410_set_timings,
+ .get_timings = tfp410_get_timings,
+ .check_timings = tfp410_check_timings,
- .read_edid = panel_dvi_read_edid,
- .detect = panel_dvi_detect,
+ .read_edid = tfp410_read_edid,
+ .detect = tfp410_detect,
.driver = {
- .name = "dvi",
+ .name = "tfp410",
.owner = THIS_MODULE,
},
};
-static int __init panel_dvi_init(void)
+static int __init tfp410_init(void)
{
- return omap_dss_register_driver(&panel_dvi_driver);
+ return omap_dss_register_driver(&tfp410_driver);
}
-static void __exit panel_dvi_exit(void)
+static void __exit tfp410_exit(void)
{
- omap_dss_unregister_driver(&panel_dvi_driver);
+ omap_dss_unregister_driver(&tfp410_driver);
}
-module_init(panel_dvi_init);
-module_exit(panel_dvi_exit);
+module_init(tfp410_init);
+module_exit(tfp410_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 662d14f..210a3c4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2076,65 +2076,6 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
}
}
-static int dsi_parse_lane_config(struct omap_dss_device *dssdev)
-{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- u8 lanes[DSI_MAX_NR_LANES];
- u8 polarities[DSI_MAX_NR_LANES];
- int num_lanes, i;
-
- static const enum dsi_lane_function functions[] = {
- DSI_LANE_CLK,
- DSI_LANE_DATA1,
- DSI_LANE_DATA2,
- DSI_LANE_DATA3,
- DSI_LANE_DATA4,
- };
-
- lanes[0] = dssdev->phy.dsi.clk_lane;
- lanes[1] = dssdev->phy.dsi.data1_lane;
- lanes[2] = dssdev->phy.dsi.data2_lane;
- lanes[3] = dssdev->phy.dsi.data3_lane;
- lanes[4] = dssdev->phy.dsi.data4_lane;
- polarities[0] = dssdev->phy.dsi.clk_pol;
- polarities[1] = dssdev->phy.dsi.data1_pol;
- polarities[2] = dssdev->phy.dsi.data2_pol;
- polarities[3] = dssdev->phy.dsi.data3_pol;
- polarities[4] = dssdev->phy.dsi.data4_pol;
-
- num_lanes = 0;
-
- for (i = 0; i < dsi->num_lanes_supported; ++i)
- dsi->lanes[i].function = DSI_LANE_UNUSED;
-
- for (i = 0; i < dsi->num_lanes_supported; ++i) {
- int num;
-
- if (lanes[i] == DSI_LANE_UNUSED)
- break;
-
- num = lanes[i] - 1;
-
- if (num >= dsi->num_lanes_supported)
- return -EINVAL;
-
- if (dsi->lanes[num].function != DSI_LANE_UNUSED)
- return -EINVAL;
-
- dsi->lanes[num].function = functions[i];
- dsi->lanes[num].polarity = polarities[i];
- num_lanes++;
- }
-
- if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported)
- return -EINVAL;
-
- dsi->num_lanes_used = num_lanes;
-
- return 0;
-}
-
static int dsi_set_lane_config(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -3975,6 +3916,74 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
}
}
+int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
+ const struct omap_dsi_pin_config *pin_cfg)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int num_pins;
+ const int *pins;
+ struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+ int num_lanes;
+ int i;
+
+ static const enum dsi_lane_function functions[] = {
+ DSI_LANE_CLK,
+ DSI_LANE_DATA1,
+ DSI_LANE_DATA2,
+ DSI_LANE_DATA3,
+ DSI_LANE_DATA4,
+ };
+
+ num_pins = pin_cfg->num_pins;
+ pins = pin_cfg->pins;
+
+ if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
+ || num_pins % 2 != 0)
+ return -EINVAL;
+
+ for (i = 0; i < DSI_MAX_NR_LANES; ++i)
+ lanes[i].function = DSI_LANE_UNUSED;
+
+ num_lanes = 0;
+
+ for (i = 0; i < num_pins; i += 2) {
+ u8 lane, pol;
+ int dx, dy;
+
+ dx = pins[i];
+ dy = pins[i + 1];
+
+ if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
+ return -EINVAL;
+
+ if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
+ return -EINVAL;
+
+ if (dx & 1) {
+ if (dy != dx - 1)
+ return -EINVAL;
+ pol = 1;
+ } else {
+ if (dy != dx + 1)
+ return -EINVAL;
+ pol = 0;
+ }
+
+ lane = dx / 2;
+
+ lanes[lane].function = functions[i / 2];
+ lanes[lane].polarity = pol;
+ num_lanes++;
+ }
+
+ memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
+ dsi->num_lanes_used = num_lanes;
+
+ return 0;
+}
+EXPORT_SYMBOL(omapdss_dsi_configure_pins);
+
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4339,12 +4348,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
int dsi_module = dsi_get_dsidev_id(dsidev);
int r;
- r = dsi_parse_lane_config(dssdev);
- if (r) {
- DSSERR("illegal lane config");
- goto err0;
- }
-
r = dsi_pll_init(dsidev, true, true);
if (r)
goto err0;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 7a0b301..e672698 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -758,7 +758,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
lcdc_write_chan(ch, LDDFR, tmp);
- lcdc_write_chan(ch, LDMLSR, ch->pitch);
+ lcdc_write_chan(ch, LDMLSR, ch->line_size);
lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
if (ch->format->yuv)
lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
@@ -847,6 +847,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
ch->base_addr_y = ch->dma_handle;
ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
+ ch->line_size = ch->pitch;
/* Enable MERAM if possible. */
if (mdev == NULL || mdev->ops == NULL ||
@@ -882,7 +883,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg,
ch->pitch, ch->yres, pixelformat,
- &ch->pitch);
+ &ch->line_size);
if (!IS_ERR(meram)) {
mdev->ops->meram_update(mdev, meram,
ch->base_addr_y, ch->base_addr_c,
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index da1c26e..5c3bddd 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -84,6 +84,7 @@ struct sh_mobile_lcdc_chan {
unsigned long base_addr_y;
unsigned long base_addr_c;
+ unsigned int line_size;
int (*notify)(struct sh_mobile_lcdc_chan *ch,
enum sh_mobile_lcdc_entity_event event,
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index a159b63..7af1e81 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1594,7 +1594,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- err("dlfb_usb_probe: failed alloc of dev struct\n");
+ dev_err(&interface->dev, "dlfb_usb_probe: failed alloc of dev struct\n");
goto error;
}
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 1a61939..f38b17a 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -46,4 +46,15 @@ config VIRTIO_BALLOON
If unsure, say N.
+config VIRTIO_MMIO_CMDLINE_DEVICES
+ bool "Memory mapped virtio devices parameter parsing"
+ depends on VIRTIO_MMIO
+ ---help---
+ Allow virtio-mmio devices instantiation via the kernel command line
+ or module parameters. Be aware that using incorrect parameters (base
+ address in particular) can crash your system - you have been warned.
+ See Documentation/kernel-parameters.txt for details.
+
+ If unsure, say 'N'.
+
endmenu
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 984c501..f355807 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -2,9 +2,10 @@
#include <linux/spinlock.h>
#include <linux/virtio_config.h>
#include <linux/module.h>
+#include <linux/idr.h>
/* Unique numbering for virtio devices. */
-static unsigned int dev_index;
+static DEFINE_IDA(virtio_index_ida);
static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf)
@@ -193,7 +194,11 @@ int register_virtio_device(struct virtio_device *dev)
dev->dev.bus = &virtio_bus;
/* Assign a unique device index and hence name. */
- dev->index = dev_index++;
+ err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL);
+ if (err < 0)
+ goto out;
+
+ dev->index = err;
dev_set_name(&dev->dev, "virtio%u", dev->index);
/* We always start by resetting the device, in case a previous
@@ -208,6 +213,7 @@ int register_virtio_device(struct virtio_device *dev)
/* device_register() causes the bus infrastructure to look for a
* matching driver. */
err = device_register(&dev->dev);
+out:
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;
@@ -217,6 +223,7 @@ EXPORT_SYMBOL_GPL(register_virtio_device);
void unregister_virtio_device(struct virtio_device *dev)
{
device_unregister(&dev->dev);
+ ida_simple_remove(&virtio_index_ida, dev->index);
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index c2d05a8..bfbc15c 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -381,20 +381,25 @@ out:
return err;
}
-static void __devexit virtballoon_remove(struct virtio_device *vdev)
+static void remove_common(struct virtio_balloon *vb)
{
- struct virtio_balloon *vb = vdev->priv;
-
- kthread_stop(vb->thread);
-
/* There might be pages left in the balloon: free them. */
while (vb->num_pages)
leak_balloon(vb, vb->num_pages);
+ update_balloon_size(vb);
/* Now we reset the device so we can clean up the queues. */
- vdev->config->reset(vdev);
+ vb->vdev->config->reset(vb->vdev);
- vdev->config->del_vqs(vdev);
+ vb->vdev->config->del_vqs(vb->vdev);
+}
+
+static void __devexit virtballoon_remove(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+
+ kthread_stop(vb->thread);
+ remove_common(vb);
kfree(vb);
}
@@ -408,17 +413,11 @@ static int virtballoon_freeze(struct virtio_device *vdev)
* function is called.
*/
- while (vb->num_pages)
- leak_balloon(vb, vb->num_pages);
- update_balloon_size(vb);
-
- /* Ensure we don't get any more requests from the host */
- vdev->config->reset(vdev);
- vdev->config->del_vqs(vdev);
+ remove_common(vb);
return 0;
}
-static int restore_common(struct virtio_device *vdev)
+static int virtballoon_restore(struct virtio_device *vdev)
{
struct virtio_balloon *vb = vdev->priv;
int ret;
@@ -431,11 +430,6 @@ static int restore_common(struct virtio_device *vdev)
update_balloon_size(vb);
return 0;
}
-
-static int virtballoon_restore(struct virtio_device *vdev)
-{
- return restore_common(vdev);
-}
#endif
static unsigned int features[] = {
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 01d6dc2..453db0c 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -6,6 +6,50 @@
* This module allows virtio devices to be used over a virtual, memory mapped
* platform device.
*
+ * The guest device(s) may be instantiated in one of three equivalent ways:
+ *
+ * 1. Static platform device in board's code, eg.:
+ *
+ * static struct platform_device v2m_virtio_device = {
+ * .name = "virtio-mmio",
+ * .id = -1,
+ * .num_resources = 2,
+ * .resource = (struct resource []) {
+ * {
+ * .start = 0x1001e000,
+ * .end = 0x1001e0ff,
+ * .flags = IORESOURCE_MEM,
+ * }, {
+ * .start = 42 + 32,
+ * .end = 42 + 32,
+ * .flags = IORESOURCE_IRQ,
+ * },
+ * }
+ * };
+ *
+ * 2. Device Tree node, eg.:
+ *
+ * virtio_block@1e000 {
+ * compatible = "virtio,mmio";
+ * reg = <0x1e000 0x100>;
+ * interrupts = <42>;
+ * }
+ *
+ * 3. Kernel module (or command line) parameter. Can be used more than once -
+ * one device will be created for each one. Syntax:
+ *
+ * [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>]
+ * where:
+ * <size> := size (can use standard suffixes like K, M or G)
+ * <baseaddr> := physical base address
+ * <irq> := interrupt number (as passed to request_irq())
+ * <id> := (optional) platform device id
+ * eg.:
+ * virtio_mmio.device=0x100@0x100b0000:48 \
+ * virtio_mmio.device=1K@0x1001e000:74
+ *
+ *
+ *
* Registers layout (all 32-bit wide):
*
* offset d. name description
@@ -42,6 +86,8 @@
* See the COPYING file in the top-level directory.
*/
+#define pr_fmt(fmt) "virtio-mmio: " fmt
+
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -449,6 +495,122 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev)
+/* Devices list parameter */
+
+#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES)
+
+static struct device vm_cmdline_parent = {
+ .init_name = "virtio-mmio-cmdline",
+};
+
+static int vm_cmdline_parent_registered;
+static int vm_cmdline_id;
+
+static int vm_cmdline_set(const char *device,
+ const struct kernel_param *kp)
+{
+ int err;
+ struct resource resources[2] = {};
+ char *str;
+ long long int base;
+ int processed, consumed = 0;
+ struct platform_device *pdev;
+
+ resources[0].flags = IORESOURCE_MEM;
+ resources[1].flags = IORESOURCE_IRQ;
+
+ resources[0].end = memparse(device, &str) - 1;
+
+ processed = sscanf(str, "@%lli:%u%n:%d%n",
+ &base, &resources[1].start, &consumed,
+ &vm_cmdline_id, &consumed);
+
+ if (processed < 2 || processed > 3 || str[consumed])
+ return -EINVAL;
+
+ resources[0].start = base;
+ resources[0].end += base;
+ resources[1].end = resources[1].start;
+
+ if (!vm_cmdline_parent_registered) {
+ err = device_register(&vm_cmdline_parent);
+ if (err) {
+ pr_err("Failed to register parent device!\n");
+ return err;
+ }
+ vm_cmdline_parent_registered = 1;
+ }
+
+ pr_info("Registering device virtio-mmio.%d at 0x%llx-0x%llx, IRQ %d.\n",
+ vm_cmdline_id,
+ (unsigned long long)resources[0].start,
+ (unsigned long long)resources[0].end,
+ (int)resources[1].start);
+
+ pdev = platform_device_register_resndata(&vm_cmdline_parent,
+ "virtio-mmio", vm_cmdline_id++,
+ resources, ARRAY_SIZE(resources), NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return 0;
+}
+
+static int vm_cmdline_get_device(struct device *dev, void *data)
+{
+ char *buffer = data;
+ unsigned int len = strlen(buffer);
+ struct platform_device *pdev = to_platform_device(dev);
+
+ snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n",
+ pdev->resource[0].end - pdev->resource[0].start + 1ULL,
+ (unsigned long long)pdev->resource[0].start,
+ (unsigned long long)pdev->resource[1].start,
+ pdev->id);
+ return 0;
+}
+
+static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
+{
+ buffer[0] = '\0';
+ device_for_each_child(&vm_cmdline_parent, buffer,
+ vm_cmdline_get_device);
+ return strlen(buffer) + 1;
+}
+
+static struct kernel_param_ops vm_cmdline_param_ops = {
+ .set = vm_cmdline_set,
+ .get = vm_cmdline_get,
+};
+
+device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
+
+static int vm_unregister_cmdline_device(struct device *dev,
+ void *data)
+{
+ platform_device_unregister(to_platform_device(dev));
+
+ return 0;
+}
+
+static void vm_unregister_cmdline_devices(void)
+{
+ if (vm_cmdline_parent_registered) {
+ device_for_each_child(&vm_cmdline_parent, NULL,
+ vm_unregister_cmdline_device);
+ device_unregister(&vm_cmdline_parent);
+ vm_cmdline_parent_registered = 0;
+ }
+}
+
+#else
+
+static void vm_unregister_cmdline_devices(void)
+{
+}
+
+#endif
+
/* Platform driver */
static struct of_device_id virtio_mmio_match[] = {
@@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void)
static void __exit virtio_mmio_exit(void)
{
platform_driver_unregister(&virtio_mmio_driver);
+ vm_unregister_cmdline_devices();
}
module_init(virtio_mmio_init);
diff --git a/drivers/staging/vme/Kconfig b/drivers/vme/Kconfig
index 6411ae5..c5c2246 100644
--- a/drivers/staging/vme/Kconfig
+++ b/drivers/vme/Kconfig
@@ -10,10 +10,10 @@ menuconfig VME_BUS
if VME_BUS
-source "drivers/staging/vme/bridges/Kconfig"
+source "drivers/vme/bridges/Kconfig"
-source "drivers/staging/vme/devices/Kconfig"
+source "drivers/vme/boards/Kconfig"
-source "drivers/staging/vme/boards/Kconfig"
+source "drivers/staging/vme/devices/Kconfig"
endif # VME
diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile
new file mode 100644
index 0000000..d7bfcb9
--- /dev/null
+++ b/drivers/vme/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the VME bridge device drivers.
+#
+obj-$(CONFIG_VME_BUS) += vme.o
+
+obj-y += bridges/
+obj-y += boards/
diff --git a/drivers/staging/vme/boards/Kconfig b/drivers/vme/boards/Kconfig
index 7616313..7616313 100644
--- a/drivers/staging/vme/boards/Kconfig
+++ b/drivers/vme/boards/Kconfig
diff --git a/drivers/staging/vme/boards/Makefile b/drivers/vme/boards/Makefile
index 4365834..4365834 100644
--- a/drivers/staging/vme/boards/Makefile
+++ b/drivers/vme/boards/Makefile
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
index 8e05bb4..8e05bb4 100644
--- a/drivers/staging/vme/boards/vme_vmivme7805.c
+++ b/drivers/vme/boards/vme_vmivme7805.c
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.h b/drivers/vme/boards/vme_vmivme7805.h
index 44c2c44..44c2c44 100644
--- a/drivers/staging/vme/boards/vme_vmivme7805.h
+++ b/drivers/vme/boards/vme_vmivme7805.h
diff --git a/drivers/staging/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig
index 9331064..9331064 100644
--- a/drivers/staging/vme/bridges/Kconfig
+++ b/drivers/vme/bridges/Kconfig
diff --git a/drivers/staging/vme/bridges/Makefile b/drivers/vme/bridges/Makefile
index 59638af..59638af 100644
--- a/drivers/staging/vme/bridges/Makefile
+++ b/drivers/vme/bridges/Makefile
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 515b8b8..e0df92e 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -29,8 +29,8 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "../vme_bridge.h"
#include "vme_ca91cx42.h"
@@ -1501,7 +1501,7 @@ static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
}
-void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
+static void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
dma_addr_t *dma)
{
struct pci_dev *pdev;
@@ -1512,8 +1512,8 @@ void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
return pci_alloc_consistent(pdev, size, dma);
}
-void ca91cx42_free_consistent(struct device *parent, size_t size, void *vaddr,
- dma_addr_t dma)
+static void ca91cx42_free_consistent(struct device *parent, size_t size,
+ void *vaddr, dma_addr_t dma)
{
struct pci_dev *pdev;
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/vme/bridges/vme_ca91cx42.h
index 02a7c79..02a7c79 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.h
+++ b/drivers/vme/bridges/vme_ca91cx42.h
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index f505821..f6385f7 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -29,8 +29,9 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/byteorder/generic.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "../vme_bridge.h"
#include "vme_tsi148.h"
@@ -1415,51 +1416,55 @@ static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
return result;
}
-static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
+static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr,
u32 aspace, u32 cycle, u32 dwidth)
{
+ u32 val;
+
+ val = be32_to_cpu(*attr);
+
/* Setup 2eSST speeds */
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
case VME_2eSST160:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_160;
+ val |= TSI148_LCSR_DSAT_2eSSTM_160;
break;
case VME_2eSST267:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_267;
+ val |= TSI148_LCSR_DSAT_2eSSTM_267;
break;
case VME_2eSST320:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_320;
+ val |= TSI148_LCSR_DSAT_2eSSTM_320;
break;
}
/* Setup cycle types */
if (cycle & VME_SCT)
- *attr |= TSI148_LCSR_DSAT_TM_SCT;
+ val |= TSI148_LCSR_DSAT_TM_SCT;
if (cycle & VME_BLT)
- *attr |= TSI148_LCSR_DSAT_TM_BLT;
+ val |= TSI148_LCSR_DSAT_TM_BLT;
if (cycle & VME_MBLT)
- *attr |= TSI148_LCSR_DSAT_TM_MBLT;
+ val |= TSI148_LCSR_DSAT_TM_MBLT;
if (cycle & VME_2eVME)
- *attr |= TSI148_LCSR_DSAT_TM_2eVME;
+ val |= TSI148_LCSR_DSAT_TM_2eVME;
if (cycle & VME_2eSST)
- *attr |= TSI148_LCSR_DSAT_TM_2eSST;
+ val |= TSI148_LCSR_DSAT_TM_2eSST;
if (cycle & VME_2eSSTB) {
dev_err(dev, "Currently not setting Broadcast Select "
"Registers\n");
- *attr |= TSI148_LCSR_DSAT_TM_2eSSTB;
+ val |= TSI148_LCSR_DSAT_TM_2eSSTB;
}
/* Setup data width */
switch (dwidth) {
case VME_D16:
- *attr |= TSI148_LCSR_DSAT_DBW_16;
+ val |= TSI148_LCSR_DSAT_DBW_16;
break;
case VME_D32:
- *attr |= TSI148_LCSR_DSAT_DBW_32;
+ val |= TSI148_LCSR_DSAT_DBW_32;
break;
default:
dev_err(dev, "Invalid data width\n");
@@ -1469,31 +1474,31 @@ static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
/* Setup address space */
switch (aspace) {
case VME_A16:
- *attr |= TSI148_LCSR_DSAT_AMODE_A16;
+ val |= TSI148_LCSR_DSAT_AMODE_A16;
break;
case VME_A24:
- *attr |= TSI148_LCSR_DSAT_AMODE_A24;
+ val |= TSI148_LCSR_DSAT_AMODE_A24;
break;
case VME_A32:
- *attr |= TSI148_LCSR_DSAT_AMODE_A32;
+ val |= TSI148_LCSR_DSAT_AMODE_A32;
break;
case VME_A64:
- *attr |= TSI148_LCSR_DSAT_AMODE_A64;
+ val |= TSI148_LCSR_DSAT_AMODE_A64;
break;
case VME_CRCSR:
- *attr |= TSI148_LCSR_DSAT_AMODE_CRCSR;
+ val |= TSI148_LCSR_DSAT_AMODE_CRCSR;
break;
case VME_USER1:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER1;
+ val |= TSI148_LCSR_DSAT_AMODE_USER1;
break;
case VME_USER2:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER2;
+ val |= TSI148_LCSR_DSAT_AMODE_USER2;
break;
case VME_USER3:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER3;
+ val |= TSI148_LCSR_DSAT_AMODE_USER3;
break;
case VME_USER4:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER4;
+ val |= TSI148_LCSR_DSAT_AMODE_USER4;
break;
default:
dev_err(dev, "Invalid address space\n");
@@ -1502,58 +1507,64 @@ static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
}
if (cycle & VME_SUPER)
- *attr |= TSI148_LCSR_DSAT_SUP;
+ val |= TSI148_LCSR_DSAT_SUP;
if (cycle & VME_PROG)
- *attr |= TSI148_LCSR_DSAT_PGM;
+ val |= TSI148_LCSR_DSAT_PGM;
+
+ *attr = cpu_to_be32(val);
return 0;
}
-static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
+static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr,
u32 aspace, u32 cycle, u32 dwidth)
{
+ u32 val;
+
+ val = be32_to_cpu(*attr);
+
/* Setup 2eSST speeds */
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
case VME_2eSST160:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_160;
+ val |= TSI148_LCSR_DDAT_2eSSTM_160;
break;
case VME_2eSST267:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_267;
+ val |= TSI148_LCSR_DDAT_2eSSTM_267;
break;
case VME_2eSST320:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_320;
+ val |= TSI148_LCSR_DDAT_2eSSTM_320;
break;
}
/* Setup cycle types */
if (cycle & VME_SCT)
- *attr |= TSI148_LCSR_DDAT_TM_SCT;
+ val |= TSI148_LCSR_DDAT_TM_SCT;
if (cycle & VME_BLT)
- *attr |= TSI148_LCSR_DDAT_TM_BLT;
+ val |= TSI148_LCSR_DDAT_TM_BLT;
if (cycle & VME_MBLT)
- *attr |= TSI148_LCSR_DDAT_TM_MBLT;
+ val |= TSI148_LCSR_DDAT_TM_MBLT;
if (cycle & VME_2eVME)
- *attr |= TSI148_LCSR_DDAT_TM_2eVME;
+ val |= TSI148_LCSR_DDAT_TM_2eVME;
if (cycle & VME_2eSST)
- *attr |= TSI148_LCSR_DDAT_TM_2eSST;
+ val |= TSI148_LCSR_DDAT_TM_2eSST;
if (cycle & VME_2eSSTB) {
dev_err(dev, "Currently not setting Broadcast Select "
"Registers\n");
- *attr |= TSI148_LCSR_DDAT_TM_2eSSTB;
+ val |= TSI148_LCSR_DDAT_TM_2eSSTB;
}
/* Setup data width */
switch (dwidth) {
case VME_D16:
- *attr |= TSI148_LCSR_DDAT_DBW_16;
+ val |= TSI148_LCSR_DDAT_DBW_16;
break;
case VME_D32:
- *attr |= TSI148_LCSR_DDAT_DBW_32;
+ val |= TSI148_LCSR_DDAT_DBW_32;
break;
default:
dev_err(dev, "Invalid data width\n");
@@ -1563,31 +1574,31 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
/* Setup address space */
switch (aspace) {
case VME_A16:
- *attr |= TSI148_LCSR_DDAT_AMODE_A16;
+ val |= TSI148_LCSR_DDAT_AMODE_A16;
break;
case VME_A24:
- *attr |= TSI148_LCSR_DDAT_AMODE_A24;
+ val |= TSI148_LCSR_DDAT_AMODE_A24;
break;
case VME_A32:
- *attr |= TSI148_LCSR_DDAT_AMODE_A32;
+ val |= TSI148_LCSR_DDAT_AMODE_A32;
break;
case VME_A64:
- *attr |= TSI148_LCSR_DDAT_AMODE_A64;
+ val |= TSI148_LCSR_DDAT_AMODE_A64;
break;
case VME_CRCSR:
- *attr |= TSI148_LCSR_DDAT_AMODE_CRCSR;
+ val |= TSI148_LCSR_DDAT_AMODE_CRCSR;
break;
case VME_USER1:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER1;
+ val |= TSI148_LCSR_DDAT_AMODE_USER1;
break;
case VME_USER2:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER2;
+ val |= TSI148_LCSR_DDAT_AMODE_USER2;
break;
case VME_USER3:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER3;
+ val |= TSI148_LCSR_DDAT_AMODE_USER3;
break;
case VME_USER4:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER4;
+ val |= TSI148_LCSR_DDAT_AMODE_USER4;
break;
default:
dev_err(dev, "Invalid address space\n");
@@ -1596,25 +1607,28 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
}
if (cycle & VME_SUPER)
- *attr |= TSI148_LCSR_DDAT_SUP;
+ val |= TSI148_LCSR_DDAT_SUP;
if (cycle & VME_PROG)
- *attr |= TSI148_LCSR_DDAT_PGM;
+ val |= TSI148_LCSR_DDAT_PGM;
+
+ *attr = cpu_to_be32(val);
return 0;
}
/*
* Add a link list descriptor to the list
+ *
+ * Note: DMA engine expects the DMA descriptor to be big endian.
*/
static int tsi148_dma_list_add(struct vme_dma_list *list,
struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
{
struct tsi148_dma_entry *entry, *prev;
- u32 address_high, address_low;
+ u32 address_high, address_low, val;
struct vme_dma_pattern *pattern_attr;
struct vme_dma_pci *pci_attr;
struct vme_dma_vme *vme_attr;
- dma_addr_t desc_ptr;
int retval = 0;
struct vme_bridge *tsi148_bridge;
@@ -1648,34 +1662,36 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
case VME_DMA_PATTERN:
pattern_attr = src->private;
- entry->descriptor.dsal = pattern_attr->pattern;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
+ entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern);
+
+ val = TSI148_LCSR_DSAT_TYP_PAT;
+
/* Default behaviour is 32 bit pattern */
if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
- entry->descriptor.dsat |= TSI148_LCSR_DSAT_PSZ;
+ val |= TSI148_LCSR_DSAT_PSZ;
/* It seems that the default behaviour is to increment */
if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
- entry->descriptor.dsat |= TSI148_LCSR_DSAT_NIN;
-
+ val |= TSI148_LCSR_DSAT_NIN;
+ entry->descriptor.dsat = cpu_to_be32(val);
break;
case VME_DMA_PCI:
pci_attr = src->private;
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
- entry->descriptor.dsau = address_high;
- entry->descriptor.dsal = address_low;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
+ entry->descriptor.dsau = cpu_to_be32(address_high);
+ entry->descriptor.dsal = cpu_to_be32(address_low);
+ entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI);
break;
case VME_DMA_VME:
vme_attr = src->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
- entry->descriptor.dsau = address_high;
- entry->descriptor.dsal = address_low;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
+ entry->descriptor.dsau = cpu_to_be32(address_high);
+ entry->descriptor.dsal = cpu_to_be32(address_low);
+ entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME);
retval = tsi148_dma_set_vme_src_attributes(
tsi148_bridge->parent, &entry->descriptor.dsat,
@@ -1691,9 +1707,8 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
}
/* Assume last link - this will be over-written by adding another */
- entry->descriptor.dnlau = 0;
- entry->descriptor.dnlal = TSI148_LCSR_DNLAL_LLA;
-
+ entry->descriptor.dnlau = cpu_to_be32(0);
+ entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA);
/* Fill out destination part */
switch (dest->type) {
@@ -1702,18 +1717,18 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
- entry->descriptor.ddau = address_high;
- entry->descriptor.ddal = address_low;
- entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
+ entry->descriptor.ddau = cpu_to_be32(address_high);
+ entry->descriptor.ddal = cpu_to_be32(address_low);
+ entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI);
break;
case VME_DMA_VME:
vme_attr = dest->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
- entry->descriptor.ddau = address_high;
- entry->descriptor.ddal = address_low;
- entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
+ entry->descriptor.ddau = cpu_to_be32(address_high);
+ entry->descriptor.ddal = cpu_to_be32(address_low);
+ entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME);
retval = tsi148_dma_set_vme_dest_attributes(
tsi148_bridge->parent, &entry->descriptor.ddat,
@@ -1729,7 +1744,7 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
}
/* Fill out count */
- entry->descriptor.dcnt = (u32)count;
+ entry->descriptor.dcnt = cpu_to_be32((u32)count);
/* Add to list */
list_add_tail(&entry->list, &list->entries);
@@ -1739,9 +1754,15 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
list);
/* We need the bus address for the pointer */
- desc_ptr = virt_to_bus(&entry->descriptor);
- reg_split(desc_ptr, &prev->descriptor.dnlau,
- &prev->descriptor.dnlal);
+ entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+ &entry->descriptor,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
+
+ reg_split((unsigned long long)entry->dma_handle, &address_high,
+ &address_low);
+ entry->descriptor.dnlau = cpu_to_be32(address_high);
+ entry->descriptor.dnlal = cpu_to_be32(address_low);
+
}
return 0;
@@ -1784,7 +1805,6 @@ static int tsi148_dma_list_exec(struct vme_dma_list *list)
struct vme_dma_resource *ctrlr;
int channel, retval = 0;
struct tsi148_dma_entry *entry;
- dma_addr_t bus_addr;
u32 bus_addr_high, bus_addr_low;
u32 val, dctlreg = 0;
struct vme_bridge *tsi148_bridge;
@@ -1817,23 +1837,29 @@ static int tsi148_dma_list_exec(struct vme_dma_list *list)
entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
list);
- bus_addr = virt_to_bus(&entry->descriptor);
+ entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+ &entry->descriptor,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
mutex_unlock(&ctrlr->mtx);
- reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
+ reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low);
iowrite32be(bus_addr_high, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
iowrite32be(bus_addr_low, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
+ dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DCTL);
+
/* Start the operation */
iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
wait_event_interruptible(bridge->dma_queue[channel],
tsi148_dma_busy(ctrlr->parent, channel));
+
/*
* Read status register, this register is valid until we kick off a
* new transfer.
@@ -1864,10 +1890,15 @@ static int tsi148_dma_list_empty(struct vme_dma_list *list)
struct list_head *pos, *temp;
struct tsi148_dma_entry *entry;
+ struct vme_bridge *tsi148_bridge = list->parent->parent;
+
/* detach and free each entry */
list_for_each_safe(pos, temp, &list->entries) {
list_del(pos);
entry = list_entry(pos, struct tsi148_dma_entry, list);
+
+ dma_unmap_single(tsi148_bridge->parent, entry->dma_handle,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
kfree(entry);
}
@@ -2110,7 +2141,7 @@ static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
return (int)slot;
}
-void *tsi148_alloc_consistent(struct device *parent, size_t size,
+static void *tsi148_alloc_consistent(struct device *parent, size_t size,
dma_addr_t *dma)
{
struct pci_dev *pdev;
@@ -2121,8 +2152,8 @@ void *tsi148_alloc_consistent(struct device *parent, size_t size,
return pci_alloc_consistent(pdev, size, dma);
}
-void tsi148_free_consistent(struct device *parent, size_t size, void *vaddr,
- dma_addr_t dma)
+static void tsi148_free_consistent(struct device *parent, size_t size,
+ void *vaddr, dma_addr_t dma)
{
struct pci_dev *pdev;
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/vme/bridges/vme_tsi148.h
index a3ac2fe..f5ed1438 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.h
+++ b/drivers/vme/bridges/vme_tsi148.h
@@ -56,16 +56,16 @@ struct tsi148_driver {
* correctly laid out - It must also be aligned on 64-bit boundaries.
*/
struct tsi148_dma_descriptor {
- u32 dsau; /* Source Address */
- u32 dsal;
- u32 ddau; /* Destination Address */
- u32 ddal;
- u32 dsat; /* Source attributes */
- u32 ddat; /* Destination attributes */
- u32 dnlau; /* Next link address */
- u32 dnlal;
- u32 dcnt; /* Byte count */
- u32 ddbs; /* 2eSST Broadcast select */
+ __be32 dsau; /* Source Address */
+ __be32 dsal;
+ __be32 ddau; /* Destination Address */
+ __be32 ddal;
+ __be32 dsat; /* Source attributes */
+ __be32 ddat; /* Destination attributes */
+ __be32 dnlau; /* Next link address */
+ __be32 dnlal;
+ __be32 dcnt; /* Byte count */
+ __be32 ddbs; /* 2eSST Broadcast select */
};
struct tsi148_dma_entry {
@@ -75,6 +75,7 @@ struct tsi148_dma_entry {
*/
struct tsi148_dma_descriptor descriptor;
struct list_head list;
+ dma_addr_t dma_handle;
};
/*
diff --git a/drivers/staging/vme/vme.c b/drivers/vme/vme.c
index 70722ae..95a9f71 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/vme/vme.c
@@ -30,8 +30,8 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "vme.h"
#include "vme_bridge.h"
/* Bitmask and list of registered buses both protected by common mutex */
@@ -98,14 +98,13 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
}
if (bridge->parent == NULL) {
- printk(KERN_ERR "Dev entry NULL for"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
return NULL;
}
if (bridge->alloc_consistent == NULL) {
- printk(KERN_ERR "alloc_consistent not supported by"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "alloc_consistent not supported by bridge %s\n",
+ bridge->name);
return NULL;
}
@@ -133,14 +132,13 @@ void vme_free_consistent(struct vme_resource *resource, size_t size,
}
if (bridge->parent == NULL) {
- printk(KERN_ERR "Dev entry NULL for"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
return;
}
if (bridge->free_consistent == NULL) {
- printk(KERN_ERR "free_consistent not supported by"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "free_consistent not supported by bridge %s\n",
+ bridge->name);
return;
}
@@ -747,15 +745,13 @@ struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
if (pattern_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for pattern "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for pattern attributes\n");
goto err_pat;
}
@@ -786,15 +782,13 @@ struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
if (pci_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for pci "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for pci attributes\n");
goto err_pci;
}
@@ -826,15 +820,13 @@ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
attributes = kmalloc(
sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
if (vme_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for vme "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for vme attributes\n");
goto err_vme;
}
@@ -982,8 +974,8 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
if (call != NULL)
call(level, statid, priv_data);
else
- printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
- "vector:%x\n", level, statid);
+ printk(KERN_WARNING "Spurilous VME interrupt, level:%x, vector:%x\n",
+ level, statid);
}
EXPORT_SYMBOL(vme_irq_handler);
@@ -1112,8 +1104,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev)
struct vme_lm_resource, list);
if (lm == NULL) {
- printk(KERN_ERR "Registered NULL Location Monitor "
- "resource\n");
+ printk(KERN_ERR "Registered NULL Location Monitor resource\n");
continue;
}
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/vme/vme_bridge.h
index 934949a..934949a 100644
--- a/drivers/staging/vme/vme_bridge.h
+++ b/drivers/vme/vme_bridge.h
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index fd2c7bd..6743bde 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -16,7 +16,7 @@ config W1_CON
depends on CONNECTOR
bool "Userspace communication over connector"
default y
- --- help ---
+ ---help---
This allows to communicate with userspace using connector. For more
information see <file:Documentation/connector/connector.txt>.
There are three types of messages between w1 core and userspace:
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index 7c8cdb8..8e813ee 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -332,7 +332,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
},
.size = 1,
.read = w1_f29_read_cond_search_mask,
- .write = 0,
},
{
.attr = {
@@ -341,7 +340,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
},
.size = 1,
.read = w1_f29_read_cond_search_polarity,
- .write = 0,
},
{
.attr = {
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 9761950..2f2e894 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1027,7 +1027,7 @@ static int __init w1_init(void)
retval = driver_register(&w1_slave_driver);
if (retval) {
printk(KERN_ERR
- "Failed to register master driver. err=%d.\n",
+ "Failed to register slave driver. err=%d.\n",
retval);
goto err_out_master_unregister;
}
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 3135b2c..e10acc2 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -31,6 +31,9 @@
static int w1_delay_parm = 1;
module_param_named(delay_coef, w1_delay_parm, int, 0);
+static int w1_disable_irqs = 0;
+module_param_named(disable_irqs, w1_disable_irqs, int, 0);
+
static u8 w1_crc8_table[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
@@ -79,6 +82,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
*/
static void w1_write_bit(struct w1_master *dev, int bit)
{
+ unsigned long flags = 0;
+
+ if(w1_disable_irqs) local_irq_save(flags);
+
if (bit) {
dev->bus_master->write_bit(dev->bus_master->data, 0);
w1_delay(6);
@@ -90,6 +97,8 @@ static void w1_write_bit(struct w1_master *dev, int bit)
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(10);
}
+
+ if(w1_disable_irqs) local_irq_restore(flags);
}
/**
@@ -158,7 +167,7 @@ EXPORT_SYMBOL_GPL(w1_write_8);
static u8 w1_read_bit(struct w1_master *dev)
{
int result;
- unsigned long flags;
+ unsigned long flags = 0;
/* sample timing is critical here */
local_irq_save(flags);
@@ -318,6 +327,9 @@ EXPORT_SYMBOL_GPL(w1_read_block);
int w1_reset_bus(struct w1_master *dev)
{
int result;
+ unsigned long flags = 0;
+
+ if(w1_disable_irqs) local_irq_save(flags);
if (dev->bus_master->reset_bus)
result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
@@ -330,19 +342,21 @@ int w1_reset_bus(struct w1_master *dev)
* cpu for such a short amount of time AND get it back in
* the maximum amount of time.
*/
- w1_delay(480);
+ w1_delay(500);
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(70);
result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
- /* minmum 70 (above) + 410 = 480 us
+ /* minmum 70 (above) + 430 = 500 us
* There aren't any timing requirements between a reset and
* the following transactions. Sleeping is safe here.
*/
- /* w1_delay(410); min required time */
+ /* w1_delay(430); min required time */
msleep(1);
}
+ if(w1_disable_irqs) local_irq_restore(flags);
+
return result;
}
EXPORT_SYMBOL_GPL(w1_reset_bus);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3709624..a18bf63 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -129,17 +129,6 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
-config IXP2000_WATCHDOG
- tristate "IXP2000 Watchdog"
- depends on ARCH_IXP2000
- help
- Say Y here if to include support for the watchdog timer
- in the Intel IXP2000(2400, 2800, 2850) network processors.
- This driver can be built as a module by choosing M. The module
- will be called ixp2000_wdt.
-
- Say N if you are unsure.
-
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
depends on ARCH_IXP4XX
@@ -543,7 +532,7 @@ config WAFER_WDT
config I6300ESB_WDT
tristate "Intel 6300ESB Timer/Watchdog"
- depends on X86 && PCI
+ depends on PCI
---help---
Hardware driver for the watchdog timer built into the Intel
6300ESB controller hub.
@@ -551,6 +540,19 @@ config I6300ESB_WDT
To compile this driver as a module, choose M here: the
module will be called i6300esb.
+config IE6XX_WDT
+ tristate "Intel Atom E6xx Watchdog"
+ depends on X86 && PCI
+ select WATCHDOG_CORE
+ select MFD_CORE
+ select LPC_SCH
+ ---help---
+ Hardware driver for the watchdog timer built into the Intel
+ Atom E6XX (TunnelCreek) processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ie6xx_wdt.
+
config INTEL_SCU_WATCHDOG
bool "Intel SCU Watchdog for Mobile Platforms"
depends on X86_MRST
@@ -607,7 +609,12 @@ config IT87_WDT
depends on X86 && EXPERIMENTAL
---help---
This is the driver for the hardware watchdog on the ITE IT8702,
- IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
+ IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
+ Super I/O chips.
+
+ If the driver does not work, then make sure that the game port in
+ the BIOS is enabled.
+
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
@@ -780,7 +787,7 @@ config SMSC37B787_WDT
config VIA_WDT
tristate "VIA Watchdog Timer"
- depends on X86
+ depends on X86 && PCI
select WATCHDOG_CORE
---help---
This is the driver for the hardware watchdog timer on VIA
@@ -937,7 +944,7 @@ config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
depends on BCM47XX
help
- Hardware driver for the Broadcom BCM47xx Watchog Timer.
+ Hardware driver for the Broadcom BCM47xx Watchdog Timer.
config RC32434_WDT
tristate "IDT RC32434 SoC Watchdog Timer"
@@ -1138,6 +1145,7 @@ config ZVM_WATCHDOG
config SH_WDT
tristate "SuperH Watchdog"
depends on SUPERH && (CPU_SH3 || CPU_SH4)
+ select WATCHDOG_CORE
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e8f479a..442bfbe 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -36,7 +36,6 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
@@ -81,6 +80,7 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
+obj-$(CONFIG_IE6XX_WDT) += ie6xx_wdt.o
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 639ae9a..dc30dbd 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -282,29 +282,19 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
if (!ar7_regs_wdt) {
pr_err("could not get registers resource\n");
- rc = -ENODEV;
- goto out;
- }
-
- if (!request_mem_region(ar7_regs_wdt->start,
- resource_size(ar7_regs_wdt), LONGNAME)) {
- pr_warn("watchdog I/O region busy\n");
- rc = -EBUSY;
- goto out;
+ return -ENODEV;
}
- ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
+ ar7_wdt = devm_request_and_ioremap(&pdev->dev, ar7_regs_wdt);
if (!ar7_wdt) {
pr_err("could not ioremap registers\n");
- rc = -ENXIO;
- goto out_mem_region;
+ return -ENXIO;
}
vbus_clk = clk_get(NULL, "vbus");
if (IS_ERR(vbus_clk)) {
pr_err("could not get vbus clock\n");
- rc = PTR_ERR(vbus_clk);
- goto out_mem_region;
+ return PTR_ERR(vbus_clk);
}
ar7_wdt_disable_wdt();
@@ -314,24 +304,21 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
rc = misc_register(&ar7_wdt_miscdev);
if (rc) {
pr_err("unable to register misc device\n");
- goto out_alloc;
+ goto out;
}
- goto out;
+ return 0;
-out_alloc:
- iounmap(ar7_wdt);
-out_mem_region:
- release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
out:
+ clk_put(vbus_clk);
+ vbus_clk = NULL;
return rc;
}
static int __devexit ar7_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&ar7_wdt_miscdev);
- iounmap(ar7_wdt);
- release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
-
+ clk_put(vbus_clk);
+ vbus_clk = NULL;
return 0;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 9f13b89..2b76381 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -147,7 +147,6 @@ struct cmn_registers {
static unsigned int hpwdt_nmi_decoding;
static unsigned int allow_kdump;
-static unsigned int priority; /* hpwdt at end of die_notify list */
static unsigned int is_icru;
static DEFINE_SPINLOCK(rom_lock);
static void *cru_rom_addr;
@@ -723,28 +722,35 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
}
/*
- * If the priority is set to 1, then we will be put first on the
- * die notify list to handle a critical NMI. The default is to
- * be last so other users of the NMI signal can function.
+ * Only one function can register for NMI_UNKNOWN
*/
- retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout,
- (priority) ? NMI_FLAG_FIRST : 0,
- "hpwdt");
- if (retval != 0) {
- dev_warn(&dev->dev,
- "Unable to register a die notifier (err=%d).\n",
- retval);
- if (cru_rom_addr)
- iounmap(cru_rom_addr);
- }
+ retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
+ if (retval)
+ goto error;
+ retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
+ if (retval)
+ goto error1;
+ retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
+ if (retval)
+ goto error2;
dev_info(&dev->dev,
"HP Watchdog Timer Driver: NMI decoding initialized"
- ", allow kernel dump: %s (default = 0/OFF)"
- ", priority: %s (default = 0/LAST).\n",
- (allow_kdump == 0) ? "OFF" : "ON",
- (priority == 0) ? "LAST" : "FIRST");
+ ", allow kernel dump: %s (default = 0/OFF)\n",
+ (allow_kdump == 0) ? "OFF" : "ON");
return 0;
+
+error2:
+ unregister_nmi_handler(NMI_SERR, "hpwdt");
+error1:
+ unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
+error:
+ dev_warn(&dev->dev,
+ "Unable to register a die notifier (err=%d).\n",
+ retval);
+ if (cru_rom_addr)
+ iounmap(cru_rom_addr);
+ return retval;
}
static void hpwdt_exit_nmi_decoding(void)
@@ -855,16 +861,6 @@ static struct pci_driver hpwdt_driver = {
.remove = __devexit_p(hpwdt_exit),
};
-static void __exit hpwdt_cleanup(void)
-{
- pci_unregister_driver(&hpwdt_driver);
-}
-
-static int __init hpwdt_init(void)
-{
- return pci_register_driver(&hpwdt_driver);
-}
-
MODULE_AUTHOR("Tom Mingarelli");
MODULE_DESCRIPTION("hp watchdog driver");
MODULE_LICENSE("GPL");
@@ -881,11 +877,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
#ifdef CONFIG_HPWDT_NMI_DECODING
module_param(allow_kdump, int, 0);
MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
-
-module_param(priority, int, 0);
-MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last"
- " (default = 0/Last)\n");
#endif /* !CONFIG_HPWDT_NMI_DECODING */
-module_init(hpwdt_init);
-module_exit(hpwdt_cleanup);
+module_pci_driver(hpwdt_driver);
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 738032a..276877d 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -492,19 +492,7 @@ static struct pci_driver esb_driver = {
.shutdown = esb_shutdown,
};
-static int __init watchdog_init(void)
-{
- return pci_register_driver(&esb_driver);
-}
-
-static void __exit watchdog_cleanup(void)
-{
- pci_unregister_driver(&esb_driver);
- pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
+module_pci_driver(esb_driver);
MODULE_AUTHOR("Ross Biro and David Härdeman");
MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c
new file mode 100644
index 0000000..5f0d776
--- /dev/null
+++ b/drivers/watchdog/ie6xx_wdt.c
@@ -0,0 +1,348 @@
+/*
+ * Intel Atom E6xx Watchdog driver
+ *
+ * Copyright (C) 2011 Alexander Stein
+ * <alexander.stein@systec-electronic.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "ie6xx_wdt"
+
+#define PV1 0x00
+#define PV2 0x04
+
+#define RR0 0x0c
+#define RR1 0x0d
+#define WDT_RELOAD 0x01
+#define WDT_TOUT 0x02
+
+#define WDTCR 0x10
+#define WDT_PRE_SEL 0x04
+#define WDT_RESET_SEL 0x08
+#define WDT_RESET_EN 0x10
+#define WDT_TOUT_EN 0x20
+
+#define DCR 0x14
+
+#define WDTLR 0x18
+#define WDT_LOCK 0x01
+#define WDT_ENABLE 0x02
+#define WDT_TOUT_CNF 0x03
+
+#define MIN_TIME 1
+#define MAX_TIME (10 * 60) /* 10 minutes */
+#define DEFAULT_TIME 60
+
+static unsigned int timeout = DEFAULT_TIME;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+ "Default Watchdog timer setting ("
+ __MODULE_STRING(DEFAULT_TIME) "s)."
+ "The range is from 1 to 600");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static u8 resetmode = 0x10;
+module_param(resetmode, byte, 0);
+MODULE_PARM_DESC(resetmode,
+ "Resetmode bits: 0x08 warm reset (cold reset otherwise), "
+ "0x10 reset enable, 0x20 disable toggle GPIO[4] (default=0x10)");
+
+static struct {
+ unsigned short sch_wdtba;
+ struct spinlock unlock_sequence;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs;
+#endif
+} ie6xx_wdt_data;
+
+/*
+ * This is needed to write to preload and reload registers
+ * struct ie6xx_wdt_data.unlock_sequence must be used
+ * to prevent sequence interrupts
+ */
+static void ie6xx_wdt_unlock_registers(void)
+{
+ outb(0x80, ie6xx_wdt_data.sch_wdtba + RR0);
+ outb(0x86, ie6xx_wdt_data.sch_wdtba + RR0);
+}
+
+static int ie6xx_wdt_ping(struct watchdog_device *wdd)
+{
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ ie6xx_wdt_unlock_registers();
+ outb(WDT_RELOAD, ie6xx_wdt_data.sch_wdtba + RR1);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+ return 0;
+}
+
+static int ie6xx_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
+{
+ u32 preload;
+ u64 clock;
+ u8 wdtcr;
+
+ /* Watchdog clock is PCI Clock (33MHz) */
+ clock = 33000000;
+ /* and the preload value is loaded into [34:15] of the down counter */
+ preload = (t * clock) >> 15;
+ /*
+ * Manual states preload must be one less.
+ * Does not wrap as t is at least 1
+ */
+ preload -= 1;
+
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+
+ /* Set ResetMode & Enable prescaler for range 10ms to 10 min */
+ wdtcr = resetmode & 0x38;
+ outb(wdtcr, ie6xx_wdt_data.sch_wdtba + WDTCR);
+
+ ie6xx_wdt_unlock_registers();
+ outl(0, ie6xx_wdt_data.sch_wdtba + PV1);
+
+ ie6xx_wdt_unlock_registers();
+ outl(preload, ie6xx_wdt_data.sch_wdtba + PV2);
+
+ ie6xx_wdt_unlock_registers();
+ outb(WDT_RELOAD | WDT_TOUT, ie6xx_wdt_data.sch_wdtba + RR1);
+
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ wdd->timeout = t;
+ return 0;
+}
+
+static int ie6xx_wdt_start(struct watchdog_device *wdd)
+{
+ ie6xx_wdt_set_timeout(wdd, wdd->timeout);
+
+ /* Enable the watchdog timer */
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ outb(WDT_ENABLE, ie6xx_wdt_data.sch_wdtba + WDTLR);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ return 0;
+}
+
+static int ie6xx_wdt_stop(struct watchdog_device *wdd)
+{
+ if (inb(ie6xx_wdt_data.sch_wdtba + WDTLR) & WDT_LOCK)
+ return -1;
+
+ /* Disable the watchdog timer */
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ outb(0, ie6xx_wdt_data.sch_wdtba + WDTLR);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ return 0;
+}
+
+static const struct watchdog_info ie6xx_wdt_info = {
+ .identity = "Intel Atom E6xx Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops ie6xx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = ie6xx_wdt_start,
+ .stop = ie6xx_wdt_stop,
+ .ping = ie6xx_wdt_ping,
+ .set_timeout = ie6xx_wdt_set_timeout,
+};
+
+static struct watchdog_device ie6xx_wdt_dev = {
+ .info = &ie6xx_wdt_info,
+ .ops = &ie6xx_wdt_ops,
+ .min_timeout = MIN_TIME,
+ .max_timeout = MAX_TIME,
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
+{
+ seq_printf(s, "PV1 = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + PV1));
+ seq_printf(s, "PV2 = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + PV2));
+ seq_printf(s, "RR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + RR0));
+ seq_printf(s, "WDTCR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + WDTCR));
+ seq_printf(s, "DCR = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + DCR));
+ seq_printf(s, "WDTLR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + WDTLR));
+
+ seq_printf(s, "\n");
+ return 0;
+}
+
+static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ie6xx_wdt_dbg_show, NULL);
+}
+
+static const struct file_operations ie6xx_wdt_dbg_operations = {
+ .open = ie6xx_wdt_dbg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+ /* /sys/kernel/debug/ie6xx_wdt */
+ ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt",
+ S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+ debugfs_remove(ie6xx_wdt_data.debugfs);
+}
+
+#else
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+}
+#endif
+
+static int __devinit ie6xx_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ u8 wdtlr;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "Watchdog region 0x%llx already in use!\n",
+ (u64)res->start);
+ return -EBUSY;
+ }
+
+ ie6xx_wdt_data.sch_wdtba = res->start;
+ dev_dbg(&pdev->dev, "WDT = 0x%X\n", ie6xx_wdt_data.sch_wdtba);
+
+ ie6xx_wdt_dev.timeout = timeout;
+ watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout);
+
+ spin_lock_init(&ie6xx_wdt_data.unlock_sequence);
+
+ wdtlr = inb(ie6xx_wdt_data.sch_wdtba + WDTLR);
+ if (wdtlr & WDT_LOCK)
+ dev_warn(&pdev->dev,
+ "Watchdog Timer is Locked (Reg=0x%x)\n", wdtlr);
+
+ ie6xx_wdt_debugfs_init();
+
+ ret = watchdog_register_device(&ie6xx_wdt_dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Watchdog timer: cannot register device (err =%d)\n",
+ ret);
+ goto misc_register_error;
+ }
+
+ return 0;
+
+misc_register_error:
+ ie6xx_wdt_debugfs_exit();
+ release_region(res->start, resource_size(res));
+ ie6xx_wdt_data.sch_wdtba = 0;
+ return ret;
+}
+
+static int __devexit ie6xx_wdt_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ ie6xx_wdt_stop(NULL);
+ watchdog_unregister_device(&ie6xx_wdt_dev);
+ ie6xx_wdt_debugfs_exit();
+ release_region(res->start, resource_size(res));
+ ie6xx_wdt_data.sch_wdtba = 0;
+
+ return 0;
+}
+
+static struct platform_driver ie6xx_wdt_driver = {
+ .probe = ie6xx_wdt_probe,
+ .remove = __devexit_p(ie6xx_wdt_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ie6xx_wdt_init(void)
+{
+ /* Check boot parameters to verify that their initial values */
+ /* are in range. */
+ if ((timeout < MIN_TIME) ||
+ (timeout > MAX_TIME)) {
+ pr_err("Watchdog timer: value of timeout %d (dec) "
+ "is out of range from %d to %d (dec)\n",
+ timeout, MIN_TIME, MAX_TIME);
+ return -EINVAL;
+ }
+
+ return platform_driver_register(&ie6xx_wdt_driver);
+}
+
+static void __exit ie6xx_wdt_exit(void)
+{
+ platform_driver_unregister(&ie6xx_wdt_driver);
+}
+
+late_initcall(ie6xx_wdt_init);
+module_exit(ie6xx_wdt_exit);
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("Intel Atom E6xx Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index 8a741bc..d3dcc69 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,7 +12,8 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
- * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
+ * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726
+ * and IT8728.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -84,6 +85,7 @@
#define IT8720_ID 0x8720
#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
+#define IT8728_ID 0x8728
/* GPIO Configuration Registers LDN=0x07 */
#define WDTCTRL 0x71
@@ -95,7 +97,7 @@
#define WDT_CIRINT 0x80
#define WDT_MOUSEINT 0x40
#define WDT_KYBINT 0x20
-#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721 */
+#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721, it8728 */
#define WDT_FORCE 0x02
#define WDT_ZERO 0x01
@@ -616,6 +618,7 @@ static int __init it87_wdt_init(void)
case IT8718_ID:
case IT8720_ID:
case IT8721_ID:
+ case IT8728_ID:
max_units = 65535;
try_gameport = 0;
break;
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
deleted file mode 100644
index 3f047a5..0000000
--- a/drivers/watchdog/ixp2000_wdt.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * drivers/char/watchdog/ixp2000_wdt.c
- *
- * Watchdog driver for Intel IXP2000 network processors
- *
- * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
- * The original version carries these notices:
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista, Software, Inc.
- * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <mach/hardware.h>
-
-static bool nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
-static unsigned long wdt_status;
-static DEFINE_SPINLOCK(wdt_lock);
-
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
-
-static unsigned long wdt_tick_rate;
-
-static void wdt_enable(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
- ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
- ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
- ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
- spin_unlock(&wdt_lock);
-}
-
-static void wdt_disable(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_T4_CTL, 0);
- spin_unlock(&wdt_lock);
-}
-
-static void wdt_keepalive(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
- spin_unlock(&wdt_lock);
-}
-
-static int ixp2000_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(WDT_IN_USE, &wdt_status))
- return -EBUSY;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- wdt_enable();
-
- return nonseekable_open(inode, file);
-}
-
-static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
-{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &wdt_status);
- }
- }
- wdt_keepalive();
- }
-
- return len;
-}
-
-
-static const struct watchdog_info ident = {
- .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING,
- .identity = "IXP2000 Watchdog",
-};
-
-static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -ENOTTY;
- int time;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- wdt_enable();
- ret = 0;
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(time, (int *)arg);
- if (ret)
- break;
-
- if (time <= 0 || time > 60) {
- ret = -EINVAL;
- break;
- }
-
- heartbeat = time;
- wdt_keepalive();
- /* Fall through */
-
- case WDIOC_GETTIMEOUT:
- ret = put_user(heartbeat, (int *)arg);
- break;
- }
-
- return ret;
-}
-
-static int ixp2000_wdt_release(struct inode *inode, struct file *file)
-{
- if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
- wdt_disable();
- else
- pr_crit("Device closed unexpectedly - timer will not stop\n");
- clear_bit(WDT_IN_USE, &wdt_status);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return 0;
-}
-
-
-static const struct file_operations ixp2000_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = ixp2000_wdt_write,
- .unlocked_ioctl = ixp2000_wdt_ioctl,
- .open = ixp2000_wdt_open,
- .release = ixp2000_wdt_release,
-};
-
-static struct miscdevice ixp2000_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &ixp2000_wdt_fops,
-};
-
-static int __init ixp2000_wdt_init(void)
-{
- if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
- pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
- return -EIO;
- }
- wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
- return misc_register(&ixp2000_wdt_miscdev);
-}
-
-static void __exit ixp2000_wdt_exit(void)
-{
- misc_deregister(&ixp2000_wdt_miscdev);
-}
-
-module_init(ixp2000_wdt_init);
-module_exit(ixp2000_wdt_exit);
-
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
-
-module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index c891399..ee6900d 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -707,6 +707,7 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
goto err_out_disable_device;
}
+ spin_lock_init(&pcipcwd_private.io_lock);
pcipcwd_private.pdev = pdev;
pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
@@ -814,22 +815,7 @@ static struct pci_driver pcipcwd_driver = {
.remove = __devexit_p(pcipcwd_card_exit),
};
-static int __init pcipcwd_init_module(void)
-{
- spin_lock_init(&pcipcwd_private.io_lock);
-
- return pci_register_driver(&pcipcwd_driver);
-}
-
-static void __exit pcipcwd_cleanup_module(void)
-{
- pci_unregister_driver(&pcipcwd_driver);
-
- pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(pcipcwd_init_module);
-module_exit(pcipcwd_cleanup_module);
+module_pci_driver(pcipcwd_driver);
MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 6b8432f..87722e1 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <mach/hardware.h>
/* WatchDog Timer - Chapter 23 Page 207 */
@@ -201,10 +202,19 @@ static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id pnx4008_wdt_match[] = {
+ { .compatible = "nxp,pnx4008-wdt" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pnx4008_wdt_match);
+#endif
+
static struct platform_driver platform_wdt_driver = {
.driver = {
.name = "pnx4008-watchdog",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pnx4008_wdt_match),
},
.probe = pnx4008_wdt_probe,
.remove = __devexit_p(pnx4008_wdt_remove),
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 04e5a6d..200ece5 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -40,6 +40,7 @@
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <mach/map.h>
@@ -201,7 +202,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
writel(count, wdt_base + S3C2410_WTDAT);
writel(wtcon, wdt_base + S3C2410_WTCON);
- wdd->timeout = timeout;
+ wdd->timeout = (count * divisor) / freq;
return 0;
}
@@ -503,8 +504,6 @@ static const struct of_device_id s3c2410_wdt_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
-#else
-#define s3c2410_wdt_match NULL
#endif
static struct platform_driver s3c2410wdt_driver = {
@@ -516,7 +515,7 @@ static struct platform_driver s3c2410wdt_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",
- .of_match_table = s3c2410_wdt_match,
+ .of_match_table = of_match_ptr(s3c2410_wdt_match),
},
};
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index bd86f32..f847700 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -41,7 +41,6 @@
#define DRV_NAME "sch311x_wdt"
/* Runtime registers */
-#define RESGEN 0x1d
#define GP60 0x47
#define WDT_TIME_OUT 0x65
#define WDT_VAL 0x66
@@ -69,10 +68,6 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-static unsigned short therm_trip;
-module_param(therm_trip, ushort, 0);
-MODULE_PARM_DESC(therm_trip, "Should a ThermTrip trigger the reset generator");
-
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
@@ -358,26 +353,16 @@ static struct miscdevice sch311x_wdt_miscdev = {
static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- unsigned char val;
int err;
spin_lock_init(&sch311x_wdt_data.io_lock);
- if (!request_region(sch311x_wdt_data.runtime_reg + RESGEN, 1,
- DRV_NAME)) {
- dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
- sch311x_wdt_data.runtime_reg + RESGEN,
- sch311x_wdt_data.runtime_reg + RESGEN);
- err = -EBUSY;
- goto exit;
- }
-
if (!request_region(sch311x_wdt_data.runtime_reg + GP60, 1, DRV_NAME)) {
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
sch311x_wdt_data.runtime_reg + GP60,
sch311x_wdt_data.runtime_reg + GP60);
err = -EBUSY;
- goto exit_release_region;
+ goto exit;
}
if (!request_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4,
@@ -386,7 +371,7 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
sch311x_wdt_data.runtime_reg + WDT_TIME_OUT,
sch311x_wdt_data.runtime_reg + WDT_CTRL);
err = -EBUSY;
- goto exit_release_region2;
+ goto exit_release_region;
}
/* Make sure that the watchdog is not running */
@@ -414,24 +399,13 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
/* Get status at boot */
sch311x_wdt_get_status(&sch311x_wdt_data.boot_status);
- /* enable watchdog */
- /* -- Reset Generator --
- * Bit 0 Enable Watchdog Timer Generation: 0* = Enabled, 1 = Disabled
- * Bit 1 Thermtrip Source Select: O* = No Source, 1 = Source
- * Bit 2 WDT2_CTL: WDT input bit
- * Bit 3-7 Reserved
- */
- outb(0, sch311x_wdt_data.runtime_reg + RESGEN);
- val = therm_trip ? 0x06 : 0x04;
- outb(val, sch311x_wdt_data.runtime_reg + RESGEN);
-
sch311x_wdt_miscdev.parent = dev;
err = misc_register(&sch311x_wdt_miscdev);
if (err != 0) {
dev_err(dev, "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, err);
- goto exit_release_region3;
+ goto exit_release_region2;
}
dev_info(dev,
@@ -440,12 +414,10 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
return 0;
-exit_release_region3:
- release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region2:
- release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
+ release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region:
- release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
+ release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
sch311x_wdt_data.runtime_reg = 0;
exit:
return err;
@@ -461,7 +433,6 @@ static int __devexit sch311x_wdt_remove(struct platform_device *pdev)
misc_deregister(&sch311x_wdt_miscdev);
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
- release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
sch311x_wdt_data.runtime_reg = 0;
return 0;
}
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 93958a7..e5b59be 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -3,7 +3,7 @@
*
* Watchdog driver for integrated watchdog in the SuperH processors.
*
- * Copyright (C) 2001 - 2010 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2001 - 2012 Paul Mundt <lethal@linux-sh.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
@@ -25,16 +25,15 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/ioport.h>
+#include <linux/pm_runtime.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/clk.h>
#include <asm/watchdog.h>
#define DRV_NAME "sh-wdt"
@@ -69,10 +68,6 @@
static int clock_division_ratio = WTCSR_CKS_4096;
#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
-static const struct watchdog_info sh_wdt_info;
-static struct platform_device *sh_wdt_dev;
-static DEFINE_SPINLOCK(shwdt_lock);
-
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -81,19 +76,22 @@ static unsigned long next_heartbeat;
struct sh_wdt {
void __iomem *base;
struct device *dev;
+ struct clk *clk;
+ spinlock_t lock;
struct timer_list timer;
-
- unsigned long enabled;
- char expect_close;
};
-static void sh_wdt_start(struct sh_wdt *wdt)
+static int sh_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
u8 csr;
- spin_lock_irqsave(&shwdt_lock, flags);
+ pm_runtime_get_sync(wdt->dev);
+ clk_enable(wdt->clk);
+
+ spin_lock_irqsave(&wdt->lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
@@ -122,15 +120,18 @@ static void sh_wdt_start(struct sh_wdt *wdt)
csr &= ~RSTCSR_RSTS;
sh_wdt_write_rstcsr(csr);
#endif
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ return 0;
}
-static void sh_wdt_stop(struct sh_wdt *wdt)
+static int sh_wdt_stop(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
u8 csr;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
del_timer(&wdt->timer);
@@ -138,28 +139,39 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
csr &= ~WTCSR_TME;
sh_wdt_write_csr(csr);
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ clk_disable(wdt->clk);
+ pm_runtime_put_sync(wdt->dev);
+
+ return 0;
}
-static inline void sh_wdt_keepalive(struct sh_wdt *wdt)
+static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ return 0;
}
-static int sh_wdt_set_heartbeat(int t)
+static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
return -EINVAL;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
heartbeat = t;
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ wdt_dev->timeout = t;
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
return 0;
}
@@ -168,7 +180,7 @@ static void sh_wdt_ping(unsigned long data)
struct sh_wdt *wdt = (struct sh_wdt *)data;
unsigned long flags;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
if (time_before(jiffies, next_heartbeat)) {
u8 csr;
@@ -182,137 +194,9 @@ static void sh_wdt_ping(unsigned long data)
} else
dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
"the watchdog\n");
- spin_unlock_irqrestore(&shwdt_lock, flags);
-}
-
-static int sh_wdt_open(struct inode *inode, struct file *file)
-{
- struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
- if (test_and_set_bit(0, &wdt->enabled))
- return -EBUSY;
- if (nowayout)
- __module_get(THIS_MODULE);
-
- file->private_data = wdt;
-
- sh_wdt_start(wdt);
-
- return nonseekable_open(inode, file);
-}
-
-static int sh_wdt_close(struct inode *inode, struct file *file)
-{
- struct sh_wdt *wdt = file->private_data;
-
- if (wdt->expect_close == 42) {
- sh_wdt_stop(wdt);
- } else {
- dev_crit(wdt->dev, "Unexpected close, not "
- "stopping watchdog!\n");
- sh_wdt_keepalive(wdt);
- }
-
- clear_bit(0, &wdt->enabled);
- wdt->expect_close = 0;
-
- return 0;
-}
-
-static ssize_t sh_wdt_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
-{
- struct sh_wdt *wdt = file->private_data;
-
- if (count) {
- if (!nowayout) {
- size_t i;
-
- wdt->expect_close = 0;
-
- for (i = 0; i != count; i++) {
- char c;
- if (get_user(c, buf + i))
- return -EFAULT;
- if (c == 'V')
- wdt->expect_close = 42;
- }
- }
- sh_wdt_keepalive(wdt);
- }
-
- return count;
+ spin_unlock_irqrestore(&wdt->lock, flags);
}
-static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct sh_wdt *wdt = file->private_data;
- int new_heartbeat;
- int options, retval = -EINVAL;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user((struct watchdog_info *)arg,
- &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, (int *)arg);
- case WDIOC_SETOPTIONS:
- if (get_user(options, (int *)arg))
- return -EFAULT;
-
- if (options & WDIOS_DISABLECARD) {
- sh_wdt_stop(wdt);
- retval = 0;
- }
-
- if (options & WDIOS_ENABLECARD) {
- sh_wdt_start(wdt);
- retval = 0;
- }
-
- return retval;
- case WDIOC_KEEPALIVE:
- sh_wdt_keepalive(wdt);
- return 0;
- case WDIOC_SETTIMEOUT:
- if (get_user(new_heartbeat, (int *)arg))
- return -EFAULT;
-
- if (sh_wdt_set_heartbeat(new_heartbeat))
- return -EINVAL;
-
- sh_wdt_keepalive(wdt);
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(heartbeat, (int *)arg);
- default:
- return -ENOTTY;
- }
- return 0;
-}
-
-static int sh_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
- if (code == SYS_DOWN || code == SYS_HALT)
- sh_wdt_stop(wdt);
-
- return NOTIFY_DONE;
-}
-
-static const struct file_operations sh_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = sh_wdt_write,
- .unlocked_ioctl = sh_wdt_ioctl,
- .open = sh_wdt_open,
- .release = sh_wdt_close,
-};
-
static const struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
@@ -320,14 +204,17 @@ static const struct watchdog_info sh_wdt_info = {
.identity = "SH WDT",
};
-static struct notifier_block sh_wdt_notifier = {
- .notifier_call = sh_wdt_notify_sys,
+static const struct watchdog_ops sh_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = sh_wdt_start,
+ .stop = sh_wdt_stop,
+ .ping = sh_wdt_keepalive,
+ .set_timeout = sh_wdt_set_heartbeat,
};
-static struct miscdevice sh_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &sh_wdt_fops,
+static struct watchdog_device sh_wdt_dev = {
+ .info = &sh_wdt_info,
+ .ops = &sh_wdt_ops,
};
static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -347,39 +234,49 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
if (unlikely(!res))
return -EINVAL;
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), DRV_NAME))
- return -EBUSY;
-
wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
- if (unlikely(!wdt)) {
- rc = -ENOMEM;
- goto out_release;
- }
+ if (unlikely(!wdt))
+ return -ENOMEM;
wdt->dev = &pdev->dev;
- wdt->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ wdt->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(wdt->clk)) {
+ /*
+ * Clock framework support is optional, continue on
+ * anyways if we don't find a matching clock.
+ */
+ wdt->clk = NULL;
+ }
+
+ wdt->base = devm_request_and_ioremap(wdt->dev, res);
if (unlikely(!wdt->base)) {
- rc = -ENXIO;
- goto out_err;
+ rc = -EADDRNOTAVAIL;
+ goto err;
}
- rc = register_reboot_notifier(&sh_wdt_notifier);
+ watchdog_set_nowayout(&sh_wdt_dev, nowayout);
+ watchdog_set_drvdata(&sh_wdt_dev, wdt);
+
+ spin_lock_init(&wdt->lock);
+
+ rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
if (unlikely(rc)) {
- dev_err(&pdev->dev,
- "Can't register reboot notifier (err=%d)\n", rc);
- goto out_unmap;
+ /* Default timeout if invalid */
+ sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
+
+ dev_warn(&pdev->dev,
+ "heartbeat value must be 1<=x<=3600, using %d\n",
+ sh_wdt_dev.timeout);
}
- sh_wdt_miscdev.parent = wdt->dev;
+ dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
+ sh_wdt_dev.timeout, nowayout);
- rc = misc_register(&sh_wdt_miscdev);
+ rc = watchdog_register_device(&sh_wdt_dev);
if (unlikely(rc)) {
- dev_err(&pdev->dev,
- "Can't register miscdev on minor=%d (err=%d)\n",
- sh_wdt_miscdev.minor, rc);
- goto out_unreg;
+ dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
+ goto err;
}
init_timer(&wdt->timer);
@@ -388,20 +285,15 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
wdt->timer.expires = next_ping_period(clock_division_ratio);
platform_set_drvdata(pdev, wdt);
- sh_wdt_dev = pdev;
dev_info(&pdev->dev, "initialized.\n");
+ pm_runtime_enable(&pdev->dev);
+
return 0;
-out_unreg:
- unregister_reboot_notifier(&sh_wdt_notifier);
-out_unmap:
- devm_iounmap(&pdev->dev, wdt->base);
-out_err:
- devm_kfree(&pdev->dev, wdt);
-out_release:
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+err:
+ clk_put(wdt->clk);
return rc;
}
@@ -409,36 +301,35 @@ out_release:
static int __devexit sh_wdt_remove(struct platform_device *pdev)
{
struct sh_wdt *wdt = platform_get_drvdata(pdev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
platform_set_drvdata(pdev, NULL);
- misc_deregister(&sh_wdt_miscdev);
+ watchdog_unregister_device(&sh_wdt_dev);
- sh_wdt_dev = NULL;
-
- unregister_reboot_notifier(&sh_wdt_notifier);
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
- devm_iounmap(&pdev->dev, wdt->base);
- devm_kfree(&pdev->dev, wdt);
+ pm_runtime_disable(&pdev->dev);
+ clk_put(wdt->clk);
return 0;
}
+static void sh_wdt_shutdown(struct platform_device *pdev)
+{
+ sh_wdt_stop(&sh_wdt_dev);
+}
+
static struct platform_driver sh_wdt_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .probe = sh_wdt_probe,
- .remove = __devexit_p(sh_wdt_remove),
+ .probe = sh_wdt_probe,
+ .remove = __devexit_p(sh_wdt_remove),
+ .shutdown = sh_wdt_shutdown,
};
static int __init sh_wdt_init(void)
{
- int rc;
-
if (unlikely(clock_division_ratio < 0x5 ||
clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096;
@@ -447,17 +338,6 @@ static int __init sh_wdt_init(void)
clock_division_ratio);
}
- rc = sh_wdt_set_heartbeat(heartbeat);
- if (unlikely(rc)) {
- heartbeat = WATCHDOG_HEARTBEAT;
-
- pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
- heartbeat);
- }
-
- pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
- heartbeat, nowayout);
-
return platform_driver_register(&sh_wdt_driver);
}
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 59108e4..ae5e82c 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -313,7 +313,7 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
tcobase_phys = val;
tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
- if (tcobase == 0) {
+ if (!tcobase) {
pr_err("failed to get tcobase address\n");
goto unreg_mem_region;
}
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index 465e082..5603e31 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -202,6 +202,9 @@ static int __devinit wdt_probe(struct pci_dev *pdev,
goto err_out_release;
}
+ if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
+ timeout = WDT_TIMEOUT;
+
wdt_dev.timeout = timeout;
watchdog_set_nowayout(&wdt_dev, nowayout);
if (readl(wdt_mem) & VIA_WDT_FIRED)
@@ -250,20 +253,7 @@ static struct pci_driver wdt_driver = {
.remove = __devexit_p(wdt_remove),
};
-static int __init wdt_init(void)
-{
- if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
- timeout = WDT_TIMEOUT;
- return pci_register_driver(&wdt_driver);
-}
-
-static void __exit wdt_exit(void)
-{
- pci_unregister_driver(&wdt_driver);
-}
-
-module_init(wdt_init);
-module_exit(wdt_exit);
+module_pci_driver(wdt_driver);
MODULE_AUTHOR("Marc Vertes");
MODULE_DESCRIPTION("Driver for watchdog timer on VIA chipset");
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 1c888c7..e32654e 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -739,39 +739,7 @@ static struct pci_driver wdtpci_driver = {
.remove = __devexit_p(wdtpci_remove_one),
};
-
-/**
- * wdtpci_cleanup:
- *
- * Unload the watchdog. You cannot do this with any file handles open.
- * If your watchdog is set to continue ticking on close and you unload
- * it, well it keeps ticking. We won't get the interrupt but the board
- * will not touch PC memory so all is fine. You just have to load a new
- * module in xx seconds or reboot.
- */
-
-static void __exit wdtpci_cleanup(void)
-{
- pci_unregister_driver(&wdtpci_driver);
-}
-
-
-/**
- * wdtpci_init:
- *
- * Set up the WDT watchdog board. All we have to do is grab the
- * resources we require and bitch if anyone beat us to them.
- * The open() function will actually kick the board off.
- */
-
-static int __init wdtpci_init(void)
-{
- return pci_register_driver(&wdtpci_driver);
-}
-
-
-module_init(wdtpci_init);
-module_exit(wdtpci_cleanup);
+module_pci_driver(wdtpci_driver);
MODULE_AUTHOR("JP Nollmann, Alan Cox");
MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index b1815c5..87d66d2 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -247,8 +247,9 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
if (pdata->update_gpio) {
- ret = gpio_request(pdata->update_gpio,
- "Watchdog update");
+ ret = gpio_request_one(pdata->update_gpio,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW,
+ "Watchdog update");
if (ret < 0) {
dev_err(wm831x->dev,
"Failed to request update GPIO: %d\n",
@@ -256,14 +257,6 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
goto err;
}
- ret = gpio_direction_output(pdata->update_gpio, 0);
- if (ret != 0) {
- dev_err(wm831x->dev,
- "gpio_direction_output returned: %d\n",
- ret);
- goto err_gpio;
- }
-
driver_data->update_gpio = pdata->update_gpio;
/* Make sure the watchdog takes hardware updates */
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index ea20c51..8d2501e 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -71,7 +71,7 @@ config XEN_DEV_EVTCHN
tristate "Xen /dev/xen/evtchn device"
default y
help
- The evtchn driver allows a userspace process to triger event
+ The evtchn driver allows a userspace process to trigger event
channels and to receive notification of an event channel
firing.
If in doubt, say yes.
OpenPOWER on IntegriCloud